auth-worker-client.c revision cac0f62d29025e5493c53c1d26c6b00c88b089eb
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "common.h"
345648b341f228bd7f0b89f8aa3ecb9c470d817eTimo Sirainen#include "base64.h"
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen#include "ioloop.h"
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen#include "network.h"
5a2cb3d097a2d9a9e930af997e7bf3400a8d840dTimo Sirainen#include "istream.h"
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen#include "ostream.h"
0cc875d28852d15005cff2a77252e7836c862a01Timo Sirainen#include "str.h"
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen#include "auth-request.h"
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen#include "auth-worker-client.h"
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
16f46efe0e090fe6975acf012a61a160f4787985Andrey Panin#include <stdlib.h>
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen#define OUTBUF_THROTTLE_SIZE (1024*10)
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainenstruct auth_worker_client {
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen int refcount;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen struct auth *auth;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen int fd;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen struct io *io;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen struct istream *input;
16f46efe0e090fe6975acf012a61a160f4787985Andrey Panin struct ostream *output;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen};
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainenstatic void
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainenauth_worker_client_check_throttle(struct auth_worker_client *client)
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen{
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen if (o_stream_get_buffer_used_size(client->output) >=
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen OUTBUF_THROTTLE_SIZE) {
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen /* stop reading new requests until client has read the pending
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen replies. */
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen if (client->io != NULL)
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen io_remove(&client->io);
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen }
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen}
7242e1ce7803b83bc82e239ef111b47c1c72dd4bAndrey Panin
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainenstatic struct auth_request *
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainenworker_auth_request_new(struct auth_worker_client *client, unsigned int id,
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen const char *args)
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen{
c57776c06ec99ba9b0dafdbf9475ea72ea8ca134Timo Sirainen struct auth_request *auth_request;
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen const char *key, *value, *const *tmp;
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen auth_request = auth_request_new_dummy(client->auth);
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen client->refcount++;
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen auth_request->context = client;
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen auth_request->id = id;
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen
4051fa1f367553cac34f74c2e332a678390bcee5Timo Sirainen if (args != NULL) {
5965eaa2d972e6264cecaf54091cd43019bc7d1fTimo Sirainen for (tmp = t_strsplit(args, "\t"); *tmp != NULL; tmp++) {
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen value = strchr(*tmp, '=');
4051fa1f367553cac34f74c2e332a678390bcee5Timo Sirainen if (value == NULL)
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen continue;
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen key = t_strdup_until(*tmp, value);
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen value++;
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen (void)auth_request_import(auth_request, key, value);
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen }
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen }
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen
1ddec6312bc6882aeb17d4d46d19cbca1723b68bTimo Sirainen return auth_request;
1ddec6312bc6882aeb17d4d46d19cbca1723b68bTimo Sirainen}
1ddec6312bc6882aeb17d4d46d19cbca1723b68bTimo Sirainen
1ddec6312bc6882aeb17d4d46d19cbca1723b68bTimo Sirainenstatic void auth_worker_send_reply(struct auth_worker_client *client,
1ddec6312bc6882aeb17d4d46d19cbca1723b68bTimo Sirainen string_t *str)
59beb411159176b39e48a52d60dd3239732e67b4Timo Sirainen{
1ddec6312bc6882aeb17d4d46d19cbca1723b68bTimo Sirainen if (shutdown_request)
1ddec6312bc6882aeb17d4d46d19cbca1723b68bTimo Sirainen o_stream_send_str(client->output, "SHUTDOWN\n");
15cb9549422ccee416b21d26fec97a556ad0fa36Florian Zeitz o_stream_send(client->output, str_data(str), str_len(str));
1ddec6312bc6882aeb17d4d46d19cbca1723b68bTimo Sirainen}
1ddec6312bc6882aeb17d4d46d19cbca1723b68bTimo Sirainen
1ddec6312bc6882aeb17d4d46d19cbca1723b68bTimo Sirainenstatic void verify_plain_callback(enum passdb_result result,
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen struct auth_request *request)
1ddec6312bc6882aeb17d4d46d19cbca1723b68bTimo Sirainen{
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen struct auth_worker_client *client = request->context;
704fbadd78375da18dcaf2c5d93ac8cfe2c61358Timo Sirainen struct auth_stream_reply *reply;
704fbadd78375da18dcaf2c5d93ac8cfe2c61358Timo Sirainen string_t *str;
704fbadd78375da18dcaf2c5d93ac8cfe2c61358Timo Sirainen
2c38504860da8a8de915f8e0f5f39d7e7bd00cf8Timo Sirainen if (request->passdb_failure && result == PASSDB_RESULT_OK)
2c38504860da8a8de915f8e0f5f39d7e7bd00cf8Timo Sirainen result = PASSDB_RESULT_PASSWORD_MISMATCH;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen reply = auth_stream_reply_init(pool_datastack_create());
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen auth_stream_reply_add(reply, NULL, dec2str(request->id));
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen if (result == PASSDB_RESULT_OK)
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen auth_stream_reply_add(reply, "OK", NULL);
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen else {
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen auth_stream_reply_add(reply, "FAIL", NULL);
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen auth_stream_reply_add(reply, NULL,
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen t_strdup_printf("%d", result));
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen }
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen if (result != PASSDB_RESULT_INTERNAL_FAILURE) {
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen auth_stream_reply_add(reply, NULL, request->user);
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen auth_stream_reply_add(reply, NULL,
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen request->passdb_password == NULL ? "" :
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen request->passdb_password);
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen if (request->extra_fields != NULL) {
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen const char *fields =
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen auth_stream_reply_export(request->extra_fields);
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen auth_stream_reply_import(reply, fields);
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen }
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen if (request->extra_cache_fields != NULL) {
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen const char *fields =
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen auth_stream_reply_export(request->extra_cache_fields);
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen auth_stream_reply_import(reply, fields);
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen }
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen }
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen str = auth_stream_reply_get_str(reply);
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen str_append_c(str, '\n');
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen auth_worker_send_reply(client, str);
0cc875d28852d15005cff2a77252e7836c862a01Timo Sirainen
0cc875d28852d15005cff2a77252e7836c862a01Timo Sirainen auth_request_unref(&request);
0cc875d28852d15005cff2a77252e7836c862a01Timo Sirainen auth_worker_client_check_throttle(client);
0cc875d28852d15005cff2a77252e7836c862a01Timo Sirainen auth_worker_client_unref(&client);
0cc875d28852d15005cff2a77252e7836c862a01Timo Sirainen}
0cc875d28852d15005cff2a77252e7836c862a01Timo Sirainen
0cc875d28852d15005cff2a77252e7836c862a01Timo Sirainenstatic void
0cc875d28852d15005cff2a77252e7836c862a01Timo Sirainenauth_worker_handle_passv(struct auth_worker_client *client,
0cc875d28852d15005cff2a77252e7836c862a01Timo Sirainen unsigned int id, const char *args)
0cc875d28852d15005cff2a77252e7836c862a01Timo Sirainen{
0cc875d28852d15005cff2a77252e7836c862a01Timo Sirainen /* verify plaintext password */
0cc875d28852d15005cff2a77252e7836c862a01Timo Sirainen struct auth_request *auth_request;
0cc875d28852d15005cff2a77252e7836c862a01Timo Sirainen struct auth_passdb *passdb;
0cc875d28852d15005cff2a77252e7836c862a01Timo Sirainen const char *password;
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen unsigned int passdb_id;
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen passdb_id = atoi(t_strcut(args, '\t'));
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen args = strchr(args, '\t');
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen if (args == NULL) {
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen i_error("BUG: Auth worker server sent us invalid PASSV");
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen return;
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen }
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen args++;
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen password = t_strcut(args, '\t');
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen args = strchr(args, '\t');
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen if (args != NULL) args++;
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen auth_request = worker_auth_request_new(client, id, args);
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen auth_request->mech_password =
966cb0c1aa58578339cea6f79b4a423a851ab074Timo Sirainen p_strdup(auth_request->pool, password);
966cb0c1aa58578339cea6f79b4a423a851ab074Timo Sirainen
966cb0c1aa58578339cea6f79b4a423a851ab074Timo Sirainen if (auth_request->user == NULL || auth_request->service == NULL) {
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen i_error("BUG: PASSV had missing parameters");
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen auth_request_unref(&auth_request);
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen return;
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen }
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen
966cb0c1aa58578339cea6f79b4a423a851ab074Timo Sirainen passdb = auth_request->passdb;
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen while (passdb != NULL && passdb->id != passdb_id)
966cb0c1aa58578339cea6f79b4a423a851ab074Timo Sirainen passdb = passdb->next;
0cc875d28852d15005cff2a77252e7836c862a01Timo Sirainen
966cb0c1aa58578339cea6f79b4a423a851ab074Timo Sirainen if (passdb == NULL) {
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen /* could be a masterdb */
966cb0c1aa58578339cea6f79b4a423a851ab074Timo Sirainen passdb = auth_request->auth->masterdbs;
966cb0c1aa58578339cea6f79b4a423a851ab074Timo Sirainen while (passdb != NULL && passdb->id != passdb_id)
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen passdb = passdb->next;
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen if (passdb == NULL) {
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen i_error("BUG: PASSV had invalid passdb ID");
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen auth_request_unref(&auth_request);
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen return;
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen }
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen }
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen auth_request->passdb = passdb;
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen passdb->passdb->iface.
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen verify_plain(auth_request, password, verify_plain_callback);
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen}
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainen
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainenstatic void
21c317a20c4c3784b54fb3e90ee3751870afdcc3Timo Sirainenlookup_credentials_callback(enum passdb_result result,
4ac2e38bdb450d13b62be41638b12df9e0658009Stephan Bosch const unsigned char *credentials, size_t size,
4ac2e38bdb450d13b62be41638b12df9e0658009Stephan Bosch struct auth_request *request)
4ac2e38bdb450d13b62be41638b12df9e0658009Stephan Bosch{
4ac2e38bdb450d13b62be41638b12df9e0658009Stephan Bosch struct auth_worker_client *client = request->context;
4ac2e38bdb450d13b62be41638b12df9e0658009Stephan Bosch struct auth_stream_reply *reply;
4ac2e38bdb450d13b62be41638b12df9e0658009Stephan Bosch string_t *str;
4ac2e38bdb450d13b62be41638b12df9e0658009Stephan Bosch
4ac2e38bdb450d13b62be41638b12df9e0658009Stephan Bosch if (request->passdb_failure && result == PASSDB_RESULT_OK)
4ac2e38bdb450d13b62be41638b12df9e0658009Stephan Bosch result = PASSDB_RESULT_PASSWORD_MISMATCH;
4ac2e38bdb450d13b62be41638b12df9e0658009Stephan Bosch
4ac2e38bdb450d13b62be41638b12df9e0658009Stephan Bosch reply = auth_stream_reply_init(pool_datastack_create());
4ac2e38bdb450d13b62be41638b12df9e0658009Stephan Bosch auth_stream_reply_add(reply, NULL, dec2str(request->id));
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen if (result != PASSDB_RESULT_OK) {
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen auth_stream_reply_add(reply, "FAIL", NULL);
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen auth_stream_reply_add(reply, NULL,
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen t_strdup_printf("%d", result));
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen } else {
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen auth_stream_reply_add(reply, "OK", NULL);
59beb411159176b39e48a52d60dd3239732e67b4Timo Sirainen auth_stream_reply_add(reply, NULL, request->user);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
2c38504860da8a8de915f8e0f5f39d7e7bd00cf8Timo Sirainen str = t_str_new(64);
6e873f135368bcfdd1de4458dded791d0c4d00cdTimo Sirainen str_printfa(str, "{%s.b64}", request->credentials_scheme);
6e873f135368bcfdd1de4458dded791d0c4d00cdTimo Sirainen base64_encode(credentials, size, str);
2c38504860da8a8de915f8e0f5f39d7e7bd00cf8Timo Sirainen auth_stream_reply_add(reply, NULL, str_c(str));
6e873f135368bcfdd1de4458dded791d0c4d00cdTimo Sirainen
6e873f135368bcfdd1de4458dded791d0c4d00cdTimo Sirainen if (request->extra_fields != NULL) {
6e873f135368bcfdd1de4458dded791d0c4d00cdTimo Sirainen const char *fields =
6e873f135368bcfdd1de4458dded791d0c4d00cdTimo Sirainen auth_stream_reply_export(request->extra_fields);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen auth_stream_reply_import(reply, fields);
15cb9549422ccee416b21d26fec97a556ad0fa36Florian Zeitz }
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen if (request->extra_cache_fields != NULL) {
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen const char *fields =
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen auth_stream_reply_export(request->extra_cache_fields);
f97cf1c086715db87094bc3d0a4fefdd80bd869cTimo Sirainen auth_stream_reply_import(reply, fields);
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen }
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen }
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen str = auth_stream_reply_get_str(reply);
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen str_append_c(str, '\n');
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen auth_worker_send_reply(client, str);
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen auth_request_unref(&request);
33c6d5807b449463e9b81db5ec99fe027cc1b984Timo Sirainen auth_worker_client_check_throttle(client);
8eea67470c1bd8562a62e7445d930bb2079b1a43Timo Sirainen auth_worker_client_unref(&client);
94a78eb438622fa53abef1e1726714dacad4b61cTimo Sirainen}
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
59beb411159176b39e48a52d60dd3239732e67b4Timo Sirainenstatic void
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenauth_worker_handle_passl(struct auth_worker_client *client,
2c38504860da8a8de915f8e0f5f39d7e7bd00cf8Timo Sirainen unsigned int id, const char *args)
6e873f135368bcfdd1de4458dded791d0c4d00cdTimo Sirainen{
6e873f135368bcfdd1de4458dded791d0c4d00cdTimo Sirainen /* lookup credentials */
2c38504860da8a8de915f8e0f5f39d7e7bd00cf8Timo Sirainen struct auth_request *auth_request;
6e873f135368bcfdd1de4458dded791d0c4d00cdTimo Sirainen const char *scheme;
6e873f135368bcfdd1de4458dded791d0c4d00cdTimo Sirainen unsigned int passdb_id;
6e873f135368bcfdd1de4458dded791d0c4d00cdTimo Sirainen
6e873f135368bcfdd1de4458dded791d0c4d00cdTimo Sirainen passdb_id = atoi(t_strcut(args, '\t'));
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen args = strchr(args, '\t');
81419a8dd69d8cef0e93d1e04bda77d135202452Timo Sirainen if (args == NULL) {
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen i_error("BUG: Auth worker server sent us invalid PASSL");
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen return;
b7c2065b3f10f9ae27787a9db5aaefbfc70d4502Timo Sirainen }
f97cf1c086715db87094bc3d0a4fefdd80bd869cTimo Sirainen args++;
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen scheme = t_strcut(args, '\t');
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen args = strchr(args, '\t');
if (args != NULL) args++;
auth_request = worker_auth_request_new(client, id, args);
auth_request->credentials_scheme = p_strdup(auth_request->pool, scheme);
if (auth_request->user == NULL || auth_request->service == NULL) {
i_error("BUG: PASSL had missing parameters");
auth_request_unref(&auth_request);
return;
}
while (auth_request->passdb->id != passdb_id) {
auth_request->passdb = auth_request->passdb->next;
if (auth_request->passdb == NULL) {
i_error("BUG: PASSL had invalid passdb ID");
auth_request_unref(&auth_request);
return;
}
}
if (auth_request->passdb->passdb->iface.lookup_credentials == NULL) {
i_error("BUG: PASSL lookup not supported by given passdb");
auth_request_unref(&auth_request);
return;
}
auth_request->passdb->passdb->iface.
lookup_credentials(auth_request, lookup_credentials_callback);
}
static void
set_credentials_callback(bool success, struct auth_request *request)
{
struct auth_worker_client *client = request->context;
string_t *str;
str = t_str_new(64);
str_printfa(str, "%u\t%s\n", request->id, success ? "OK" : "FAIL");
auth_worker_send_reply(client, str);
auth_request_unref(&request);
auth_worker_client_check_throttle(client);
auth_worker_client_unref(&client);
}
static void
auth_worker_handle_setcred(struct auth_worker_client *client,
unsigned int id, const char *args)
{
struct auth_request *auth_request;
unsigned int passdb_id;
const char *data;
passdb_id = atoi(t_strcut(args, '\t'));
args = strchr(args, '\t');
if (args == NULL) {
i_error("BUG: Auth worker server sent us invalid SETCRED");
return;
}
args++;
data = t_strcut(args, '\t');
args = strchr(args, '\t');
if (args != NULL) args++;
auth_request = worker_auth_request_new(client, id, args);
if (auth_request->user == NULL || auth_request->service == NULL) {
i_error("BUG: SETCRED had missing parameters");
auth_request_unref(&auth_request);
return;
}
while (auth_request->passdb->id != passdb_id) {
auth_request->passdb = auth_request->passdb->next;
if (auth_request->passdb == NULL) {
i_error("BUG: SETCRED had invalid passdb ID");
auth_request_unref(&auth_request);
return;
}
}
auth_request->passdb->passdb->iface.
set_credentials(auth_request, data, set_credentials_callback);
}
static void
lookup_user_callback(enum userdb_result result,
struct auth_request *auth_request)
{
struct auth_worker_client *client = auth_request->context;
struct auth_stream_reply *reply = auth_request->userdb_reply;
string_t *str;
if (auth_request->userdb_lookup_failed)
result = USERDB_RESULT_INTERNAL_FAILURE;
str = t_str_new(128);
str_printfa(str, "%u\t", auth_request->id);
switch (result) {
case USERDB_RESULT_INTERNAL_FAILURE:
str_append(str, "FAIL\t");
break;
case USERDB_RESULT_USER_UNKNOWN:
str_append(str, "NOTFOUND\t");
break;
case USERDB_RESULT_OK:
str_append(str, "OK\t");
str_append(str, auth_stream_reply_export(reply));
break;
}
str_append_c(str, '\n');
auth_worker_send_reply(client, str);
auth_request_unref(&auth_request);
auth_worker_client_check_throttle(client);
auth_worker_client_unref(&client);
}
static void
auth_worker_handle_user(struct auth_worker_client *client,
unsigned int id, const char *args)
{
/* lookup user */
struct auth_request *auth_request;
unsigned int num;
num = atoi(t_strcut(args, '\t'));
args = strchr(args, '\t');
if (args != NULL) args++;
auth_request = worker_auth_request_new(client, id, args);
if (auth_request->user == NULL || auth_request->service == NULL) {
i_error("BUG: USER had missing parameters");
auth_request_unref(&auth_request);
return;
}
for (; num > 0; num--) {
auth_request->userdb = auth_request->userdb->next;
if (auth_request->userdb == NULL) {
i_error("BUG: USER had invalid userdb num");
auth_request_unref(&auth_request);
return;
}
}
auth_request->userdb->userdb->iface->
lookup(auth_request, lookup_user_callback);
}
static bool
auth_worker_handle_line(struct auth_worker_client *client, const char *line)
{
const char *p;
unsigned int id;
p = strchr(line, '\t');
if (p == NULL)
return FALSE;
id = (unsigned int)strtoul(t_strdup_until(line, p), NULL, 10);
line = p + 1;
if (strncmp(line, "PASSV\t", 6) == 0)
auth_worker_handle_passv(client, id, line + 6);
else if (strncmp(line, "PASSL\t", 6) == 0)
auth_worker_handle_passl(client, id, line + 6);
else if (strncmp(line, "SETCRED\t", 8) == 0)
auth_worker_handle_setcred(client, id, line + 8);
else if (strncmp(line, "USER\t", 5) == 0)
auth_worker_handle_user(client, id, line + 5);
return TRUE;
}
static void auth_worker_input(struct auth_worker_client *client)
{
char *line;
bool ret;
switch (i_stream_read(client->input)) {
case 0:
return;
case -1:
/* disconnected */
auth_worker_client_destroy(&client);
return;
case -2:
/* buffer full */
i_error("BUG: Auth worker server sent us more than %d bytes",
(int)AUTH_WORKER_MAX_LINE_LENGTH);
auth_worker_client_destroy(&client);
return;
}
client->refcount++;
while ((line = i_stream_next_line(client->input)) != NULL) {
T_BEGIN {
ret = auth_worker_handle_line(client, line);
} T_END;
if (!ret) {
auth_worker_client_destroy(&client);
break;
}
}
auth_worker_client_unref(&client);
}
static int auth_worker_output(struct auth_worker_client *client)
{
if (o_stream_flush(client->output) < 0) {
auth_worker_client_destroy(&client);
return 1;
}
if (o_stream_get_buffer_used_size(client->output) <=
OUTBUF_THROTTLE_SIZE/3 && client->io == NULL) {
/* allow input again */
client->io = io_add(client->fd, IO_READ,
auth_worker_input, client);
}
return 1;
}
struct auth_worker_client *
auth_worker_client_create(struct auth *auth, int fd)
{
struct auth_worker_client *client;
client = i_new(struct auth_worker_client, 1);
client->refcount = 1;
client->auth = auth;
client->fd = fd;
client->input = i_stream_create_fd(fd, AUTH_WORKER_MAX_LINE_LENGTH,
FALSE);
client->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
o_stream_set_flush_callback(client->output, auth_worker_output, client);
client->io = io_add(fd, IO_READ, auth_worker_input, client);
return client;
}
void auth_worker_client_destroy(struct auth_worker_client **_client)
{
struct auth_worker_client *client = *_client;
*_client = NULL;
if (client->fd == -1)
return;
i_stream_close(client->input);
o_stream_close(client->output);
if (client->io != NULL)
io_remove(&client->io);
net_disconnect(client->fd);
client->fd = -1;
io_loop_stop(ioloop);
}
void auth_worker_client_unref(struct auth_worker_client **_client)
{
struct auth_worker_client *client = *_client;
if (--client->refcount > 0) {
*_client = NULL;
return;
}
if (client->fd != -1)
auth_worker_client_destroy(_client);
i_stream_unref(&client->input);
o_stream_unref(&client->output);
i_free(client);
}