Mercurial > dovecot > original-hg > dovecot-1.2
view src/auth/login-connection.c @ 1000:0fbafade2d85 HEAD
If auth/login process died unexpectedly, the exit status or killing signal
wasn't logged.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Tue, 21 Jan 2003 09:58:49 +0200 |
parents | d0845dca7eca |
children | fe49ece0f3ea |
line wrap: on
line source
/* Copyright (C) 2002 Timo Sirainen */ #include "common.h" #include "ioloop.h" #include "istream.h" #include "ostream.h" #include "network.h" #include "safe-memset.h" #include "cookie.h" #include "login-connection.h" #include <stdlib.h> #include <syslog.h> #define MAX_INBUF_SIZE \ (sizeof(struct auth_continued_request_data) + \ AUTH_MAX_REQUEST_DATA_SIZE) #define MAX_OUTBUF_SIZE \ (10 * (sizeof(struct auth_reply_data) + AUTH_MAX_REPLY_DATA_SIZE)) struct login_connection { struct login_connection *next; int fd; struct io *io; struct istream *input; struct ostream *output; unsigned int pid; enum auth_request_type type; }; static struct auth_init_data auth_init_data; static struct login_connection *connections; static void request_callback(struct auth_reply_data *reply, const void *data, void *context) { struct login_connection *conn = context; i_assert(reply->data_size <= AUTH_MAX_REPLY_DATA_SIZE); if (o_stream_send(conn->output, reply, sizeof(*reply)) < 0) login_connection_destroy(conn); else if (reply->data_size > 0) { if (o_stream_send(conn->output, data, reply->data_size) < 0) login_connection_destroy(conn); } } static struct login_connection *login_find_pid(unsigned int pid) { struct login_connection *conn; for (conn = connections; conn != NULL; conn = conn->next) { if (conn->pid == pid) return conn; } return NULL; } static void login_input_handshake(struct login_connection *conn) { struct client_auth_init_data rec; unsigned char *data; size_t size; data = i_stream_get_modifyable_data(conn->input, &size); if (size < sizeof(struct client_auth_init_data)) return; /* Don't just cast because of alignment issues. */ memcpy(&rec, data, sizeof(rec)); i_stream_skip(conn->input, sizeof(rec)); if (rec.pid == 0) { i_error("BUG: imap-login said it's PID 0"); login_connection_destroy(conn); } else if (login_find_pid(rec.pid) != NULL) { /* well, it might have just reconnected very fast .. although there's not much reason for it. */ i_error("BUG: imap-login gave a PID of existing connection"); login_connection_destroy(conn); } else { conn->pid = rec.pid; if (verbose) { i_info("Login process %d sent handshake: PID %s", conn->fd, dec2str(conn->pid)); } } } static void login_input_request(struct login_connection *conn) { unsigned char *data; size_t size; data = i_stream_get_modifyable_data(conn->input, &size); if (size < sizeof(enum auth_request_type)) return; /* note that we can't directly cast the received data pointer into structures, as it may not be aligned properly. */ if (conn->type == AUTH_REQUEST_NONE) { /* get the request type */ memcpy(&conn->type, data, sizeof(enum auth_request_type)); } if (conn->type == AUTH_REQUEST_INIT) { struct auth_init_request_data request; if (size < sizeof(request)) return; memcpy(&request, data, sizeof(request)); i_stream_skip(conn->input, sizeof(request)); /* we have a full init request */ auth_init_request(conn->pid, &request, request_callback, conn); conn->type = AUTH_REQUEST_NONE; } else if (conn->type == AUTH_REQUEST_CONTINUE) { struct auth_continued_request_data request; if (size < sizeof(request)) return; memcpy(&request, data, sizeof(request)); if (size < sizeof(request) + request.data_size) return; i_stream_skip(conn->input, sizeof(request) + request.data_size); /* we have a full continued request */ auth_continue_request(conn->pid, &request, data + sizeof(request), request_callback, conn); conn->type = AUTH_REQUEST_NONE; /* clear any sensitive data from memory */ safe_memset(data + sizeof(request), 0, request.data_size); } else { /* unknown request */ i_error("BUG: imap-login sent us unknown request %u", conn->type); login_connection_destroy(conn); } } static void login_input(void *context, int fd __attr_unused__, struct io *io __attr_unused__) { struct login_connection *conn = context; switch (i_stream_read(conn->input)) { case 0: return; case -1: /* disconnected */ login_connection_destroy(conn); return; case -2: /* buffer full */ i_error("BUG: imap-login sent us more than %d bytes of data", (int)MAX_INBUF_SIZE); login_connection_destroy(conn); return; } if (conn->pid == 0) login_input_handshake(conn); else login_input_request(conn); } struct login_connection *login_connection_create(int fd) { struct login_connection *conn; if (verbose) i_info("Login process %d connected", fd); conn = i_new(struct login_connection, 1); conn->fd = fd; conn->input = i_stream_create_file(fd, default_pool, MAX_INBUF_SIZE, FALSE); conn->output = o_stream_create_file(fd, default_pool, MAX_OUTBUF_SIZE, IO_PRIORITY_DEFAULT, FALSE); conn->io = io_add(fd, IO_READ, login_input, conn); conn->type = AUTH_REQUEST_NONE; conn->next = connections; connections = conn; if (o_stream_send(conn->output, &auth_init_data, sizeof(auth_init_data)) < 0) { login_connection_destroy(conn); conn = NULL; } return conn; } void login_connection_destroy(struct login_connection *conn) { struct login_connection **pos; if (verbose) i_info("Login process %d disconnected", conn->fd); for (pos = &connections; *pos != NULL; pos = &(*pos)->next) { if (*pos == conn) { *pos = conn->next; break; } } cookies_remove_login_pid(conn->pid); i_stream_unref(conn->input); o_stream_unref(conn->output); io_remove(conn->io); net_disconnect(conn->fd); i_free(conn); } void login_connections_init(void) { const char *env; env = getenv("AUTH_PROCESS"); if (env == NULL) i_fatal("AUTH_PROCESS environment is unset"); memset(&auth_init_data, 0, sizeof(auth_init_data)); auth_init_data.auth_process = atoi(env); auth_init_data.auth_mechanisms = auth_mechanisms; connections = NULL; } void login_connections_deinit(void) { struct login_connection *next; while (connections != NULL) { next = connections->next; login_connection_destroy(connections); connections = next; } }