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

#include "lib.h"
#include "array.h"
#include "ioloop.h"
#include "network.h"
#include "istream.h"
#include "ostream.h"
#include "env-util.h"
#include "restrict-access.h"
#include "auth-client.h"

#include <stdlib.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include <sysexits.h>

#define AUTH_REQUEST_TIMEOUT 60
#define MAX_INBUF_SIZE 8192
#define MAX_OUTBUF_SIZE 512

static int return_value;

struct auth_connection {
	int fd;
	struct timeout *to;
	struct io *io;
	struct istream *input;
	struct ostream *output;

	struct ioloop *ioloop;
	uid_t euid;
	const char *auth_socket;
	const char *user;
	ARRAY_TYPE(string) *extra_fields;

	unsigned int handshaked:1;
};

static void auth_connection_destroy(struct auth_connection *conn)
{
	io_loop_stop(conn->ioloop);

	if (conn->to != NULL)
		timeout_remove(&conn->to);
	io_remove(&conn->io);
	i_stream_unref(&conn->input);
	o_stream_unref(&conn->output);
	if (close(conn->fd) < 0)
		i_error("close() failed: %m");
	i_free(conn);
}

static bool parse_uid(const char *str, uid_t *uid_r)
{
	struct passwd *pw;
	char *p;

	if (*str >= '0' && *str <= '9') {
		*uid_r = (uid_t)strtoul(str, &p, 10);
		if (*p == '\0')
			return TRUE;
	}

	pw = getpwnam(str);
	if (pw == NULL)
		return FALSE;

	*uid_r = pw->pw_uid;
	return TRUE;
}

static bool parse_gid(const char *str, gid_t *gid_r)
{
	struct group *gr;
	char *p;

	if (*str >= '0' && *str <= '9') {
		*gid_r = (gid_t)strtoul(str, &p, 10);
		if (*p == '\0')
			return TRUE;
	}

	gr = getgrnam(str);
	if (gr == NULL)
		return FALSE;

	*gid_r = gr->gr_gid;
	return TRUE;
}

static void auth_parse_input(struct auth_connection *conn, const char *args)
{
	const char *const *tmp, *extra_groups;
	uid_t uid = 0;
	gid_t gid = 0;
	const char *chroot = getenv("MAIL_CHROOT");
	bool debug = getenv("DEBUG") != NULL;

	for (tmp = t_strsplit(args, "\t"); *tmp != NULL; tmp++) {
		if (debug)
			i_info("auth input: %s", *tmp);

		if (strncmp(*tmp, "uid=", 4) == 0) {
			uid = strtoul(*tmp + 4, NULL, 10);

			if (uid == 0) {
				i_error("userdb(%s) returned 0 as uid",
					conn->user);
				return_value = EX_TEMPFAIL;
			}
			if (conn->euid != uid) {
				env_put(t_strconcat("RESTRICT_SETUID=",
						    dec2str(uid), NULL));
			}
		} else if (strncmp(*tmp, "gid=", 4) == 0) {
			gid = strtoul(*tmp + 4, NULL, 10);

			if (gid == 0) {
				i_error("userdb(%s) returned 0 as gid",
					conn->user);
				return_value = EX_TEMPFAIL;
			}

			if (conn->euid == 0 || getegid() != gid) {
				env_put(t_strconcat("RESTRICT_SETGID=",
						    *tmp + 4, NULL));
			}
		} else if (strncmp(*tmp, "chroot=", 7) == 0) {
			chroot = *tmp + 7;
		} else {
			char *field = i_strdup(*tmp);

			if (strncmp(field, "home=", 5) == 0)
				env_put(t_strconcat("HOME=", field + 5, NULL));

			array_append(conn->extra_fields, &field, 1);
		}
	}

	if (uid == 0 && getenv("MAIL_UID")) {
		if (!parse_uid(getenv("MAIL_UID"), &uid) || uid == 0) {
			i_error("mail_uid setting is invalid");
			return_value = EX_TEMPFAIL;
			return;
		}
	}
	if (uid == 0) {
		i_error("User %s is missing UID (set mail_uid)", conn->user);
		return_value = EX_TEMPFAIL;
		return;
	}
	if (gid == 0 && getenv("MAIL_GID")) {
		if (!parse_gid(getenv("MAIL_GID"), &gid) || gid == 0) {
			i_error("mail_gid setting is invalid");
			return_value = EX_TEMPFAIL;
			return;
		}
	}
	if (gid == 0) {
		i_error("User %s is missing GID (set mail_gid)", conn->user);
		return_value = EX_TEMPFAIL;
		return;
	}

	if (chroot != NULL)
		env_put(t_strconcat("RESTRICT_CHROOT=", chroot, NULL));

	extra_groups = getenv("MAIL_EXTRA_GROUPS");
	if (extra_groups != NULL) {
		env_put(t_strconcat("RESTRICT_SETEXTRAGROUPS=",
				    extra_groups, NULL));
	}

	restrict_access_by_env(TRUE);
	return_value = EX_OK;
}

