auth-worker-client.c revision 9ed2951bd0bb1878a27437d7c00611b2baadd614
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2005-2010 Dovecot authors, see the included COPYING file */
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen#include "auth-common.h"
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen#include "base64.h"
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen#include "ioloop.h"
687d1dee0e92229232aa8be416897b640df67d07Timo Sirainen#include "network.h"
65988f5a8abed57e9894fec77105941e046d3490Timo Sirainen#include "istream.h"
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen#include "ostream.h"
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen#include "str.h"
687d1dee0e92229232aa8be416897b640df67d07Timo Sirainen#include "master-service.h"
dabb4cec4cf9bdb34013de682b08f1284cfb670fTimo Sirainen#include "auth-request.h"
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen#include "auth-worker-client.h"
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen#include <stdlib.h>
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen#define OUTBUF_THROTTLE_SIZE (1024*10)
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainenstruct auth_worker_client {
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen int refcount;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen struct auth *auth;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen int fd;
64510d2cc23a79d2142030bf5bade44baa490db3Timo Sirainen struct io *io;
64510d2cc23a79d2142030bf5bade44baa490db3Timo Sirainen struct istream *input;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen struct ostream *output;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen};
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainenstruct auth_worker_list_context {
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen struct auth_worker_client *client;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen struct userdb_module *userdb;
5cbefc6537aefbf1491416c433de00fc3e649a13Timo Sirainen struct userdb_iterate_context *iter;
f335accff54f408a8bbb328f8098ad458f2ff58eTimo Sirainen unsigned int id;
f335accff54f408a8bbb328f8098ad458f2ff58eTimo Sirainen bool sending, sent, done;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen};
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainenstruct auth_worker_client *auth_worker_client;
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainenstatic void auth_worker_input(struct auth_worker_client *client);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainenstatic int auth_worker_output(struct auth_worker_client *client);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainenstatic void
db24d60c306c9d477392ff5b61cb3fc95fef3bb7Timo Sirainenauth_worker_client_check_throttle(struct auth_worker_client *client)
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen{
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen if (o_stream_get_buffer_used_size(client->output) >=
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen OUTBUF_THROTTLE_SIZE) {
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen /* stop reading new requests until client has read the pending
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen replies. */
5cbefc6537aefbf1491416c433de00fc3e649a13Timo Sirainen if (client->io != NULL)
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen io_remove(&client->io);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen }
5cbefc6537aefbf1491416c433de00fc3e649a13Timo Sirainen}
5cbefc6537aefbf1491416c433de00fc3e649a13Timo Sirainen
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainenstatic struct auth_request *
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainenworker_auth_request_new(struct auth_worker_client *client, unsigned int id,
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen const char *args)
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen{
5cbefc6537aefbf1491416c433de00fc3e649a13Timo Sirainen struct auth_request *auth_request;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen const char *key, *value, *const *tmp;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen
db24d60c306c9d477392ff5b61cb3fc95fef3bb7Timo Sirainen auth_request = auth_request_new_dummy();
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen client->refcount++;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen auth_request->context = client;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen auth_request->id = id;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen if (args != NULL) {
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen for (tmp = t_strsplit(args, "\t"); *tmp != NULL; tmp++) {
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen value = strchr(*tmp, '=');
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen if (value == NULL)
c69a255a68103a50fa3f04a527281a169075403fTimo Sirainen continue;
c69a255a68103a50fa3f04a527281a169075403fTimo Sirainen
c69a255a68103a50fa3f04a527281a169075403fTimo Sirainen key = t_strdup_until(*tmp, value);
db24d60c306c9d477392ff5b61cb3fc95fef3bb7Timo Sirainen value++;
0f66f12eb4cdbf47670975044c88d8f388bf92dfTimo Sirainen
0f66f12eb4cdbf47670975044c88d8f388bf92dfTimo Sirainen (void)auth_request_import(auth_request, key, value);
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen }
c69a255a68103a50fa3f04a527281a169075403fTimo Sirainen }
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen auth_request_init(auth_request);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen return auth_request;
687d1dee0e92229232aa8be416897b640df67d07Timo Sirainen}
687d1dee0e92229232aa8be416897b640df67d07Timo Sirainen
687d1dee0e92229232aa8be416897b640df67d07Timo Sirainenstatic void auth_worker_send_reply(struct auth_worker_client *client,
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen string_t *str)
687d1dee0e92229232aa8be416897b640df67d07Timo Sirainen{
687d1dee0e92229232aa8be416897b640df67d07Timo Sirainen if (shutdown_request)
687d1dee0e92229232aa8be416897b640df67d07Timo Sirainen o_stream_send_str(client->output, "SHUTDOWN\n");
687d1dee0e92229232aa8be416897b640df67d07Timo Sirainen o_stream_send(client->output, str_data(str), str_len(str));
687d1dee0e92229232aa8be416897b640df67d07Timo Sirainen}
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen
687d1dee0e92229232aa8be416897b640df67d07Timo Sirainenstatic void verify_plain_callback(enum passdb_result result,
687d1dee0e92229232aa8be416897b640df67d07Timo Sirainen struct auth_request *request)
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen{
b38dd9a0b8eb6b599c346acbeea9dbe129bb086eTimo Sirainen struct auth_worker_client *client = request->context;
687d1dee0e92229232aa8be416897b640df67d07Timo Sirainen struct auth_stream_reply *reply;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen string_t *str;
87b426af6a2365c6840b14281a98c23e903bf28eTimo Sirainen
87b426af6a2365c6840b14281a98c23e903bf28eTimo Sirainen if (request->passdb_failure && result == PASSDB_RESULT_OK)
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen result = PASSDB_RESULT_PASSWORD_MISMATCH;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen reply = auth_stream_reply_init(pool_datastack_create());
87b426af6a2365c6840b14281a98c23e903bf28eTimo Sirainen auth_stream_reply_add(reply, NULL, dec2str(request->id));
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen
87b426af6a2365c6840b14281a98c23e903bf28eTimo Sirainen if (result == PASSDB_RESULT_OK)
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen auth_stream_reply_add(reply, "OK", NULL);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen else {
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen auth_stream_reply_add(reply, "FAIL", NULL);
87b426af6a2365c6840b14281a98c23e903bf28eTimo Sirainen auth_stream_reply_add(reply, NULL,
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen t_strdup_printf("%d", result));
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen }
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen if (result != PASSDB_RESULT_INTERNAL_FAILURE) {
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen auth_stream_reply_add(reply, NULL, request->user);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen auth_stream_reply_add(reply, NULL,
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen request->passdb_password == NULL ? "" :
687d1dee0e92229232aa8be416897b640df67d07Timo Sirainen request->passdb_password);
687d1dee0e92229232aa8be416897b640df67d07Timo Sirainen if (request->extra_fields != NULL) {
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen const char *fields =
687d1dee0e92229232aa8be416897b640df67d07Timo Sirainen auth_stream_reply_export(request->extra_fields);
dabb4cec4cf9bdb34013de682b08f1284cfb670fTimo Sirainen auth_stream_reply_import(reply, fields);
687d1dee0e92229232aa8be416897b640df67d07Timo Sirainen }
687d1dee0e92229232aa8be416897b640df67d07Timo Sirainen if (request->extra_cache_fields != NULL) {
687d1dee0e92229232aa8be416897b640df67d07Timo Sirainen const char *fields =
687d1dee0e92229232aa8be416897b640df67d07Timo Sirainen auth_stream_reply_export(request->extra_cache_fields);
687d1dee0e92229232aa8be416897b640df67d07Timo Sirainen auth_stream_reply_import(reply, fields);
687d1dee0e92229232aa8be416897b640df67d07Timo Sirainen }
687d1dee0e92229232aa8be416897b640df67d07Timo Sirainen }
687d1dee0e92229232aa8be416897b640df67d07Timo Sirainen str = auth_stream_reply_get_str(reply);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen str_append_c(str, '\n');
687d1dee0e92229232aa8be416897b640df67d07Timo Sirainen auth_worker_send_reply(client, str);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen
dabb4cec4cf9bdb34013de682b08f1284cfb670fTimo Sirainen auth_request_unref(&request);
dabb4cec4cf9bdb34013de682b08f1284cfb670fTimo Sirainen auth_worker_client_check_throttle(client);
dabb4cec4cf9bdb34013de682b08f1284cfb670fTimo Sirainen auth_worker_client_unref(&client);
dabb4cec4cf9bdb34013de682b08f1284cfb670fTimo Sirainen}
dabb4cec4cf9bdb34013de682b08f1284cfb670fTimo Sirainen
687d1dee0e92229232aa8be416897b640df67d07Timo Sirainenstatic void
687d1dee0e92229232aa8be416897b640df67d07Timo Sirainenauth_worker_handle_passv(struct auth_worker_client *client,
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen unsigned int id, const char *args)
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen{
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen /* verify plaintext password */
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen struct auth_request *auth_request;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen struct auth_passdb *passdb;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen const char *password;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen unsigned int passdb_id;
5cbefc6537aefbf1491416c433de00fc3e649a13Timo Sirainen
0ce8f754204c7eeb33805993807393f74faf2cd3Timo Sirainen passdb_id = atoi(t_strcut(args, '\t'));
0ce8f754204c7eeb33805993807393f74faf2cd3Timo Sirainen args = strchr(args, '\t');
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen if (args == NULL) {
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen i_error("BUG: Auth worker server sent us invalid PASSV");
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen return;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen }
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen args++;
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen password = t_strcut(args, '\t');
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen args = strchr(args, '\t');
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (args != NULL) args++;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen auth_request = worker_auth_request_new(client, id, args);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen auth_request->mech_password =
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen p_strdup(auth_request->pool, password);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen if (auth_request->user == NULL || auth_request->service == NULL) {
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen i_error("BUG: PASSV had missing parameters");
5cbefc6537aefbf1491416c433de00fc3e649a13Timo Sirainen auth_request_unref(&auth_request);
0ce8f754204c7eeb33805993807393f74faf2cd3Timo Sirainen return;
0ce8f754204c7eeb33805993807393f74faf2cd3Timo Sirainen }
5cbefc6537aefbf1491416c433de00fc3e649a13Timo Sirainen
65988f5a8abed57e9894fec77105941e046d3490Timo Sirainen passdb = auth_request->passdb;
65988f5a8abed57e9894fec77105941e046d3490Timo Sirainen while (passdb != NULL && passdb->passdb->id != passdb_id)
e1b83f64e62cc3e8967c75fcc3f9b5dbb243d3b3Timo Sirainen passdb = passdb->next;
e1b83f64e62cc3e8967c75fcc3f9b5dbb243d3b3Timo Sirainen
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen if (passdb == NULL) {
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen /* could be a masterdb */
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen passdb = auth_request_get_auth(auth_request)->masterdbs;
0ce8f754204c7eeb33805993807393f74faf2cd3Timo Sirainen while (passdb != NULL && passdb->passdb->id != passdb_id)
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen passdb = passdb->next;
5cbefc6537aefbf1491416c433de00fc3e649a13Timo Sirainen
e1b83f64e62cc3e8967c75fcc3f9b5dbb243d3b3Timo Sirainen if (passdb == NULL) {
e1b83f64e62cc3e8967c75fcc3f9b5dbb243d3b3Timo Sirainen i_error("BUG: PASSV had invalid passdb ID");
e1b83f64e62cc3e8967c75fcc3f9b5dbb243d3b3Timo Sirainen auth_request_unref(&auth_request);
e1b83f64e62cc3e8967c75fcc3f9b5dbb243d3b3Timo Sirainen return;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen }
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen }
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen auth_request->passdb = passdb;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen passdb->passdb->iface.
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen verify_plain(auth_request, password, verify_plain_callback);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen}
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainenstatic void
62394a19cba1a8df01cad66eaa9331a70464441eTimo Sirainenlookup_credentials_callback(enum passdb_result result,
62394a19cba1a8df01cad66eaa9331a70464441eTimo Sirainen const unsigned char *credentials, size_t size,
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen struct auth_request *request)
62394a19cba1a8df01cad66eaa9331a70464441eTimo Sirainen{
62394a19cba1a8df01cad66eaa9331a70464441eTimo Sirainen struct auth_worker_client *client = request->context;
62394a19cba1a8df01cad66eaa9331a70464441eTimo Sirainen struct auth_stream_reply *reply;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen string_t *str;
62394a19cba1a8df01cad66eaa9331a70464441eTimo Sirainen
62394a19cba1a8df01cad66eaa9331a70464441eTimo Sirainen if (request->passdb_failure && result == PASSDB_RESULT_OK)
62394a19cba1a8df01cad66eaa9331a70464441eTimo Sirainen result = PASSDB_RESULT_PASSWORD_MISMATCH;
62394a19cba1a8df01cad66eaa9331a70464441eTimo Sirainen
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen reply = auth_stream_reply_init(pool_datastack_create());
62394a19cba1a8df01cad66eaa9331a70464441eTimo Sirainen auth_stream_reply_add(reply, NULL, dec2str(request->id));
62394a19cba1a8df01cad66eaa9331a70464441eTimo Sirainen
62394a19cba1a8df01cad66eaa9331a70464441eTimo Sirainen if (result != PASSDB_RESULT_OK) {
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen auth_stream_reply_add(reply, "FAIL", NULL);
62394a19cba1a8df01cad66eaa9331a70464441eTimo Sirainen auth_stream_reply_add(reply, NULL,
62394a19cba1a8df01cad66eaa9331a70464441eTimo Sirainen t_strdup_printf("%d", result));
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen } else {
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen auth_stream_reply_add(reply, "OK", NULL);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen auth_stream_reply_add(reply, NULL, request->user);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen str = t_str_new(64);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen str_printfa(str, "{%s.b64}", request->credentials_scheme);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen base64_encode(credentials, size, str);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen auth_stream_reply_add(reply, NULL, str_c(str));
5cbefc6537aefbf1491416c433de00fc3e649a13Timo Sirainen
5cbefc6537aefbf1491416c433de00fc3e649a13Timo Sirainen if (request->extra_fields != NULL) {
5cbefc6537aefbf1491416c433de00fc3e649a13Timo Sirainen const char *fields =
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen auth_stream_reply_export(request->extra_fields);
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen auth_stream_reply_import(reply, fields);
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen }
87506860556bf42f656b13f4b14cf81b75261e95Timo Sirainen if (request->extra_cache_fields != NULL) {
87506860556bf42f656b13f4b14cf81b75261e95Timo Sirainen const char *fields =
87506860556bf42f656b13f4b14cf81b75261e95Timo Sirainen auth_stream_reply_export(request->extra_cache_fields);
87506860556bf42f656b13f4b14cf81b75261e95Timo Sirainen auth_stream_reply_import(reply, fields);
87506860556bf42f656b13f4b14cf81b75261e95Timo Sirainen }
87506860556bf42f656b13f4b14cf81b75261e95Timo Sirainen }
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen str = auth_stream_reply_get_str(reply);
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen str_append_c(str, '\n');
87506860556bf42f656b13f4b14cf81b75261e95Timo Sirainen auth_worker_send_reply(client, str);
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen auth_request_unref(&request);
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen auth_worker_client_check_throttle(client);
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen auth_worker_client_unref(&client);
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen}
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainenstatic void
5cbefc6537aefbf1491416c433de00fc3e649a13Timo Sirainenauth_worker_handle_passl(struct auth_worker_client *client,
5cbefc6537aefbf1491416c433de00fc3e649a13Timo Sirainen unsigned int id, const char *args)
5cbefc6537aefbf1491416c433de00fc3e649a13Timo Sirainen{
5cbefc6537aefbf1491416c433de00fc3e649a13Timo Sirainen /* lookup credentials */
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen struct auth_request *auth_request;
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen const char *scheme;
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen unsigned int passdb_id;
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen passdb_id = atoi(t_strcut(args, '\t'));
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen args = strchr(args, '\t');
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen if (args == NULL) {
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen i_error("BUG: Auth worker server sent us invalid PASSL");
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen return;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen }
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen args++;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen
db24d60c306c9d477392ff5b61cb3fc95fef3bb7Timo Sirainen scheme = t_strcut(args, '\t');
e619ecbbc00cba9e6e1e8322caa59776507fac02Timo Sirainen args = strchr(args, '\t');
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen if (args != NULL) args++;
db24d60c306c9d477392ff5b61cb3fc95fef3bb7Timo Sirainen
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen auth_request = worker_auth_request_new(client, id, args);
db24d60c306c9d477392ff5b61cb3fc95fef3bb7Timo Sirainen auth_request->credentials_scheme = p_strdup(auth_request->pool, scheme);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen if (auth_request->user == NULL || auth_request->service == NULL) {
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen i_error("BUG: PASSL had missing parameters");
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen auth_request_unref(&auth_request);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen return;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen }
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen while (auth_request->passdb->passdb->id != passdb_id) {
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen auth_request->passdb = auth_request->passdb->next;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen if (auth_request->passdb == NULL) {
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen i_error("BUG: PASSL had invalid passdb ID");
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen auth_request_unref(&auth_request);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen return;
db24d60c306c9d477392ff5b61cb3fc95fef3bb7Timo Sirainen }
db24d60c306c9d477392ff5b61cb3fc95fef3bb7Timo Sirainen }
db24d60c306c9d477392ff5b61cb3fc95fef3bb7Timo Sirainen
db24d60c306c9d477392ff5b61cb3fc95fef3bb7Timo Sirainen if (auth_request->passdb->passdb->iface.lookup_credentials == NULL) {
db24d60c306c9d477392ff5b61cb3fc95fef3bb7Timo Sirainen i_error("BUG: PASSL lookup not supported by given passdb");
db24d60c306c9d477392ff5b61cb3fc95fef3bb7Timo Sirainen auth_request_unref(&auth_request);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen return;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen }
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen auth_request->prefer_plain_credentials = TRUE;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen auth_request->passdb->passdb->iface.
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen lookup_credentials(auth_request, lookup_credentials_callback);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen}
db24d60c306c9d477392ff5b61cb3fc95fef3bb7Timo Sirainen
db24d60c306c9d477392ff5b61cb3fc95fef3bb7Timo Sirainenstatic void
db24d60c306c9d477392ff5b61cb3fc95fef3bb7Timo Sirainenset_credentials_callback(bool success, struct auth_request *request)
db24d60c306c9d477392ff5b61cb3fc95fef3bb7Timo Sirainen{
db24d60c306c9d477392ff5b61cb3fc95fef3bb7Timo Sirainen struct auth_worker_client *client = request->context;
db24d60c306c9d477392ff5b61cb3fc95fef3bb7Timo Sirainen
db24d60c306c9d477392ff5b61cb3fc95fef3bb7Timo Sirainen string_t *str;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen
e619ecbbc00cba9e6e1e8322caa59776507fac02Timo Sirainen str = t_str_new(64);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen str_printfa(str, "%u\t%s\n", request->id, success ? "OK" : "FAIL");
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen auth_worker_send_reply(client, str);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen auth_request_unref(&request);
e619ecbbc00cba9e6e1e8322caa59776507fac02Timo Sirainen auth_worker_client_check_throttle(client);
64510d2cc23a79d2142030bf5bade44baa490db3Timo Sirainen auth_worker_client_unref(&client);
db24d60c306c9d477392ff5b61cb3fc95fef3bb7Timo Sirainen}
db24d60c306c9d477392ff5b61cb3fc95fef3bb7Timo Sirainen
64510d2cc23a79d2142030bf5bade44baa490db3Timo Sirainenstatic void
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainenauth_worker_handle_setcred(struct auth_worker_client *client,
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen unsigned int id, const char *args)
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen{
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen struct auth_request *auth_request;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen unsigned int passdb_id;
db24d60c306c9d477392ff5b61cb3fc95fef3bb7Timo Sirainen const char *data;
db24d60c306c9d477392ff5b61cb3fc95fef3bb7Timo Sirainen
db24d60c306c9d477392ff5b61cb3fc95fef3bb7Timo Sirainen passdb_id = atoi(t_strcut(args, '\t'));
db24d60c306c9d477392ff5b61cb3fc95fef3bb7Timo Sirainen args = strchr(args, '\t');
db24d60c306c9d477392ff5b61cb3fc95fef3bb7Timo Sirainen if (args == NULL) {
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen i_error("BUG: Auth worker server sent us invalid SETCRED");
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen return;
5cbefc6537aefbf1491416c433de00fc3e649a13Timo Sirainen }
5cbefc6537aefbf1491416c433de00fc3e649a13Timo Sirainen args++;
5cbefc6537aefbf1491416c433de00fc3e649a13Timo Sirainen
5cbefc6537aefbf1491416c433de00fc3e649a13Timo Sirainen data = t_strcut(args, '\t');
7aa59f55d8a4e02c7039fbd22660c4055bfc8393Timo Sirainen args = strchr(args, '\t');
5cbefc6537aefbf1491416c433de00fc3e649a13Timo Sirainen if (args != NULL) args++;
65988f5a8abed57e9894fec77105941e046d3490Timo Sirainen
0ae99441ae9ef80f435f3eb85fad16e136036b0bTimo Sirainen auth_request = worker_auth_request_new(client, id, args);
e1b83f64e62cc3e8967c75fcc3f9b5dbb243d3b3Timo Sirainen
e1b83f64e62cc3e8967c75fcc3f9b5dbb243d3b3Timo Sirainen if (auth_request->user == NULL || auth_request->service == NULL) {
7aa59f55d8a4e02c7039fbd22660c4055bfc8393Timo Sirainen i_error("BUG: SETCRED had missing parameters");
7aa59f55d8a4e02c7039fbd22660c4055bfc8393Timo Sirainen auth_request_unref(&auth_request);
7aa59f55d8a4e02c7039fbd22660c4055bfc8393Timo Sirainen return;
e1b83f64e62cc3e8967c75fcc3f9b5dbb243d3b3Timo Sirainen }
7aa59f55d8a4e02c7039fbd22660c4055bfc8393Timo Sirainen
7aa59f55d8a4e02c7039fbd22660c4055bfc8393Timo Sirainen while (auth_request->passdb->passdb->id != passdb_id) {
e1b83f64e62cc3e8967c75fcc3f9b5dbb243d3b3Timo Sirainen auth_request->passdb = auth_request->passdb->next;
919733fcead68b0e9617cfff86ae5c74d097c6cdTimo Sirainen if (auth_request->passdb == NULL) {
1dba794aa92dc13e6afd7a50a8c33cb19d6aa235Timo Sirainen i_error("BUG: SETCRED had invalid passdb ID");
7aa59f55d8a4e02c7039fbd22660c4055bfc8393Timo Sirainen auth_request_unref(&auth_request);
7aa59f55d8a4e02c7039fbd22660c4055bfc8393Timo Sirainen return;
7aa59f55d8a4e02c7039fbd22660c4055bfc8393Timo Sirainen }
7aa59f55d8a4e02c7039fbd22660c4055bfc8393Timo Sirainen }
7aa59f55d8a4e02c7039fbd22660c4055bfc8393Timo Sirainen
7aa59f55d8a4e02c7039fbd22660c4055bfc8393Timo Sirainen auth_request->passdb->passdb->iface.
7aa59f55d8a4e02c7039fbd22660c4055bfc8393Timo Sirainen set_credentials(auth_request, data, set_credentials_callback);
7aa59f55d8a4e02c7039fbd22660c4055bfc8393Timo Sirainen}
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainenstatic void
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainenlookup_user_callback(enum userdb_result result,
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen struct auth_request *auth_request)
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen{
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen struct auth_worker_client *client = auth_request->context;
055f4599bba1874fa1148a8fa488517fa077619cTimo Sirainen struct auth_stream_reply *reply = auth_request->userdb_reply;
055f4599bba1874fa1148a8fa488517fa077619cTimo Sirainen string_t *str;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen if (auth_request->userdb_lookup_failed)
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen result = USERDB_RESULT_INTERNAL_FAILURE;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen str = t_str_new(128);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen str_printfa(str, "%u\t", auth_request->id);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen switch (result) {
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen case USERDB_RESULT_INTERNAL_FAILURE:
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen str_append(str, "FAIL\t");
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen break;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen case USERDB_RESULT_USER_UNKNOWN:
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen str_append(str, "NOTFOUND\t");
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen break;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen case USERDB_RESULT_OK:
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen str_append(str, "OK\t");
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen str_append(str, auth_stream_reply_export(reply));
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen break;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen }
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen str_append_c(str, '\n');
f335accff54f408a8bbb328f8098ad458f2ff58eTimo Sirainen
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen auth_worker_send_reply(client, str);
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen auth_request_unref(&auth_request);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen auth_worker_client_check_throttle(client);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen auth_worker_client_unref(&client);
f335accff54f408a8bbb328f8098ad458f2ff58eTimo Sirainen}
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainenstatic void
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainenauth_worker_handle_user(struct auth_worker_client *client,
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen unsigned int id, const char *args)
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen{
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen /* lookup user */
9ae664e94e6eeb5c1f900bb90642052633031832Timo Sirainen struct auth_request *auth_request;
9ae664e94e6eeb5c1f900bb90642052633031832Timo Sirainen unsigned int num;
5cbefc6537aefbf1491416c433de00fc3e649a13Timo Sirainen
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen num = atoi(t_strcut(args, '\t'));
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen args = strchr(args, '\t');
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen if (args != NULL) args++;
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen auth_request = worker_auth_request_new(client, id, args);
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen if (auth_request->user == NULL || auth_request->service == NULL) {
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen i_error("BUG: USER had missing parameters");
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen auth_request_unref(&auth_request);
db24d60c306c9d477392ff5b61cb3fc95fef3bb7Timo Sirainen return;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen }
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 void list_iter_deinit(struct auth_worker_list_context *ctx)
{
struct auth_worker_client *client = ctx->client;
string_t *str;
i_assert(client->io == NULL);
str = t_str_new(32);
if (ctx->userdb->iface->iterate_deinit(ctx->iter) < 0)
str_printfa(str, "%u\tFAIL\n", ctx->id);
else
str_printfa(str, "%u\tOK\n", ctx->id);
auth_worker_send_reply(client, str);
client->io = io_add(client->fd, IO_READ, auth_worker_input, client);
o_stream_set_flush_callback(client->output, auth_worker_output, client);
auth_worker_client_unref(&client);
i_free(ctx);
}
static void list_iter_callback(const char *user, void *context)
{
struct auth_worker_list_context *ctx = context;
string_t *str;
if (user == NULL) {
if (ctx->sending)
ctx->done = TRUE;
else
list_iter_deinit(ctx);
return;
}
T_BEGIN {
str = t_str_new(128);
str_printfa(str, "%u\t*\t%s\n", ctx->id, user);
o_stream_send(ctx->client->output, str_data(str), str_len(str));
} T_END;
if (ctx->sending) {
/* avoid recursively looping to this same function */
ctx->sent = TRUE;
return;
}
do {
ctx->sending = TRUE;
ctx->sent = FALSE;
ctx->userdb->iface->iterate_next(ctx->iter);
} while (ctx->sent &&
o_stream_get_buffer_used_size(ctx->client->output) == 0);
ctx->sending = FALSE;
if (ctx->done)
list_iter_deinit(ctx);
}
static int auth_worker_list_output(struct auth_worker_list_context *ctx)
{
int ret;
if ((ret = o_stream_flush(ctx->client->output)) < 0) {
list_iter_deinit(ctx);
return 1;
}
if (ret > 0)
ctx->userdb->iface->iterate_next(ctx->iter);
return 1;
}
static void
auth_worker_handle_list(struct auth_worker_client *client,
unsigned int id, const char *args)
{
struct auth_worker_list_context *ctx;
struct auth_userdb *userdb;
unsigned int num;
userdb = client->auth->userdbs;
for (num = atoi(args); num > 0; num--) {
userdb = userdb->next;
if (userdb == NULL) {
i_error("BUG: LIST had invalid userdb num");
return;
}
}
ctx = i_new(struct auth_worker_list_context, 1);
ctx->client = client;
ctx->id = id;
ctx->userdb = userdb->userdb;
io_remove(&ctx->client->io);
o_stream_set_flush_callback(ctx->client->output,
auth_worker_list_output, ctx);
client->refcount++;
ctx->iter = ctx->userdb->iface->
iterate_init(userdb->userdb, list_iter_callback, ctx);
ctx->userdb->iface->iterate_next(ctx->iter);
}
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);
else if (strncmp(line, "LIST\t", 5) == 0)
auth_worker_handle_list(client, id, line + 5);
else
i_error("BUG: Auth-worker received unknown command: %s", line);
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);
auth_worker_client = 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;
auth_worker_client_unref(&client);
auth_worker_client = NULL;
master_service_client_connection_destroyed(master_service);
}
void auth_worker_client_unref(struct auth_worker_client **_client)
{
struct auth_worker_client *client = *_client;
*_client = NULL;
if (--client->refcount > 0)
return;
i_stream_unref(&client->input);
o_stream_unref(&client->output);
i_free(client);
}