auth-process.c revision 657afb33796f8216c568ad813627da89970760be
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (C) 2002 Timo Sirainen */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "common.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "ioloop.h"
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen#include "env-util.h"
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen#include "fd-close-on-exec.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "network.h"
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen#include "istream.h"
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen#include "ostream.h"
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen#include "str.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "restrict-access.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "restrict-process-size.h"
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen#include "auth-process.h"
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen#include "../auth/auth-master-interface.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "log.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainen#include <stdlib.h>
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen#include <unistd.h>
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include <pwd.h>
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include <syslog.h>
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include <sys/stat.h>
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#define MAX_INBUF_SIZE 8192
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#define MAX_OUTBUF_SIZE 65536
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
4c1deab456fe8877bf025d11843167ac1f36327aTimo Sirainenstruct auth_process_group {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct auth_process_group *next;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen int listen_fd;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct auth_settings *set;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainen unsigned int process_count;
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainen struct auth_process *processes;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen};
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstruct auth_process {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct auth_process *next;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen struct auth_process_group *group;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen pid_t pid;
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen int fd;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct io *io;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct istream *input;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct ostream *output;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct hash_table *requests;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen unsigned int private_listener:1;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen unsigned int external:1;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen unsigned int version_received:1;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen unsigned int initialized:1;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen unsigned int in_auth_reply:1;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen};
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic struct timeout *to;
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainenstatic unsigned int auth_tag;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic struct auth_process_group *process_groups;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic void auth_process_destroy(struct auth_process *p);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenvoid auth_process_request(struct auth_process *process, unsigned int login_pid,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen unsigned int login_id, void *context)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen string_t *str;
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen ssize_t ret;
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen t_push();
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen str = t_str_new(256);
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen str_printfa(str, "REQUEST\t%u\t%u\t%u\n",
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen ++auth_tag, login_pid, login_id);
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen ret = o_stream_send(process->output, str_data(str), str_len(str));
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen if (ret != (ssize_t)str_len(str)) {
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen if (ret >= 0) {
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen /* FIXME: well .. I'm not sure if it'd be better to
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen just block here. I don't think this condition should
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen happen often, so this could mean that the auth
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen process is stuck. Or that the computer is just
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen too heavily loaded. Possibility to block infinitely
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen is annoying though, so for now don't do it. */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_warning("Auth process %s transmit buffer full, "
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen "killing..", dec2str(process->pid));
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen auth_process_destroy(process);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen } else {
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen hash_insert(process->requests, POINTER_CAST(auth_tag), context);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen t_pop();
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen}
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainenstatic int
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainenauth_process_input_user(struct auth_process *process, const char *args)
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen void *context;
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen const char *const *list;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen unsigned int id;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* <id> <userid> [..] */
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen list = t_strsplit(args, "\t");
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (list[0] == NULL || list[1] == NULL) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_error("BUG: Auth process %s sent corrupted USER line",
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen dec2str(process->pid));
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen return FALSE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen id = (unsigned int)strtoul(list[0], NULL, 10);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen context = hash_lookup(process->requests, POINTER_CAST(id));
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (context == NULL) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_error("BUG: Auth process %s sent unrequested reply with ID "
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen "%u", dec2str(process->pid), id);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return FALSE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen auth_master_callback(list[1], list + 2, context);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen hash_remove(process->requests, POINTER_CAST(id));
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return TRUE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic int
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenauth_process_input_notfound(struct auth_process *process, const char *args)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen void *context;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen unsigned int id;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen id = (unsigned int)strtoul(args, NULL, 10);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen context = hash_lookup(process->requests, POINTER_CAST(id));
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (context == NULL) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_error("BUG: Auth process %s sent unrequested reply with ID "
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen "%u", dec2str(process->pid), id);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return FALSE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen auth_master_callback(NULL, NULL, context);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen hash_remove(process->requests, POINTER_CAST(id));
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return TRUE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenstatic int
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenauth_process_input_spid(struct auth_process *process, const char *args)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen{
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen unsigned int pid;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (process->initialized) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_error("BUG: Authentication server re-handshaking");
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return FALSE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen pid = (unsigned int)strtoul(args, NULL, 10);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (pid == 0) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_error("BUG: Authentication server said it's PID 0");
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen return FALSE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen if (process->pid != 0 && process->pid != (pid_t)pid) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_error("BUG: Authentication server sent invalid SPID "
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen "(%u != %s)", pid, dec2str(process->pid));
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen return FALSE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen process->pid = pid;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen process->initialized = TRUE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return TRUE;
5494a6bc149da8f02fd25c0434a9d612ac33f659Timo Sirainen}
5494a6bc149da8f02fd25c0434a9d612ac33f659Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic int
3c493c276f599d9b9cd10764876d648003046954Timo Sirainenauth_process_input_fail(struct auth_process *process, const char *args)
72ba6a8227bfdf02282d7e4f4c49194af5c354ddTimo Sirainen{
72ba6a8227bfdf02282d7e4f4c49194af5c354ddTimo Sirainen void *context;
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen const char *error;
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen unsigned int id;
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen
72ba6a8227bfdf02282d7e4f4c49194af5c354ddTimo Sirainen error = strchr(args, '\t');
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen if (error != NULL)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen error++;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen id = (unsigned int)strtoul(args, NULL, 10);
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen context = hash_lookup(process->requests, POINTER_CAST(id));
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen if (context == NULL) {
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen i_error("BUG: Auth process %s sent unrequested reply with ID "
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen "%u", dec2str(process->pid), id);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return FALSE;
5494a6bc149da8f02fd25c0434a9d612ac33f659Timo Sirainen }
5494a6bc149da8f02fd25c0434a9d612ac33f659Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen auth_master_callback(NULL, NULL, context);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen hash_remove(process->requests, POINTER_CAST(id));
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return TRUE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
5494a6bc149da8f02fd25c0434a9d612ac33f659Timo Sirainenstatic void auth_process_input(void *context)
5494a6bc149da8f02fd25c0434a9d612ac33f659Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct auth_process *process = context;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen const char *line;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen int ret;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen switch (i_stream_read(process->input)) {
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen case 0:
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen return;
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen case -1:
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen /* disconnected */
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen auth_process_destroy(process);
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen return;
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen case -2:
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen /* buffer full */
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen i_error("BUG: Auth process %s sent us more than %d "
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen "bytes of data", dec2str(process->pid),
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen (int)MAX_INBUF_SIZE);
7fa561fecd106f0e3f58315db2402f7ba83c4226Timo Sirainen auth_process_destroy(process);
7fa561fecd106f0e3f58315db2402f7ba83c4226Timo Sirainen return;
5494a6bc149da8f02fd25c0434a9d612ac33f659Timo Sirainen }
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen
5494a6bc149da8f02fd25c0434a9d612ac33f659Timo Sirainen if (!process->version_received) {
5494a6bc149da8f02fd25c0434a9d612ac33f659Timo Sirainen line = i_stream_next_line(process->input);
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen if (line == NULL)
5494a6bc149da8f02fd25c0434a9d612ac33f659Timo Sirainen return;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* make sure the major version matches */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (strncmp(line, "VERSION\t", 8) != 0 ||
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen atoi(t_strcut(line + 8, '\t')) !=
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen AUTH_MASTER_PROTOCOL_MAJOR_VERSION) {
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainen i_error("Auth process %s not compatible with master "
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen "process (mixed old and new binaries?)",
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen dec2str(process->pid));
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen auth_process_destroy(process);
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainen return;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen process->version_received = TRUE;
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen }
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen while ((line = i_stream_next_line(process->input)) != NULL) {
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen t_push();
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen if (strncmp(line, "USER\t", 5) == 0)
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen ret = auth_process_input_user(process, line + 5);
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen else if (strncmp(line, "NOTFOUND\t", 9) == 0)
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen ret = auth_process_input_notfound(process, line + 9);
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen else if (strncmp(line, "FAIL\t", 5) == 0)
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen ret = auth_process_input_fail(process, line + 5);
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen else if (strncmp(line, "SPID\t", 5) == 0)
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen ret = auth_process_input_spid(process, line + 5);
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen else
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen ret = TRUE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen t_pop();
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (!ret) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen auth_process_destroy(process);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen break;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic struct auth_process *
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenauth_process_new(pid_t pid, int fd, struct auth_process_group *group)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
c1a6ff4972754448985f179358f236e9032ac8daTimo Sirainen struct auth_process *p;
c1a6ff4972754448985f179358f236e9032ac8daTimo Sirainen const char *handshake;
c1a6ff4972754448985f179358f236e9032ac8daTimo Sirainen
c1a6ff4972754448985f179358f236e9032ac8daTimo Sirainen if (pid != 0)
c1a6ff4972754448985f179358f236e9032ac8daTimo Sirainen PID_ADD_PROCESS_TYPE(pid, PROCESS_TYPE_AUTH);
c1a6ff4972754448985f179358f236e9032ac8daTimo Sirainen
c1a6ff4972754448985f179358f236e9032ac8daTimo Sirainen p = i_new(struct auth_process, 1);
c1a6ff4972754448985f179358f236e9032ac8daTimo Sirainen p->group = group;
c1a6ff4972754448985f179358f236e9032ac8daTimo Sirainen p->pid = pid;
c1a6ff4972754448985f179358f236e9032ac8daTimo Sirainen p->fd = fd;
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen p->io = io_add(fd, IO_READ, auth_process_input, p);
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen p->input = i_stream_create_file(fd, default_pool,
a91bd6256b33729531c33ff8bc66ee1ae95840f9Timo Sirainen MAX_INBUF_SIZE, FALSE);
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen p->output = o_stream_create_file(fd, default_pool, MAX_OUTBUF_SIZE,
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen FALSE);
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen p->requests = hash_create(default_pool, default_pool, 0, NULL, NULL);
a91bd6256b33729531c33ff8bc66ee1ae95840f9Timo Sirainen
c1a6ff4972754448985f179358f236e9032ac8daTimo Sirainen handshake = t_strdup_printf("VERSION\t%u\t%u\n",
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen AUTH_MASTER_PROTOCOL_MAJOR_VERSION,
d61d56a652282cf94910e8836c869f3904da5b16Timo Sirainen AUTH_MASTER_PROTOCOL_MINOR_VERSION);
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen (void)o_stream_send_str(p->output, handshake);
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen if (group->listen_fd == -1)
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen p->private_listener = TRUE;
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen p->next = group->processes;
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen group->processes = p;
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen group->process_count++;
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen return p;
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen}
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen
3c493c276f599d9b9cd10764876d648003046954Timo Sirainenstatic void auth_process_destroy(struct auth_process *p)
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen{
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen struct hash_iterate_context *iter;
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen const char *path;
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen void *key, *value;
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen struct auth_process **pos;
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen if (!p->initialized && io_loop_is_running(ioloop) && !p->external) {
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen i_error("Auth process died too early - shutting down");
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen io_loop_stop(ioloop);
c1a6ff4972754448985f179358f236e9032ac8daTimo Sirainen }
c1a6ff4972754448985f179358f236e9032ac8daTimo Sirainen
c1a6ff4972754448985f179358f236e9032ac8daTimo Sirainen for (pos = &p->group->processes; *pos != NULL; pos = &(*pos)->next) {
c1a6ff4972754448985f179358f236e9032ac8daTimo Sirainen if (*pos == p) {
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen *pos = p->next;
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen break;
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen }
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen }
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen p->group->process_count--;
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen if (p->private_listener) {
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen path = t_strconcat(p->group->set->parent->defaults->login_dir,
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen "/", p->group->set->name, dec2str(p->pid),
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen NULL);
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen (void)unlink(path);
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen }
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen iter = hash_iterate_init(p->requests);
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen while (hash_iterate(iter, &key, &value))
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen auth_master_callback(NULL, NULL, value);
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen hash_iterate_deinit(iter);
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen hash_destroy(p->requests);
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen i_stream_unref(p->input);
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen o_stream_unref(p->output);
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen io_remove(p->io);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (close(p->fd) < 0)
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen i_error("close(auth) failed: %m");
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen i_free(p);
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen}
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainenstatic void
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainensocket_settings_env_put(const char *env_base, struct socket_settings *set)
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen{
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen if (set->path == NULL)
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen return;
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen env_put(t_strdup_printf("%s=%s", env_base, set->path));
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen if (set->mode != 0)
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen env_put(t_strdup_printf("%s_MODE=%o", env_base, set->mode));
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen if (set->user != NULL)
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen env_put(t_strdup_printf("%s_USER=%s", env_base, set->user));
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen if (set->group != NULL)
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen env_put(t_strdup_printf("%s_GROUP=%s", env_base, set->group));
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen}
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainenstatic int connect_auth_socket(struct auth_process_group *group,
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen const char *path)
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen{
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen struct auth_process *auth;
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen int fd;
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen fd = net_connect_unix(path);
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen if (fd == -1) {
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen i_error("net_connect_unix(%s) failed: %m", path);
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen return -1;
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen }
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen net_set_nonblock(fd, TRUE);
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen fd_close_on_exec(fd, TRUE);
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen auth = auth_process_new(0, fd, group);
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen auth->external = TRUE;
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen return 0;
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen}
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainenstatic int auth_process_socket_create(struct auth_settings *auth_set, pid_t pid)
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen{
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen const char *path;
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen mode_t old_umask;
7cf1c7dd3dfd989cba1ed32a8e17c1b031c4629bTimo Sirainen int fd;
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen
fd057522c580091ec9803c0dceb4747d8bcaece5Timo Sirainen path = t_strconcat(auth_set->parent->defaults->login_dir, "/",
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen auth_set->name, pid == 0 ? NULL : dec2str(pid),
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen NULL);
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen (void)unlink(path);
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen old_umask = umask(0117); /* we want 0660 mode for the socket */
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen fd = net_listen_unix(path);
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen umask(old_umask);
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen if (fd < 0)
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen i_fatal("Can't listen in UNIX socket %s: %m", path);
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen net_set_nonblock(fd, TRUE);
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen fd_close_on_exec(fd, TRUE);
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen /* set correct permissions */
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen if (chown(path, master_uid, auth_set->parent->login_gid) < 0) {
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen i_fatal("login: chown(%s, %s, %s) failed: %m",
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen path, dec2str(master_uid),
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen dec2str(auth_set->parent->login_gid));
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen return fd;
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen}
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainenstatic int create_auth_process(struct auth_process_group *group)
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen{
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen struct auth_socket_settings *as;
1e4623e33bc4e37e61fcdc1e24e22327e49e303aTimo Sirainen const char *prefix, *str;
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen struct log_io *log;
bdb026e2dc8a7c77585ed5ba489f0056df8074d4Timo Sirainen pid_t pid;
10a2e8716e9040908fb60fcda56b5315ea4c1312Timo Sirainen int fd[2], log_fd, listen_fd, i;
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen /* see if this is a connect socket */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen as = group->set->sockets;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (as != NULL && strcmp(as->type, "connect") == 0)
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen return connect_auth_socket(group, as->master.path);
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen /* create communication to process with a socket pair */
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0) {
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen i_error("socketpair() failed: %m");
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen return -1;
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen }
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen log_fd = log_create_pipe(&log);
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen if (log_fd < 0)
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen pid = -1;
095c07765b69592c1dd644361f05ee37b1d39bd4Timo Sirainen else {
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen pid = fork();
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen if (pid < 0)
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen i_error("fork() failed: %m");
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen }
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen if (pid < 0) {
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen (void)close(fd[0]);
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen (void)close(fd[1]);
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen (void)close(log_fd);
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen return -1;
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen }
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen if (pid != 0) {
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen /* master */
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen prefix = t_strdup_printf("auth(%s): ", group->set->name);
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen log_set_prefix(log, prefix);
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen net_set_nonblock(fd[0], TRUE);
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen fd_close_on_exec(fd[0], TRUE);
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen auth_process_new(pid, fd[0], group);
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen (void)close(fd[1]);
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen (void)close(log_fd);
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen return 0;
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen }
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen prefix = t_strdup_printf("master-auth(%s): ", group->set->name);
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen log_set_prefix(log, prefix);
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen
4dd0cbd517dc5d1210956a7c3e9e1ae714451dd8Timo Sirainen /* move master communication handle to 0 */
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen if (dup2(fd[1], 0) < 0)
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen i_fatal("dup2(stdin) failed: %m");
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen (void)close(fd[0]);
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen (void)close(fd[1]);
4dd0cbd517dc5d1210956a7c3e9e1ae714451dd8Timo Sirainen
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen /* set stdout to /dev/null, so anything written into it gets ignored. */
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen if (dup2(null_fd, 1) < 0)
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen i_fatal("dup2(stdout) failed: %m");
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen if (dup2(log_fd, 2) < 0)
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen i_fatal("dup2(stderr) failed: %m");
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen child_process_init_env();
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen
253201e2b423d3eceb6a8b41cb3493edeab4d224Timo Sirainen /* move login communication handle to 3. do it last so we can be
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen sure it's not closed afterwards. */
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen listen_fd = group->listen_fd != -1 ? group->listen_fd :
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen auth_process_socket_create(group->set, getpid());
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen if (listen_fd != 3) {
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen if (dup2(listen_fd, 3) < 0)
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen i_fatal("dup2() failed: %m");
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen }
10a2e8716e9040908fb60fcda56b5315ea4c1312Timo Sirainen
10a2e8716e9040908fb60fcda56b5315ea4c1312Timo Sirainen for (i = 0; i <= 3; i++)
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen fd_close_on_exec(i, FALSE);
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen /* setup access environment */
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen restrict_access_set_env(group->set->user, group->set->uid,
ae1a57954535642c09c3b8aee184736ddbb06cdfTimo Sirainen group->set->gid, group->set->chroot,
ae1a57954535642c09c3b8aee184736ddbb06cdfTimo Sirainen 0, 0, NULL);
ae1a57954535642c09c3b8aee184736ddbb06cdfTimo Sirainen
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen /* set other environment */
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen env_put("DOVECOT_MASTER=1");
f35141938f1ce4fd822a589045c7a01e866922a2Timo Sirainen env_put(t_strconcat("MECHANISMS=", group->set->mechanisms, NULL));
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen env_put(t_strconcat("REALMS=", group->set->realms, NULL));
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen env_put(t_strconcat("DEFAULT_REALM=", group->set->default_realm, NULL));
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen env_put(t_strconcat("USERDB=", group->set->userdb, NULL));
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen env_put(t_strconcat("PASSDB=", group->set->passdb, NULL));
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen env_put(t_strconcat("USERNAME_CHARS=", group->set->username_chars, NULL));
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen env_put(t_strconcat("USERNAME_TRANSLATION=",
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen group->set->username_translation, NULL));
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen env_put(t_strconcat("ANONYMOUS_USERNAME=",
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen group->set->anonymous_username, NULL));
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen env_put(t_strdup_printf("CACHE_SIZE=%u", group->set->cache_size));
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen env_put(t_strdup_printf("CACHE_TTL=%u", group->set->cache_ttl));
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen for (as = group->set->sockets, i = 1; as != NULL; as = as->next, i++) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (strcmp(as->type, "listen") != 0)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen continue;
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen str = t_strdup_printf("AUTH_%u", i);
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen socket_settings_env_put(str, &as->client);
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen socket_settings_env_put(t_strconcat(str, "_MASTER", NULL),
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen &as->master);
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen }
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen if (group->set->verbose)
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen env_put("VERBOSE=1");
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen if (group->set->debug)
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen env_put("VERBOSE_DEBUG=1");
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen if (group->set->ssl_require_client_cert)
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen env_put("SSL_REQUIRE_CLIENT_CERT=1");
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen restrict_process_size(group->set->process_size, (unsigned int)-1);
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen /* make sure we don't leak syslog fd, but do it last so that
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen any errors above will be logged */
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen closelog();
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen client_process_exec(group->set->executable, "");
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen i_fatal_status(FATAL_EXEC, "execv(%s) failed: %m",
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen group->set->executable);
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen return -1;
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen}
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainenstruct auth_process *auth_process_find(unsigned int pid)
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen{
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen struct auth_process_group *group;
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen struct auth_process *p;
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen
4b2e3b39bc79281211ba9887ab1ebc6fa21da79aTimo Sirainen for (group = process_groups; group != NULL; group = group->next) {
4b2e3b39bc79281211ba9887ab1ebc6fa21da79aTimo Sirainen for (p = group->processes; p != NULL; p = p->next) {
4b2e3b39bc79281211ba9887ab1ebc6fa21da79aTimo Sirainen if ((unsigned int)p->pid == pid)
4b2e3b39bc79281211ba9887ab1ebc6fa21da79aTimo Sirainen return p;
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen }
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen }
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen
4b2e3b39bc79281211ba9887ab1ebc6fa21da79aTimo Sirainen return NULL;
4b2e3b39bc79281211ba9887ab1ebc6fa21da79aTimo Sirainen}
4b2e3b39bc79281211ba9887ab1ebc6fa21da79aTimo Sirainen
4b2e3b39bc79281211ba9887ab1ebc6fa21da79aTimo Sirainenstatic void auth_process_group_create(struct auth_settings *auth_set)
4b2e3b39bc79281211ba9887ab1ebc6fa21da79aTimo Sirainen{
4b2e3b39bc79281211ba9887ab1ebc6fa21da79aTimo Sirainen struct auth_process_group *group;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen group = i_new(struct auth_process_group, 1);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen group->set = auth_set;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen group->next = process_groups;
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen process_groups = group;
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen
fea7b8b3fc182e415b1875d79587c0aa1adb09d7Timo Sirainen if (auth_set->sockets != NULL &&
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen strcmp(auth_set->sockets->type, "connect") == 0)
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen return;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen /* If we keep long running login processes, we want them to use
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen all the auth processes in round robin. this means we have to create
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen separate socket for all of them. So, group->listen_fd is only
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen used with login_process_per_connection. */
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (auth_set->parent->defaults->login_process_per_connection)
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen group->listen_fd = auth_process_socket_create(auth_set, 0);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen else
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen group->listen_fd = -1;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen}
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainenstatic void auth_process_group_destroy(struct auth_process_group *group)
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen{
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen struct auth_process *next;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen const char *path;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen while (group->processes != NULL) {
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen next = group->processes->next;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen auth_process_destroy(group->processes);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen group->processes = next;
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen }
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen if (group->listen_fd != -1) {
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen path = t_strconcat(group->set->parent->defaults->login_dir, "/",
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen group->set->name, NULL);
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen (void)unlink(path);
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen if (close(group->listen_fd) < 0)
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen i_error("close(%s) failed: %m", path);
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen }
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen i_free(group);
0e5f8c4589cfeccb752307c8ac35a2f1633e4ecaTimo Sirainen}
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainenvoid auth_processes_destroy_all(void)
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen{
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen struct auth_process_group *next;
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen
0e5f8c4589cfeccb752307c8ac35a2f1633e4ecaTimo Sirainen while (process_groups != NULL) {
0e5f8c4589cfeccb752307c8ac35a2f1633e4ecaTimo Sirainen next = process_groups->next;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen auth_process_group_destroy(process_groups);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen process_groups = next;
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen }
bdb026e2dc8a7c77585ed5ba489f0056df8074d4Timo Sirainen}
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainenstatic void auth_process_groups_create(struct server_settings *server)
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen{
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen struct auth_settings *auth_set;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen while (server != NULL) {
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen auth_set = server->auths;
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen for (; auth_set != NULL; auth_set = auth_set->next)
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen auth_process_group_create(auth_set);
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen server = server->next;
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen }
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen}
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen
10a2e8716e9040908fb60fcda56b5315ea4c1312Timo Sirainenstatic void
10a2e8716e9040908fb60fcda56b5315ea4c1312Timo Sirainenauth_processes_start_missing(void *context __attr_unused__)
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen{
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen struct auth_process_group *group;
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen unsigned int count;
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen if (process_groups == NULL) {
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen /* first time here, create the groups */
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen auth_process_groups_create(settings_root);
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen }
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen for (group = process_groups; group != NULL; group = group->next) {
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen count = group->process_count;
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen for (; count < group->set->count; count++)
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen (void)create_auth_process(group);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen }
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen}
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenvoid auth_processes_init(void)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen{
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen process_groups = NULL;
48ca4c43ebca6fa3eee217bd4439cba5b5376dd4Timo Sirainen to = timeout_add(1000, auth_processes_start_missing, NULL);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenvoid auth_processes_deinit(void)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
77c462c3a415536f9c87028ee34546ee96fd1445Timo Sirainen timeout_remove(to);
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen auth_processes_destroy_all();
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen