<commit_before>/* Copyright (c) 2004-2011 Dovecot authors, see the included COPYING file */

#include "auth-common.h"

#if defined(PASSDB_CHECKPASSWORD) || defined(USERDB_CHECKPASSWORD)

#include "var-expand.h"
#include "db-checkpassword.h"

static void env_put_extra_fields(const char *extra_fields)
{
	const char *const *tmp;
	const char *key, *p;

	for (tmp = t_strsplit(extra_fields, "\t"); *tmp != NULL; tmp++) {
		key = t_str_ucase(t_strcut(*tmp, '='));
		p = strchr(*tmp, '=');
		if (p == NULL)
			env_put(t_strconcat(key, "=1", NULL));
		else
			env_put(t_strconcat(key, p, NULL));
	}
}

static void checkpassword_request_close(struct chkpw_auth_request *request)
{
	if (request->io_in != NULL)
		io_remove(&request->io_in);
	if (request->io_out != NULL)
		io_remove(&request->io_out);

	if (request->fd_in != -1) {
		if (close(request->fd_in) < 0)
			i_error("checkpassword: close() failed: %m");
		request->fd_in = -1;
	}
	if (request->fd_out != -1) {
		if (close(request->fd_out) < 0)
			i_error("checkpassword: close() failed: %m");
	}
}

void checkpassword_request_free(struct chkpw_auth_request *request)
{
	checkpassword_request_close(request);
	if (request->input_buf != NULL)
		str_free(&request->input_buf);

	if (request->password != NULL) {
		safe_memset(request->password, 0, strlen(request->password));
		i_free(request->password);
	}
	i_free(request);
}

enum checkpassword_sigchld_handler_result
checkpassword_sigchld_handler(const struct child_wait_status *child_wait_status,
			      struct chkpw_auth_request *request)
{
	int status = child_wait_status->status;
	pid_t pid = child_wait_status->pid;

	if (request == NULL) {
		i_error("checkpassword: sighandler called for unknown child %s",
			dec2str(pid));
		return SIGCHLD_RESULT_UNKNOWN_CHILD;
	}

	if (WIFSIGNALED(status)) {
		i_error("checkpassword: Child %s died with signal %d",
			dec2str(pid), WTERMSIG(status));
		return SIGCHLD_RESULT_DEAD_CHILD;
	} else if (WIFEXITED(status)) {
		request->exited = TRUE;
		request->exit_status = WEXITSTATUS(status);

		auth_request_log_debug(request->request,
				       "checkpassword", "exit_status=%d",
				       request->exit_status);
		return SIGCHLD_RESULT_OK;
	} else {
		/* shouldn't happen */
		auth_request_log_debug(request->request, "checkpassword",
				       "Child exited with status=%d", status);
		return SIGCHLD_RESULT_UNKNOWN_ERROR;
	}
}

void checkpassword_setup_env(struct auth_request *request)
{
	/* Besides passing the standard username and password in a
	   pipe, also pass some other possibly interesting information
	   via environment. Use UCSPI names for local/remote IPs. */
	env_put("PROTO=TCP"); /* UCSPI */
	env_put(t_strconcat("SERVICE=", request->service, NULL));
	if (request->local_ip.family != 0) {
		env_put(t_strconcat("TCPLOCALIP=",
				    net_ip2addr(&request->local_ip), NULL));
		/* FIXME: for backwards compatibility only,
		   remove some day */
		env_put(t_strconcat("LOCAL_IP=",
				    net_ip2addr(&request->local_ip), NULL));
	}
	if (request->remote_ip.family != 0) {
		env_put(t_strconcat("TCPREMOTEIP=",
				    net_ip2addr(&request->remote_ip), NULL));
		/* FIXME: for backwards compatibility only,
		   remove some day */
		env_put(t_strconcat("REMOTE_IP=",
				    net_ip2addr(&request->remote_ip), NULL));
	}
	if (request->local_port != 0) {
		env_put(t_strdup_printf("TCPLOCALPORT=%u",
					request->local_port));
	}
	if (request->remote_port != 0) {
		env_put(t_strdup_printf("TCPREMOTEPORT=%u",
					request->remote_port));
	}
	if (request->master_user != NULL) {
		env_put(t_strconcat("MASTER_USER=",
				    request->master_user, NULL));
	}
	if (request->extra_fields != NULL) {
		const char *fields =
			auth_stream_reply_export(request->extra_fields);

		/* extra fields could come from master db */
		env_put_extra_fields(fields);
	}
}

