auth-server-connection.c revision 3c296d819c54e21ce05c3d2eeeedc79be42ac593
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2003-2012 Dovecot authors, see the included COPYING file */
6ec925f52d04ec8700e47cb005bd7ddc65ac5614Timo Sirainen#define AUTH_SERVER_CONN_MAX_LINE_LENGTH AUTH_CLIENT_MAX_LINE_LENGTH
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenauth_server_connection_reconnect(struct auth_server_connection *conn,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenauth_server_input_mech(struct auth_server_connection *conn,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *const *args)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_error("BUG: Authentication server already sent handshake");
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen i_error("BUG: Authentication server sent broken MECH line");
e9ac518aaf49a06d976bf7f24ab14a3e2d6d86abTimo Sirainen mech_desc.name = p_strdup(conn->pool, args[0]);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen else if (strcmp(*args, "forward-secrecy") == 0)
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen array_append(&conn->available_auth_mechs, &mech_desc, 1);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainenauth_server_input_spid(struct auth_server_connection *conn,
e9ac518aaf49a06d976bf7f24ab14a3e2d6d86abTimo Sirainen const char *const *args)
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen i_error("BUG: Authentication server already sent handshake");
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen if (str_to_uint(args[0], &conn->server_pid) < 0) {
f7423cbbd9dea363a5df18ebb96da055a977ae79Timo Sirainen i_error("BUG: Authentication server sent invalid PID");
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainenauth_server_input_cuid(struct auth_server_connection *conn,
617e13833c798435e2be425b99c27ecaad1b8393Timo Sirainen const char *const *args)
e9ac518aaf49a06d976bf7f24ab14a3e2d6d86abTimo Sirainen i_error("BUG: Authentication server already sent handshake");
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen str_to_uint(args[0], &conn->connect_uid) < 0) {
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen i_error("BUG: Authentication server sent broken CUID line");
e9ac518aaf49a06d976bf7f24ab14a3e2d6d86abTimo Sirainenauth_server_input_cookie(struct auth_server_connection *conn,
e9ac518aaf49a06d976bf7f24ab14a3e2d6d86abTimo Sirainen const char *const *args)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_error("BUG: Authentication server already sent cookie");
efc5c69c572e83db7bf7eab5d4698c0ab0d3d886Timo Sirainenstatic int auth_server_input_done(struct auth_server_connection *conn)
efc5c69c572e83db7bf7eab5d4698c0ab0d3d886Timo Sirainen if (array_count(&conn->available_auth_mechs) == 0) {
efc5c69c572e83db7bf7eab5d4698c0ab0d3d886Timo Sirainen i_error("BUG: Authentication server returned no mechanisms");
dc07b75b7ea83ff5f447970a20419032725271a7Timo Sirainen i_error("BUG: Authentication server didn't send a cookie");
29f32cdcf44cda9688576bfdc7450a8a15e90e86Timo Sirainen if (conn->client->connect_notify_callback != NULL) {
29f32cdcf44cda9688576bfdc7450a8a15e90e86Timo Sirainen conn->client->connect_notify_callback(conn->client, TRUE,
b955a1c1b6d466977d971c029a9305bee492f73cTimo Sirainenauth_server_lookup_request(struct auth_server_connection *conn,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int id;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (id_arg == NULL || str_to_uint(id_arg, &id) < 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_error("BUG: Authentication server input missing ID");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen request = hash_table_lookup(conn->requests, POINTER_CAST(id));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_error("BUG: Authentication server sent unknown id %u", id);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (remove || auth_client_request_is_aborted(request))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen hash_table_remove(conn->requests, POINTER_CAST(id));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenauth_server_input_ok(struct auth_server_connection *conn,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *const *args)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (auth_server_lookup_request(conn, args[0], TRUE, &request) < 0)
e1f866daa1bd1a5cd7516f3b19c6f197bcf6cc8aTimo Sirainen auth_client_request_server_input(request, AUTH_REQUEST_STATUS_OK,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic int auth_server_input_cont(struct auth_server_connection *conn,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *const *args)
e1f866daa1bd1a5cd7516f3b19c6f197bcf6cc8aTimo Sirainen i_error("BUG: Authentication server sent broken CONT line");
e1f866daa1bd1a5cd7516f3b19c6f197bcf6cc8aTimo Sirainen if (auth_server_lookup_request(conn, args[0], FALSE, &request) < 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen auth_client_request_server_input(request, AUTH_REQUEST_STATUS_CONTINUE,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstatic int auth_server_input_fail(struct auth_server_connection *conn,
72cc352b25ad401b923436c6ed0f1f3adaffa737Timo Sirainen const char *const *args)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (auth_server_lookup_request(conn, args[0], TRUE, &request) < 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen auth_client_request_server_input(request, AUTH_REQUEST_STATUS_FAIL,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenauth_server_connection_input_line(struct auth_server_connection *conn,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *const *args;
5d46f4d076fc13ae2779c365cf4bd9bda3a5bc69Timo Sirainen return auth_server_input_cont(conn, args + 1);
5d46f4d076fc13ae2779c365cf4bd9bda3a5bc69Timo Sirainen return auth_server_input_fail(conn, args + 1);
5d46f4d076fc13ae2779c365cf4bd9bda3a5bc69Timo Sirainen return auth_server_input_mech(conn, args + 1);
d482079eb385cd071bbc9637cacee225e4aff968Timo Sirainen return auth_server_input_spid(conn, args + 1);
3a0f9aa9504497e4e47f32df54fbf47fdc7423b6Timo Sirainen return auth_server_input_cuid(conn, args + 1);
1ffb2afe6d7e8860a2231a4827078cf2ef9c22cdTimo Sirainen return auth_server_input_cookie(conn, args + 1);
788f275469ad9ed530e440d6690d0e4381a323b2Timo Sirainen i_error("Auth server sent unknown command: %s", args[0]);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void auth_server_connection_input(struct auth_server_connection *conn)
5d46f4d076fc13ae2779c365cf4bd9bda3a5bc69Timo Sirainen /* disconnected */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen auth_server_connection_reconnect(conn, error);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* buffer full - can't happen unless auth is buggy */
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen i_error("BUG: Auth server sent us more than %d bytes of data",
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen auth_server_connection_disconnect(conn, "buffer full");
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* make sure the major version matches */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_error("Authentication server not compatible with "
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "this client (mixed old and new binaries?)");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "incompatible serevr");
e5097d2c8efecdd274272b222cf2b30a8ae4ca2aTimo Sirainen while ((line = i_stream_next_line(input)) != NULL && !input->closed) {
e5097d2c8efecdd274272b222cf2b30a8ae4ca2aTimo Sirainen ret = auth_server_connection_input_line(conn, line);
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen auth_server_connection_disconnect(conn, t_strdup_printf(
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenauth_server_connection_init(struct auth_client *client)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen pool = pool_alloconly_create("auth server connection", 1024);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen conn = p_new(pool, struct auth_server_connection, 1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen conn->requests = hash_table_create(default_pool, pool, 100, NULL, NULL);
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainenauth_server_connection_remove_requests(struct auth_server_connection *conn,
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen static const char *const temp_failure_args[] = { "temp", NULL };
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int request_count = 0;
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainen iter = hash_table_iterate_init(conn->requests);
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen while (hash_table_iterate(iter, &key, &value)) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!auth_client_request_is_aborted(request)) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen created = auth_client_request_get_create_time(request);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_warning("Auth connection closed with %u pending requests "
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid auth_server_connection_disconnect(struct auth_server_connection *conn,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_error("close(auth server connection) failed: %m");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen auth_server_connection_remove_requests(conn, reason);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (conn->client->connect_notify_callback != NULL) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen conn->client->connect_notify_callback(conn->client, FALSE,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void auth_server_reconnect_timeout(struct auth_server_connection *conn)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenauth_server_connection_reconnect(struct auth_server_connection *conn,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen auth_server_connection_disconnect(conn, disconnect_reason);
61618d4c58080570f689614fec204ae14e90cef2Timo Sirainen next_connect = conn->last_connect + AUTH_SERVER_RECONNECT_TIMEOUT_SECS;
19d01d72f98e7f28a1d8aed146adb6a777158092Timo Sirainen conn->to = timeout_add(ioloop_time >= next_connect ? 0 :
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid auth_server_connection_deinit(struct auth_server_connection **_conn)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen auth_server_connection_disconnect(conn, "deinitializing");
129db31de1780783a175633eba5811e44c361a81Timo Sirainen i_assert(hash_table_count(conn->requests) == 0);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void auth_client_handshake_timeout(struct auth_server_connection *conn)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_error("Timeout waiting for handshake from auth server. "
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen conn->client->client_pid, conn->input->v_offset);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen auth_server_connection_reconnect(conn, "auth server timeout");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenint auth_server_connection_connect(struct auth_server_connection *conn)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* max. 1 second wait here. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen fd = net_connect_unix_with_retries(conn->client->auth_socket_path,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen conn->io = io_add(fd, IO_READ, auth_server_connection_input, conn);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen conn->input = i_stream_create_fd(fd, AUTH_SERVER_CONN_MAX_LINE_LENGTH,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen handshake = t_strdup_printf("VERSION\t%u\t%u\nCPID\t%u\n",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (o_stream_send_str(conn->output, handshake) < 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_warning("Error sending handshake to auth server: %m");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen conn->to = timeout_add(AUTH_HANDSHAKE_TIMEOUT,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenauth_server_connection_add_request(struct auth_server_connection *conn,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int id;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* wrapped - ID 0 not allowed */