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

#include "auth-common.h"

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

#include "lib-signals.h"
#include "buffer.h"
#include "str.h"
#include "ioloop.h"
#include "hash.h"
#include "execv-const.h"
#include "env-util.h"
#include "safe-memset.h"
#include "child-wait.h"
#include "var-expand.h"
#include "db-checkpassword.h"

#include <stdlib.h>
#include <unistd.h>

#define CHECKPASSWORD_MAX_REQUEST_LEN 512

struct chkpw_auth_request {
	struct db_checkpassword *db;
	struct auth_request *request;
	char *auth_password;

	db_checkpassword_callback_t *callback;
	void *context;

	pid_t pid;
	int fd_out, fd_in;
	struct io *io_out, *io_in;

	string_t *input_buf;
	unsigned int output_pos, output_len;

	int exit_status;
	unsigned int exited:1;
};

struct db_checkpassword {
	char *checkpassword_path, *checkpassword_reply_path;

	struct hash_table *clients;
	struct child_wait *child_wait;
};

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");
	}
}

static void checkpassword_request_free(struct chkpw_auth_request **_request)
{
	struct chkpw_auth_request *request = *_request;

	*_request = NULL;

	if (!request->exited)
		child_wait_remove_pid(request->db->child_wait, request->pid);
	checkpassword_request_close(request);

	if (request->auth_password != NULL) {
		safe_memset(request->auth_password, 0,
			    strlen(request->auth_password));
		i_free(request->auth_password);
	}
	auth_request_unref(&request->request);
	str_free(&request->input_buf);
	i_free(request);
}

static void checkpassword_finish(struct chkpw_auth_request **_request,
				 enum db_checkpassword_status status)<commit_msg>checkpassword: Error handling fix<commit_after>/* Copyright (c) 2004-2012 Dovecot authors, see the included COPYING file */

#include "auth-common.h"

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

#include "lib-signals.h"
#include "buffer.h"
#include "str.h"
#include "ioloop.h"
#include "hash.h"
#include "execv-const.h"
#include "env-util.h"
#include "safe-memset.h"
#include "child-wait.h"
#include "var-expand.h"
#include "db-checkpassword.h"

#include <stdlib.h>
#include <unistd.h>

#define CHECKPASSWORD_MAX_REQUEST_LEN 512

struct chkpw_auth_request {
	struct db_checkpassword *db;
	struct auth_request *request;
	char *auth_password;

	db_checkpassword_callback_t *callback;
	void *context;

	pid_t pid;
	int fd_out, fd_in;
	struct io *io_out, *io_in;

	string_t *input_buf;
	unsigned int output_pos, output_len;

	int exit_status;
	unsigned int exited:1;
};

struct db_checkpassword {
	char *checkpassword_path, *checkpassword_reply_path;

	struct hash_table *clients;
	struct child_wait *child_wait;
};

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");
	}
}

static void checkpassword_request_free(struct chkpw_auth_request **_request)
{
	struct chkpw_auth_request *request = *_request;

	*_request = NULL;

	if (!request->exited) {
		hash_table_remove(request->db->clients,
				  POINTER_CAST(request->pid));
		child_wait_remove_pid(request->db->child_wait, request->pid);
	}
	checkpassword_request_close(request);

	if (request->auth_password != <PASSWORD>) {
		safe_memset(request->auth_password, 0,
			    strlen(request->auth_password));
		i_free(request->auth_password);
	}
	auth_request_unref(&request->request);
	str_free(&request->input_buf);
	i_free(request);
}

static void checkpassword_finish(struct chkpw_auth_request **_request,
				 enum db_checkpassword_status status)
{'fraction_non_alphanumeric': 0.14356632247815726, 'fraction_numerical': 0.007545671167593328, 'mean_word_length': 5.457692307692308, 'pattern_counts': {'":': 0, '<': 12, '<?xml version=': 0, '>': 49, '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': '5080674', 'n_tokens_mistral': 1987, 'n_tokens_neox': 1880, 'n_words': 390}