static void auth_input(struct auth_connection *conn)
{
	const char *line;

	switch (i_stream_read(conn->input)) {
	case 0:
		return;
	case -1:
		/* disconnected */
		auth_connection_destroy(conn);
		return;
	case -2:<commit_msg>mail_uid and mail_gid settings weren't handled correctly.<commit_after>/* Copyright (c) 2005-2008 Dovecot authors, see the included COPYING file */

#include "lib.h"
#include "array.h"
#include "ioloop.h"
#include "network.h"
#include "istream.h"
#include "ostream.h"
#include "env-util.h"
#include "restrict-access.h"
#include "auth-client.h"

#include <stdlib.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include <sysexits.h>

#define AUTH_REQUEST_TIMEOUT 60
#define MAX_INBUF_SIZE 8192
#define MAX_OUTBUF_SIZE 512

static int return_value;

struct auth_connection {
	int fd;
	struct timeout *to;
	struct io *io;
	struct istream *input;
	struct ostream *output;

	struct ioloop *ioloop;
	uid_t euid;
	const char *auth_socket;
	const char *user;
	ARRAY_TYPE(string) *extra_fields;

	unsigned int handshaked:1;
};

static void auth_connection_destroy(struct auth_connection *conn)
{
	io_loop_stop(conn->ioloop);

	if (conn->to != NULL)
		timeout_remove(&conn->to);
	io_remove(&conn->io);
	i_stream_unref(&conn->input);
	o_stream_unref(&conn->output);
	if (close(conn->fd) < 0)
		i_error("close() failed: %m");
	i_free(conn);
}

static bool parse_uid(const char *str, uid_t *uid_r)
{
	struct passwd *pw;
	char *p;

	if (*str >= '0' && *str <= '9') {
		*uid_r = (uid_t)strtoul(str, &p, 10);
		if (*p == '\0')
			return TRUE;
	}

	pw = getpwnam(str);
	if (pw == NULL)
		return FALSE;

	*uid_r = pw->pw_uid;
	return TRUE;
}

static bool parse_gid(const char *str, gid_t *gid_r)
{
	struct group *gr;
	char *p;

	if (*str >= '0' && *str <= '9') {
		*gid_r = (gid_t)strtoul(str, &p, 10);
		if (*p == '\0')
			return TRUE;
	}

	gr = getgrnam(str);
	if (gr == NULL)
		return FALSE;

	*gid_r = gr->gr_gid;
	return TRUE;
}

static void auth_parse_input(struct auth_connection *conn, const char *args)
{
	const char *const *tmp, *extra_groups;
	uid_t uid = 0;
	gid_t gid = 0;
	const char *chroot = getenv("MAIL_CHROOT");
	bool debug = getenv("DEBUG") != NULL;

	for (tmp = t_strsplit(args, "\t"); *tmp != NULL; tmp++) {
		if (debug)
			i_info("auth input: %s", *tmp);

		if (strncmp(*tmp, "uid=", 4) == 0) {
			uid = strtoul(*tmp + 4, NULL, 10);

			if (uid == 0) {
				i_error("userdb(%s) returned 0 as uid",
					conn->user);
				return_value = EX_TEMPFAIL;
			}
		} else if (strncmp(*tmp, "gid=", 4) == 0) {
			gid = strtoul(*tmp + 4, NULL, 10);

			if (gid == 0) {
				i_error("userdb(%s) returned 0 as gid",
					conn->user);
				return_value = EX_TEMPFAIL;
			}
		} else if (strncmp(*tmp, "chroot=", 7) == 0) {
			chroot = *tmp + 7;
		} else {
			char *field = i_strdup(*tmp);

			if (strncmp(field, "home=", 5) == 0)
				env_put(t_strconcat("HOME=", field + 5, NULL));

			array_append(conn->extra_fields, &field, 1);
		}
	}

	if (uid == 0 && getenv("MAIL_UID") != NULL) {
		if (!parse_uid(getenv("MAIL_UID"), &uid) || uid == 0) {
			i_error("mail_uid setting is invalid");
			return_value = EX_TEMPFAIL;
			return;
		}
	}
	if (uid == 0) {
		i_error("User %s is missing UID (set mail_uid)", conn->user);
		return_value = EX_TEMPFAIL;
		return;
	}
	if (gid == 0 && getenv("MAIL_GID") != NULL) {
		if (!parse_gid(getenv("MAIL_GID"), &gid) || gid == 0) {
			i_error("mail_gid setting is invalid");
			return_value = EX_TEMPFAIL;
			return;
		}
	}
	if (gid == 0) {
		i_error("User %s is missing GID (set mail_gid)", conn->user);
		return_value = EX_TEMPFAIL;
		return;
	}

	if (conn->euid != uid)
		env_put(t_strconcat("RESTRICT_SETUID=", dec2str(uid), NULL));
	if (conn->euid == 0 || getegid() != gid)
		env_put(t_strconcat("RESTRICT_SETGID=", dec2str(gid), NULL));

	if (chroot != NULL)
		env_put(t_strconcat("RESTRICT_CHROOT=", chroot, NULL));

	extra_groups = getenv("MAIL_EXTRA_GROUPS");
	if (extra_groups != NULL) {
		env_put(t_strconcat("RESTRICT_SETEXTRAGROUPS=",
				    extra_groups, NULL));
	}

	restrict_access_by_env(TRUE);
	return_value = EX_OK;
}

static void auth_input(struct auth_connection *conn)
{
	const char *line;

	switch (i_stream_read(conn->input)) {
	case 0:
		return;
	case -1:
		/* disconnected */
		auth_connection_destroy(conn);
		return;
	case -2:
{'fraction_non_alphanumeric': 0.1736247544204322, 'fraction_numerical': 0.015717092337917484, 'mean_word_length': 3.9244256348246673, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 51, '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': '1277219', 'n_tokens_mistral': 3721, 'n_tokens_neox': 3332, 'n_words': 800}