auth-worker-client.c revision eddd9bf1a1369aea4a2715f6be1137da6d17d293
183bea41fa640dc8117f3eb45ff935cd81377a84Timo Sirainen/* Copyright (c) 2005-2007 Dovecot authors, see the included COPYING file */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#include "common.h"
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#include "base64.h"
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#include "ioloop.h"
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#include "network.h"
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#include "istream.h"
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#include "ostream.h"
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#include "str.h"
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#include "auth-request.h"
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#include "auth-worker-client.h"
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#include <stdlib.h>
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen/* If no requests have come within this time, kill ourself */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#define AUTH_WORKER_MAX_IDLE (60*10)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#define OUTBUF_THROTTLE_SIZE (1024*10)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainenstruct auth_worker_client {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen int refcount;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen struct auth *auth;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen int fd;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen struct io *io;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen struct istream *input;
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen struct ostream *output;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen time_t last_request;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen struct timeout *to;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen};
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenstatic void
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenauth_worker_client_check_throttle(struct auth_worker_client *client)
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen{
1ff487015234b23c32cf8bb4c9f8c02922535b8eTimo Sirainen if (o_stream_get_buffer_used_size(client->output) >=
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen OUTBUF_THROTTLE_SIZE) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* stop reading new requests until client has read the pending
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen replies. */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (client->io != NULL)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen io_remove(&client->io);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen}
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenstatic struct auth_request *
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenworker_auth_request_new(struct auth_worker_client *client, unsigned int id,
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen const char *args)
1ff487015234b23c32cf8bb4c9f8c02922535b8eTimo Sirainen{
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen struct auth_request *auth_request;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen const char *key, *value, *const *tmp;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen auth_request = auth_request_new_dummy(client->auth);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen client->refcount++;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen auth_request->context = client;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen auth_request->id = id;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (args != NULL) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen for (tmp = t_strsplit(args, "\t"); *tmp != NULL; tmp++) {
8bb360f9e5de1c25e4f875205bb06e8bf15dae14Timo Sirainen value = strchr(*tmp, '=');
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (value == NULL)
c2f2a6cdf7dd55a4aabe72495cabb4deaa59cffcTimo Sirainen continue;
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen key = t_strdup_until(*tmp, value);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen value++;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen (void)auth_request_import(auth_request, key, value);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen return auth_request;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen}
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
1ff487015234b23c32cf8bb4c9f8c02922535b8eTimo Sirainenstatic void add_userdb_replies(string_t *str, const char *data)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen{
1ff487015234b23c32cf8bb4c9f8c02922535b8eTimo Sirainen const char *const *tmp;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen for (tmp = t_strsplit(data, "\t"); *tmp != NULL; tmp++)
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen str_printfa(str, "\tuserdb_%s", *tmp);
1ff487015234b23c32cf8bb4c9f8c02922535b8eTimo Sirainen}
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenstatic void verify_plain_callback(enum passdb_result result,
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen struct auth_request *request)
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen{
c2f2a6cdf7dd55a4aabe72495cabb4deaa59cffcTimo Sirainen struct auth_worker_client *client = request->context;
c2f2a6cdf7dd55a4aabe72495cabb4deaa59cffcTimo Sirainen string_t *str;
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen if (request->passdb_failure && result == PASSDB_RESULT_OK)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen result = PASSDB_RESULT_PASSWORD_MISMATCH;
c2f2a6cdf7dd55a4aabe72495cabb4deaa59cffcTimo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen str = t_str_new(64);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen str_printfa(str, "%u\t", request->id);
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (result == PASSDB_RESULT_INTERNAL_FAILURE)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen str_printfa(str, "FAIL\t%d", result);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen else {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (result != PASSDB_RESULT_OK)
c2f2a6cdf7dd55a4aabe72495cabb4deaa59cffcTimo Sirainen str_printfa(str, "FAIL\t%d\t", result);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen else
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen str_append(str, "OK\t");
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen str_append(str, request->user);
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen str_append_c(str, '\t');
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (request->passdb_password != NULL)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen str_append(str, request->passdb_password);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (request->no_password)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen str_append(str, "\tnopassword");
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (request->userdb_reply != NULL) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen const char *data =
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen auth_stream_reply_export(request->userdb_reply);
f16712057c1b82c6d2a3a4267c4521d357cd4b4cTimo Sirainen add_userdb_replies(str, data);
cc3da53f3a49304a251bfae88f814505326ac210Timo Sirainen }
cc3da53f3a49304a251bfae88f814505326ac210Timo Sirainen if (request->extra_fields != NULL) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen const char *field =
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen auth_stream_reply_export(request->extra_fields);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen str_append_c(str, '\t');
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen str_append(str, field);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
51c331377beb4a2acb81aee4d12bc8ef6c496625Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen str_append_c(str, '\n');
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen o_stream_send(client->output, str_data(str), str_len(str));
51c331377beb4a2acb81aee4d12bc8ef6c496625Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen auth_request_unref(&request);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen auth_worker_client_check_throttle(client);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen auth_worker_client_unref(&client);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen}
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenstatic void
cc3da53f3a49304a251bfae88f814505326ac210Timo Sirainenauth_worker_handle_passv(struct auth_worker_client *client,
cc3da53f3a49304a251bfae88f814505326ac210Timo Sirainen unsigned int id, const char *args)
cc3da53f3a49304a251bfae88f814505326ac210Timo Sirainen{
cc3da53f3a49304a251bfae88f814505326ac210Timo Sirainen /* verify plaintext password */
cc3da53f3a49304a251bfae88f814505326ac210Timo Sirainen struct auth_request *auth_request;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen struct auth_passdb *passdb;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen const char *password;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen unsigned int passdb_id;
c2f2a6cdf7dd55a4aabe72495cabb4deaa59cffcTimo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen passdb_id = atoi(t_strcut(args, '\t'));
ad4cd18ba6c43fe94987408f81ed6547b29132d6Timo Sirainen args = strchr(args, '\t');
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (args == NULL) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen i_error("BUG: Auth worker server sent us invalid PASSV");
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen return;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen args++;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen password = t_strcut(args, '\t');
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen args = strchr(args, '\t');
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (args != NULL) args++;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen auth_request = worker_auth_request_new(client, id, args);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen auth_request->mech_password =
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen p_strdup(auth_request->pool, password);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (auth_request->user == NULL || auth_request->service == NULL) {
c2f2a6cdf7dd55a4aabe72495cabb4deaa59cffcTimo Sirainen i_error("BUG: PASSV had missing parameters");
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen auth_request_unref(&auth_request);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen return;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen passdb = auth_request->passdb;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen while (passdb != NULL && passdb->id != passdb_id)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen passdb = passdb->next;
c2f2a6cdf7dd55a4aabe72495cabb4deaa59cffcTimo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (passdb == NULL) {
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen /* could be a masterdb */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen passdb = auth_request->auth->masterdbs;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen while (passdb != NULL && passdb->id != passdb_id)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen passdb = passdb->next;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (passdb == NULL) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen i_error("BUG: PASSV had invalid passdb ID");
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen auth_request_unref(&auth_request);
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen return;
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
f16712057c1b82c6d2a3a4267c4521d357cd4b4cTimo Sirainen
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen auth_request->passdb = passdb;
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen passdb->passdb->iface.
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen verify_plain(auth_request, password, verify_plain_callback);
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen}
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainenstatic void
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainenlookup_credentials_callback(enum passdb_result result,
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen const unsigned char *credentials, size_t size,
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen struct auth_request *request)
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen{
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen struct auth_worker_client *client = request->context;
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen string_t *str;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen if (request->passdb_failure && result == PASSDB_RESULT_OK)
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen result = PASSDB_RESULT_PASSWORD_MISMATCH;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen str = t_str_new(64);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen str_printfa(str, "%u\t", request->id);
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (result != PASSDB_RESULT_OK)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen str_printfa(str, "FAIL\t%d", result);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen else {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen str_printfa(str, "OK\t%s\t{%s.b64}", request->user,
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen request->credentials_scheme);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen base64_encode(credentials, size, str);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen str_append_c(str, '\t');
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (request->extra_fields != NULL) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen const char *field =
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen auth_stream_reply_export(request->extra_fields);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen str_append(str, field);
f16712057c1b82c6d2a3a4267c4521d357cd4b4cTimo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (request->userdb_reply != NULL) {
f16712057c1b82c6d2a3a4267c4521d357cd4b4cTimo Sirainen const char *data =
f16712057c1b82c6d2a3a4267c4521d357cd4b4cTimo Sirainen auth_stream_reply_export(request->userdb_reply);
f16712057c1b82c6d2a3a4267c4521d357cd4b4cTimo Sirainen add_userdb_replies(str, data);
51c331377beb4a2acb81aee4d12bc8ef6c496625Timo Sirainen }
51c331377beb4a2acb81aee4d12bc8ef6c496625Timo Sirainen }
51c331377beb4a2acb81aee4d12bc8ef6c496625Timo Sirainen str_append_c(str, '\n');
51c331377beb4a2acb81aee4d12bc8ef6c496625Timo Sirainen o_stream_send(client->output, str_data(str), str_len(str));
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen auth_request_unref(&request);
f16712057c1b82c6d2a3a4267c4521d357cd4b4cTimo Sirainen auth_worker_client_check_throttle(client);
f16712057c1b82c6d2a3a4267c4521d357cd4b4cTimo Sirainen auth_worker_client_unref(&client);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen}
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenstatic void
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenauth_worker_handle_passl(struct auth_worker_client *client,
c2f2a6cdf7dd55a4aabe72495cabb4deaa59cffcTimo Sirainen unsigned int id, const char *args)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen{
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* lookup credentials */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen struct auth_request *auth_request;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen const char *scheme;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen unsigned int passdb_id;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen passdb_id = atoi(t_strcut(args, '\t'));
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen args = strchr(args, '\t');
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (args == NULL) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen i_error("BUG: Auth worker server sent us invalid PASSL");
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen return;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen args++;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen scheme = t_strcut(args, '\t');
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen args = strchr(args, '\t');
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (args != NULL) args++;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen auth_request = worker_auth_request_new(client, id, args);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen auth_request->credentials_scheme = p_strdup(auth_request->pool, scheme);
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen if (auth_request->user == NULL || auth_request->service == NULL) {
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen i_error("BUG: PASSL had missing parameters");
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen auth_request_unref(&auth_request);
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen return;
c2f2a6cdf7dd55a4aabe72495cabb4deaa59cffcTimo Sirainen }
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen while (auth_request->passdb->id != passdb_id) {
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen auth_request->passdb = auth_request->passdb->next;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (auth_request->passdb == NULL) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen i_error("BUG: PASSL had invalid passdb ID");
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen auth_request_unref(&auth_request);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen return;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
cc3da53f3a49304a251bfae88f814505326ac210Timo Sirainen
cc3da53f3a49304a251bfae88f814505326ac210Timo Sirainen if (auth_request->passdb->passdb->iface.lookup_credentials == NULL) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen i_error("BUG: PASSL lookup not supported by given passdb");
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen auth_request_unref(&auth_request);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen return;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen auth_request->passdb->passdb->iface.
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen lookup_credentials(auth_request, lookup_credentials_callback);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen}
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenstatic void
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenset_credentials_callback(bool success, struct auth_request *request)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen{
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen struct auth_worker_client *client = request->context;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen string_t *str;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen str = t_str_new(64);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen str_printfa(str, "%u\t%s\n", request->id, success ? "OK" : "FAIL");
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen o_stream_send(client->output, str_data(str), str_len(str));
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen auth_request_unref(&request);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen auth_worker_client_check_throttle(client);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen auth_worker_client_unref(&client);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen}
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenstatic void
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenauth_worker_handle_setcred(struct auth_worker_client *client,
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen unsigned int id, const char *args)
c52eba0224a0ff239f4778a7f6ed5ce38d92a5ddTimo Sirainen{
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen struct auth_request *auth_request;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen unsigned int passdb_id;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen const char *data;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen passdb_id = atoi(t_strcut(args, '\t'));
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen args = strchr(args, '\t');
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (args == NULL) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen i_error("BUG: Auth worker server sent us invalid SETCRED");
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen return;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen args++;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen data = t_strcut(args, '\t');
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen args = strchr(args, '\t');
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (args != NULL) args++;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen auth_request = worker_auth_request_new(client, id, args);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (auth_request->user == NULL || auth_request->service == NULL) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen i_error("BUG: SETCRED had missing parameters");
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen auth_request_unref(&auth_request);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen return;
f3aff3c6bf32d5bb0a61993b76a3fbe5ad798c09Timo Sirainen }
200500ebd3c93a5771e7ae2f442659b9acb16eb6Timo Sirainen
200500ebd3c93a5771e7ae2f442659b9acb16eb6Timo Sirainen while (auth_request->passdb->id != passdb_id) {
200500ebd3c93a5771e7ae2f442659b9acb16eb6Timo Sirainen auth_request->passdb = auth_request->passdb->next;
f3aff3c6bf32d5bb0a61993b76a3fbe5ad798c09Timo Sirainen if (auth_request->passdb == NULL) {
f3aff3c6bf32d5bb0a61993b76a3fbe5ad798c09Timo Sirainen i_error("BUG: SETCRED had invalid passdb ID");
f3aff3c6bf32d5bb0a61993b76a3fbe5ad798c09Timo Sirainen auth_request_unref(&auth_request);
f3aff3c6bf32d5bb0a61993b76a3fbe5ad798c09Timo Sirainen return;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
f3aff3c6bf32d5bb0a61993b76a3fbe5ad798c09Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen auth_request->passdb->passdb->iface.
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen set_credentials(auth_request, data, set_credentials_callback);
f3aff3c6bf32d5bb0a61993b76a3fbe5ad798c09Timo Sirainen}
f3aff3c6bf32d5bb0a61993b76a3fbe5ad798c09Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenstatic void
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenlookup_user_callback(enum userdb_result result,
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen struct auth_request *auth_request)
1ff487015234b23c32cf8bb4c9f8c02922535b8eTimo Sirainen{
1ff487015234b23c32cf8bb4c9f8c02922535b8eTimo Sirainen struct auth_worker_client *client = auth_request->context;
1ff487015234b23c32cf8bb4c9f8c02922535b8eTimo Sirainen struct auth_stream_reply *reply = auth_request->userdb_reply;
1ff487015234b23c32cf8bb4c9f8c02922535b8eTimo Sirainen string_t *str;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (auth_request->userdb_lookup_failed)
15362cdf9df29fef8795e865957e17ec027a9ebfTimo Sirainen result = USERDB_RESULT_INTERNAL_FAILURE;
15362cdf9df29fef8795e865957e17ec027a9ebfTimo Sirainen
15362cdf9df29fef8795e865957e17ec027a9ebfTimo Sirainen str = t_str_new(128);
15362cdf9df29fef8795e865957e17ec027a9ebfTimo Sirainen str_printfa(str, "%u\t", auth_request->id);
15362cdf9df29fef8795e865957e17ec027a9ebfTimo Sirainen switch (result) {
15362cdf9df29fef8795e865957e17ec027a9ebfTimo Sirainen case USERDB_RESULT_INTERNAL_FAILURE:
e161a5225abda0837b5deb8746ef808ba5e98d94Timo Sirainen str_append(str, "FAIL\t");
e161a5225abda0837b5deb8746ef808ba5e98d94Timo Sirainen break;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen case USERDB_RESULT_USER_UNKNOWN:
e161a5225abda0837b5deb8746ef808ba5e98d94Timo Sirainen str_append(str, "NOTFOUND\t");
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen break;
15362cdf9df29fef8795e865957e17ec027a9ebfTimo Sirainen case USERDB_RESULT_OK:
15362cdf9df29fef8795e865957e17ec027a9ebfTimo Sirainen str_append(str, "OK\t");
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen str_append(str, auth_stream_reply_export(reply));
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen break;
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen }
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen str_append_c(str, '\n');
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen o_stream_send(client->output, str_data(str), str_len(str));
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen auth_request_unref(&auth_request);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen auth_worker_client_check_throttle(client);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen auth_worker_client_unref(&client);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen}
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenstatic void
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenauth_worker_handle_user(struct auth_worker_client *client,
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen unsigned int id, const char *args)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen{
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* lookup user */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen struct auth_request *auth_request;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen unsigned int num;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen num = atoi(t_strcut(args, '\t'));
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen args = strchr(args, '\t');
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (args != NULL) args++;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen auth_request = worker_auth_request_new(client, id, args);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (auth_request->user == NULL || auth_request->service == NULL) {
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen i_error("BUG: USER had missing parameters");
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen auth_request_unref(&auth_request);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen return;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen for (; num > 0; num--) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen auth_request->userdb = auth_request->userdb->next;
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen if (auth_request->userdb == NULL) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen i_error("BUG: USER had invalid userdb num");
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen auth_request_unref(&auth_request);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen return;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen auth_request->userdb->userdb->iface->
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen lookup(auth_request, lookup_user_callback);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen}
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenstatic bool
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenauth_worker_handle_line(struct auth_worker_client *client, const char *line)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen{
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen const char *p;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen 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->last_request = ioloop_time;
client->refcount++;
while ((line = i_stream_next_line(client->input)) != NULL) {
T_FRAME(
ret = auth_worker_handle_line(client, line);
);
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;
}
static void auth_worker_client_timeout(struct auth_worker_client *client)
{
if (client->last_request + AUTH_WORKER_MAX_IDLE <= ioloop_time)
auth_worker_client_destroy(&client);
}
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);
client->last_request = ioloop_time;
client->to = timeout_add(1000*60, auth_worker_client_timeout, 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;
timeout_remove(&client->to);
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);
}