<commit_before>/*
 * Copyright (C) 2015 SektionEins GmbH / <NAME>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * 	http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

// for asprintf on linux
#define _GNU_SOURCE

#include "common.h"
#include "scd.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <gcrypt.h>
#include <locale.h>

// for asprintf with not too old libgpg-error
#ifdef GPGRT_VERSION
#define asprintf gpgrt_asprintf
#endif


struct sec_signature {
	uchar *pSignature;
	unsigned long *pulSignatureLen;
};


static gpg_error_t find_gpg_socket(char *buf, size_t len)
{
	char *tmp, *t, *ext = NULL;
	tmp = getenv("GPG_AGENT_INFO");
	if (tmp) {
		t = strchr(tmp, ':');
		if (t) {
			if (t-tmp + 1 > len)
				return 1;
			strncpy(buf, tmp, t-tmp);
			buf[t-tmp] = '\0';
			return 0;
		}
	}
	tmp = getenv("GNUPGHOME");
	if (tmp) {
		ext = "/S.gpg-agent";
		if (strlen(tmp) + strlen(ext) + 1 > len)
			return 1;
		t = stpcpy(buf, tmp);
		stpcpy(t, ext);
		return 0;
	}
	tmp = getenv("HOME");
	if (tmp) {
		ext = "/.gnupg/S.gpg-agent";
		if (strlen(tmp) + strlen(ext) + 1 > len)
			return 1;
		t = stpcpy(buf, tmp);
		stpcpy(t, ext);
		return 0;
	}
	return 1;
}

static inline int is_optstr_clean(char *str)
{
	while (*str != 0) {
		if (*str < 32) { return 0; }
		str++;
	}
	return 1;
}

gpg_error_t scd_set_option(assuan_context_t ctx, char *key, char *value)
{
	if (!key || *key == 0) {
		SDEBUG("OPTION key not set");
		return 1;
	}
	if (!value) {
		SDEBUG("OPTION value not set for key '%s'", key);
		return 1;
	}

	if (!is_optstr_clean(value) || !is_optstr_clean(key)) {
		SDEBUG("OPTION key or value contains illegal characters for key '%s'", key);
		return 1;
	}

	char *cmd;
	if (asprintf(&cmd, "OPTION %s=%s", key, value) < 0) {
		SDEBUG("OPITON out of memory for key '%s'", key);
		return 1;
	}

	gpg_error_t err;
	err = assuan_transact(ctx, cmd, NULL, NULL, NULL, NULL, NULL, NULL);

	if (err) {
		sec_log_err("error setting OPTION '%s=%s'", key, value);
	}

	free(cmd);
	return err;
}

gpg_error_t scd_agent_connect(assuan_context_t *ctx)
{
	gpg_error_t err;
	char gpg_agent_socket_name[1024];

	if (ctx == NULL) { return 1; }
	if (*ctx != NULL) { return 0; }

	err = find_gpg_socket(gpg_agent_socket_name, 1024);
	if (err) { return err; }

	err = assuan_new(ctx);
	if (err) { return err; }

	err = assuan_socket_connect(*ctx, gpg_agent_socket_name, ASSUAN_INVALID_PID, 0);
	if (err) {
		assuan_release(*ctx);
		*ctx = NULL;
		return err;
	}

	// set options. ignore errors - see debug log for debugging problems
	char *val = NULL;
	val = getenv("GPG_TTY");
	if (!val) {
		val = getenv("TTY");
	}
	if (!val) {
		val = ttyname(0);
	}
	scd_set_option(*ctx, "ttyname", val);

	scd_set_option(*ctx, "display", getenv("DISPLAY"));
	scd_set_option(*ctx, "ttytype", getenv("TERM"));
	scd_set_option(*ctx, "lc-ctype", setlocale(LC_CTYPE, NULL));
	scd_set_option(*ctx, "lc-messages", setlocale(LC_MESSAGES, NULL));
	scd_set_option(*ctx, "xauthority", getenv("XAUTHORITY"));
	scd_set_option(*ctx, "pinentry-user-data", getenv("PINENTRY_USER_DATA"));
	scd_set_option(*ctx, "use-cache-for-signing", getenv("GPG_USE_CACHE_FOR_SIGNING"));
	scd_set_option(*ctx, "allow-pinentry-notify", getenv("GPG_ALLOW_PINENTRY_NOTIFY"));
	scd_set_option(*ctx, "pinentry-mode", getenv("PINENTRY_MODE"));
	scd_set_option(*ctx, "cache-ttl-opt-preset", getenv("GPG_CACHE_TTL_OPT_PRESET"));
	scd_set_option(*ctx, "s2k-count", getenv("GPG_S2K_COUNT"));

	return 0;<commit_msg>debug log when agent path cannot be found or failed to connect<commit_after>/*
 * Copyright (C) 2015 SektionEins GmbH / <NAME>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * 	http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

// for asprintf on linux
#define _GNU_SOURCE

#include "common.h"
#include "scd.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <gcrypt.h>
#include <locale.h>

// for asprintf with not too old libgpg-error
#ifdef GPGRT_VERSION
#define asprintf gpgrt_asprintf
#endif


struct sec_signature {
	uchar *pSignature;
	unsigned long *pulSignatureLen;
};


static gpg_error_t find_gpg_socket(char *buf, size_t len)
{
	char *tmp, *t, *ext = NULL;
	tmp = getenv("GPG_AGENT_INFO");
	if (tmp) {
		t = strchr(tmp, ':');
		if (t) {
			if (t-tmp + 1 > len)
				return 1;
			strncpy(buf, tmp, t-tmp);
			buf[t-tmp] = '\0';
			return 0;
		}
	}
	tmp = getenv("GNUPGHOME");
	if (tmp) {
		ext = "/S.gpg-agent";
		if (strlen(tmp) + strlen(ext) + 1 > len)
			return 1;
		t = stpcpy(buf, tmp);
		stpcpy(t, ext);
		return 0;
	}
	tmp = getenv("HOME");
	if (tmp) {
		ext = "/.gnupg/S.gpg-agent";
		if (strlen(tmp) + strlen(ext) + 1 > len)
			return 1;
		t = stpcpy(buf, tmp);
		stpcpy(t, ext);
		return 0;
	}
	return 1;
}

static inline int is_optstr_clean(char *str)
{
	while (*str != 0) {
		if (*str < 32) { return 0; }
		str++;
	}
	return 1;
}

gpg_error_t scd_set_option(assuan_context_t ctx, char *key, char *value)
{
	if (!key || *key == 0) {
		SDEBUG("OPTION key not set");
		return 1;
	}
	if (!value) {
		SDEBUG("OPTION value not set for key '%s'", key);
		return 1;
	}

	if (!is_optstr_clean(value) || !is_optstr_clean(key)) {
		SDEBUG("OPTION key or value contains illegal characters for key '%s'", key);
		return 1;
	}

	char *cmd;
	if (asprintf(&cmd, "OPTION %s=%s", key, value) < 0) {
		SDEBUG("OPITON out of memory for key '%s'", key);
		return 1;
	}

	gpg_error_t err;
	err = assuan_transact(ctx, cmd, NULL, NULL, NULL, NULL, NULL, NULL);

	if (err) {
		sec_log_err("error setting OPTION '%s=%s'", key, value);
	}

	free(cmd);
	return err;
}

gpg_error_t scd_agent_connect(assuan_context_t *ctx)
{
	gpg_error_t err;
	char gpg_agent_socket_name[1024];

	if (ctx == NULL) { return 1; }
	if (*ctx != NULL) { return 0; }

	err = find_gpg_socket(gpg_agent_socket_name, 1024);
	if (err) { 
		SDEBUG("Could not find agent path, check env. variables");
		return err; 
	}

	err = assuan_new(ctx);
	if (err) { return err; }

	err = assuan_socket_connect(*ctx, gpg_agent_socket_name, ASSUAN_INVALID_PID, 0);
	if (err) {
		assuan_release(*ctx);
		*ctx = NULL;
		SDEBUG("Could not connect to agent via socket: '%s'", gpg_agent_socket_name);
		return err;
	}

	// set options. ignore errors - see debug log for debugging problems
	char *val = NULL;
	val = getenv("GPG_TTY");
	if (!val) {
		val = getenv("TTY");
	}
	if (!val) {
		val = ttyname(0);
	}
	scd_set_option(*ctx, "ttyname", val);

	scd_set_option(*ctx, "display", getenv("DISPLAY"));
	scd_set_option(*ctx, "ttytype", getenv("TERM"));
	scd_set_option(*ctx, "lc-ctype", setlocale(LC_CTYPE, NULL));
	scd_set_option(*ctx, "lc-messages", setlocale(LC_MESSAGES, NULL));
	scd_set_option(*ctx, "xauthority", getenv("XAUTHORITY"));
	scd_set_option(*ctx, "pinentry-user-data", getenv("PINENTRY_USER_DATA"));
	scd_set_option(*ctx, "use-cache-for-signing", getenv("GPG_USE_CACHE_FOR_SIGNING"));
	scd_set_option(*ctx, "allow-pinentry-notify", getenv("GPG_ALLOW_PINENTRY_NOTIFY"));
	scd_set_option(*ctx, "pinentry-mode", getenv("PINENTRY_MODE"));
	scd_set_option(*ctx, "cache-ttl-opt-preset", getenv("GPG_CACHE_TTL_OPT_PRESET"));
	scd_set_option(*ctx, "s2k-count", getenv("GPG_S2K_COUNT"));

	return 0;
{'fraction_non_alphanumeric': 0.15537947257645165, 'fraction_numerical': 0.011142751021418843, 'mean_word_length': 4.29011132940406, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6352585', 'n_tokens_mistral': 3372, 'n_tokens_neox': 3170, 'n_words': 840}