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