const char *
checkpassword_get_cmd(struct auth_request *request, const char *args,
		      const char *checkpassword_reply_path)
{<commit_msg>checkpassword: Export all auth %variables to AUTH_* environment.<commit_after>/* Copyright (c) 2004-2011 Dovecot authors, see the included COPYING file */

#include "auth-common.h"

#if defined(PASSDB_CHECKPASSWORD) || defined(USERDB_CHECKPASSWORD)

#include "var-expand.h"
#include "db-checkpassword.h"

static void env_put_extra_fields(const char *extra_fields)
{
	const char *const *tmp;
	const char *key, *p;

	for (tmp = t_strsplit(extra_fields, "\t"); *tmp != NULL; tmp++) {
		key = t_str_ucase(t_strcut(*tmp, '='));
		p = strchr(*tmp, '=');
		if (p == NULL)
			env_put(t_strconcat(key, "=1", NULL));
		else
			env_put(t_strconcat(key, p, NULL));
	}
}

static void checkpassword_request_close(struct chkpw_auth_request *request)
{
	if (request->io_in != NULL)
		io_remove(&request->io_in);
	if (request->io_out != NULL)
		io_remove(&request->io_out);

	if (request->fd_in != -1) {
		if (close(request->fd_in) < 0)
			i_error("checkpassword: close() failed: %m");
		request->fd_in = -1;
	}
	if (request->fd_out != -1) {
		if (close(request->fd_out) < 0)
			i_error("checkpassword: close() failed: %m");
	}
}

void checkpassword_request_free(struct chkpw_auth_request *request)
{
	checkpassword_request_close(request);
	if (request->input_buf != NULL)
		str_free(&request->input_buf);

	if (request->password != NULL) {
		safe_memset(request->password, 0, strlen(request->password));
		i_free(request->password);
	}
	i_free(request);
}

enum checkpassword_sigchld_handler_result
checkpassword_sigchld_handler(const struct child_wait_status *child_wait_status,
			      struct chkpw_auth_request *request)
{
	int status = child_wait_status->status;
	pid_t pid = child_wait_status->pid;

	if (request == NULL) {
		i_error("checkpassword: sighandler called for unknown child %s",
			dec2str(pid));
		return SIGCHLD_RESULT_UNKNOWN_CHILD;
	}

	if (WIFSIGNALED(status)) {
		i_error("checkpassword: Child %s died with signal %d",
			dec2str(pid), WTERMSIG(status));
		return SIGCHLD_RESULT_DEAD_CHILD;
	} else if (WIFEXITED(status)) {
		request->exited = TRUE;
		request->exit_status = WEXITSTATUS(status);

		auth_request_log_debug(request->request,
				       "checkpassword", "exit_status=%d",
				       request->exit_status);
		return SIGCHLD_RESULT_OK;
	} else {
		/* shouldn't happen */
		auth_request_log_debug(request->request, "checkpassword",
				       "Child exited with status=%d", status);
		return SIGCHLD_RESULT_UNKNOWN_ERROR;
	}
}

static void env_put_auth_vars(struct auth_request *request)
{
	const struct var_expand_table *tab;
	unsigned int i;

	tab = auth_request_get_var_expand_table(request, NULL);
	for (i = 0; tab[i].key != '\0' || tab[i].long_key != NULL; i++) {
		if (tab[i].long_key != NULL && tab[i].value != NULL) {
			env_put(t_strdup_printf("AUTH_%s=%s",
						t_str_ucase(tab[i].long_key),
						tab[i].value));
		}
	}
}

void checkpassword_setup_env(struct auth_request *request)
{
	/* Besides passing the standard username and password in a
	   pipe, also pass some other possibly interesting information
	   via environment. Use UCSPI names for local/remote IPs. */
	env_put("PROTO=TCP"); /* UCSPI */
	env_put(t_strconcat("SERVICE=", request->service, NULL));
	if (request->local_ip.family != 0) {
		env_put(t_strconcat("TCPLOCALIP=",
				    net_ip2addr(&request->local_ip), NULL));
		/* FIXME: for backwards compatibility only,
		   remove some day */
		env_put(t_strconcat("LOCAL_IP=",
				    net_ip2addr(&request->local_ip), NULL));
	}
	if (request->remote_ip.family != 0) {
		env_put(t_strconcat("TCPREMOTEIP=",
				    net_ip2addr(&request->remote_ip), NULL));
		/* FIXME: for backwards compatibility only,
		   remove some day */
		env_put(t_strconcat("REMOTE_IP=",
				    net_ip2addr(&request->remote_ip), NULL));
	}
	if (request->local_port != 0) {
		env_put(t_strdup_printf("TCPLOCALPORT=%u",
					request->local_port));
	}
	if (request->remote_port != 0) {
		env_put(t_strdup_printf("TCPREMOTEPORT=%u",
					request->remote_port));
	}
	if (request->master_user != NULL) {
		env_put(t_strconcat("MASTER_USER=",
				    request->master_user, NULL));
	}
	if (request->extra_fields != NULL) {
		const char *fields =
			auth_stream_reply_export(request->extra_fields);

		/* extra fields could come from master db */
		env_put_extra_fields(fields);
	}
	env_put_auth_vars(request);
}

const char *
checkpassword_get_cmd(struct auth_request *request, const char *args,
		      const char *checkpassword_reply_path)
{
{'fraction_non_alphanumeric': 0.14263676278628218, 'fraction_numerical': 0.006170641984098731, 'mean_word_length': 4.713898305084745, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 77, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '6584065', 'n_tokens_mistral': 3245, 'n_tokens_neox': 2989, 'n_words': 603}