auth-server-connection.c revision eddd9bf1a1369aea4a2715f6be1137da6d17d293
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2003-2007 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "buffer.h"
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include "hash.h"
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include "ioloop.h"
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen#include "istream.h"
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen#include "ostream.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "network.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "auth-client.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "auth-server-connection.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "auth-server-request.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <unistd.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <stdlib.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#define AUTH_HANDSHAKE_TIMEOUT (30*1000)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void auth_server_connection_unref(struct auth_server_connection *conn);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void update_available_auth_mechs(struct auth_server_connection *conn)
66ecc94150cbce23aad3240135e0782e0a74d479Timo Sirainen{
66ecc94150cbce23aad3240135e0782e0a74d479Timo Sirainen struct auth_client *client = conn->client;
ef5fb27361cc5e15766e85e28355750ff04b13c9Timo Sirainen const struct auth_mech_desc *mech;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct auth_mech_desc *new_mech;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int i;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mech = conn->available_auth_mechs;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (i = 0; i < conn->available_auth_mechs_count; i++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (auth_client_find_mech(client, mech[i].name) == NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen new_mech = buffer_append_space_unsafe(
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen client->available_auth_mechs, sizeof(*mech));
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen *new_mech = mech[i];
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen new_mech->name = i_strdup(mech[i].name);
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen }
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen }
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic bool
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenauth_client_input_mech(struct auth_server_connection *conn, const char *args)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen const char *const *list;
ad850190d946d34966a56838cfdb216e021b5b5fTimo Sirainen struct auth_mech_desc mech_desc;
ad850190d946d34966a56838cfdb216e021b5b5fTimo Sirainen
ad850190d946d34966a56838cfdb216e021b5b5fTimo Sirainen if (conn->handshake_received) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_error("BUG: Authentication server already sent handshake");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen }
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen list = t_strsplit(args, "\t");
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (list[0] == NULL) {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen i_error("BUG: Authentication server sent broken MECH line");
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen memset(&mech_desc, 0, sizeof(mech_desc));
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen mech_desc.name = p_strdup(conn->pool, list[0]);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (strcmp(mech_desc.name, "PLAIN") == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen conn->has_plain_mech = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (list++; *list != NULL; list++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (strcmp(*list, "private") == 0)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen mech_desc.flags |= MECH_SEC_PRIVATE;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen else if (strcmp(*list, "anonymous") == 0)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen mech_desc.flags |= MECH_SEC_ANONYMOUS;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else if (strcmp(*list, "plaintext") == 0)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen mech_desc.flags |= MECH_SEC_PLAINTEXT;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else if (strcmp(*list, "dictionary") == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mech_desc.flags |= MECH_SEC_DICTIONARY;
6e235046e1d8e9d89fc948f5c623676c20421a28Timo Sirainen else if (strcmp(*list, "active") == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mech_desc.flags |= MECH_SEC_ACTIVE;
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen else if (strcmp(*list, "forward-secrecy") == 0)
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen mech_desc.flags |= MECH_SEC_FORWARD_SECRECY;
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen else if (strcmp(*list, "mutual-auth") == 0)
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen mech_desc.flags |= MECH_SEC_MUTUAL_AUTH;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_append(conn->auth_mechs_buf, &mech_desc, sizeof(mech_desc));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic bool
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenauth_client_input_spid(struct auth_server_connection *conn, const char *args)
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen{
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen if (conn->handshake_received) {
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen i_error("BUG: Authentication server already sent handshake");
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen return FALSE;
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen }
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen conn->server_pid = (unsigned int)strtoul(args, NULL, 10);
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen return TRUE;
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen}
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainenstatic bool
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainenauth_client_input_cuid(struct auth_server_connection *conn, const char *args)
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen{
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen if (conn->handshake_received) {
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen i_error("BUG: Authentication server already sent handshake");
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen return FALSE;
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen }
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen conn->connect_uid = (unsigned int)strtoul(args, NULL, 10);
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen return TRUE;
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen}
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainenstatic bool auth_client_input_done(struct auth_server_connection *conn)
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen{
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen conn->available_auth_mechs = conn->auth_mechs_buf->data;
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen conn->available_auth_mechs_count =
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen conn->auth_mechs_buf->used / sizeof(struct auth_mech_desc);
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen if (conn->available_auth_mechs_count == 0) {
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen i_error("BUG: Authentication server returned no mechanisms");
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen return FALSE;
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen }
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen if (conn->to != NULL)
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen timeout_remove(&conn->to);
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen conn->handshake_received = TRUE;
66ecc94150cbce23aad3240135e0782e0a74d479Timo Sirainen conn->client->conn_waiting_handshake_count--;
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen update_available_auth_mechs(conn);
04b8a90af181cc4c7959266855e8ed50a22ed413Timo Sirainen
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen if (conn->client->connect_notify_callback != NULL &&
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen auth_client_is_connected(conn->client)) {
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen conn->client->connect_notify_callback(conn->client, TRUE,
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen conn->client->connect_notify_context);
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen }
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen return TRUE;
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen}
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainenstatic bool
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainenauth_client_input_line(struct auth_server_connection *conn, const char *line)
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen{
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen if (strncmp(line, "OK\t", 3) == 0)
66ecc94150cbce23aad3240135e0782e0a74d479Timo Sirainen return auth_client_input_ok(conn, line + 3);
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen else if (strncmp(line, "CONT\t", 5) == 0)
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen return auth_client_input_cont(conn, line + 5);
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen else if (strncmp(line, "FAIL\t", 5) == 0)
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen return auth_client_input_fail(conn, line + 5);
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen else if (strncmp(line, "MECH\t", 5) == 0)
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen return auth_client_input_mech(conn, line + 5);
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen else if (strncmp(line, "SPID\t", 5) == 0)
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen return auth_client_input_spid(conn, line + 5);
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen else if (strncmp(line, "CUID\t", 5) == 0)
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen return auth_client_input_cuid(conn, line + 5);
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen else if (strcmp(line, "DONE") == 0)
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen return auth_client_input_done(conn);
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen else {
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen /* ignore unknown command */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return TRUE;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen}
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainenstatic void auth_client_input(struct auth_server_connection *conn)
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen{
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen const char *line;
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen int ret;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen switch (i_stream_read(conn->input)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case 0:
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen return;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen case -1:
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen /* disconnected */
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen auth_server_connection_destroy(&conn, TRUE);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen return;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen case -2:
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen /* buffer full - can't happen unless auth is buggy */
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen i_error("BUG: Auth server sent us more than %d bytes of data",
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen AUTH_CLIENT_MAX_LINE_LENGTH);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen auth_server_connection_destroy(&conn, FALSE);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (conn->version_received) {
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen line = i_stream_next_line(conn->input);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen if (line == NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* make sure the major version matches */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (strncmp(line, "VERSION\t", 8) != 0 ||
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen atoi(t_strcut(line + 8, '\t')) !=
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen AUTH_CLIENT_PROTOCOL_MAJOR_VERSION) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen i_error("Authentication server not compatible with "
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen "this client (mixed old and new binaries?)");
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen auth_server_connection_destroy(&conn, FALSE);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen return;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen }
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen conn->version_received = TRUE;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen }
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen conn->refcount++;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen while ((line = i_stream_next_line(conn->input)) != NULL) {
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen T_FRAME(
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen ret = auth_client_input_line(conn, line);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen );
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!ret) {
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen auth_server_connection_destroy(&conn, FALSE);
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen break;
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen }
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen }
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen auth_server_connection_unref(conn);
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen}
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainenstatic void auth_client_handshake_timeout(struct auth_server_connection *conn)
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen{
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen i_error("Timeout waiting for handshake from auth server. "
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen "my pid=%u, input bytes=%"PRIuUOFF_T,
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen conn->client->pid, conn->input->v_offset);
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen auth_server_connection_destroy(&conn, TRUE);
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen}
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainenstruct auth_server_connection *
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainenauth_server_connection_new(struct auth_client *client, const char *path)
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen{
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen struct auth_server_connection *conn;
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen const char *handshake;
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen pool_t pool;
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen int fd, try;
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen /* max. 1 second wait here. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (try = 0; try < 10; try++) {
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen fd = net_connect_unix(path);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (fd != -1 || (errno != EAGAIN && errno != ECONNREFUSED))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* busy. wait for a while. */
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen usleep(((rand() % 10) + 1) * 10000);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (fd == -1) {
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen i_error("Can't connect to auth server at %s: %m", path);
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen return NULL;
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen }
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen /* use blocking connection since we depend on auth server -
e192a3b1ca8ae857e7d87298ea507d32977ba570Timo Sirainen if it's slow, just wait */
e192a3b1ca8ae857e7d87298ea507d32977ba570Timo Sirainen
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen pool = pool_alloconly_create("Auth connection", 1024);
e192a3b1ca8ae857e7d87298ea507d32977ba570Timo Sirainen conn = p_new(pool, struct auth_server_connection, 1);
811f2e26d9782d9cb99fdf82e18ffa0a77564fe2Timo Sirainen conn->refcount = 1;
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen conn->pool = pool;
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen
c4877db8b6559846f4b58be8e42422dc734c193fTimo Sirainen conn->client = client;
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen conn->path = p_strdup(pool, path);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen conn->fd = fd;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen conn->io = io_add(fd, IO_READ, auth_client_input, conn);
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen conn->input = i_stream_create_fd(fd, AUTH_CLIENT_MAX_LINE_LENGTH,
8b9342aa96b2f297e23afb261f9f7dd859800952Timo Sirainen FALSE);
8b9342aa96b2f297e23afb261f9f7dd859800952Timo Sirainen conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
8b9342aa96b2f297e23afb261f9f7dd859800952Timo Sirainen conn->requests = hash_create(default_pool, pool, 100, NULL, NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen conn->auth_mechs_buf = buffer_create_dynamic(default_pool, 256);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
37e6cf44d61a81c6839e3ab76234b54309d8d292Timo Sirainen conn->to = timeout_add(AUTH_HANDSHAKE_TIMEOUT,
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen auth_client_handshake_timeout, conn);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen conn->next = client->connections;
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen client->connections = conn;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen handshake = t_strdup_printf("VERSION\t%u\t%u\nCPID\t%u\n",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen AUTH_CLIENT_PROTOCOL_MAJOR_VERSION,
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen AUTH_CLIENT_PROTOCOL_MINOR_VERSION,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client->pid);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client->conn_waiting_handshake_count++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (o_stream_send_str(conn->output, handshake) < 0) {
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen errno = conn->output->stream_errno;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen i_warning("Error sending handshake to auth server: %m");
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen auth_server_connection_destroy(&conn, TRUE);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen return NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen return conn;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainenvoid auth_server_connection_destroy(struct auth_server_connection **_conn,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen bool reconnect)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen{
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen struct auth_server_connection *conn = *_conn;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen struct auth_client *client = conn->client;
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen struct auth_server_connection **pos;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen *_conn = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (conn->fd == -1)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen return;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen pos = &conn->client->connections;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen for (; *pos != NULL; pos = &(*pos)->next) {
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (*pos == conn) {
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen *pos = conn->next;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen break;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen }
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen }
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen if (!conn->handshake_received)
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen client->conn_waiting_handshake_count--;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen if (conn->to != NULL)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen timeout_remove(&conn->to);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (conn->io != NULL)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen io_remove(&conn->io);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen i_stream_close(conn->input);
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen o_stream_close(conn->output);
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen if (close(conn->fd) < 0)
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen i_error("close(auth) failed: %m");
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen conn->fd = -1;
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen auth_server_requests_remove_all(conn);
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen auth_server_connection_unref(conn);
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen if (reconnect)
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen auth_client_connect_missing_servers(client);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen else if (client->connect_notify_callback != NULL) {
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen client->connect_notify_callback(client,
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen auth_client_is_connected(client),
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen client->connect_notify_context);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen }
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen}
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void auth_server_connection_unref(struct auth_server_connection *conn)
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (--conn->refcount > 0)
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(conn->refcount == 0);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen hash_destroy(&conn->requests);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_free(&conn->auth_mechs_buf);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen i_stream_unref(&conn->input);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen o_stream_unref(&conn->output);
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen pool_unref(&conn->pool);
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen}
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainenstruct auth_server_connection *
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainenauth_server_connection_find_path(struct auth_client *client, const char *path)
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct auth_server_connection *conn;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (conn = client->connections; conn != NULL; conn = conn->next) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (strcmp(conn->path, path) == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return conn;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct auth_server_connection *
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenauth_server_connection_find_mech(struct auth_client *client,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *name, const char **error_r)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct auth_server_connection *conn, *match;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen const struct auth_mech_desc *mech;
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen unsigned int i, n, match_n;
f519e4c2ad4ef826f1b08f3e0138b9b287a52c80Timo Sirainen
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen /* find a connection which has this mechanism. if there are multiple
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen available connections to use, do round robin load balancing */
d565eaa943f29a49b97230ced57eec40ee65b4f9Timo Sirainen match = NULL; match_n = n = 0;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen for (conn = client->connections; conn != NULL; conn = conn->next, n++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mech = conn->available_auth_mechs;
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen for (i = 0; i < conn->available_auth_mechs_count; i++) {
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen if (strcasecmp(mech[i].name, name) == 0) {
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen if (n > client->last_used_auth_process) {
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen client->last_used_auth_process = n;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return conn;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen if (match == NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen match = conn;
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen match_n = n;
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen }
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen break;
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen }
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen }
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen }
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (match != NULL) {
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen client->last_used_auth_process = match_n;
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen return match;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (auth_client_find_mech(client, name) == NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *error_r = "Unsupported authentication mechanism";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *error_r = "Authentication server isn't connected, "
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "try again later..";
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen }
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return NULL;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen