master-login.c revision 5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen/* Copyright (c) 2009-2013 Dovecot authors, see the included COPYING file */
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen#include "lib.h"
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen#include "ioloop.h"
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen#include "ostream.h"
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen#include "fdpass.h"
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen#include "fd-close-on-exec.h"
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen#include "llist.h"
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen#include "str.h"
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen#include "strescape.h"
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen#include "master-service-private.h"
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen#include "master-login.h"
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen#include "master-login-auth.h"
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen#include <sys/stat.h>
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen#include <unistd.h>
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen#define master_login_conn_is_closed(conn) \
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen ((conn)->fd == -1)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen#define master_login_conn_has_clients(conn) \
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen ((conn)->refcount > 1)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstruct master_login_connection {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct master_login_connection *prev, *next;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct master_login *login;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen int refcount;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen int fd;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct io *io;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen struct ostream *output;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen unsigned int login_success:1;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen};
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstruct master_login_postlogin {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct master_login_client *client;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
9dcb7a41eaaf832f641b7743060b5cf5ed7c80b3Timo Sirainen int fd;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct io *io;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen struct timeout *to;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen string_t *input;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen char *username;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen};
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainenstruct master_login {
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen struct master_service *service;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen master_login_callback_t *callback;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen master_login_failure_callback_t *failure_callback;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct master_login_connection *conns;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen struct master_login_auth *auth;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen char *postlogin_socket_path;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen unsigned int postlogin_timeout_secs;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen unsigned int stopping:1;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen};
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic void master_login_conn_close(struct master_login_connection *conn);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic void master_login_conn_unref(struct master_login_connection **_conn);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstruct master_login *
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenmaster_login_init(struct master_service *service,
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen const struct master_login_settings *set)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen{
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct master_login *login;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_assert(set->postlogin_socket_path == NULL ||
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen set->postlogin_timeout_secs > 0);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen login = i_new(struct master_login, 1);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen login->service = service;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen login->callback = set->callback;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen login->failure_callback = set->failure_callback;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen login->auth = master_login_auth_init(set->auth_socket_path,
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen set->request_auth_token);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen login->postlogin_socket_path = i_strdup(set->postlogin_socket_path);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen login->postlogin_timeout_secs = set->postlogin_timeout_secs;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen i_assert(service->login == NULL);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen service->login = login;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen return login;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen}
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenvoid master_login_deinit(struct master_login **_login)
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen{
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct master_login *login = *_login;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen *_login = NULL;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_assert(login->service->login == login);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen login->service->login = NULL;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen master_login_auth_deinit(&login->auth);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen while (login->conns != NULL) {
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen struct master_login_connection *conn = login->conns;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen master_login_conn_close(conn);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen master_login_conn_unref(&conn);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen i_free(login->postlogin_socket_path);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen i_free(login);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen}
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainenstatic int
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainenmaster_login_conn_read_request(struct master_login_connection *conn,
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen struct master_auth_request *req_r,
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen unsigned char data[MASTER_AUTH_MAX_DATA_SIZE],
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen int *client_fd_r)
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen{
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen struct stat st;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen ssize_t ret;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen *client_fd_r = -1;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen ret = fd_read(conn->fd, req_r, sizeof(*req_r), client_fd_r);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (ret != sizeof(*req_r)) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (ret == 0) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen /* disconnected */
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen if (master_login_conn_has_clients(conn))
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_error("Login client disconnected too early");
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen } else if (ret > 0) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen /* request wasn't fully read */
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_error("fd_read() partial input (%d/%d)",
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen (int)ret, (int)sizeof(*req_r));
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen } else {
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen if (errno == EAGAIN)
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen return 0;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen i_error("fd_read() failed: %m");
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen }
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen return -1;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen }
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen if (req_r->data_size != 0) {
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen if (req_r->data_size > MASTER_AUTH_MAX_DATA_SIZE) {
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen i_error("Too large auth data_size sent");
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen return -1;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen /* @UNSAFE */
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen ret = read(conn->fd, data, req_r->data_size);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (ret != (ssize_t)req_r->data_size) {
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen if (ret == 0) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen /* disconnected */
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (master_login_conn_has_clients(conn)) {
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen i_error("Login client disconnected too early "
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen "(while reading data)");
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
9dcb7a41eaaf832f641b7743060b5cf5ed7c80b3Timo Sirainen } else if (ret > 0) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen /* request wasn't fully read */
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_error("Data read partially %d/%u",
9dcb7a41eaaf832f641b7743060b5cf5ed7c80b3Timo Sirainen (int)ret, req_r->data_size);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen } else {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_error("read(data) failed: %m");
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen }
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen return -1;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (*client_fd_r == -1) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_error("Auth request missing a file descriptor");
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen return -1;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen }
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (fstat(*client_fd_r, &st) < 0) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_error("fstat(fd_read client) failed: %m");
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen return -1;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (st.st_ino != req_r->ino) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_error("Auth request inode mismatch: %s != %s",
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen dec2str(st.st_ino), dec2str(req_r->ino));
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen return -1;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen return 1;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen}
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic void master_login_client_free(struct master_login_client **_client)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen{
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct master_login_client *client = *_client;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen *_client = NULL;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (client->fd != -1) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (close(client->fd) < 0)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_error("close(fd_read client) failed: %m");
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen /* this client failed (login callback wasn't called).
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen reset prefix to default. */
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_set_failure_prefix("%s: ", client->conn->login->service->name);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen /* FIXME: currently we create a separate connection for each request,
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen so close the connection after we're done with this client */
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (!master_login_conn_is_closed(client->conn)) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_assert(client->conn->refcount > 1);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen client->conn->refcount--;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen master_login_conn_unref(&client->conn);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_free(client);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen}
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic void master_login_auth_finish(struct master_login_client *client,
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen const char *const *auth_args)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen{
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct master_login *login = client->conn->login;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct master_service *service = login->service;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen bool close_sockets;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen close_sockets = service->master_status.available_count == 0 &&
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen service->service_count_left == 1;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen client->conn->login_success = TRUE;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen login->callback(client, auth_args[0], auth_args+1);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (close_sockets) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen /* we're dying as soon as this connection closes. */
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_assert(master_login_auth_request_count(login->auth) == 0);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen master_login_auth_disconnect(login->auth);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen master_service_close_config_fd(service);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen } else if (login->stopping) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen /* try stopping again */
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen master_login_stop(login);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen client->fd = -1;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen master_login_client_free(&client);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen}
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic void master_login_postlogin_free(struct master_login_postlogin *pl)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen{
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen timeout_remove(&pl->to);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen io_remove(&pl->io);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (close(pl->fd) < 0)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_error("close(postlogin) failed: %m");
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen str_free(&pl->input);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_free(pl->username);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_free(pl);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen}
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic void master_login_postlogin_input(struct master_login_postlogin *pl)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen{
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct master_login *login = pl->client->conn->login;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen char buf[1024];
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen const char **auth_args, **p;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen unsigned int len;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen ssize_t ret;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen int fd = -1;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen while ((ret = fd_read(pl->fd, buf, sizeof(buf), &fd)) > 0) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (fd != -1) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen /* post-login script replaced fd */
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (close(pl->client->fd) < 0)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_error("close(client) failed: %m");
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen pl->client->fd = fd;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen str_append_n(pl->input, buf, ret);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen len = str_len(pl->input);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (len > 0 && str_c(pl->input)[len-1] == '\n') {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen /* finished reading the input */
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen str_truncate(pl->input, len-1);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen } else {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (ret < 0) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (errno == EAGAIN)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen return;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_error("fd_read(%s) failed: %m",
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen login->postlogin_socket_path);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen } else if (str_len(pl->input) > 0) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_error("fd_read(%s) failed: disconnected",
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen login->postlogin_socket_path);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen } else {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_info("Post-login script denied access to user %s",
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen pl->username);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen master_login_client_free(&pl->client);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen master_login_postlogin_free(pl);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen return;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen auth_args = t_strsplit_tab(str_c(pl->input));
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen for (p = auth_args; *p != NULL; p++)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen *p = str_tabunescape(t_strdup_noconst(*p));
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen master_login_auth_finish(pl->client, auth_args);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen master_login_postlogin_free(pl);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen}
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic void master_login_postlogin_timeout(struct master_login_postlogin *pl)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen{
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct master_login *login = pl->client->conn->login;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_error("%s: Timeout waiting for post-login script to finish, aborting",
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen login->postlogin_socket_path);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen master_login_client_free(&pl->client);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen master_login_postlogin_free(pl);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen}
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic int master_login_postlogin(struct master_login_client *client,
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen const char *const *auth_args)
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen{
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen struct master_login *login = client->conn->login;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen struct master_login_postlogin *pl;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen string_t *str;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen unsigned int i;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen int fd;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen ssize_t ret;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen fd = net_connect_unix_with_retries(login->postlogin_socket_path, 1000);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen if (fd == -1) {
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen i_error("net_connect_unix(%s) failed: %m",
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen login->postlogin_socket_path);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen return -1;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen str = t_str_new(256);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen str_printfa(str, "VERSION\tscript-login\t1\t0\n"
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen "%s\t%s", net_ip2addr(&client->auth_req.local_ip),
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen net_ip2addr(&client->auth_req.remote_ip));
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen for (i = 0; auth_args[i] != NULL; i++) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen str_append_c(str, '\t');
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen str_append_tabescaped(str, auth_args[i]);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen str_append_c(str, '\n');
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen ret = fd_send(fd, client->fd, str_data(str), str_len(str));
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen if (ret != (ssize_t)str_len(str)) {
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen if (ret < 0) {
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen i_error("write(%s) failed: %m",
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen login->postlogin_socket_path);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen } else {
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen i_error("write(%s) failed: partial write",
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen login->postlogin_socket_path);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_close_fd(&fd);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen return -1;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen net_set_nonblock(fd, TRUE);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen pl = i_new(struct master_login_postlogin, 1);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen pl->client = client;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen pl->username = i_strdup(auth_args[0]);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen pl->fd = fd;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen pl->io = io_add(fd, IO_READ, master_login_postlogin_input, pl);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen pl->to = timeout_add(login->postlogin_timeout_secs * 1000,
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen master_login_postlogin_timeout, pl);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen pl->input = str_new(default_pool, 512);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen return 0;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen}
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic void
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenmaster_login_auth_callback(const char *const *auth_args, const char *errormsg,
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen void *context)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen{
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct master_login_client *client = context;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct master_login_connection *conn = client->conn;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct master_auth_reply reply;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen memset(&reply, 0, sizeof(reply));
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen reply.tag = client->auth_req.tag;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen reply.status = errormsg == NULL ? MASTER_AUTH_STATUS_OK :
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen MASTER_AUTH_STATUS_INTERNAL_ERROR;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen reply.mail_pid = getpid();
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen o_stream_nsend(conn->output, &reply, sizeof(reply));
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (errormsg != NULL || auth_args[0] == NULL) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (auth_args != NULL) {
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen i_error("login client: Username missing from auth reply");
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen errormsg = MASTER_AUTH_ERRMSG_INTERNAL_FAILURE;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen }
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen conn->login->failure_callback(client, errormsg);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen master_login_client_free(&client);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen return;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_set_failure_prefix("%s(%s): ", client->conn->login->service->name,
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen auth_args[0]);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen if (conn->login->postlogin_socket_path == NULL)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen master_login_auth_finish(client, auth_args);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen else {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen /* we've sent the reply. the connection is no longer needed,
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen so disconnect it (before login process disconnects us and
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen logs an error) */
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen master_login_conn_close(conn);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen master_login_conn_unref(&conn);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen /* execute post-login scripts before finishing auth */
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (master_login_postlogin(client, auth_args) < 0)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen master_login_client_free(&client);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen}
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic void master_login_conn_input(struct master_login_connection *conn)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen{
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct master_auth_request req;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct master_login_client *client;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct master_login *login = conn->login;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen unsigned char data[MASTER_AUTH_MAX_DATA_SIZE];
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen unsigned int i, session_len = 0;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen int ret, client_fd;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen ret = master_login_conn_read_request(conn, &req, data, &client_fd);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (ret <= 0) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (ret < 0) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen master_login_conn_close(conn);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen master_login_conn_unref(&conn);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (client_fd != -1) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (close(client_fd) < 0)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_error("close(fd_read client) failed: %m");
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen }
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen return;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen }
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen fd_close_on_exec(client_fd, TRUE);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen /* extract the session ID from the request data */
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen for (i = 0; i < req.data_size; i++) {
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen if (data[i] == '\0') {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen session_len = i++;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen break;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen }
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen }
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen if (session_len >= sizeof(client->session_id)) {
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen i_error("login client: Session ID too long");
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen session_len = 0;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen }
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen /* @UNSAFE: we have a request. do userdb lookup for it. */
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen req.data_size -= i;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen client = i_malloc(sizeof(struct master_login_client) + req.data_size);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen client->conn = conn;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen client->fd = client_fd;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen client->auth_req = req;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen memcpy(client->session_id, data, session_len);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen memcpy(client->data, data+i, req.data_size);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen conn->refcount++;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen master_login_auth_request(login->auth, &req,
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen master_login_auth_callback, client);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen}
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainenvoid master_login_add(struct master_login *login, int fd)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen{
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct master_login_connection *conn;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen conn = i_new(struct master_login_connection, 1);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen conn->refcount = 1;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen conn->login = login;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen conn->fd = fd;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen conn->io = io_add(conn->fd, IO_READ, master_login_conn_input, conn);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen o_stream_set_no_error_handling(conn->output, TRUE);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen DLLIST_PREPEND(&login->conns, conn);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen /* NOTE: currently there's a separate connection for each request. */
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen}
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic void master_login_conn_close(struct master_login_connection *conn)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen{
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (master_login_conn_is_closed(conn))
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen return;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen DLLIST_REMOVE(&conn->login->conns, conn);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (conn->io != NULL)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen io_remove(&conn->io);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen o_stream_close(conn->output);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen if (close(conn->fd) < 0)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen i_error("close(master login) failed: %m");
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen conn->fd = -1;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen}
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic void master_login_conn_unref(struct master_login_connection **_conn)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen{
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct master_login_connection *conn = *_conn;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen i_assert(conn->refcount > 0);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen if (--conn->refcount > 0)
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen return;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen *_conn = NULL;
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen master_login_conn_close(conn);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen o_stream_unref(&conn->output);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen if (!conn->login_success)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen master_service_client_connection_destroyed(conn->login->service);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen i_free(conn);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen}
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainenvoid master_login_stop(struct master_login *login)
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen{
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen login->stopping = TRUE;
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen if (master_login_auth_request_count(login->auth) == 0) {
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen master_login_auth_disconnect(login->auth);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen master_service_close_config_fd(login->service);
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen }
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen}
7ca63fa4166f89fee900b7c14d87d53fbac47242Timo Sirainen