auth-server-connection.c revision 4b8c92b4773677a7b4064816e469eeafc976ba75
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#include "lib.h"
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen#include "buffer.h"
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#include "hash.h"
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#include "ioloop.h"
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#include "istream.h"
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#include "ostream.h"
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#include "network.h"
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#include "auth-client.h"
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#include "auth-server-connection.h"
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#include "auth-server-request.h"
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#include <unistd.h>
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen#include <stdlib.h>
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainenstatic void auth_server_connection_unref(struct auth_server_connection *conn);
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainenstatic void update_available_auth_mechs(struct auth_server_connection *conn)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen{
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen struct auth_client *client = conn->client;
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen const struct auth_mech_desc *mech;
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen struct auth_mech_desc *new_mech;
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen unsigned int i;
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen mech = conn->available_auth_mechs;
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen for (i = 0; i < conn->available_auth_mechs_count; i++) {
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen if (auth_client_find_mech(client, mech[i].name) == NULL) {
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen new_mech = buffer_append_space_unsafe(
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen client->available_auth_mechs, sizeof(*mech));
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen *new_mech = mech[i];
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen new_mech->name = i_strdup(mech[i].name);
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen }
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen }
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen}
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainenstatic int
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainenauth_client_input_mech(struct auth_server_connection *conn, const char *args)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen{
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen const char *const *list;
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen struct auth_mech_desc mech_desc;
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen if (conn->handshake_received) {
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen i_error("BUG: Authentication server already sent handshake");
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen return FALSE;
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen }
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen list = t_strsplit(args, "\t");
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen if (list[0] == NULL) {
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen i_error("BUG: Authentication server sent broken MECH line");
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen return FALSE;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen }
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen memset(&mech_desc, 0, sizeof(mech_desc));
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen mech_desc.name = p_strdup(conn->pool, list[0]);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen if (strcmp(mech_desc.name, "PLAIN") == 0)
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen conn->has_plain_mech = TRUE;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen for (list++; *list != NULL; list++) {
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen if (strcmp(*list, "private") == 0)
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen mech_desc.flags |= MECH_SEC_PRIVATE;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen else if (strcmp(*list, "anonymous") == 0)
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen mech_desc.flags |= MECH_SEC_ANONYMOUS;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen else if (strcmp(*list, "plaintext") == 0)
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen mech_desc.flags |= MECH_SEC_PLAINTEXT;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen else if (strcmp(*list, "dictionary") == 0)
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen mech_desc.flags |= MECH_SEC_DICTIONARY;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen else if (strcmp(*list, "active") == 0)
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen mech_desc.flags |= MECH_SEC_ACTIVE;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen else if (strcmp(*list, "forward-secrecy") == 0)
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen mech_desc.flags |= MECH_SEC_FORWARD_SECRECY;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen else if (strcmp(*list, "mutual-auth") == 0)
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen mech_desc.flags |= MECH_SEC_MUTUAL_AUTH;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen }
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen buffer_append(conn->auth_mechs_buf, &mech_desc, sizeof(mech_desc));
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen return TRUE;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen}
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainenstatic int
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainenauth_client_input_spid(struct auth_server_connection *conn, const char *args)
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen{
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen if (conn->handshake_received) {
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen i_error("BUG: Authentication server already sent handshake");
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen return FALSE;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen }
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen conn->server_pid = (unsigned int)strtoul(args, NULL, 10);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen return TRUE;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen}
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainenstatic int
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainenauth_client_input_cuid(struct auth_server_connection *conn, const char *args)
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen{
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen if (conn->handshake_received) {
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen i_error("BUG: Authentication server already sent handshake");
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen return FALSE;
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen }
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen conn->connect_uid = (unsigned int)strtoul(args, NULL, 10);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen return TRUE;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen}
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainenstatic int auth_client_input_done(struct auth_server_connection *conn)
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen{
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen conn->available_auth_mechs = conn->auth_mechs_buf->data;
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen conn->available_auth_mechs_count =
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen conn->auth_mechs_buf->used / sizeof(struct auth_mech_desc);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen conn->handshake_received = TRUE;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen conn->client->conn_waiting_handshake_count--;
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen update_available_auth_mechs(conn);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
7a87427770874f38d1d299635b37d699f9772860Timo Sirainen if (conn->client->connect_notify_callback != NULL &&
7a87427770874f38d1d299635b37d699f9772860Timo Sirainen auth_client_is_connected(conn->client)) {
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen conn->client->connect_notify_callback(conn->client, TRUE,
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen conn->client->connect_notify_context);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen }
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen return TRUE;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen}
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainenstatic void auth_client_input(void *context)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen{
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen struct auth_server_connection *conn = context;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen const char *line;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen int ret;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen switch (i_stream_read(conn->input)) {
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen case 0:
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen return;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen case -1:
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen /* disconnected */
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen auth_server_connection_destroy(conn, TRUE);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen return;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen case -2:
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen /* buffer full - can't happen unless auth is buggy */
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen i_error("BUG: Auth server sent us more than %d bytes of data",
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen AUTH_CLIENT_MAX_LINE_LENGTH);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen auth_server_connection_destroy(conn, FALSE);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen return;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen }
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen if (conn->version_received) {
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen line = i_stream_next_line(conn->input);
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen if (line == NULL)
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen return;
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen /* make sure the major version matches */
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen if (strncmp(line, "VERSION\t", 8) != 0 ||
4b8c92b4773677a7b4064816e469eeafc976ba75Timo Sirainen atoi(t_strcut(line + 8, '\t')) !=
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen AUTH_CLIENT_PROTOCOL_MAJOR_VERSION) {
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen i_error("Authentication server not compatible with "
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen "this client (mixed old and new binaries?)");
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen auth_server_connection_destroy(conn, FALSE);
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen return;
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen }
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen conn->version_received = TRUE;
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen }
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen conn->refcount++;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen while ((line = i_stream_next_line(conn->input)) != NULL) {
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen if (strncmp(line, "OK\t", 3) == 0)
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen ret = auth_client_input_ok(conn, line + 3);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen else if (strncmp(line, "CONT\t", 5) == 0)
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen ret = auth_client_input_cont(conn, line + 5);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen else if (strncmp(line, "FAIL\t", 5) == 0)
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen ret = auth_client_input_fail(conn, line + 5);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen else if (strncmp(line, "MECH\t", 5) == 0)
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen ret = auth_client_input_mech(conn, line + 5);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen else if (strncmp(line, "SPID\t", 5) == 0)
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen ret = auth_client_input_spid(conn, line + 5);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen else if (strncmp(line, "CUID\t", 5) == 0)
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen ret = auth_client_input_cuid(conn, line + 5);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen else if (strcmp(line, "DONE") == 0)
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen ret = auth_client_input_done(conn);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen else {
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen /* ignore unknown command */
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen ret = TRUE;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen }
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen if (!ret) {
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen auth_server_connection_destroy(conn, FALSE);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen break;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen }
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen }
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen auth_server_connection_unref(conn);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen}
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainenstruct auth_server_connection *
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainenauth_server_connection_new(struct auth_client *client, const char *path)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen{
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen struct auth_server_connection *conn;
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen const char *handshake;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen pool_t pool;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen int fd;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen fd = net_connect_unix(path);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if (fd == -1) {
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen i_error("Can't connect to auth server at %s: %m", path);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen return NULL;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen }
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen /* use blocking connection since we depend on auth server -
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if it's slow, just wait */
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen pool = pool_alloconly_create("Auth connection", 1024);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen conn = p_new(pool, struct auth_server_connection, 1);
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen conn->refcount = 1;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen conn->pool = pool;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen conn->client = client;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen conn->path = p_strdup(pool, path);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen conn->fd = fd;
acf3b7bf3a8891b118a71c45e6c48d17bc90b259Timo Sirainen if (client->ext_input_add == NULL)
acf3b7bf3a8891b118a71c45e6c48d17bc90b259Timo Sirainen conn->io = io_add(fd, IO_READ, auth_client_input, conn);
acf3b7bf3a8891b118a71c45e6c48d17bc90b259Timo Sirainen else {
acf3b7bf3a8891b118a71c45e6c48d17bc90b259Timo Sirainen conn->ext_input_io =
acf3b7bf3a8891b118a71c45e6c48d17bc90b259Timo Sirainen client->ext_input_add(fd, auth_client_input, conn);
acf3b7bf3a8891b118a71c45e6c48d17bc90b259Timo Sirainen }
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen conn->input = i_stream_create_file(fd, default_pool,
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen AUTH_CLIENT_MAX_LINE_LENGTH, FALSE);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen conn->output = o_stream_create_file(fd, default_pool, (size_t)-1,
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen FALSE);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen conn->requests = hash_create(default_pool, pool, 100, NULL, NULL);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen conn->auth_mechs_buf = buffer_create_dynamic(default_pool, 256);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen conn->next = client->connections;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen client->connections = conn;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
4b8c92b4773677a7b4064816e469eeafc976ba75Timo Sirainen handshake = t_strdup_printf("VERSION\t%u\t%u\nCPID\t%u\n",
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen AUTH_CLIENT_PROTOCOL_MAJOR_VERSION,
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen AUTH_CLIENT_PROTOCOL_MINOR_VERSION,
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen client->pid);
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen client->conn_waiting_handshake_count++;
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen if (o_stream_send_str(conn->output, handshake) < 0) {
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen errno = conn->output->stream_errno;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen i_warning("Error sending handshake to auth server: %m");
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen auth_server_connection_destroy(conn, TRUE);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen return NULL;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen }
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen return conn;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen}
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainenvoid auth_server_connection_destroy(struct auth_server_connection *conn,
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen int reconnect)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen{
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen struct auth_client *client = conn->client;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen struct auth_server_connection **pos;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen if (conn->fd == -1)
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen return;
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen pos = &conn->client->connections;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen for (; *pos != NULL; pos = &(*pos)->next) {
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if (*pos == conn) {
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen *pos = conn->next;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen break;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen }
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen }
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if (!conn->handshake_received)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen client->conn_waiting_handshake_count--;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
acf3b7bf3a8891b118a71c45e6c48d17bc90b259Timo Sirainen if (conn->ext_input_io != NULL) {
acf3b7bf3a8891b118a71c45e6c48d17bc90b259Timo Sirainen client->ext_input_remove(conn->ext_input_io);
acf3b7bf3a8891b118a71c45e6c48d17bc90b259Timo Sirainen conn->ext_input_io = NULL;
acf3b7bf3a8891b118a71c45e6c48d17bc90b259Timo Sirainen }
acf3b7bf3a8891b118a71c45e6c48d17bc90b259Timo Sirainen if (conn->io != NULL) {
acf3b7bf3a8891b118a71c45e6c48d17bc90b259Timo Sirainen io_remove(conn->io);
acf3b7bf3a8891b118a71c45e6c48d17bc90b259Timo Sirainen conn->io = NULL;
acf3b7bf3a8891b118a71c45e6c48d17bc90b259Timo Sirainen }
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen i_stream_close(conn->input);
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen o_stream_close(conn->output);
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if (close(conn->fd) < 0)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen i_error("close(auth) failed: %m");
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen conn->fd = -1;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen auth_server_requests_remove_all(conn);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen auth_server_connection_unref(conn);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if (reconnect)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen auth_client_connect_missing_servers(client);
7a87427770874f38d1d299635b37d699f9772860Timo Sirainen else if (client->connect_notify_callback != NULL) {
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen client->connect_notify_callback(client,
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen auth_client_is_connected(client),
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen client->connect_notify_context);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen }
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen}
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainenstatic void auth_server_connection_unref(struct auth_server_connection *conn)
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen{
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen if (--conn->refcount > 0)
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen return;
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen i_assert(conn->refcount == 0);
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen hash_destroy(conn->requests);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen buffer_free(conn->auth_mechs_buf);
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen i_stream_unref(conn->input);
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen o_stream_unref(conn->output);
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen pool_unref(conn->pool);
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen}
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainenstruct auth_server_connection *
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainenauth_server_connection_find_path(struct auth_client *client, const char *path)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen{
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen struct auth_server_connection *conn;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen for (conn = client->connections; conn != NULL; conn = conn->next) {
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if (strcmp(conn->path, path) == 0)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen return conn;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen }
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen return NULL;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen}
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainenstruct auth_server_connection *
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainenauth_server_connection_find_mech(struct auth_client *client,
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen const char *name, const char **error_r)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen{
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen struct auth_server_connection *conn;
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen const struct auth_mech_desc *mech;
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen unsigned int i;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen for (conn = client->connections; conn != NULL; conn = conn->next) {
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen mech = conn->available_auth_mechs;
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen for (i = 0; i < conn->available_auth_mechs_count; i++) {
acf3b7bf3a8891b118a71c45e6c48d17bc90b259Timo Sirainen if (strcasecmp(mech[i].name, name) == 0)
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen return conn;
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen }
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen }
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen if (auth_client_find_mech(client, name) == NULL)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen *error_r = "Unsupported authentication mechanism";
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen else {
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen *error_r = "Authentication server isn't connected, "
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen "try again later..";
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen }
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen return NULL;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen}