bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen#include "lib.h"
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen#include "ioloop.h"
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen#include "ostream.h"
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen#include "fdpass.h"
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen#include "llist.h"
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen#include "str.h"
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen#include "strescape.h"
3ba9a079592f46e94ce846e5aa80e4d479cd5e41Timo Sirainen#include "master-service-private.h"
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen#include "master-login.h"
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen#include "master-login-auth.h"
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen#include <sys/stat.h>
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen#include <unistd.h>
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
e871bfe83e8c5cc7768de30afe0127a3c4373adeTimo Sirainen#define master_login_conn_is_closed(conn) \
8149f4a09d07464f33de747d8e1e620f6d9f7faeTimo Sirainen ((conn)->fd == -1)
f89e92a6ff4125dc35b4a0cb976da98b3702395cTimo Sirainen#define master_login_conn_has_clients(conn) \
f89e92a6ff4125dc35b4a0cb976da98b3702395cTimo Sirainen ((conn)->refcount > 1)
e871bfe83e8c5cc7768de30afe0127a3c4373adeTimo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstruct master_login_connection {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen struct master_login_connection *prev, *next;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen struct master_login *login;
4e56e6408815c04f2e5b904a648a366a2dcbd408Timo Sirainen int refcount;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen int fd;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen struct io *io;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen struct ostream *output;
baca06331782e2752734199486e51a26d7c93d75Timo Sirainen
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool login_success:1;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen};
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainenstruct master_login_postlogin {
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen struct master_login_client *client;
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen int fd;
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen struct io *io;
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen struct timeout *to;
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen string_t *input;
f633c533a2c793ae188bff21e173e2ff63ba35f9Timo Sirainen char *username;
b3d5afcc92e4ce1452db499b3c956d12447babc7Timo Sirainen char *socket_path;
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen};
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstruct master_login {
3ba9a079592f46e94ce846e5aa80e4d479cd5e41Timo Sirainen struct master_service *service;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen master_login_callback_t *callback;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen master_login_failure_callback_t *failure_callback;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen struct master_login_connection *conns;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen struct master_login_auth *auth;
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen char *postlogin_socket_path;
53dff078a5f49e9d28d6c81d3437755e27526e3eTimo Sirainen unsigned int postlogin_timeout_secs;
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool stopping:1;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen};
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
e871bfe83e8c5cc7768de30afe0127a3c4373adeTimo Sirainenstatic void master_login_conn_close(struct master_login_connection *conn);
4e56e6408815c04f2e5b904a648a366a2dcbd408Timo Sirainenstatic void master_login_conn_unref(struct master_login_connection **_conn);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstruct master_login *
53dff078a5f49e9d28d6c81d3437755e27526e3eTimo Sirainenmaster_login_init(struct master_service *service,
53dff078a5f49e9d28d6c81d3437755e27526e3eTimo Sirainen const struct master_login_settings *set)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen{
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen struct master_login *login;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
53dff078a5f49e9d28d6c81d3437755e27526e3eTimo Sirainen i_assert(set->postlogin_socket_path == NULL ||
53dff078a5f49e9d28d6c81d3437755e27526e3eTimo Sirainen set->postlogin_timeout_secs > 0);
53dff078a5f49e9d28d6c81d3437755e27526e3eTimo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen login = i_new(struct master_login, 1);
3ba9a079592f46e94ce846e5aa80e4d479cd5e41Timo Sirainen login->service = service;
53dff078a5f49e9d28d6c81d3437755e27526e3eTimo Sirainen login->callback = set->callback;
53dff078a5f49e9d28d6c81d3437755e27526e3eTimo Sirainen login->failure_callback = set->failure_callback;
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch login->auth = master_login_auth_init(set->auth_socket_path,
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch set->request_auth_token);
53dff078a5f49e9d28d6c81d3437755e27526e3eTimo Sirainen login->postlogin_socket_path = i_strdup(set->postlogin_socket_path);
53dff078a5f49e9d28d6c81d3437755e27526e3eTimo Sirainen login->postlogin_timeout_secs = set->postlogin_timeout_secs;
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen i_assert(service->login == NULL);
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen service->login = login;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return login;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen}
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenvoid master_login_deinit(struct master_login **_login)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen{
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen struct master_login *login = *_login;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen *_login = NULL;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen i_assert(login->service->login == login);
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen login->service->login = NULL;
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen master_login_auth_deinit(&login->auth);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen while (login->conns != NULL) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen struct master_login_connection *conn = login->conns;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
e871bfe83e8c5cc7768de30afe0127a3c4373adeTimo Sirainen master_login_conn_close(conn);
e871bfe83e8c5cc7768de30afe0127a3c4373adeTimo Sirainen master_login_conn_unref(&conn);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen i_free(login->postlogin_socket_path);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen i_free(login);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen}
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstatic int
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenmaster_login_conn_read_request(struct master_login_connection *conn,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen struct master_auth_request *req_r,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen unsigned char data[MASTER_AUTH_MAX_DATA_SIZE],
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen int *client_fd_r)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen{
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen struct stat st;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen ssize_t ret;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen *client_fd_r = -1;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen ret = fd_read(conn->fd, req_r, sizeof(*req_r), client_fd_r);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (ret != sizeof(*req_r)) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (ret == 0) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* disconnected */
f89e92a6ff4125dc35b4a0cb976da98b3702395cTimo Sirainen if (master_login_conn_has_clients(conn))
f89e92a6ff4125dc35b4a0cb976da98b3702395cTimo Sirainen i_error("Login client disconnected too early");
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen } else if (ret > 0) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* request wasn't fully read */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen i_error("fd_read() partial input (%d/%d)",
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen (int)ret, (int)sizeof(*req_r));
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen } else {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (errno == EAGAIN)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return 0;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen i_error("fd_read() failed: %m");
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return -1;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (req_r->data_size != 0) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (req_r->data_size > MASTER_AUTH_MAX_DATA_SIZE) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen i_error("Too large auth data_size sent");
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return -1;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* @UNSAFE */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen ret = read(conn->fd, data, req_r->data_size);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (ret != (ssize_t)req_r->data_size) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (ret == 0) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* disconnected */
f89e92a6ff4125dc35b4a0cb976da98b3702395cTimo Sirainen if (master_login_conn_has_clients(conn)) {
f89e92a6ff4125dc35b4a0cb976da98b3702395cTimo Sirainen i_error("Login client disconnected too early "
f89e92a6ff4125dc35b4a0cb976da98b3702395cTimo Sirainen "(while reading data)");
f89e92a6ff4125dc35b4a0cb976da98b3702395cTimo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen } else if (ret > 0) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* request wasn't fully read */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen i_error("Data read partially %d/%u",
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen (int)ret, req_r->data_size);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen } else {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen i_error("read(data) failed: %m");
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return -1;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (*client_fd_r == -1) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen i_error("Auth request missing a file descriptor");
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return -1;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (fstat(*client_fd_r, &st) < 0) {
47f1c273dfaea552c034ffbecdec096f7cbaef35Timo Sirainen i_error("fstat(fd_read client) failed: %m");
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return -1;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (st.st_ino != req_r->ino) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen i_error("Auth request inode mismatch: %s != %s",
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen dec2str(st.st_ino), dec2str(req_r->ino));
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return -1;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return 1;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen}
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
4e56e6408815c04f2e5b904a648a366a2dcbd408Timo Sirainenstatic void master_login_client_free(struct master_login_client **_client)
4e56e6408815c04f2e5b904a648a366a2dcbd408Timo Sirainen{
4e56e6408815c04f2e5b904a648a366a2dcbd408Timo Sirainen struct master_login_client *client = *_client;
4e56e6408815c04f2e5b904a648a366a2dcbd408Timo Sirainen
4e56e6408815c04f2e5b904a648a366a2dcbd408Timo Sirainen *_client = NULL;
4e56e6408815c04f2e5b904a648a366a2dcbd408Timo Sirainen if (client->fd != -1) {
4e56e6408815c04f2e5b904a648a366a2dcbd408Timo Sirainen if (close(client->fd) < 0)
4e56e6408815c04f2e5b904a648a366a2dcbd408Timo Sirainen i_error("close(fd_read client) failed: %m");
a7bbdb8faa0dd2c4e9bb094e06fe705856e39cbfTimo Sirainen /* this client failed (login callback wasn't called).
a7bbdb8faa0dd2c4e9bb094e06fe705856e39cbfTimo Sirainen reset prefix to default. */
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen i_set_failure_prefix("%s: ", client->conn->login->service->name);
4e56e6408815c04f2e5b904a648a366a2dcbd408Timo Sirainen }
4e56e6408815c04f2e5b904a648a366a2dcbd408Timo Sirainen
e871bfe83e8c5cc7768de30afe0127a3c4373adeTimo Sirainen /* FIXME: currently we create a separate connection for each request,
e871bfe83e8c5cc7768de30afe0127a3c4373adeTimo Sirainen so close the connection after we're done with this client */
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen if (!master_login_conn_is_closed(client->conn)) {
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen i_assert(client->conn->refcount > 1);
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen client->conn->refcount--;
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen }
4e56e6408815c04f2e5b904a648a366a2dcbd408Timo Sirainen master_login_conn_unref(&client->conn);
404150692ba0f5e710600220c0dccfbdf1b1d7ccTimo Sirainen i_free(client->session_id);
4e56e6408815c04f2e5b904a648a366a2dcbd408Timo Sirainen i_free(client);
4e56e6408815c04f2e5b904a648a366a2dcbd408Timo Sirainen}
4e56e6408815c04f2e5b904a648a366a2dcbd408Timo Sirainen
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainenstatic void master_login_auth_finish(struct master_login_client *client,
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen const char *const *auth_args)
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen{
e871bfe83e8c5cc7768de30afe0127a3c4373adeTimo Sirainen struct master_login *login = client->conn->login;
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen struct master_service *service = login->service;
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen bool close_sockets;
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen close_sockets = service->master_status.available_count == 0 &&
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen service->service_count_left == 1;
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen
baca06331782e2752734199486e51a26d7c93d75Timo Sirainen client->conn->login_success = TRUE;
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen login->callback(client, auth_args[0], auth_args+1);
4e56e6408815c04f2e5b904a648a366a2dcbd408Timo Sirainen
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen if (close_sockets) {
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen /* we're dying as soon as this connection closes. */
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen i_assert(master_login_auth_request_count(login->auth) == 0);
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen master_login_auth_disconnect(login->auth);
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen master_service_close_config_fd(service);
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen } else if (login->stopping) {
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen /* try stopping again */
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen master_login_stop(login);
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen }
f096367f0f7b0e481f8abe0969afdf2d8250057eTimo Sirainen
f096367f0f7b0e481f8abe0969afdf2d8250057eTimo Sirainen client->fd = -1;
f096367f0f7b0e481f8abe0969afdf2d8250057eTimo Sirainen master_login_client_free(&client);
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen}
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainenstatic void master_login_postlogin_free(struct master_login_postlogin *pl)
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen{
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen timeout_remove(&pl->to);
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen io_remove(&pl->io);
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen if (close(pl->fd) < 0)
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen i_error("close(postlogin) failed: %m");
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen str_free(&pl->input);
b3d5afcc92e4ce1452db499b3c956d12447babc7Timo Sirainen i_free(pl->socket_path);
f633c533a2c793ae188bff21e173e2ff63ba35f9Timo Sirainen i_free(pl->username);
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen i_free(pl);
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen}
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainenstatic void master_login_postlogin_input(struct master_login_postlogin *pl)
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen{
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen char buf[1024];
ef0c36aa8114feee80aa696d9cb8106140371243Timo Sirainen const char *const *auth_args;
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen size_t len;
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen ssize_t ret;
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen int fd = -1;
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen while ((ret = fd_read(pl->fd, buf, sizeof(buf), &fd)) > 0) {
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen if (fd != -1) {
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen /* post-login script replaced fd */
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen if (close(pl->client->fd) < 0)
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen i_error("close(client) failed: %m");
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen pl->client->fd = fd;
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen }
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen str_append_n(pl->input, buf, ret);
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen }
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen len = str_len(pl->input);
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen if (len > 0 && str_c(pl->input)[len-1] == '\n') {
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen /* finished reading the input */
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen str_truncate(pl->input, len-1);
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen } else {
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen if (ret < 0) {
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen if (errno == EAGAIN)
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen return;
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen
b3d5afcc92e4ce1452db499b3c956d12447babc7Timo Sirainen i_error("fd_read(%s) failed: %m", pl->socket_path);
f633c533a2c793ae188bff21e173e2ff63ba35f9Timo Sirainen } else if (str_len(pl->input) > 0) {
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen i_error("fd_read(%s) failed: disconnected",
b3d5afcc92e4ce1452db499b3c956d12447babc7Timo Sirainen pl->socket_path);
f633c533a2c793ae188bff21e173e2ff63ba35f9Timo Sirainen } else {
f633c533a2c793ae188bff21e173e2ff63ba35f9Timo Sirainen i_info("Post-login script denied access to user %s",
f633c533a2c793ae188bff21e173e2ff63ba35f9Timo Sirainen pl->username);
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen }
4e56e6408815c04f2e5b904a648a366a2dcbd408Timo Sirainen master_login_client_free(&pl->client);
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen master_login_postlogin_free(pl);
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen return;
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen }
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen
ef0c36aa8114feee80aa696d9cb8106140371243Timo Sirainen auth_args = t_strsplit_tabescaped(str_c(pl->input));
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen master_login_auth_finish(pl->client, auth_args);
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen master_login_postlogin_free(pl);
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen}
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainenstatic void master_login_postlogin_timeout(struct master_login_postlogin *pl)
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen{
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen i_error("%s: Timeout waiting for post-login script to finish, aborting",
b3d5afcc92e4ce1452db499b3c956d12447babc7Timo Sirainen pl->socket_path);
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen
4e56e6408815c04f2e5b904a648a366a2dcbd408Timo Sirainen master_login_client_free(&pl->client);
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen master_login_postlogin_free(pl);
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen}
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainenstatic int master_login_postlogin(struct master_login_client *client,
b3d5afcc92e4ce1452db499b3c956d12447babc7Timo Sirainen const char *const *auth_args,
b3d5afcc92e4ce1452db499b3c956d12447babc7Timo Sirainen const char *socket_path)
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen{
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen struct master_login *login = client->conn->login;
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen struct master_login_postlogin *pl;
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen string_t *str;
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen unsigned int i;
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen int fd;
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen ssize_t ret;
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen
b3d5afcc92e4ce1452db499b3c956d12447babc7Timo Sirainen fd = net_connect_unix_with_retries(socket_path, 1000);
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen if (fd == -1) {
b52230a2649019208b13dcbc0469eecde80f76d2Timo Sirainen i_error("net_connect_unix(%s) failed: %m%s",
b3d5afcc92e4ce1452db499b3c956d12447babc7Timo Sirainen socket_path, errno != EAGAIN ? "" :
b52230a2649019208b13dcbc0469eecde80f76d2Timo Sirainen " - http://wiki2.dovecot.org/SocketUnavailable");
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen return -1;
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen }
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen str = t_str_new(256);
bf27c70b784ed67e324ddfe1ad4f46bf571d3a09Timo Sirainen str_printfa(str, "VERSION\tscript-login\t1\t0\n"
bf27c70b784ed67e324ddfe1ad4f46bf571d3a09Timo Sirainen "%s\t%s", net_ip2addr(&client->auth_req.local_ip),
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen net_ip2addr(&client->auth_req.remote_ip));
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen for (i = 0; auth_args[i] != NULL; i++) {
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen str_append_c(str, '\t');
d03a871a77f8ec36f48f5fea98d810e51b186fdbTimo Sirainen str_append_tabescaped(str, auth_args[i]);
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen }
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen str_append_c(str, '\n');
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen ret = fd_send(fd, client->fd, str_data(str), str_len(str));
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen if (ret != (ssize_t)str_len(str)) {
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen if (ret < 0) {
b3d5afcc92e4ce1452db499b3c956d12447babc7Timo Sirainen i_error("write(%s) failed: %m", socket_path);
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen } else {
b3d5afcc92e4ce1452db499b3c956d12447babc7Timo Sirainen i_error("write(%s) failed: partial write", socket_path);
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen }
4307c886579381dbb1897ea1388ae6978c96f560Timo Sirainen i_close_fd(&fd);
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen return -1;
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen }
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen net_set_nonblock(fd, TRUE);
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen pl = i_new(struct master_login_postlogin, 1);
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen pl->client = client;
f633c533a2c793ae188bff21e173e2ff63ba35f9Timo Sirainen pl->username = i_strdup(auth_args[0]);
b3d5afcc92e4ce1452db499b3c956d12447babc7Timo Sirainen pl->socket_path = i_strdup(socket_path);
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen pl->fd = fd;
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen pl->io = io_add(fd, IO_READ, master_login_postlogin_input, pl);
53dff078a5f49e9d28d6c81d3437755e27526e3eTimo Sirainen pl->to = timeout_add(login->postlogin_timeout_secs * 1000,
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen master_login_postlogin_timeout, pl);
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen pl->input = str_new(default_pool, 512);
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen return 0;
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen}
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen
b3d5afcc92e4ce1452db499b3c956d12447babc7Timo Sirainenstatic const char *
b3d5afcc92e4ce1452db499b3c956d12447babc7Timo Sirainenauth_args_find_postlogin_socket(const char *const *auth_args)
b3d5afcc92e4ce1452db499b3c956d12447babc7Timo Sirainen{
b3d5afcc92e4ce1452db499b3c956d12447babc7Timo Sirainen for (unsigned int i = 0; auth_args[i] != NULL; i++) {
b3d5afcc92e4ce1452db499b3c956d12447babc7Timo Sirainen if (strncmp(auth_args[i], "postlogin=", 10) == 0)
b3d5afcc92e4ce1452db499b3c956d12447babc7Timo Sirainen return auth_args[i]+10;
b3d5afcc92e4ce1452db499b3c956d12447babc7Timo Sirainen }
b3d5afcc92e4ce1452db499b3c956d12447babc7Timo Sirainen return NULL;
b3d5afcc92e4ce1452db499b3c956d12447babc7Timo Sirainen}
b3d5afcc92e4ce1452db499b3c956d12447babc7Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstatic void
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainenmaster_login_auth_callback(const char *const *auth_args, const char *errormsg,
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen void *context)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen{
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen struct master_login_client *client = context;
dfb7dad13078cc8674749ac7135436197890bcdcTimo Sirainen struct master_login_connection *conn = client->conn;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen struct master_auth_reply reply;
b3d5afcc92e4ce1452db499b3c956d12447babc7Timo Sirainen const char *postlogin_socket_path;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&reply);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen reply.tag = client->auth_req.tag;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen reply.status = errormsg == NULL ? MASTER_AUTH_STATUS_OK :
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen MASTER_AUTH_STATUS_INTERNAL_ERROR;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen reply.mail_pid = getpid();
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend(conn->output, &reply, sizeof(reply));
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen if (errormsg != NULL || auth_args[0] == NULL) {
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen if (auth_args != NULL) {
b71f152acb8a197d20b709ca74366e6d765bd200Timo Sirainen i_error("login client: Username missing from auth reply");
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen errormsg = MASTER_AUTH_ERRMSG_INTERNAL_FAILURE;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen }
dfb7dad13078cc8674749ac7135436197890bcdcTimo Sirainen conn->login->failure_callback(client, errormsg);
4e56e6408815c04f2e5b904a648a366a2dcbd408Timo Sirainen master_login_client_free(&client);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen i_set_failure_prefix("%s(%s): ", client->conn->login->service->name,
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen auth_args[0]);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
b3d5afcc92e4ce1452db499b3c956d12447babc7Timo Sirainen postlogin_socket_path = auth_args_find_postlogin_socket(auth_args);
b3d5afcc92e4ce1452db499b3c956d12447babc7Timo Sirainen if (postlogin_socket_path == NULL)
b3d5afcc92e4ce1452db499b3c956d12447babc7Timo Sirainen postlogin_socket_path = conn->login->postlogin_socket_path;
b3d5afcc92e4ce1452db499b3c956d12447babc7Timo Sirainen
b3d5afcc92e4ce1452db499b3c956d12447babc7Timo Sirainen if (postlogin_socket_path == NULL)
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen master_login_auth_finish(client, auth_args);
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen else {
dfb7dad13078cc8674749ac7135436197890bcdcTimo Sirainen /* we've sent the reply. the connection is no longer needed,
dfb7dad13078cc8674749ac7135436197890bcdcTimo Sirainen so disconnect it (before login process disconnects us and
dfb7dad13078cc8674749ac7135436197890bcdcTimo Sirainen logs an error) */
dfb7dad13078cc8674749ac7135436197890bcdcTimo Sirainen master_login_conn_close(conn);
dfb7dad13078cc8674749ac7135436197890bcdcTimo Sirainen master_login_conn_unref(&conn);
dfb7dad13078cc8674749ac7135436197890bcdcTimo Sirainen
1d3b9fce06b466bcf64f9ab7b622f3a6e4e939baTimo Sirainen /* execute post-login scripts before finishing auth */
b3d5afcc92e4ce1452db499b3c956d12447babc7Timo Sirainen if (master_login_postlogin(client, auth_args,
b3d5afcc92e4ce1452db499b3c956d12447babc7Timo Sirainen postlogin_socket_path) < 0)
4e56e6408815c04f2e5b904a648a366a2dcbd408Timo Sirainen master_login_client_free(&client);
3ba9a079592f46e94ce846e5aa80e4d479cd5e41Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen}
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstatic void master_login_conn_input(struct master_login_connection *conn)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen{
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen struct master_auth_request req;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen struct master_login_client *client;
442232f2d1cfdf28f3a18aa00a5c19246d321036Timo Sirainen struct master_login *login = conn->login;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen unsigned char data[MASTER_AUTH_MAX_DATA_SIZE];
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen size_t i, session_len = 0;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen int ret, client_fd;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen ret = master_login_conn_read_request(conn, &req, data, &client_fd);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (ret <= 0) {
e871bfe83e8c5cc7768de30afe0127a3c4373adeTimo Sirainen if (ret < 0) {
e871bfe83e8c5cc7768de30afe0127a3c4373adeTimo Sirainen master_login_conn_close(conn);
e871bfe83e8c5cc7768de30afe0127a3c4373adeTimo Sirainen master_login_conn_unref(&conn);
e871bfe83e8c5cc7768de30afe0127a3c4373adeTimo Sirainen }
a943ed0f901e312445fd393249b91932797bba79Josef 'Jeff' Sipek i_close_fd(&client_fd);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen fd_close_on_exec(client_fd, TRUE);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen /* extract the session ID from the request data */
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen for (i = 0; i < req.data_size; i++) {
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen if (data[i] == '\0') {
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen session_len = i++;
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen break;
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen }
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen }
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* @UNSAFE: we have a request. do userdb lookup for it. */
8e78ed2dfcc036bea26b039f1dd10e7f7075b6ccTimo Sirainen req.data_size -= i;
e7d0bea63a08b08c47c4b5c187d2cb7127859657Timo Sirainen client = i_malloc(MALLOC_ADD(sizeof(struct master_login_client), req.data_size));
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen client->conn = conn;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen client->fd = client_fd;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen client->auth_req = req;
404150692ba0f5e710600220c0dccfbdf1b1d7ccTimo Sirainen client->session_id = i_strndup(data, session_len);
8e78ed2dfcc036bea26b039f1dd10e7f7075b6ccTimo Sirainen memcpy(client->data, data+i, req.data_size);
4e56e6408815c04f2e5b904a648a366a2dcbd408Timo Sirainen conn->refcount++;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
442232f2d1cfdf28f3a18aa00a5c19246d321036Timo Sirainen master_login_auth_request(login->auth, &req,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen master_login_auth_callback, client);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen}
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenvoid master_login_add(struct master_login *login, int fd)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen{
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen struct master_login_connection *conn;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen conn = i_new(struct master_login_connection, 1);
4e56e6408815c04f2e5b904a648a366a2dcbd408Timo Sirainen conn->refcount = 1;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen conn->login = login;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen conn->fd = fd;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen conn->io = io_add(conn->fd, IO_READ, master_login_conn_input, conn);
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi conn->output = o_stream_create_fd(fd, (size_t)-1);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_set_no_error_handling(conn->output, TRUE);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen DLLIST_PREPEND(&login->conns, conn);
442232f2d1cfdf28f3a18aa00a5c19246d321036Timo Sirainen
baca06331782e2752734199486e51a26d7c93d75Timo Sirainen /* NOTE: currently there's a separate connection for each request. */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen}
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
e871bfe83e8c5cc7768de30afe0127a3c4373adeTimo Sirainenstatic void master_login_conn_close(struct master_login_connection *conn)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen{
8149f4a09d07464f33de747d8e1e620f6d9f7faeTimo Sirainen if (master_login_conn_is_closed(conn))
f096367f0f7b0e481f8abe0969afdf2d8250057eTimo Sirainen return;
f096367f0f7b0e481f8abe0969afdf2d8250057eTimo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen DLLIST_REMOVE(&conn->login->conns, conn);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
5f1d689131a75c39f064cbd4202373e7edf78f18Josef 'Jeff' Sipek io_remove(&conn->io);
d795594a018d8dcf47b6b569b8ca20e53e275293Timo Sirainen o_stream_close(conn->output);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (close(conn->fd) < 0)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen i_error("close(master login) failed: %m");
f096367f0f7b0e481f8abe0969afdf2d8250057eTimo Sirainen conn->fd = -1;
4e56e6408815c04f2e5b904a648a366a2dcbd408Timo Sirainen}
4e56e6408815c04f2e5b904a648a366a2dcbd408Timo Sirainen
4e56e6408815c04f2e5b904a648a366a2dcbd408Timo Sirainenstatic void master_login_conn_unref(struct master_login_connection **_conn)
4e56e6408815c04f2e5b904a648a366a2dcbd408Timo Sirainen{
4e56e6408815c04f2e5b904a648a366a2dcbd408Timo Sirainen struct master_login_connection *conn = *_conn;
4e56e6408815c04f2e5b904a648a366a2dcbd408Timo Sirainen
4e56e6408815c04f2e5b904a648a366a2dcbd408Timo Sirainen i_assert(conn->refcount > 0);
4e56e6408815c04f2e5b904a648a366a2dcbd408Timo Sirainen
d795594a018d8dcf47b6b569b8ca20e53e275293Timo Sirainen if (--conn->refcount > 0)
d795594a018d8dcf47b6b569b8ca20e53e275293Timo Sirainen return;
d795594a018d8dcf47b6b569b8ca20e53e275293Timo Sirainen
d795594a018d8dcf47b6b569b8ca20e53e275293Timo Sirainen *_conn = NULL;
e871bfe83e8c5cc7768de30afe0127a3c4373adeTimo Sirainen master_login_conn_close(conn);
d795594a018d8dcf47b6b569b8ca20e53e275293Timo Sirainen o_stream_unref(&conn->output);
9ba5c6da815d5d4b43861387dd08fcea321a0423Timo Sirainen
9ba5c6da815d5d4b43861387dd08fcea321a0423Timo Sirainen if (!conn->login_success)
9ba5c6da815d5d4b43861387dd08fcea321a0423Timo Sirainen master_service_client_connection_destroyed(conn->login->service);
d795594a018d8dcf47b6b569b8ca20e53e275293Timo Sirainen i_free(conn);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen}
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainenvoid master_login_stop(struct master_login *login)
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen{
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen login->stopping = TRUE;
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen if (master_login_auth_request_count(login->auth) == 0) {
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen master_login_auth_disconnect(login->auth);
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen master_service_close_config_fd(login->service);
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen }
7891c8e6debdcfec552cb1beea2a0230fe89957bTimo Sirainen}