auth-server-connection.c revision 63b70dd3e4b4d68a02b1bf7d78e92076210e3e1a
bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2003-2010 Dovecot authors, see the included COPYING file */
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "lib.h"
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen#include "array.h"
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen#include "hash.h"
eff552f5fdc275c940c4c709eeeddb833bc51b40Timo Sirainen#include "ioloop.h"
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen#include "istream.h"
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen#include "ostream.h"
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen#include "network.h"
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen#include "eacces-error.h"
b42f37ae6f65ed986315b6885568d32115e589b1Timo Sirainen#include "auth-client-private.h"
9d75363d3fbabc2fbc2d80f06672e3ed8965804aTimo Sirainen#include "auth-client-request.h"
9d75363d3fbabc2fbc2d80f06672e3ed8965804aTimo Sirainen#include "auth-server-connection.h"
9d75363d3fbabc2fbc2d80f06672e3ed8965804aTimo Sirainen
9d75363d3fbabc2fbc2d80f06672e3ed8965804aTimo Sirainen#include <unistd.h>
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen#include <stdlib.h>
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen#define AUTH_SERVER_CONN_MAX_LINE_LENGTH AUTH_CLIENT_MAX_LINE_LENGTH
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen#define AUTH_HANDSHAKE_TIMEOUT (30*1000)
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen#define AUTH_SERVER_RECONNECT_TIMEOUT_SECS 5
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainenstatic void
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainenauth_server_connection_reconnect(struct auth_server_connection *conn);
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainenstatic int
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainenauth_server_input_mech(struct auth_server_connection *conn,
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen const char *const *args)
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen{
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen struct auth_mech_desc mech_desc;
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen
5c99eaa4e3e07ee065580d163240b4ce95b66befTimo Sirainen if (conn->handshake_received) {
5c99eaa4e3e07ee065580d163240b4ce95b66befTimo Sirainen i_error("BUG: Authentication server already sent handshake");
5c99eaa4e3e07ee065580d163240b4ce95b66befTimo Sirainen return -1;
5c99eaa4e3e07ee065580d163240b4ce95b66befTimo Sirainen }
5c99eaa4e3e07ee065580d163240b4ce95b66befTimo Sirainen if (args[0] == NULL) {
5c99eaa4e3e07ee065580d163240b4ce95b66befTimo Sirainen i_error("BUG: Authentication server sent broken MECH line");
5c99eaa4e3e07ee065580d163240b4ce95b66befTimo Sirainen return -1;
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen }
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen memset(&mech_desc, 0, sizeof(mech_desc));
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen mech_desc.name = p_strdup(conn->pool, args[0]);
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen if (strcmp(mech_desc.name, "PLAIN") == 0)
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen conn->has_plain_mech = TRUE;
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen for (args++; *args != NULL; args++) {
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen if (strcmp(*args, "private") == 0)
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen mech_desc.flags |= MECH_SEC_PRIVATE;
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen else if (strcmp(*args, "anonymous") == 0)
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen mech_desc.flags |= MECH_SEC_ANONYMOUS;
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen else if (strcmp(*args, "plaintext") == 0)
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen mech_desc.flags |= MECH_SEC_PLAINTEXT;
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen else if (strcmp(*args, "dictionary") == 0)
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen mech_desc.flags |= MECH_SEC_DICTIONARY;
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen else if (strcmp(*args, "active") == 0)
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen mech_desc.flags |= MECH_SEC_ACTIVE;
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen else if (strcmp(*args, "forward-secrecy") == 0)
1f1e81aab38d833d1c9cdc244c91fd762e0080d4Timo Sirainen mech_desc.flags |= MECH_SEC_FORWARD_SECRECY;
12aad74464367f7e8be11eafe1af985bf7b1adecTimo Sirainen else if (strcmp(*args, "mutual-auth") == 0)
12aad74464367f7e8be11eafe1af985bf7b1adecTimo Sirainen mech_desc.flags |= MECH_SEC_MUTUAL_AUTH;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen }
2521482f3f897c83f7d5a2f9e17fe99fa4ba2cbeTimo Sirainen array_append(&conn->available_auth_mechs, &mech_desc, 1);
12aad74464367f7e8be11eafe1af985bf7b1adecTimo Sirainen return 0;
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen}
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainenstatic int
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainenauth_server_input_spid(struct auth_server_connection *conn,
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen const char *const *args)
12aad74464367f7e8be11eafe1af985bf7b1adecTimo Sirainen{
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen if (conn->handshake_received) {
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen i_error("BUG: Authentication server already sent handshake");
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen return -1;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen }
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen
12aad74464367f7e8be11eafe1af985bf7b1adecTimo Sirainen conn->server_pid = (unsigned int)strtoul(args[0], NULL, 10);
6135260095e1704ed6edff9d00bdfc043c11429cTimo Sirainen return 0;
73e19ec2d5069ea125dcd1ede5d8a70f701fd9a8Timo Sirainen}
12aad74464367f7e8be11eafe1af985bf7b1adecTimo Sirainen
12aad74464367f7e8be11eafe1af985bf7b1adecTimo Sirainenstatic int
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainenauth_server_input_cuid(struct auth_server_connection *conn,
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen const char *const *args)
12aad74464367f7e8be11eafe1af985bf7b1adecTimo Sirainen{
12aad74464367f7e8be11eafe1af985bf7b1adecTimo Sirainen if (conn->handshake_received) {
12aad74464367f7e8be11eafe1af985bf7b1adecTimo Sirainen i_error("BUG: Authentication server already sent handshake");
12aad74464367f7e8be11eafe1af985bf7b1adecTimo Sirainen return -1;
12aad74464367f7e8be11eafe1af985bf7b1adecTimo Sirainen }
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen if (args[0] == NULL) {
2521482f3f897c83f7d5a2f9e17fe99fa4ba2cbeTimo Sirainen i_error("BUG: Authentication server sent broken CUID line");
12aad74464367f7e8be11eafe1af985bf7b1adecTimo Sirainen return -1;
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen }
ccfc6441cadb577084daeb1f0aa3dd7bdfa2a220Timo Sirainen
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen conn->connect_uid = (unsigned int)strtoul(args[0], NULL, 10);
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen return 0;
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen}
12aad74464367f7e8be11eafe1af985bf7b1adecTimo Sirainen
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainenstatic int
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainenauth_server_input_cookie(struct auth_server_connection *conn,
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen const char *const *args)
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen{
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen if (conn->cookie != NULL) {
12aad74464367f7e8be11eafe1af985bf7b1adecTimo Sirainen i_error("BUG: Authentication server already sent cookie");
6135260095e1704ed6edff9d00bdfc043c11429cTimo Sirainen return -1;
73e19ec2d5069ea125dcd1ede5d8a70f701fd9a8Timo Sirainen }
12aad74464367f7e8be11eafe1af985bf7b1adecTimo Sirainen conn->cookie = p_strdup(conn->pool, args[0]);
12aad74464367f7e8be11eafe1af985bf7b1adecTimo Sirainen return 0;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen}
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen
12aad74464367f7e8be11eafe1af985bf7b1adecTimo Sirainenstatic int auth_server_input_done(struct auth_server_connection *conn)
12aad74464367f7e8be11eafe1af985bf7b1adecTimo Sirainen{
12aad74464367f7e8be11eafe1af985bf7b1adecTimo Sirainen if (array_count(&conn->available_auth_mechs) == 0) {
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen i_error("BUG: Authentication server returned no mechanisms");
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen return -1;
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen }
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen if (conn->cookie == NULL) {
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen i_error("BUG: Authentication server didn't send a cookie");
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen return -1;
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen }
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen if (conn->to != NULL)
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen timeout_remove(&conn->to);
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen conn->handshake_received = TRUE;
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen if (conn->client->connect_notify_callback != NULL) {
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen conn->client->connect_notify_callback(conn->client, TRUE,
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen conn->client->connect_notify_context);
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen }
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen return 0;
e48d89622047bd8bbd0475b881ca9377d592f535Timo Sirainen}
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainenstatic int
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainenauth_server_lookup_request(struct auth_server_connection *conn,
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen const char *id_arg, bool remove,
e48d89622047bd8bbd0475b881ca9377d592f535Timo Sirainen struct auth_client_request **request_r)
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen{
965ed6ea3fc8f7637bd0d159d2fdb283a191ce34Timo Sirainen struct auth_client_request *request;
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen unsigned int id;
8ff9812659728d4166df8e003a1dd3524ae8514eTimo Sirainen
966cb0c1aa58578339cea6f79b4a423a851ab074Timo Sirainen if (id_arg == NULL) {
966cb0c1aa58578339cea6f79b4a423a851ab074Timo Sirainen i_error("BUG: Authentication server input missing ID");
966cb0c1aa58578339cea6f79b4a423a851ab074Timo Sirainen return -1;
966cb0c1aa58578339cea6f79b4a423a851ab074Timo Sirainen }
d5abbb932a0a598f002da39a8b3326643b1b5efcTimo Sirainen id = (unsigned int)strtoul(id_arg, NULL, 10);
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen
d5abbb932a0a598f002da39a8b3326643b1b5efcTimo Sirainen request = hash_table_lookup(conn->requests, POINTER_CAST(id));
d5abbb932a0a598f002da39a8b3326643b1b5efcTimo Sirainen if (request == NULL) {
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen i_error("BUG: Authentication server sent unknown id %u", id);
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen return -1;
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen }
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen if (remove || auth_client_request_is_aborted(request))
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen hash_table_remove(conn->requests, POINTER_CAST(id));
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen
747e77e3ab073a8e9e69c7a3e71b4593c5655d03Timo Sirainen *request_r = request;
dd93aba1901a457346990f49c54a738947dc7128Timo Sirainen return 0;
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen}
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainenstatic int
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainenauth_server_input_ok(struct auth_server_connection *conn,
e48d89622047bd8bbd0475b881ca9377d592f535Timo Sirainen const char *const *args)
e48d89622047bd8bbd0475b881ca9377d592f535Timo Sirainen{
e48d89622047bd8bbd0475b881ca9377d592f535Timo Sirainen struct auth_client_request *request;
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen
e48d89622047bd8bbd0475b881ca9377d592f535Timo Sirainen if (auth_server_lookup_request(conn, args[0], TRUE, &request) < 0)
e48d89622047bd8bbd0475b881ca9377d592f535Timo Sirainen return -1;
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen auth_client_request_server_input(request, AUTH_REQUEST_STATUS_OK,
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen args + 1);
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen return 0;
e48d89622047bd8bbd0475b881ca9377d592f535Timo Sirainen}
08aea01ef9a9d20703e0fcf8618e6195c0037a44Timo Sirainen
08aea01ef9a9d20703e0fcf8618e6195c0037a44Timo Sirainenstatic int auth_server_input_cont(struct auth_server_connection *conn,
f3d506e525a720f214020ca0f989a1966b30edaeTimo Sirainen const char *const *args)
08aea01ef9a9d20703e0fcf8618e6195c0037a44Timo Sirainen{
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen struct auth_client_request *request;
f3d506e525a720f214020ca0f989a1966b30edaeTimo Sirainen
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen if (str_array_length(args) < 2) {
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen i_error("BUG: Authentication server sent broken CONT line");
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen return -1;
849969f639a00eab26791db3cb1b66430420c0cdTimo Sirainen }
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen if (auth_server_lookup_request(conn, args[0], FALSE, &request) < 0)
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen return -1;
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen auth_client_request_server_input(request, AUTH_REQUEST_STATUS_CONTINUE,
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen args + 1);
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen return 0;
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen}
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainenstatic int auth_server_input_fail(struct auth_server_connection *conn,
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen const char *const *args)
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen{
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen struct auth_client_request *request;
849969f639a00eab26791db3cb1b66430420c0cdTimo Sirainen
849969f639a00eab26791db3cb1b66430420c0cdTimo Sirainen if (auth_server_lookup_request(conn, args[0], TRUE, &request) < 0)
9d75363d3fbabc2fbc2d80f06672e3ed8965804aTimo Sirainen return -1;
9d75363d3fbabc2fbc2d80f06672e3ed8965804aTimo Sirainen auth_client_request_server_input(request, AUTH_REQUEST_STATUS_FAIL,
9d75363d3fbabc2fbc2d80f06672e3ed8965804aTimo Sirainen args + 1);
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen return 0;
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen}
9625595c47c665f5aee57ebfcb1fcbe9ad1bf3a0Martti Rannanjärvi
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainenstatic int
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainenauth_server_connection_input_line(struct auth_server_connection *conn,
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen const char *line)
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen{
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen const char *const *args;
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen if (conn->client->debug)
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen i_debug("auth input: %s", line);
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen args = t_strsplit(line, "\t");
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen if (strcmp(args[0], "OK") == 0)
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen return auth_server_input_ok(conn, args + 1);
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen else if (strcmp(args[0], "CONT") == 0)
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen return auth_server_input_cont(conn, args + 1);
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen else if (strcmp(args[0], "FAIL") == 0)
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen return auth_server_input_fail(conn, args + 1);
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen else if (strcmp(args[0], "MECH") == 0)
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen return auth_server_input_mech(conn, args + 1);
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen else if (strcmp(args[0], "SPID") == 0)
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen return auth_server_input_spid(conn, args + 1);
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen else if (strcmp(args[0], "CUID") == 0)
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen return auth_server_input_cuid(conn, args + 1);
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen else if (strcmp(args[0], "COOKIE") == 0)
51ead2f4c04ee85615d23c453924633b9ed8a4c2Timo Sirainen return auth_server_input_cookie(conn, args + 1);
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen else if (strcmp(args[0], "DONE") == 0)
9698cd24356147d8a5471260062ea7e10e692fdfAki Tuomi return auth_server_input_done(conn);
9698cd24356147d8a5471260062ea7e10e692fdfAki Tuomi else {
9698cd24356147d8a5471260062ea7e10e692fdfAki Tuomi i_error("Auth server sent unknown command: %s", args[0]);
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen return -1;
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen }
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen}
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainenstatic void auth_server_connection_input(struct auth_server_connection *conn)
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen{
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen struct istream *input;
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen const char *line;
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen int ret;
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen switch (i_stream_read(conn->input)) {
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen case 0:
51ead2f4c04ee85615d23c453924633b9ed8a4c2Timo Sirainen return;
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen case -1:
9698cd24356147d8a5471260062ea7e10e692fdfAki Tuomi /* disconnected */
9698cd24356147d8a5471260062ea7e10e692fdfAki Tuomi auth_server_connection_reconnect(conn);
9698cd24356147d8a5471260062ea7e10e692fdfAki Tuomi return;
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen case -2:
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen /* buffer full - can't happen unless auth is buggy */
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen i_error("BUG: Auth server sent us more than %d bytes of data",
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen AUTH_SERVER_CONN_MAX_LINE_LENGTH);
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen auth_server_connection_disconnect(conn);
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen return;
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen }
if (!conn->version_received) {
line = i_stream_next_line(conn->input);
if (line == NULL)
return;
/* make sure the major version matches */
if (strncmp(line, "VERSION\t", 8) != 0 ||
atoi(t_strcut(line + 8, '\t')) !=
AUTH_CLIENT_PROTOCOL_MAJOR_VERSION) {
i_error("Authentication server not compatible with "
"this client (mixed old and new binaries?)");
auth_server_connection_disconnect(conn);
return;
}
conn->version_received = TRUE;
}
input = conn->input;
i_stream_ref(input);
while ((line = i_stream_next_line(input)) != NULL && !input->closed) {
T_BEGIN {
ret = auth_server_connection_input_line(conn, line);
} T_END;
if (ret < 0) {
auth_server_connection_disconnect(conn);
break;
}
}
i_stream_unref(&input);
}
struct auth_server_connection *
auth_server_connection_init(struct auth_client *client)
{
struct auth_server_connection *conn;
pool_t pool;
pool = pool_alloconly_create("auth server connection", 1024);
conn = p_new(pool, struct auth_server_connection, 1);
conn->pool = pool;
conn->client = client;
conn->fd = -1;
conn->requests = hash_table_create(default_pool, pool, 100, NULL, NULL);
i_array_init(&conn->available_auth_mechs, 8);
return conn;
}
static void
auth_server_connection_remove_requests(struct auth_server_connection *conn)
{
static const char *const temp_failure_args[] = { "temp", NULL };
struct hash_iterate_context *iter;
void *key, *value;
iter = hash_table_iterate_init(conn->requests);
while (hash_table_iterate(iter, &key, &value)) {
struct auth_client_request *request = value;
auth_client_request_server_input(request,
AUTH_REQUEST_STATUS_FAIL,
temp_failure_args);
}
hash_table_iterate_deinit(&iter);
hash_table_clear(conn->requests, FALSE);
}
void auth_server_connection_disconnect(struct auth_server_connection *conn)
{
conn->handshake_received = FALSE;
conn->version_received = FALSE;
conn->has_plain_mech = FALSE;
conn->server_pid = 0;
conn->connect_uid = 0;
conn->cookie = NULL;
array_clear(&conn->available_auth_mechs);
if (conn->to != NULL)
timeout_remove(&conn->to);
if (conn->io != NULL)
io_remove(&conn->io);
if (conn->fd != -1) {
i_stream_destroy(&conn->input);
o_stream_destroy(&conn->output);
if (close(conn->fd) < 0)
i_error("close(auth server connection) failed: %m");
conn->fd = -1;
}
auth_server_connection_remove_requests(conn);
if (conn->client->connect_notify_callback != NULL) {
conn->client->connect_notify_callback(conn->client, FALSE,
conn->client->connect_notify_context);
}
}
static void auth_server_reconnect_timeout(struct auth_server_connection *conn)
{
timeout_remove(&conn->to);
(void)auth_server_connection_connect(conn);
}
static void
auth_server_connection_reconnect(struct auth_server_connection *conn)
{
time_t next_connect;
auth_server_connection_disconnect(conn);
next_connect = conn->last_connect + AUTH_SERVER_RECONNECT_TIMEOUT_SECS;
conn->to = timeout_add(ioloop_time >= next_connect ? 0 :
(next_connect - ioloop_time) * 1000,
auth_server_reconnect_timeout, conn);
}
void auth_server_connection_deinit(struct auth_server_connection **_conn)
{
struct auth_server_connection *conn = *_conn;
*_conn = NULL;
auth_server_connection_disconnect(conn);
hash_table_destroy(&conn->requests);
array_free(&conn->available_auth_mechs);
pool_unref(&conn->pool);
}
static void auth_client_handshake_timeout(struct auth_server_connection *conn)
{
i_error("Timeout waiting for handshake from auth server. "
"my pid=%u, input bytes=%"PRIuUOFF_T,
conn->client->client_pid, conn->input->v_offset);
auth_server_connection_reconnect(conn);
}
int auth_server_connection_connect(struct auth_server_connection *conn)
{
const char *handshake;
int fd;
i_assert(conn->fd == -1);
conn->last_connect = ioloop_time;
/* max. 1 second wait here. */
fd = net_connect_unix_with_retries(conn->client->auth_socket_path,
1000);
if (fd == -1) {
if (errno == EACCES) {
i_error("auth: %s",
eacces_error_get("connect",
conn->client->auth_socket_path));
} else {
i_error("auth: connect(%s) failed: %m",
conn->client->auth_socket_path);
}
return -1;
}
conn->fd = fd;
conn->io = io_add(fd, IO_READ, auth_server_connection_input, conn);
conn->input = i_stream_create_fd(fd, AUTH_SERVER_CONN_MAX_LINE_LENGTH,
FALSE);
conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
handshake = t_strdup_printf("VERSION\t%u\t%u\nCPID\t%u\n",
AUTH_CLIENT_PROTOCOL_MAJOR_VERSION,
AUTH_CLIENT_PROTOCOL_MINOR_VERSION,
conn->client->client_pid);
if (o_stream_send_str(conn->output, handshake) < 0) {
i_warning("Error sending handshake to auth server: %m");
auth_server_connection_disconnect(conn);
return -1;
}
conn->to = timeout_add(AUTH_HANDSHAKE_TIMEOUT,
auth_client_handshake_timeout, conn);
return 0;
}
unsigned int
auth_server_connection_add_request(struct auth_server_connection *conn,
struct auth_client_request *request)
{
unsigned int id;
id = ++conn->client->request_id_counter;
if (id == 0) {
/* wrapped - ID 0 not allowed */
id = ++conn->client->request_id_counter;
}
hash_table_insert(conn->requests, POINTER_CAST(id), request);
return id;
}