auth-worker-client.c revision 82f53ea81671bcc7b9bf24a34b04a4ba2752efd3
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen/* Copyright (C) 2005 Timo Sirainen */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "common.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "ioloop.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "network.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "istream.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "ostream.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "str.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "auth-request.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "auth-worker-client.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include <stdlib.h>
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
c1ebcdad1b4d950eb22219704dd9d64a89d0568fTimo Sirainen/* If no requests have come within this time, kill ourself */
c1ebcdad1b4d950eb22219704dd9d64a89d0568fTimo Sirainen#define AUTH_WORKER_MAX_IDLE (60*10)
c1ebcdad1b4d950eb22219704dd9d64a89d0568fTimo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#define OUTBUF_THROTTLE_SIZE (1024*10)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstruct auth_worker_client {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen int refcount;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen struct auth *auth;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen int fd;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen struct io *io;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen struct istream *input;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen struct ostream *output;
c1ebcdad1b4d950eb22219704dd9d64a89d0568fTimo Sirainen
c1ebcdad1b4d950eb22219704dd9d64a89d0568fTimo Sirainen time_t last_request;
c1ebcdad1b4d950eb22219704dd9d64a89d0568fTimo Sirainen struct timeout *to;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen};
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic void
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenauth_worker_client_check_throttle(struct auth_worker_client *client)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (o_stream_get_buffer_used_size(client->output) >=
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen OUTBUF_THROTTLE_SIZE) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* stop reading new requests until client has read the pending
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen replies. */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (client->io != NULL) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen io_remove(client->io);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen client->io = NULL;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic struct auth_request *
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenworker_auth_request_new(struct auth_worker_client *client, unsigned int id,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const char *args)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen struct auth_request *auth_request;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const char *key, *value, *const *tmp;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen auth_request = auth_request_new_dummy(client->auth);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen client->refcount++;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen auth_request->context = client;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen auth_request->id = id;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen t_push();
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen for (tmp = t_strsplit(args, "\t"); *tmp != NULL; tmp++) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen value = strchr(*tmp, '=');
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (value == NULL)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen continue;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen key = t_strdup_until(*tmp, value);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen value++;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen (void)auth_request_import(auth_request, key, value);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen t_pop();
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return auth_request;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic void verify_plain_callback(enum passdb_result result,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen struct auth_request *request)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen struct auth_worker_client *client = request->context;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen string_t *str;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str = t_str_new(64);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_printfa(str, "%u\t", request->id);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (result != PASSDB_RESULT_OK)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_printfa(str, "FAIL\t%d", result);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen else {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_append(str, "OK\t");
3d370bb6763ac4af4a0d143ad7c93300d5ddff89Timo Sirainen str_append(str, request->user);
3d370bb6763ac4af4a0d143ad7c93300d5ddff89Timo Sirainen str_append_c(str, '\t');
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (request->passdb_password != NULL)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_append(str, request->passdb_password);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_append_c(str, '\t');
72bb770023dd5c2eb4e0b56a79203233548b2aefTimo Sirainen if (request->proxy) {
72bb770023dd5c2eb4e0b56a79203233548b2aefTimo Sirainen /* we're proxying - send back the password that was
72bb770023dd5c2eb4e0b56a79203233548b2aefTimo Sirainen sent by user (not the password in passdb). */
72bb770023dd5c2eb4e0b56a79203233548b2aefTimo Sirainen str_printfa(str, "pass=%s\t", request->mech_password);
72bb770023dd5c2eb4e0b56a79203233548b2aefTimo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (request->extra_fields != NULL)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_append_str(str, request->extra_fields);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_append_c(str, '\n');
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen o_stream_send(client->output, str_data(str), str_len(str));
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen auth_request_unref(request);
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen auth_worker_client_check_throttle(client);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen auth_worker_client_unref(client);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic void
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenauth_worker_handle_passv(struct auth_worker_client *client,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen unsigned int id, const char *args)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* verify plaintext password */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen struct auth_request *auth_request;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const char *password;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen unsigned int num;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen num = atoi(t_strcut(args, '\t'));
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen args = strchr(args, '\t');
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen if (args == NULL) {
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen i_error("BUG: Auth worker server sent us invalid PASSV");
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen return;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen }
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen args++;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen password = t_strcut(args, '\t');
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen args = strchr(args, '\t');
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (args != NULL) args++;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen auth_request = worker_auth_request_new(client, id, args);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen auth_request->mech_password =
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen p_strdup(auth_request->pool, password);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen if (auth_request->user == NULL || auth_request->service == NULL) {
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen i_error("BUG: PASSV had missing parameters");
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen auth_request_unref(auth_request);
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen return;
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen }
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen
bd354c19cb93c07ade79477674328a54146ea332Timo Sirainen for (; num > 0; num--) {
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen auth_request->passdb = auth_request->passdb->next;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen if (auth_request->passdb == NULL) {
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen i_error("BUG: PASSV had invalid passdb num");
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen auth_request_unref(auth_request);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen return;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen }
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen }
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen auth_request->passdb->passdb->verify_plain(auth_request, password,
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen verify_plain_callback);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic void
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenlookup_credentials_callback(enum passdb_result result, const char *credentials,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen struct auth_request *request)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen struct auth_worker_client *client = request->context;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen string_t *str;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str = t_str_new(64);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_printfa(str, "%u\t", request->id);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (result != PASSDB_RESULT_OK)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_printfa(str, "FAIL\t%d", result);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen else {
3d370bb6763ac4af4a0d143ad7c93300d5ddff89Timo Sirainen str_printfa(str, "OK\t%s\t{%s}%s\t", request->user,
0af3274706d337b2930bd34f0377f2cc2dbcd18aTimo Sirainen passdb_credentials_to_str(request->credentials),
0af3274706d337b2930bd34f0377f2cc2dbcd18aTimo Sirainen credentials);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (request->extra_fields != NULL)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_append_str(str, request->extra_fields);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_append_c(str, '\n');
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen o_stream_send(client->output, str_data(str), str_len(str));
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen auth_request_unref(request);
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen auth_worker_client_check_throttle(client);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen auth_worker_client_unref(client);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic void
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenauth_worker_handle_passl(struct auth_worker_client *client,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen unsigned int id, const char *args)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* lookup credentials */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen struct auth_request *auth_request;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const char *credentials_str;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen enum passdb_credentials credentials;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen unsigned int num;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen num = atoi(t_strcut(args, '\t'));
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen args = strchr(args, '\t');
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen if (args == NULL) {
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen i_error("BUG: Auth worker server sent us invalid PASSL");
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen return;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen }
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen args++;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen credentials_str = t_strcut(args, '\t');
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen args = strchr(args, '\t');
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (args != NULL) args++;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen credentials = atoi(credentials_str);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen auth_request = worker_auth_request_new(client, id, args);
2efe0618b62fb1e3cd41a692f02d674a54c7720eTimo Sirainen auth_request->credentials = credentials;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen if (auth_request->user == NULL || auth_request->service == NULL) {
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen i_error("BUG: PASSL had missing parameters");
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen auth_request_unref(auth_request);
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen return;
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen }
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen
bd354c19cb93c07ade79477674328a54146ea332Timo Sirainen for (; num > 0; num--) {
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen auth_request->passdb = auth_request->passdb->next;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen if (auth_request->passdb == NULL) {
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen i_error("BUG: PASSL had invalid passdb num");
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen auth_request_unref(auth_request);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen return;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen }
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen }
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen auth_request->passdb->passdb->
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen lookup_credentials(auth_request, credentials,
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen lookup_credentials_callback);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic void
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenlookup_user_callback(const char *result, struct auth_request *auth_request)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen struct auth_worker_client *client = auth_request->context;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen string_t *str;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str = t_str_new(64);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_printfa(str, "%u\t", auth_request->id);
c2f24d55319fad0b6c03425f402f0cb0cb1a318bTimo Sirainen if (result != NULL)
c2f24d55319fad0b6c03425f402f0cb0cb1a318bTimo Sirainen str_append(str, result);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_append_c(str, '\n');
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen o_stream_send(client->output, str_data(str), str_len(str));
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen auth_request_unref(auth_request);
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen auth_worker_client_check_throttle(client);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen auth_worker_client_unref(client);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic void
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenauth_worker_handle_user(struct auth_worker_client *client,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen unsigned int id, const char *args)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* lookup user */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen struct auth_request *auth_request;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen unsigned int num;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen num = atoi(t_strcut(args, '\t'));
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen args = strchr(args, '\t');
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen if (args != NULL) args++;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen auth_request = worker_auth_request_new(client, id, args);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen if (auth_request->user == NULL || auth_request->service == NULL) {
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen i_error("BUG: USER had missing parameters");
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen auth_request_unref(auth_request);
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen return;
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen }
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen
bd354c19cb93c07ade79477674328a54146ea332Timo Sirainen for (; num > 0; num--) {
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen auth_request->userdb = auth_request->userdb->next;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen if (auth_request->userdb == NULL) {
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen i_error("BUG: USER had invalid userdb num");
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen auth_request_unref(auth_request);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen return;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen }
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen }
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen auth_request->userdb->userdb->
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen lookup(auth_request, lookup_user_callback);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic int
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenauth_worker_handle_line(struct auth_worker_client *client, const char *line)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const char *p;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen unsigned int id;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen p = strchr(line, '\t');
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (p == NULL)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return FALSE;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen id = (unsigned int)strtoul(t_strdup_until(line, p), NULL, 10);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen line = p + 1;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (strncmp(line, "PASSV\t", 6) == 0)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen auth_worker_handle_passv(client, id, line + 6);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen else if (strncmp(line, "PASSL\t", 6) == 0)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen auth_worker_handle_passl(client, id, line + 6);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen else if (strncmp(line, "USER\t", 5) == 0)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen auth_worker_handle_user(client, id, line + 5);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return TRUE;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic void auth_worker_input(void *context)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen struct auth_worker_client *client = context;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen char *line;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen int ret;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen switch (i_stream_read(client->input)) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen case 0:
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen case -1:
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* disconnected */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen auth_worker_client_destroy(client);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen case -2:
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* buffer full */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_error("BUG: Auth worker server sent us more than %d bytes",
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen (int)AUTH_WORKER_MAX_LINE_LENGTH);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen auth_worker_client_destroy(client);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
c1ebcdad1b4d950eb22219704dd9d64a89d0568fTimo Sirainen client->last_request = ioloop_time;
c1ebcdad1b4d950eb22219704dd9d64a89d0568fTimo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen client->refcount++;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen while ((line = i_stream_next_line(client->input)) != NULL) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen t_push();
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ret = auth_worker_handle_line(client, line);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen t_pop();
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (!ret) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen auth_worker_client_destroy(client);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen break;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen auth_worker_client_unref(client);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic int auth_worker_output(void *context)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen struct auth_worker_client *client = context;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (o_stream_flush(client->output) < 0) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen auth_worker_client_destroy(client);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return 1;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (o_stream_get_buffer_used_size(client->output) <=
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen OUTBUF_THROTTLE_SIZE/3 && client->io == NULL) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* allow input again */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen client->io = io_add(client->fd, IO_READ,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen auth_worker_input, client);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return 1;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
c1ebcdad1b4d950eb22219704dd9d64a89d0568fTimo Sirainenstatic void auth_worker_client_timeout(void *context)
c1ebcdad1b4d950eb22219704dd9d64a89d0568fTimo Sirainen{
c1ebcdad1b4d950eb22219704dd9d64a89d0568fTimo Sirainen struct auth_worker_client *client = context;
c1ebcdad1b4d950eb22219704dd9d64a89d0568fTimo Sirainen
c1ebcdad1b4d950eb22219704dd9d64a89d0568fTimo Sirainen if (client->last_request + AUTH_WORKER_MAX_IDLE <= ioloop_time)
c1ebcdad1b4d950eb22219704dd9d64a89d0568fTimo Sirainen auth_worker_client_destroy(client);
c1ebcdad1b4d950eb22219704dd9d64a89d0568fTimo Sirainen}
c1ebcdad1b4d950eb22219704dd9d64a89d0568fTimo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstruct auth_worker_client *
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenauth_worker_client_create(struct auth *auth, int fd)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen struct auth_worker_client *client;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen client = i_new(struct auth_worker_client, 1);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen client->refcount = 1;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen client->auth = auth;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen client->fd = fd;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen client->input =
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_stream_create_file(fd, default_pool,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen AUTH_WORKER_MAX_LINE_LENGTH, FALSE);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen client->output =
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen o_stream_create_file(fd, default_pool, (size_t)-1, FALSE);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen o_stream_set_flush_callback(client->output, auth_worker_output, client);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen client->io = io_add(fd, IO_READ, auth_worker_input, client);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
c1ebcdad1b4d950eb22219704dd9d64a89d0568fTimo Sirainen client->last_request = ioloop_time;
c1ebcdad1b4d950eb22219704dd9d64a89d0568fTimo Sirainen client->to = timeout_add(1000*60, auth_worker_client_timeout, client);
c1ebcdad1b4d950eb22219704dd9d64a89d0568fTimo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return client;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenvoid auth_worker_client_destroy(struct auth_worker_client *client)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (client->fd == -1)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
c1ebcdad1b4d950eb22219704dd9d64a89d0568fTimo Sirainen timeout_remove(client->to);
c1ebcdad1b4d950eb22219704dd9d64a89d0568fTimo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_stream_close(client->input);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen o_stream_close(client->output);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (client->io != NULL) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen io_remove(client->io);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen client->io = NULL;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen net_disconnect(client->fd);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen client->fd = -1;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen io_loop_stop(ioloop);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainenvoid auth_worker_client_unref(struct auth_worker_client *client)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (--client->refcount > 0)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen if (client->fd != -1)
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen auth_worker_client_destroy(client);
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_stream_unref(client->input);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen o_stream_unref(client->output);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_free(client);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}