auth-worker-client.c revision 3c9828bc22054744d740925fc9519d02ecb89184
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2005-2010 Dovecot authors, see the included COPYING file */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#include "auth-common.h"
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#include "base64.h"
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#include "ioloop.h"
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#include "network.h"
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#include "istream.h"
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#include "ostream.h"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#include "hex-binary.h"
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#include "str.h"
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#include "master-service.h"
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#include "auth-request.h"
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#include "auth-worker-client.h"
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#include <stdlib.h>
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen#define OUTBUF_THROTTLE_SIZE (1024*10)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstruct auth_worker_client {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen int refcount;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct auth *auth;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen int fd;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct io *io;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct istream *input;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct ostream *output;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen unsigned int version_received:1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen unsigned int dbhash_received:1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen};
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstruct auth_worker_list_context {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct auth_worker_client *client;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct userdb_module *userdb;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct userdb_iterate_context *iter;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen unsigned int id;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen bool sending, sent, done;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen};
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstruct auth_worker_client *auth_worker_client;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic void auth_worker_input(struct auth_worker_client *client);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic int auth_worker_output(struct auth_worker_client *client);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic void
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainenauth_worker_client_check_throttle(struct auth_worker_client *client)
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (o_stream_get_buffer_used_size(client->output) >=
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen OUTBUF_THROTTLE_SIZE) {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen /* stop reading new requests until client has read the pending
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen replies. */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (client->io != NULL)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen io_remove(&client->io);
27a44fcfd8d19bffe0f267f20a2b5d3fe7600fddTimo Sirainen }
27a44fcfd8d19bffe0f267f20a2b5d3fe7600fddTimo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic struct auth_request *
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenworker_auth_request_new(struct auth_worker_client *client, unsigned int id,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen const char *const *args)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct auth_request *auth_request;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen const char *key, *value;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_request = auth_request_new_dummy();
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen client->refcount++;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen auth_request->context = client;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_request->id = id;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen for (; *args != NULL; args++) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen value = strchr(*args, '=');
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (value != NULL) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen key = t_strdup_until(*args, value++);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen (void)auth_request_import(auth_request, key, value);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_request_init(auth_request);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return auth_request;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic void auth_worker_send_reply(struct auth_worker_client *client,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen string_t *str)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (shutdown_request)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen o_stream_send_str(client->output, "SHUTDOWN\n");
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen o_stream_send(client->output, str_data(str), str_len(str));
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic void verify_plain_callback(enum passdb_result result,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct auth_request *request)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct auth_worker_client *client = request->context;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct auth_stream_reply *reply;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen string_t *str;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (request->passdb_failure && result == PASSDB_RESULT_OK)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen result = PASSDB_RESULT_PASSWORD_MISMATCH;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen reply = auth_stream_reply_init(pool_datastack_create());
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen auth_stream_reply_add(reply, NULL, dec2str(request->id));
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (result == PASSDB_RESULT_OK)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen auth_stream_reply_add(reply, "OK", NULL);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen else {
27902ecd70d903ee3b426ac363443268f8934b9aTimo Sirainen auth_stream_reply_add(reply, "FAIL", NULL);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen auth_stream_reply_add(reply, NULL,
27902ecd70d903ee3b426ac363443268f8934b9aTimo Sirainen t_strdup_printf("%d", result));
1f85b15e9bfabc5ee390d2cddcfa347a33af8689Timo Sirainen }
1f85b15e9bfabc5ee390d2cddcfa347a33af8689Timo Sirainen if (result != PASSDB_RESULT_INTERNAL_FAILURE) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_stream_reply_add(reply, NULL, request->user);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen auth_stream_reply_add(reply, NULL,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen request->passdb_password == NULL ? "" :
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen request->passdb_password);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (request->extra_fields != NULL) {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen const char *fields =
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen auth_stream_reply_export(request->extra_fields);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen auth_stream_reply_import(reply, fields);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (request->extra_cache_fields != NULL) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen const char *fields =
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen auth_stream_reply_export(request->extra_cache_fields);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen auth_stream_reply_import(reply, fields);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen str = auth_stream_reply_get_str(reply);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen str_append_c(str, '\n');
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen auth_worker_send_reply(client, str);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen auth_request_unref(&request);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen auth_worker_client_check_throttle(client);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen auth_worker_client_unref(&client);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenstatic bool
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenauth_worker_handle_passv(struct auth_worker_client *client,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen unsigned int id, const char *const *args)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* verify plaintext password */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct auth_request *auth_request;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct auth_passdb *passdb;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen const char *password;
1f85b15e9bfabc5ee390d2cddcfa347a33af8689Timo Sirainen unsigned int passdb_id;
1f85b15e9bfabc5ee390d2cddcfa347a33af8689Timo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* <passdb id> <password> [<args>] */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (str_to_uint(args[0], &passdb_id) < 0 || args[1] == NULL) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen i_error("BUG: Auth worker server sent us invalid PASSV");
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return FALSE;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen password = args[1];
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen auth_request = worker_auth_request_new(client, id, args + 2);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen auth_request->mech_password =
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen p_strdup(auth_request->pool, password);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen if (auth_request->user == NULL || auth_request->service == NULL) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_error("BUG: PASSV had missing parameters");
27902ecd70d903ee3b426ac363443268f8934b9aTimo Sirainen auth_request_unref(&auth_request);
27902ecd70d903ee3b426ac363443268f8934b9aTimo Sirainen return FALSE;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen passdb = auth_request->passdb;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen while (passdb != NULL && passdb->passdb->id != passdb_id)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen passdb = passdb->next;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (passdb == NULL) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* could be a masterdb */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen passdb = auth_request_get_auth(auth_request)->masterdbs;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen while (passdb != NULL && passdb->passdb->id != passdb_id)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen passdb = passdb->next;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (passdb == NULL) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_error("BUG: PASSV had invalid passdb ID");
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_request_unref(&auth_request);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return FALSE;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen }
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_request->passdb = passdb;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen passdb->passdb->iface.
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen verify_plain(auth_request, password, verify_plain_callback);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return TRUE;
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic void
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenlookup_credentials_callback(enum passdb_result result,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen const unsigned char *credentials, size_t size,
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen struct auth_request *request)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct auth_worker_client *client = request->context;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct auth_stream_reply *reply;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen string_t *str;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (request->passdb_failure && result == PASSDB_RESULT_OK)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen result = PASSDB_RESULT_PASSWORD_MISMATCH;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen reply = auth_stream_reply_init(pool_datastack_create());
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_stream_reply_add(reply, NULL, dec2str(request->id));
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen if (result != PASSDB_RESULT_OK) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_stream_reply_add(reply, "FAIL", NULL);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_stream_reply_add(reply, NULL,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen t_strdup_printf("%d", result));
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen } else {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_stream_reply_add(reply, "OK", NULL);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_stream_reply_add(reply, NULL, request->user);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen str = t_str_new(64);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen str_printfa(str, "{%s.b64}", request->credentials_scheme);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen base64_encode(credentials, size, str);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_stream_reply_add(reply, NULL, str_c(str));
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (request->extra_fields != NULL) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen const char *fields =
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_stream_reply_export(request->extra_fields);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen auth_stream_reply_import(reply, fields);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (request->extra_cache_fields != NULL) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen const char *fields =
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_stream_reply_export(request->extra_cache_fields);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_stream_reply_import(reply, fields);
27caac427c21cc358ca969fa1ccebfa476874123Timo Sirainen }
27caac427c21cc358ca969fa1ccebfa476874123Timo Sirainen }
27caac427c21cc358ca969fa1ccebfa476874123Timo Sirainen str = auth_stream_reply_get_str(reply);
27caac427c21cc358ca969fa1ccebfa476874123Timo Sirainen str_append_c(str, '\n');
27caac427c21cc358ca969fa1ccebfa476874123Timo Sirainen auth_worker_send_reply(client, str);
27caac427c21cc358ca969fa1ccebfa476874123Timo Sirainen
27caac427c21cc358ca969fa1ccebfa476874123Timo Sirainen auth_request_unref(&request);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_worker_client_check_throttle(client);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_worker_client_unref(&client);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic bool
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainenauth_worker_handle_passl(struct auth_worker_client *client,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen unsigned int id, const char *const *args)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* lookup credentials */
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen struct auth_request *auth_request;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen const char *scheme;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen unsigned int passdb_id;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen /* <passdb id> <scheme> [<args>] */
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen if (str_to_uint(args[0], &passdb_id) < 0 || args[1] == NULL) {
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen i_error("BUG: Auth worker server sent us invalid PASSL");
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen return FALSE;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen }
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen scheme = args[1];
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen auth_request = worker_auth_request_new(client, id, args + 2);
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen auth_request->credentials_scheme = p_strdup(auth_request->pool, scheme);
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen if (auth_request->user == NULL || auth_request->service == NULL) {
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen i_error("BUG: PASSL had missing parameters");
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen auth_request_unref(&auth_request);
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen return FALSE;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen }
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen while (auth_request->passdb->passdb->id != passdb_id) {
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen auth_request->passdb = auth_request->passdb->next;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen if (auth_request->passdb == NULL) {
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen i_error("BUG: PASSL had invalid passdb ID");
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen auth_request_unref(&auth_request);
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen return FALSE;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen }
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen }
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen if (auth_request->passdb->passdb->iface.lookup_credentials == NULL) {
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen i_error("BUG: PASSL lookup not supported by given passdb");
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen auth_request_unref(&auth_request);
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen return FALSE;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen }
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen auth_request->prefer_plain_credentials = TRUE;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen auth_request->passdb->passdb->iface.
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen lookup_credentials(auth_request, lookup_credentials_callback);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return TRUE;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenstatic void
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenset_credentials_callback(bool success, struct auth_request *request)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct auth_worker_client *client = request->context;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen string_t *str;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen str = t_str_new(64);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen str_printfa(str, "%u\t%s\n", request->id, success ? "OK" : "FAIL");
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen auth_worker_send_reply(client, str);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_request_unref(&request);
50854b51d6408653be4dd90bd0427978df25c2b7Timo Sirainen auth_worker_client_check_throttle(client);
50854b51d6408653be4dd90bd0427978df25c2b7Timo Sirainen auth_worker_client_unref(&client);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic bool
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainenauth_worker_handle_setcred(struct auth_worker_client *client,
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen unsigned int id, const char *const *args)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct auth_request *auth_request;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen unsigned int passdb_id;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen const char *creds;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* <passdb id> <credentials> [<args>] */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (str_to_uint(args[0], &passdb_id) < 0 || args[1] == NULL) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_error("BUG: Auth worker server sent us invalid SETCRED");
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen return FALSE;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen }
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen creds = args[1];
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_request = worker_auth_request_new(client, id, args + 2);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (auth_request->user == NULL || auth_request->service == NULL) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_error("BUG: SETCRED had missing parameters");
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_request_unref(&auth_request);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return FALSE;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen while (auth_request->passdb->passdb->id != passdb_id) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_request->passdb = auth_request->passdb->next;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (auth_request->passdb == NULL) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_error("BUG: SETCRED had invalid passdb ID");
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_request_unref(&auth_request);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return FALSE;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_request->passdb->passdb->iface.
50854b51d6408653be4dd90bd0427978df25c2b7Timo Sirainen set_credentials(auth_request, creds, set_credentials_callback);
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen return TRUE;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic void
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenlookup_user_callback(enum userdb_result result,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct auth_request *auth_request)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct auth_worker_client *client = auth_request->context;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct auth_stream_reply *reply = auth_request->userdb_reply;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen string_t *str;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen const char *value;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (auth_request->userdb_lookup_failed)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen result = USERDB_RESULT_INTERNAL_FAILURE;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen str = t_str_new(128);
a81b240cfe84231eac64084efd5b0e1e91a9e817Timo Sirainen str_printfa(str, "%u\t", auth_request->id);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen switch (result) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen case USERDB_RESULT_INTERNAL_FAILURE:
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen str_append(str, "FAIL\t");
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (auth_request->userdb_lookup_failed) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen value = auth_stream_reply_find(reply, "reason");
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (value != NULL)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen str_printfa(str, "reason=%s", value);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen break;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen case USERDB_RESULT_USER_UNKNOWN:
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen str_append(str, "NOTFOUND\t");
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen break;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen case USERDB_RESULT_OK:
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen str_append(str, "OK\t");
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen str_append(str, auth_stream_reply_export(reply));
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen break;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen str_append_c(str, '\n');
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen auth_worker_send_reply(client, str);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_request_unref(&auth_request);
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen auth_worker_client_check_throttle(client);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_worker_client_unref(&client);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic struct auth_userdb *
27caac427c21cc358ca969fa1ccebfa476874123Timo Sirainenauth_userdb_find_by_id(struct auth_userdb *userdbs, unsigned int id)
27caac427c21cc358ca969fa1ccebfa476874123Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct auth_userdb *db;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen for (db = userdbs; db != NULL; db = db->next) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (db->userdb->id == id)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return db;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return NULL;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic bool
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenauth_worker_handle_user(struct auth_worker_client *client,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen unsigned int id, const char *const *args)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* lookup user */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct auth_request *auth_request;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen unsigned int userdb_id;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen /* <userdb id> [<args>] */
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen if (str_to_uint(args[0], &userdb_id) < 0) {
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen i_error("BUG: Auth worker server sent us invalid USER");
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen return FALSE;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen }
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen auth_request = worker_auth_request_new(client, id, args + 1);
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen if (auth_request->user == NULL || auth_request->service == NULL) {
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen i_error("BUG: USER had missing parameters");
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen auth_request_unref(&auth_request);
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen return FALSE;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen }
d646a63462a696824b1facd73e00732d4ac0f3dcTimo Sirainen
d646a63462a696824b1facd73e00732d4ac0f3dcTimo Sirainen auth_request->userdb =
d646a63462a696824b1facd73e00732d4ac0f3dcTimo Sirainen auth_userdb_find_by_id(auth_request->userdb, userdb_id);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (auth_request->userdb == NULL) {
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen i_error("BUG: USER had invalid userdb ID");
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen auth_request_unref(&auth_request);
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen return FALSE;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
d646a63462a696824b1facd73e00732d4ac0f3dcTimo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_request->userdb->userdb->iface->
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen lookup(auth_request, lookup_user_callback);
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen return TRUE;
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen}
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainenstatic void list_iter_deinit(struct auth_worker_list_context *ctx)
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen{
74375781364492f62348e1f873d9fa72fb1ec540Timo Sirainen struct auth_worker_client *client = ctx->client;
50854b51d6408653be4dd90bd0427978df25c2b7Timo Sirainen string_t *str;
d646a63462a696824b1facd73e00732d4ac0f3dcTimo Sirainen
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen i_assert(client->io == NULL);
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen
50854b51d6408653be4dd90bd0427978df25c2b7Timo Sirainen str = t_str_new(32);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (ctx->userdb->iface->iterate_deinit(ctx->iter) < 0)
50854b51d6408653be4dd90bd0427978df25c2b7Timo Sirainen str_printfa(str, "%u\tFAIL\n", ctx->id);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen else
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen str_printfa(str, "%u\tOK\n", ctx->id);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen auth_worker_send_reply(client, str);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen client->io = io_add(client->fd, IO_READ, auth_worker_input, client);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen o_stream_set_flush_callback(client->output, auth_worker_output, client);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_worker_client_unref(&client);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_free(ctx);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic void list_iter_callback(const char *user, void *context)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct auth_worker_list_context *ctx = context;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen string_t *str;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (user == NULL) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (ctx->sending)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ctx->done = TRUE;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen else
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen list_iter_deinit(ctx);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen T_BEGIN {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen str = t_str_new(128);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen str_printfa(str, "%u\t*\t%s\n", ctx->id, user);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen o_stream_send(ctx->client->output, str_data(str), str_len(str));
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen } T_END;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (ctx->sending) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* avoid recursively looping to this same function */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ctx->sent = TRUE;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen do {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ctx->sending = TRUE;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ctx->sent = FALSE;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ctx->userdb->iface->iterate_next(ctx->iter);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen } while (ctx->sent &&
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen o_stream_get_buffer_used_size(ctx->client->output) == 0);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ctx->sending = FALSE;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (ctx->done)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen list_iter_deinit(ctx);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic int auth_worker_list_output(struct auth_worker_list_context *ctx)
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen int ret;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if ((ret = o_stream_flush(ctx->client->output)) < 0) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen list_iter_deinit(ctx);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return 1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (ret > 0)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ctx->userdb->iface->iterate_next(ctx->iter);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return 1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic bool
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenauth_worker_handle_list(struct auth_worker_client *client,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen unsigned int id, const char *const *args)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct auth_worker_list_context *ctx;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct auth_userdb *userdb;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen unsigned int userdb_id;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (str_to_uint(args[0], &userdb_id) < 0) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_error("BUG: Auth worker server sent us invalid LIST");
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return FALSE;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen userdb = auth_userdb_find_by_id(client->auth->userdbs, userdb_id);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (userdb == NULL) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_error("BUG: LIST had invalid userdb ID");
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return FALSE;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ctx = i_new(struct auth_worker_list_context, 1);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ctx->client = client;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ctx->id = id;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ctx->userdb = userdb->userdb;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen io_remove(&ctx->client->io);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen o_stream_set_flush_callback(ctx->client->output,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_worker_list_output, ctx);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen client->refcount++;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ctx->iter = ctx->userdb->iface->
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen iterate_init(userdb->userdb, list_iter_callback, ctx);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ctx->userdb->iface->iterate_next(ctx->iter);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return TRUE;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic bool
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenauth_worker_handle_line(struct auth_worker_client *client, const char *line)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen const char *const *args;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen unsigned int id;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen bool ret = FALSE;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen args = t_strsplit(line, "\t");
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (args[0] == NULL || args[1] == NULL || args[2] == NULL ||
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen str_to_uint(args[0], &id) < 0) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_error("BUG: Invalid input: %s", line);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return FALSE;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (strcmp(args[1], "PASSV") == 0)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ret = auth_worker_handle_passv(client, id, args + 2);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen else if (strcmp(args[1], "PASSL") == 0)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ret = auth_worker_handle_passl(client, id, args + 2);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen else if (strcmp(args[1], "SETCRED") == 0)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ret = auth_worker_handle_setcred(client, id, args + 2);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen else if (strcmp(args[1], "USER") == 0)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ret = auth_worker_handle_user(client, id, args + 2);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen else if (strcmp(args[1], "LIST") == 0)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ret = auth_worker_handle_list(client, id, args + 2);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen else {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_error("BUG: Auth-worker received unknown command: %s",
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen args[1]);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return ret;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic bool auth_worker_verify_db_hash(const char *line)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen string_t *str;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen unsigned char passdb_md5[MD5_RESULTLEN];
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen unsigned char userdb_md5[MD5_RESULTLEN];
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen passdbs_generate_md5(passdb_md5);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen userdbs_generate_md5(userdb_md5);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen str = t_str_new(128);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen str_append(str, "DBHASH\t");
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen binary_to_hex_append(str, passdb_md5, sizeof(passdb_md5));
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen str_append_c(str, '\t');
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen binary_to_hex_append(str, userdb_md5, sizeof(userdb_md5));
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return strcmp(line, str_c(str)) == 0;
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen}
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstatic void auth_worker_input(struct auth_worker_client *client)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen char *line;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen bool ret;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen switch (i_stream_read(client->input)) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen case 0:
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen case -1:
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* disconnected */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_worker_client_destroy(&client);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen case -2:
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* buffer full */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_error("BUG: Auth worker server sent us more than %d bytes",
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen (int)AUTH_WORKER_MAX_LINE_LENGTH);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_worker_client_destroy(&client);
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen return;
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (!client->version_received) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen line = i_stream_next_line(client->input);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (line == NULL)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (strncmp(line, "VERSION\tauth-worker\t", 20) != 0 ||
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen !str_uint_equals(t_strcut(line + 20, '\t'),
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen AUTH_WORKER_PROTOCOL_MAJOR_VERSION)) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_error("Auth worker not compatible with this server "
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen "(mixed old and new binaries?)");
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen auth_worker_client_destroy(&client);
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen return;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen }
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen client->version_received = TRUE;
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (!client->dbhash_received) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen line = i_stream_next_line(client->input);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (line == NULL)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (!auth_worker_verify_db_hash(line)) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_error("Auth worker sees different passdbs/userdbs "
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen "than auth server. Maybe config just changed "
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen "and this goes away automatically?");
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_worker_client_destroy(&client);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen client->dbhash_received = TRUE;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen client->refcount++;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen while ((line = i_stream_next_line(client->input)) != NULL) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen T_BEGIN {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen ret = auth_worker_handle_line(client, line);
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen } T_END;
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (!ret) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct auth_worker_client *client2 = client;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_worker_client_destroy(&client2);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen break;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_worker_client_unref(&client);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainenstatic int auth_worker_output(struct auth_worker_client *client)
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen{
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen if (o_stream_flush(client->output) < 0) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_worker_client_destroy(&client);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return 1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (o_stream_get_buffer_used_size(client->output) <=
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen OUTBUF_THROTTLE_SIZE/3 && client->io == NULL) {
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen /* allow input again */
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen client->io = io_add(client->fd, IO_READ,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen auth_worker_input, client);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen }
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return 1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenstruct auth_worker_client *
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainenauth_worker_client_create(struct auth *auth, int fd)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct auth_worker_client *client;
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen client = i_new(struct auth_worker_client, 1);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen client->refcount = 1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen client->auth = auth;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen client->fd = fd;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen client->input = i_stream_create_fd(fd, AUTH_WORKER_MAX_LINE_LENGTH,
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen FALSE);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen client->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen o_stream_set_flush_callback(client->output, auth_worker_output, client);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen client->io = io_add(fd, IO_READ, auth_worker_input, client);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
b5c89a33fa14f3b8b19673c44eeecf1d131d690dTimo Sirainen auth_worker_client = client;
b5c89a33fa14f3b8b19673c44eeecf1d131d690dTimo Sirainen return client;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen}
4ca83616715c3bd417e34ced2c1d61852513e427Timo Sirainen
50854b51d6408653be4dd90bd0427978df25c2b7Timo Sirainenvoid auth_worker_client_destroy(struct auth_worker_client **_client)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen{
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen struct auth_worker_client *client = *_client;
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen *_client = NULL;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (client->fd == -1)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen return;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen i_stream_close(client->input);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen o_stream_close(client->output);
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen if (client->io != NULL)
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen io_remove(&client->io);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen net_disconnect(client->fd);
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen client->fd = -1;
5fb3f13537dffd15a31e997da133a721c0728af8Timo Sirainen 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);
}