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

#include "lib.h"
#include "ioloop.h"
#include "ostream.h"
#include "fdpass.h"
#include "fd-close-on-exec.h"
#include "llist.h"
#include "str.h"
#include "strescape.h"
#include "master-service-private.h"
#include "master-login.h"
#include "master-login-auth.h"

#include <sys/stat.h>
#include <unistd.h>

#define MASTER_LOGIN_POSTLOGIN_TIMEOUT_MSECS (60*1000)

#define master_login_conn_is_closed(conn) \
	((conn)->fd == -1)

struct master_login_connection {
	struct master_login_connection *prev, *next;

	struct master_login *login;
	int refcount;
	int fd;
	struct io *io;
	struct ostream *output;

	unsigned int login_success:1;
};

struct master_login_postlogin {
	struct master_login_client *client;

	int fd;
	struct io *io;
	struct timeout *to;
	string_t *input;
};

struct master_login {
	struct master_service *service;
	master_login_callback_t *callback;
	master_login_failure_callback_t *failure_callback;
	struct master_login_connection *conns;
	struct master_login_auth *auth;
	char *postlogin_socket_path;

	unsigned int stopping:1;
};

static void master_login_conn_close(struct master_login_connection *conn);
static void master_login_conn_unref(struct master_login_connection **_conn);

struct master_login *
master_login_init(struct master_service *service, const char *auth_socket_path,
		  const char *postlogin_socket_path,
		  master_login_callback_t *callback,
		  master_login_failure_callback_t *failure_callback)
{
	struct master_login *login;

	login = i_new(struct master_login, 1);
	login->service = service;
	login->callback = callback;
	login->failure_callback = failure_callback;
	login->auth = master_login_auth_init(auth_socket_path);
	login->postlogin_socket_path = i_strdup(postlogin_socket_path);

	i_assert(service->login == NULL);
	service->login = login;
	return login;
}

void master_login_deinit(struct master_login **_login)
{
	struct master_login *login = *_login;

	*_login = NULL;

	i_assert(login->service->login == login);
	login->service->login = NULL;

	master_login_auth_deinit(&login->auth);
	while (login->conns != NULL) {
		struct master_login_connection *conn = login->conns;

		master_login_conn_close(conn);
		master_login_conn_unref(&conn);
	}
	i_free(login->postlogin_socket_path);
	i_free(login);
}

