<commit_before>/* Copyright (C) 2004-2005 <NAME> */

#include "common.h"

#ifdef PASSDB_CHECKPASSWORD

#include "lib-signals.h"
#include "buffer.h"
#include "str.h"
#include "ioloop.h"
#include "hash.h"
#include "env-util.h"
#include "passdb.h"
#include "safe-memset.h"

#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

struct checkpassword_passdb_module {
	struct passdb_module module;

	const char *checkpassword_path, *checkpassword_reply_path;
	struct hash_table *clients;
};

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

	string_t *input_buf;
	char *password;
	unsigned int write_pos;

	struct auth_request *request;
	verify_plain_callback_t *callback;

	int exit_status;
	unsigned int exited:1;
};

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_finish(struct chkpw_auth_request *request,
					 enum passdb_result result)
{
	struct passdb_module *_module = request->request->passdb->passdb;
	struct checkpassword_passdb_module *module =
		(struct checkpassword_passdb_module *)_module;

	hash_remove(module->clients, POINTER_CAST(request->pid));

	if (request->input_buf != NULL &&
	    strchr(str_c(request->input_buf), '\n') != NULL) {
		auth_request_log_error(request->request, "checkpassword",
				       "LF characters in checkpassword reply");
		result = PASSDB_RESULT_INTERNAL_FAILURE;
	}

	if (result == PASSDB_RESULT_OK) {
		request->request->extra_fields =
			auth_stream_reply_init(request->request);
		auth_stream_reply_import(request->request->extra_fields,
					 str_c(request->input_buf));
	}

	request->callback(result, request->request);
	auth_request_unref(&request->request);

        checkpassword_request_close(request);

	if (request->input_buf != NULL)
		str_free(&request->input_buf);

	safe_memset(request->password, 0, strlen(request->password));
	i_free(request->password);
	i_free(request);
}

static void
checkpassword_request_half_finish(struct chkpw_auth_request *request)
{
	if (!request->exited || request->fd_in != -1)
		return;

	switch (request->exit_status) {
	case 1:
		auth_request_log_info(request->request, "checkpassword",
				      "Password not accepted");
		checkpassword_request_finish(request,
					     PASSDB_RESULT_PASSWORD_MISMATCH);
		break;
	case 0:<commit_msg>Handle vpopmail's nonstandard exit codes.<commit_after>/* Copyright (C) 2004-2005 <NAME> */

#include "common.h"

#ifdef PASSDB_CHECKPASSWORD

#include "lib-signals.h"
#include "buffer.h"
#include "str.h"
#include "ioloop.h"
#include "hash.h"
#include "env-util.h"
#include "passdb.h"
#include "safe-memset.h"

#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

struct checkpassword_passdb_module {
	struct passdb_module module;

	const char *checkpassword_path, *checkpassword_reply_path;
	struct hash_table *clients;
};

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

	string_t *input_buf;
	char *password;
	unsigned int write_pos;

	struct auth_request *request;
	verify_plain_callback_t *callback;

	int exit_status;
	unsigned int exited:1;
};

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_finish(struct chkpw_auth_request *request,
					 enum passdb_result result)
{
	struct passdb_module *_module = request->request->passdb->passdb;
	struct checkpassword_passdb_module *module =
		(struct checkpassword_passdb_module *)_module;

	hash_remove(module->clients, POINTER_CAST(request->pid));

	if (request->input_buf != NULL &&
	    strchr(str_c(request->input_buf), '\n') != NULL) {
		auth_request_log_error(request->request, "checkpassword",
				       "LF characters in checkpassword reply");
		result = PASSDB_RESULT_INTERNAL_FAILURE;
	}

	if (result == PASSDB_RESULT_OK) {
		request->request->extra_fields =
			auth_stream_reply_init(request->request);
		auth_stream_reply_import(request->request->extra_fields,
					 str_c(request->input_buf));
	}

	request->callback(result, request->request);
	auth_request_unref(&request->request);

        checkpassword_request_close(request);

	if (request->input_buf != NULL)
		str_free(&request->input_buf);

	safe_memset(request->password, 0, strlen(request->password));
	i_free(request->password);
	i_free(request);
}

static void
checkpassword_request_half_finish(struct chkpw_auth_request *request)
{
	if (!request->exited || request->fd_in != -1)
		return;

	switch (request->exit_status) {
	/* vpopmail exit codes: */
	case 3:		/* password fail / vpopmail user not found */
	case 12: 	/* null user name given */
	case 13:	/* null password given */
	case 15:	/* user has no password */
	case 20:	/* invalid user/domain characters */
	case 21:	/* system user not found */
	case 22:	/* system user shadow entry not found */
	case 23:	/* system password fail */

	/* standard checkpassword exit codes: */
	case 1:
		/* (1 is additionally defined in vpopmail for
		   "pop/smtp/webmal/ imap/access denied") */
		auth_request_log_info(request->request, "checkpassword",
				      "Login failed (status=%d)",
				      request->exit_status);
		checkpassword_request_finish(request,
					     PASSDB_RESULT_PASSWORD_MISMATCH);
		break;
	case 0:
{'fraction_non_alphanumeric': 0.13363288400732234, 'fraction_numerical': 0.008653686137460476, 'mean_word_length': 4.886385896180215, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 82, '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': '4128743', 'n_tokens_mistral': 2258, 'n_tokens_neox': 2089, 'n_words': 440}