auth-server-connection.c revision b6e1d85292485a7fb4cfa5f40dd1ec131ab07cc1
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi/* Copyright (c) 2003-2009 Dovecot authors, see the included COPYING file */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#include "lib.h"
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#include "array.h"
80ab886d233f514d54c2a6bdeb9fdfd951bd6881wesolows#include "hash.h"
80ab886d233f514d54c2a6bdeb9fdfd951bd6881wesolows#include "ioloop.h"
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#include "istream.h"
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#include "ostream.h"
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#include "network.h"
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#include "eacces-error.h"
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#include "auth-client-private.h"
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#include "auth-client-request.h"
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#include "auth-server-connection.h"
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#include <unistd.h>
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#include <stdlib.h>
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#define AUTH_SERVER_CONN_MAX_LINE_LENGTH AUTH_CLIENT_MAX_LINE_LENGTH
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#define AUTH_HANDSHAKE_TIMEOUT (30*1000)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#define AUTH_SERVER_RECONNECT_TIMEOUT_SECS 5
80ab886d233f514d54c2a6bdeb9fdfd951bd6881wesolows
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindistatic void
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanianauth_server_connection_disconnect(struct auth_server_connection *conn);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindistatic int
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindiauth_server_input_mech(struct auth_server_connection *conn,
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanian const char *const *args)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi{
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi struct auth_mech_desc mech_desc;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (conn->handshake_received) {
14ea4bb737263733ad80a36b4f73f681c30a6b45sd i_error("BUG: Authentication server already sent handshake");
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return -1;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (args[0] == NULL) {
0eb822a1c0c2bea495647510b75f77f0e57633ebcindi i_error("BUG: Authentication server sent broken MECH line");
0eb822a1c0c2bea495647510b75f77f0e57633ebcindi return -1;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
14ea4bb737263733ad80a36b4f73f681c30a6b45sd
14ea4bb737263733ad80a36b4f73f681c30a6b45sd memset(&mech_desc, 0, sizeof(mech_desc));
14ea4bb737263733ad80a36b4f73f681c30a6b45sd mech_desc.name = p_strdup(conn->pool, args[0]);
14ea4bb737263733ad80a36b4f73f681c30a6b45sd
14ea4bb737263733ad80a36b4f73f681c30a6b45sd if (strcmp(mech_desc.name, "PLAIN") == 0)
14ea4bb737263733ad80a36b4f73f681c30a6b45sd conn->has_plain_mech = TRUE;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
0eb822a1c0c2bea495647510b75f77f0e57633ebcindi for (args++; *args != NULL; args++) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (strcmp(*args, "private") == 0)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mech_desc.flags |= MECH_SEC_PRIVATE;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi else if (strcmp(*args, "anonymous") == 0)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mech_desc.flags |= MECH_SEC_ANONYMOUS;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi else if (strcmp(*args, "plaintext") == 0)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mech_desc.flags |= MECH_SEC_PLAINTEXT;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi else if (strcmp(*args, "dictionary") == 0)
d5ea2ced3a0abbaf6cd28ea669168246d35920e7Scott Davenport mech_desc.flags |= MECH_SEC_DICTIONARY;
d5ea2ced3a0abbaf6cd28ea669168246d35920e7Scott Davenport else if (strcmp(*args, "active") == 0)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mech_desc.flags |= MECH_SEC_ACTIVE;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi else if (strcmp(*args, "forward-secrecy") == 0)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mech_desc.flags |= MECH_SEC_FORWARD_SECRECY;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi else if (strcmp(*args, "mutual-auth") == 0)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi mech_desc.flags |= MECH_SEC_MUTUAL_AUTH;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi array_append(&conn->available_auth_mechs, &mech_desc, 1);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return 0;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi}
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
0eb822a1c0c2bea495647510b75f77f0e57633ebcindistatic int
d5ea2ced3a0abbaf6cd28ea669168246d35920e7Scott Davenportauth_server_input_spid(struct auth_server_connection *conn,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi const char *const *args)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi{
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (conn->handshake_received) {
0eb822a1c0c2bea495647510b75f77f0e57633ebcindi i_error("BUG: Authentication server already sent handshake");
0eb822a1c0c2bea495647510b75f77f0e57633ebcindi return -1;
0eb822a1c0c2bea495647510b75f77f0e57633ebcindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
0eb822a1c0c2bea495647510b75f77f0e57633ebcindi conn->server_pid = (unsigned int)strtoul(args[0], NULL, 10);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return 0;
0eb822a1c0c2bea495647510b75f77f0e57633ebcindi}
0eb822a1c0c2bea495647510b75f77f0e57633ebcindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindistatic int
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindiauth_server_input_cuid(struct auth_server_connection *conn,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi const char *const *args)
0eb822a1c0c2bea495647510b75f77f0e57633ebcindi{
0eb822a1c0c2bea495647510b75f77f0e57633ebcindi if (conn->handshake_received) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi i_error("BUG: Authentication server already sent handshake");
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return -1;
0eb822a1c0c2bea495647510b75f77f0e57633ebcindi }
0eb822a1c0c2bea495647510b75f77f0e57633ebcindi if (args[0] == NULL) {
0eb822a1c0c2bea495647510b75f77f0e57633ebcindi i_error("BUG: Authentication server sent broken CUID line");
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return -1;
0eb822a1c0c2bea495647510b75f77f0e57633ebcindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi conn->connect_uid = (unsigned int)strtoul(args[0], NULL, 10);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return 0;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi}
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
0eb822a1c0c2bea495647510b75f77f0e57633ebcindistatic int
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindiauth_server_input_cookie(struct auth_server_connection *conn,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi const char *const *args)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi{
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (conn->cookie != NULL) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi i_error("BUG: Authentication server already sent cookie");
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return -1;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
0eb822a1c0c2bea495647510b75f77f0e57633ebcindi conn->cookie = p_strdup(conn->pool, args[0]);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return 0;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi}
0eb822a1c0c2bea495647510b75f77f0e57633ebcindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindistatic int auth_server_input_done(struct auth_server_connection *conn)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi{
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (array_count(&conn->available_auth_mechs) == 0) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi i_error("BUG: Authentication server returned no mechanisms");
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return -1;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
0eb822a1c0c2bea495647510b75f77f0e57633ebcindi if (conn->cookie == NULL) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi i_error("BUG: Authentication server didn't send a cookie");
0eb822a1c0c2bea495647510b75f77f0e57633ebcindi return -1;
0eb822a1c0c2bea495647510b75f77f0e57633ebcindi }
0eb822a1c0c2bea495647510b75f77f0e57633ebcindi
0eb822a1c0c2bea495647510b75f77f0e57633ebcindi if (conn->to != NULL)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi timeout_remove(&conn->to);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi conn->handshake_received = TRUE;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (conn->client->connect_notify_callback != NULL) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi conn->client->connect_notify_callback(conn->client, TRUE,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi conn->client->connect_notify_context);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
0eb822a1c0c2bea495647510b75f77f0e57633ebcindi return 0;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi}
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindistatic int
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindiauth_server_lookup_request(struct auth_server_connection *conn,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi const char *id_arg, bool remove,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi struct auth_client_request **request_r)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi{
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi struct auth_client_request *request;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi unsigned int id;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (id_arg == NULL) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi i_error("BUG: Authentication server input missing ID");
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return -1;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi id = (unsigned int)strtoul(id_arg, NULL, 10);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi request = hash_table_lookup(conn->requests, POINTER_CAST(id));
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (request == NULL) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi i_error("BUG: Authentication server sent unknown id %u", id);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return -1;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (remove || auth_client_request_is_aborted(request))
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi hash_table_remove(conn->requests, POINTER_CAST(id));
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi *request_r = request;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return 0;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi}
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindistatic int
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindiauth_server_input_ok(struct auth_server_connection *conn,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi const char *const *args)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi{
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi struct auth_client_request *request;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (auth_server_lookup_request(conn, args[0], TRUE, &request) < 0)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return -1;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi auth_client_request_server_input(request, AUTH_REQUEST_STATUS_OK,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi args + 1);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return 0;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi}
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindistatic int auth_server_input_cont(struct auth_server_connection *conn,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi const char *const *args)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi{
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi struct auth_client_request *request;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (str_array_length(args) < 2) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi i_error("BUG: Authentication server sent broken CONT line");
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return -1;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (auth_server_lookup_request(conn, args[0], FALSE, &request) < 0)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return -1;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi auth_client_request_server_input(request, AUTH_REQUEST_STATUS_CONTINUE,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi args + 1);
0eb822a1c0c2bea495647510b75f77f0e57633ebcindi return 0;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi}
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindistatic int auth_server_input_fail(struct auth_server_connection *conn,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi const char *const *args)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi{
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi struct auth_client_request *request;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (auth_server_lookup_request(conn, args[0], TRUE, &request) < 0)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return -1;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi auth_client_request_server_input(request, AUTH_REQUEST_STATUS_FAIL,
0eb822a1c0c2bea495647510b75f77f0e57633ebcindi args + 1);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return 0;
14ea4bb737263733ad80a36b4f73f681c30a6b45sd}
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindistatic int
14ea4bb737263733ad80a36b4f73f681c30a6b45sdauth_server_connection_input_line(struct auth_server_connection *conn,
7bebe46c240b554f47faeed19186123896281967jc const char *line)
14ea4bb737263733ad80a36b4f73f681c30a6b45sd{
14ea4bb737263733ad80a36b4f73f681c30a6b45sd const char *const *args;
14ea4bb737263733ad80a36b4f73f681c30a6b45sd
14ea4bb737263733ad80a36b4f73f681c30a6b45sd if (conn->client->debug)
14ea4bb737263733ad80a36b4f73f681c30a6b45sd i_debug("auth input: %s", line);
14ea4bb737263733ad80a36b4f73f681c30a6b45sd
14ea4bb737263733ad80a36b4f73f681c30a6b45sd args = t_strsplit(line, "\t");
7bebe46c240b554f47faeed19186123896281967jc if (strcmp(args[0], "OK") == 0)
14ea4bb737263733ad80a36b4f73f681c30a6b45sd return auth_server_input_ok(conn, args + 1);
7bebe46c240b554f47faeed19186123896281967jc else if (strcmp(args[0], "CONT") == 0)
7bebe46c240b554f47faeed19186123896281967jc return auth_server_input_cont(conn, args + 1);
7bebe46c240b554f47faeed19186123896281967jc else if (strcmp(args[0], "FAIL") == 0)
7bebe46c240b554f47faeed19186123896281967jc return auth_server_input_fail(conn, args + 1);
14ea4bb737263733ad80a36b4f73f681c30a6b45sd else if (strcmp(args[0], "MECH") == 0)
14ea4bb737263733ad80a36b4f73f681c30a6b45sd return auth_server_input_mech(conn, args + 1);
14ea4bb737263733ad80a36b4f73f681c30a6b45sd else if (strcmp(args[0], "SPID") == 0)
14ea4bb737263733ad80a36b4f73f681c30a6b45sd return auth_server_input_spid(conn, args + 1);
14ea4bb737263733ad80a36b4f73f681c30a6b45sd else if (strcmp(args[0], "CUID") == 0)
14ea4bb737263733ad80a36b4f73f681c30a6b45sd return auth_server_input_cuid(conn, args + 1);
14ea4bb737263733ad80a36b4f73f681c30a6b45sd else if (strcmp(args[0], "COOKIE") == 0)
14ea4bb737263733ad80a36b4f73f681c30a6b45sd return auth_server_input_cookie(conn, args + 1);
7bebe46c240b554f47faeed19186123896281967jc else if (strcmp(args[0], "DONE") == 0)
7bebe46c240b554f47faeed19186123896281967jc return auth_server_input_done(conn);
7bebe46c240b554f47faeed19186123896281967jc else {
14ea4bb737263733ad80a36b4f73f681c30a6b45sd i_error("Auth server sent unknown command: %s", args[0]);
14ea4bb737263733ad80a36b4f73f681c30a6b45sd return -1;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi}
14ea4bb737263733ad80a36b4f73f681c30a6b45sd
7bebe46c240b554f47faeed19186123896281967jcstatic void auth_server_connection_input(struct auth_server_connection *conn)
14ea4bb737263733ad80a36b4f73f681c30a6b45sd{
7bebe46c240b554f47faeed19186123896281967jc struct istream *input;
7bebe46c240b554f47faeed19186123896281967jc const char *line;
7bebe46c240b554f47faeed19186123896281967jc int ret;
14ea4bb737263733ad80a36b4f73f681c30a6b45sd
14ea4bb737263733ad80a36b4f73f681c30a6b45sd switch (i_stream_read(conn->input)) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi case 0:
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return;
14ea4bb737263733ad80a36b4f73f681c30a6b45sd case -1:
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi /* disconnected */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi auth_server_connection_disconnect(conn);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi case -2:
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi /* buffer full - can't happen unless auth is buggy */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi i_error("BUG: Auth server sent us more than %d bytes of data",
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi AUTH_SERVER_CONN_MAX_LINE_LENGTH);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi auth_server_connection_disconnect(conn);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (!conn->version_received) {
7bebe46c240b554f47faeed19186123896281967jc line = i_stream_next_line(conn->input);
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanian if (line == NULL)
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanian return;
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanian
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi /* make sure the major version matches */
7bebe46c240b554f47faeed19186123896281967jc if (strncmp(line, "VERSION\t", 8) != 0 ||
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi atoi(t_strcut(line + 8, '\t')) !=
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi AUTH_CLIENT_PROTOCOL_MAJOR_VERSION) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi i_error("Authentication server not compatible with "
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "this client (mixed old and new binaries?)");
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi auth_server_connection_disconnect(conn);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi conn->version_received = TRUE;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7bebe46c240b554f47faeed19186123896281967jc input = conn->input;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi i_stream_ref(input);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi while ((line = i_stream_next_line(input)) != NULL && !input->closed) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi T_BEGIN {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi ret = auth_server_connection_input_line(conn, line);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi } T_END;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (ret < 0) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi auth_server_connection_disconnect(conn);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi break;
7bebe46c240b554f47faeed19186123896281967jc }
7bebe46c240b554f47faeed19186123896281967jc }
7bebe46c240b554f47faeed19186123896281967jc i_stream_unref(&input);
7bebe46c240b554f47faeed19186123896281967jc}
7bebe46c240b554f47faeed19186123896281967jc
7bebe46c240b554f47faeed19186123896281967jcstruct auth_server_connection *
7bebe46c240b554f47faeed19186123896281967jcauth_server_connection_init(struct auth_client *client)
7bebe46c240b554f47faeed19186123896281967jc{
7bebe46c240b554f47faeed19186123896281967jc struct auth_server_connection *conn;
7bebe46c240b554f47faeed19186123896281967jc pool_t pool;
7bebe46c240b554f47faeed19186123896281967jc
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanian pool = pool_alloconly_create("auth server connection", 1024);
7bebe46c240b554f47faeed19186123896281967jc conn = p_new(pool, struct auth_server_connection, 1);
7bebe46c240b554f47faeed19186123896281967jc conn->pool = pool;
7bebe46c240b554f47faeed19186123896281967jc
7bebe46c240b554f47faeed19186123896281967jc conn->client = client;
7bebe46c240b554f47faeed19186123896281967jc conn->fd = -1;
7bebe46c240b554f47faeed19186123896281967jc conn->requests = hash_table_create(default_pool, pool, 100, NULL, NULL);
7bebe46c240b554f47faeed19186123896281967jc i_array_init(&conn->available_auth_mechs, 8);
7bebe46c240b554f47faeed19186123896281967jc return conn;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi}
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindistatic void
7bebe46c240b554f47faeed19186123896281967jcauth_server_connection_remove_requests(struct auth_server_connection *conn)
7bebe46c240b554f47faeed19186123896281967jc{
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanian static const char *const temp_failure_args[] = { "temp", NULL };
7bebe46c240b554f47faeed19186123896281967jc struct hash_iterate_context *iter;
7bebe46c240b554f47faeed19186123896281967jc void *key, *value;
7bebe46c240b554f47faeed19186123896281967jc
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanian iter = hash_table_iterate_init(conn->requests);
7bebe46c240b554f47faeed19186123896281967jc while (hash_table_iterate(iter, &key, &value)) {
7bebe46c240b554f47faeed19186123896281967jc struct auth_client_request *request = value;
7bebe46c240b554f47faeed19186123896281967jc
7bebe46c240b554f47faeed19186123896281967jc auth_client_request_server_input(request,
7bebe46c240b554f47faeed19186123896281967jc AUTH_REQUEST_STATUS_FAIL,
7bebe46c240b554f47faeed19186123896281967jc temp_failure_args);
7bebe46c240b554f47faeed19186123896281967jc }
7bebe46c240b554f47faeed19186123896281967jc hash_table_iterate_deinit(&iter);
7bebe46c240b554f47faeed19186123896281967jc}
7bebe46c240b554f47faeed19186123896281967jc
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanianstatic void auth_server_connection_close(struct auth_server_connection *conn)
7bebe46c240b554f47faeed19186123896281967jc{
7bebe46c240b554f47faeed19186123896281967jc conn->handshake_received = FALSE;
7bebe46c240b554f47faeed19186123896281967jc conn->version_received = FALSE;
7bebe46c240b554f47faeed19186123896281967jc conn->has_plain_mech = FALSE;
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanian conn->server_pid = 0;
7bebe46c240b554f47faeed19186123896281967jc conn->connect_uid = 0;
7bebe46c240b554f47faeed19186123896281967jc conn->cookie = NULL;
7bebe46c240b554f47faeed19186123896281967jc array_clear(&conn->available_auth_mechs);
7bebe46c240b554f47faeed19186123896281967jc
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (conn->to != NULL)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi timeout_remove(&conn->to);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (conn->io != NULL)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi io_remove(&conn->io);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (conn->fd != -1) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi i_stream_destroy(&conn->input);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi o_stream_destroy(&conn->output);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (close(conn->fd) < 0)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi i_error("close(auth server connection) failed: %m");
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi conn->fd = -1;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi auth_server_connection_remove_requests(conn);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (conn->client->connect_notify_callback != NULL) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi conn->client->connect_notify_callback(conn->client, FALSE,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi conn->client->connect_notify_context);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi }
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi}
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindistatic void auth_server_reconnect_timeout(struct auth_server_connection *conn)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi{
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi timeout_remove(&conn->to);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi (void)auth_server_connection_connect(conn);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi}
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindistatic void
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindiauth_server_connection_disconnect(struct auth_server_connection *conn)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi{
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi time_t next_connect;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi auth_server_connection_close(conn);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi next_connect = conn->last_connect + AUTH_SERVER_RECONNECT_TIMEOUT_SECS;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi conn->to = timeout_add(ioloop_time >= next_connect ? 0 :
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi (next_connect - ioloop_time) * 1000,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi auth_server_reconnect_timeout, conn);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi}
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindivoid auth_server_connection_deinit(struct auth_server_connection **_conn)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi{
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi struct auth_server_connection *conn = *_conn;
80ab886d233f514d54c2a6bdeb9fdfd951bd6881wesolows
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanian *_conn = NULL;
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanian
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanian auth_server_connection_close(conn);
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanian
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanian hash_table_destroy(&conn->requests);
7bebe46c240b554f47faeed19186123896281967jc array_free(&conn->available_auth_mechs);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi pool_unref(&conn->pool);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi}
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindistatic void auth_client_handshake_timeout(struct auth_server_connection *conn)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi{
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi i_error("Timeout waiting for handshake from auth server. "
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi "my pid=%u, input bytes=%"PRIuUOFF_T,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi conn->client->client_pid, conn->input->v_offset);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi auth_server_connection_disconnect(conn);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi}
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindiint auth_server_connection_connect(struct auth_server_connection *conn)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi{
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi const char *handshake;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi int fd;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi i_assert(conn->fd == -1);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi conn->last_connect = ioloop_time;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi /* max. 1 second wait here. */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi fd = net_connect_unix_with_retries(conn->client->auth_socket_path,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi 1000);
7bebe46c240b554f47faeed19186123896281967jc if (fd == -1) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (errno == EACCES) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi i_error("auth: %s",
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi eacces_error_get("connect",
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi conn->client->auth_socket_path));
7bebe46c240b554f47faeed19186123896281967jc } else {
7bebe46c240b554f47faeed19186123896281967jc i_error("auth: connect(%s) failed: %m",
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanian conn->client->auth_socket_path);
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanian }
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanian return -1;
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanian }
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanian conn->fd = fd;
7bebe46c240b554f47faeed19186123896281967jc conn->io = io_add(fd, IO_READ, auth_server_connection_input, conn);
7bebe46c240b554f47faeed19186123896281967jc conn->input = i_stream_create_fd(fd, AUTH_SERVER_CONN_MAX_LINE_LENGTH,
7bebe46c240b554f47faeed19186123896281967jc FALSE);
7bebe46c240b554f47faeed19186123896281967jc conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
7bebe46c240b554f47faeed19186123896281967jc
7bebe46c240b554f47faeed19186123896281967jc handshake = t_strdup_printf("VERSION\t%u\t%u\nCPID\t%u\n",
7bebe46c240b554f47faeed19186123896281967jc AUTH_CLIENT_PROTOCOL_MAJOR_VERSION,
7bebe46c240b554f47faeed19186123896281967jc AUTH_CLIENT_PROTOCOL_MINOR_VERSION,
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanian conn->client->client_pid);
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanian if (o_stream_send_str(conn->output, handshake) < 0) {
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanian i_warning("Error sending handshake to auth server: %m");
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanian auth_server_connection_disconnect(conn);
7bebe46c240b554f47faeed19186123896281967jc return -1;
7bebe46c240b554f47faeed19186123896281967jc }
7bebe46c240b554f47faeed19186123896281967jc
7bebe46c240b554f47faeed19186123896281967jc conn->to = timeout_add(AUTH_HANDSHAKE_TIMEOUT,
7bebe46c240b554f47faeed19186123896281967jc auth_client_handshake_timeout, conn);
7bebe46c240b554f47faeed19186123896281967jc return 0;
7bebe46c240b554f47faeed19186123896281967jc}
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanian
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanianunsigned int
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanianauth_server_connection_add_request(struct auth_server_connection *conn,
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanian struct auth_client_request *request)
7bebe46c240b554f47faeed19186123896281967jc{
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanian unsigned int id;
7bebe46c240b554f47faeed19186123896281967jc
7bebe46c240b554f47faeed19186123896281967jc id = ++conn->client->request_id_counter;
7bebe46c240b554f47faeed19186123896281967jc if (id == 0) {
7bebe46c240b554f47faeed19186123896281967jc /* wrapped - ID 0 not allowed */
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanian id = ++conn->client->request_id_counter;
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanian }
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanian hash_table_insert(conn->requests, POINTER_CAST(id), request);
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanian return id;
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanian}
a62774df315360f02521d6470eab7d5080137dadSinanallur Balasubramanian