auth-server-connection.c revision 7a87427770874f38d1d299635b37d699f9772860
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen/* Copyright (C) 2003 Timo Sirainen */
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#include "lib.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>
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen/* Maximum size for an auth reply. 50kB should be more than enough. */
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#define MAX_INBUF_SIZE (1024*50)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#define MAX_OUTBUF_SIZE \
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen (sizeof(struct auth_client_request_continue) + \
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen AUTH_CLIENT_MAX_REQUEST_DATA_SIZE)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainenstatic void update_available_auth_mechs(struct auth_client *client)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen{
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen struct auth_server_connection *conn;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen client->available_auth_mechs = 0;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen for (conn = client->connections; conn != NULL; conn = conn->next)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen client->available_auth_mechs |= conn->available_auth_mechs;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen}
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainenstatic void auth_handle_handshake(struct auth_server_connection *conn,
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen struct auth_client_handshake_reply *handshake)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen{
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if (handshake->server_pid == 0) {
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen i_error("BUG: Auth server said it's PID 0");
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen auth_server_connection_destroy(conn, FALSE);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen return;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen }
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen conn->pid = handshake->server_pid;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen conn->available_auth_mechs = handshake->auth_mechanisms;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen conn->handshake_received = TRUE;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen conn->client->conn_waiting_handshake_count--;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen update_available_auth_mechs(conn->client);
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 }
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen}
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainenstatic void auth_client_input(void *context)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen{
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen struct auth_server_connection *conn = context;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen struct auth_client_handshake_reply handshake;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen const unsigned char *data;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen size_t size;
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",
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen MAX_INBUF_SIZE);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen auth_server_connection_destroy(conn, FALSE);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen return;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen }
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if (!conn->handshake_received) {
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen data = i_stream_get_data(conn->input, &size);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if (size == sizeof(handshake)) {
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen memcpy(&handshake, data, sizeof(handshake));
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen i_stream_skip(conn->input, sizeof(handshake));
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen auth_handle_handshake(conn, &handshake);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen } else if (size > sizeof(handshake)) {
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen i_error("BUG: Auth server sent us too large handshake "
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen "(%"PRIuSIZE_T " vs %"PRIuSIZE_T")", size,
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen sizeof(handshake));
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen auth_server_connection_destroy(conn, FALSE);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen }
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen return;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen }
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if (!conn->reply_received) {
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen data = i_stream_get_data(conn->input, &size);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if (size < sizeof(conn->reply))
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen return;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen memcpy(&conn->reply, data, sizeof(conn->reply));
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen i_stream_skip(conn->input, sizeof(conn->reply));
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen conn->reply_received = TRUE;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen }
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen data = i_stream_get_data(conn->input, &size);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if (size < conn->reply.data_size)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen return;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen /* we've got a full reply */
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen conn->reply_received = FALSE;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen auth_server_request_handle_reply(conn, &conn->reply, data);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen i_stream_skip(conn->input, conn->reply.data_size);
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;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen struct auth_client_handshake_request 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);
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;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen conn->io = io_add(fd, IO_READ, auth_client_input, conn);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen conn->input = i_stream_create_file(fd, default_pool, MAX_INBUF_SIZE,
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen FALSE);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen conn->output = o_stream_create_file(fd, default_pool, MAX_OUTBUF_SIZE,
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen FALSE);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen conn->requests = hash_create(default_pool, pool, 100, NULL, NULL);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen conn->next = client->connections;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen client->connections = conn;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen /* send our handshake */
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen memset(&handshake, 0, sizeof(handshake));
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen handshake.client_pid = client->pid;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen client->conn_waiting_handshake_count++;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if (o_stream_send(conn->output, &handshake, sizeof(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
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
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen io_remove(conn->io);
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);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen hash_destroy(conn->requests);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen i_stream_unref(conn->input);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen o_stream_unref(conn->output);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen pool_unref(conn->pool);
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
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,
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen enum auth_mech mech, const char **error_r)
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 ((conn->available_auth_mechs & mech))
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen return conn;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen }
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if ((client->available_auth_mechs & mech) == 0)
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}