static int
master_login_conn_read_request(struct master_login_connection *conn,
			       struct master_auth_request *req_r,
			       unsigned char data[MASTER_AUTH_MAX_DATA_SIZE],
			       int *client_fd_r)
{
	struct stat st;
	ssize_t ret;

	*client_fd_r = -1;

	ret = fd_read(conn->fd, req_r, sizeof(*req_r), client_fd_r);
	if (ret != sizeof(*req_r)) {
		if (ret == 0) {
			/* disconnected */
		} else if (ret > 0) {
			/* request wasn't fully read */
			i_error("fd_read() partial input (%d/%d)",
				(int)ret, (int)sizeof(*req_r));
		} else {
			if (errno == EAGAIN)
				return 0;

			i_error("fd_read() failed: %m");
		}
		return -1;
	}

	if (req_r->data_size != 0) {
		if (req_r->data_size > MASTER_AUTH_MAX_DATA_SIZE) {
			i_error("Too large auth data_size sent");
			return -1;
		}
		/* @UNSAFE */
		ret = read(conn->fd, data, req_r->data_size);
		if (ret != (ssize_t)req_r->data_size) {
			if (ret == 0) {
				/* disconnected */
			} else if (ret > 0) {<commit_msg>lib-master: Log an error if login client disconnects too early.<commit_after>/* Copyright (c) 2009-2010 Dovecot authors, see the included COPYING file */

#include "lib.h"
#include "ioloop.h"
#include "ostream.h"
#include "fdpass.h"
#include "fd-close-on-exec.h"
#include "llist.h"
#include "str.h"
#include "strescape.h"
#include "master-service-private.h"
#include "master-login.h"
#include "master-login-auth.h"

#include <sys/stat.h>
#include <unistd.h>

#define MASTER_LOGIN_POSTLOGIN_TIMEOUT_MSECS (60*1000)

#define master_login_conn_is_closed(conn) \
	((conn)->fd == -1)
#define master_login_conn_has_clients(conn) \
	((conn)->refcount > 1)

struct master_login_connection {
	struct master_login_connection *prev, *next;

	struct master_login *login;
	int refcount;
	int fd;
	struct io *io;
	struct ostream *output;

	unsigned int login_success:1;
};

struct master_login_postlogin {
	struct master_login_client *client;

	int fd;
	struct io *io;
	struct timeout *to;
	string_t *input;
};

struct master_login {
	struct master_service *service;
	master_login_callback_t *callback;
	master_login_failure_callback_t *failure_callback;
	struct master_login_connection *conns;
	struct master_login_auth *auth;
	char *postlogin_socket_path;

	unsigned int stopping:1;
};

static void master_login_conn_close(struct master_login_connection *conn);
static void master_login_conn_unref(struct master_login_connection **_conn);

struct master_login *
master_login_init(struct master_service *service, const char *auth_socket_path,
		  const char *postlogin_socket_path,
		  master_login_callback_t *callback,
		  master_login_failure_callback_t *failure_callback)
{
	struct master_login *login;

	login = i_new(struct master_login, 1);
	login->service = service;
	login->callback = callback;
	login->failure_callback = failure_callback;
	login->auth = master_login_auth_init(auth_socket_path);
	login->postlogin_socket_path = i_strdup(postlogin_socket_path);

	i_assert(service->login == NULL);
	service->login = login;
	return login;
}

void master_login_deinit(struct master_login **_login)
{
	struct master_login *login = *_login;

	*_login = NULL;

	i_assert(login->service->login == login);
	login->service->login = NULL;

	master_login_auth_deinit(&login->auth);
	while (login->conns != NULL) {
		struct master_login_connection *conn = login->conns;

		master_login_conn_close(conn);
		master_login_conn_unref(&conn);
	}
	i_free(login->postlogin_socket_path);
	i_free(login);
}

static int
master_login_conn_read_request(struct master_login_connection *conn,
			       struct master_auth_request *req_r,
			       unsigned char data[MASTER_AUTH_MAX_DATA_SIZE],
			       int *client_fd_r)
{
	struct stat st;
	ssize_t ret;

	*client_fd_r = -1;

	ret = fd_read(conn->fd, req_r, sizeof(*req_r), client_fd_r);
	if (ret != sizeof(*req_r)) {
		if (ret == 0) {
			/* disconnected */
			if (master_login_conn_has_clients(conn))
				i_error("Login client disconnected too early");
		} else if (ret > 0) {
			/* request wasn't fully read */
			i_error("fd_read() partial input (%d/%d)",
				(int)ret, (int)sizeof(*req_r));
		} else {
			if (errno == EAGAIN)
				return 0;

			i_error("fd_read() failed: %m");
		}
		return -1;
	}

	if (req_r->data_size != 0) {
		if (req_r->data_size > MASTER_AUTH_MAX_DATA_SIZE) {
			i_error("Too large auth data_size sent");
			return -1;
		}
		/* @UNSAFE */
		ret = read(conn->fd, data, req_r->data_size);
		if (ret != (ssize_t)req_r->data_size) {
			if (ret == 0) {
				/* disconnected */
				if (master_login_conn_has_clients(conn)) {
					i_error("Login client disconnected too early "
						"(while reading data)");
				}
			} else if (ret > 0) {
{'fraction_non_alphanumeric': 0.125, 'fraction_numerical': 0.007848173515981735, 'mean_word_length': 4.85547201336675, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 59, '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': '98431', 'n_tokens_mistral': 2713, 'n_tokens_neox': 2506, 'n_words': 552}