bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "auth-common.h"
29d4c6eac14a0b3d79656eb6b206a102fd09d24aTimo Sirainen#include "buffer.h"
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#include "hash.h"
29d4c6eac14a0b3d79656eb6b206a102fd09d24aTimo Sirainen#include "llist.h"
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen#include "str.h"
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen#include "strescape.h"
5cda7e699876c1de203c30777924c899d2a20221Timo Sirainen#include "str-sanitize.h"
419baa2c17c63ae516b2df6cc5695f15aaccbff8Timo Sirainen#include "hostpid.h"
419baa2c17c63ae516b2df6cc5695f15aaccbff8Timo Sirainen#include "hex-binary.h"
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#include "ioloop.h"
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#include "net.h"
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen#include "istream.h"
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#include "ostream.h"
8eefc42b2559db19d06d7ad7b8ad9d1cd2a09178Timo Sirainen#include "ipwd.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "master-service.h"
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#include "userdb.h"
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen#include "userdb-blocking.h"
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen#include "master-interface.h"
39dcbe101c4538ee25d8b196eab30e5f0faa22eeTimo Sirainen#include "passdb-cache.h"
657afb33796f8216c568ad813627da89970760beTimo Sirainen#include "auth-request-handler.h"
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#include "auth-client-connection.h"
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#include "auth-master-connection.h"
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
76213404317a7ed17bec0beadb5137c82785d816Timo Sirainen#include <unistd.h>
76213404317a7ed17bec0beadb5137c82785d816Timo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen#define MAX_INBUF_SIZE 1024
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#define MAX_OUTBUF_SIZE (1024*50)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainenstruct master_userdb_request {
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen struct auth_master_connection *conn;
6c2c5f20760b06bfb4a40b0ee2ef5ab016bc41f0Timo Sirainen struct auth_request *auth_request;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen};
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainenstruct master_list_iter_ctx {
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen struct auth_master_connection *conn;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen struct userdb_iterate_context *iter;
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen struct auth_request *auth_request;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen bool failed;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen};
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainenstatic void master_input(struct auth_master_connection *conn);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
29d4c6eac14a0b3d79656eb6b206a102fd09d24aTimo Sirainenstatic struct auth_master_connection *auth_master_connections;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
c96a1bff0db10e7f7e1d50bc434c95bf1f071805Timo Sirainenstatic const char *
c96a1bff0db10e7f7e1d50bc434c95bf1f071805Timo Sirainenauth_master_reply_hide_passwords(struct auth_master_connection *conn,
c96a1bff0db10e7f7e1d50bc434c95bf1f071805Timo Sirainen const char *str)
c96a1bff0db10e7f7e1d50bc434c95bf1f071805Timo Sirainen{
c96a1bff0db10e7f7e1d50bc434c95bf1f071805Timo Sirainen char **args, *p, *p2;
c96a1bff0db10e7f7e1d50bc434c95bf1f071805Timo Sirainen unsigned int i;
c96a1bff0db10e7f7e1d50bc434c95bf1f071805Timo Sirainen
c96a1bff0db10e7f7e1d50bc434c95bf1f071805Timo Sirainen if (conn->auth->set->debug_passwords)
c96a1bff0db10e7f7e1d50bc434c95bf1f071805Timo Sirainen return str;
c96a1bff0db10e7f7e1d50bc434c95bf1f071805Timo Sirainen
c96a1bff0db10e7f7e1d50bc434c95bf1f071805Timo Sirainen /* hide all parameters that have "pass" in their key */
c96a1bff0db10e7f7e1d50bc434c95bf1f071805Timo Sirainen args = p_strsplit(pool_datastack_create(), str, "\t");
c96a1bff0db10e7f7e1d50bc434c95bf1f071805Timo Sirainen for (i = 0; args[i] != NULL; i++) {
c96a1bff0db10e7f7e1d50bc434c95bf1f071805Timo Sirainen p = strstr(args[i], "pass");
c96a1bff0db10e7f7e1d50bc434c95bf1f071805Timo Sirainen p2 = strchr(args[i], '=');
c96a1bff0db10e7f7e1d50bc434c95bf1f071805Timo Sirainen if (p != NULL && p < p2) {
c96a1bff0db10e7f7e1d50bc434c95bf1f071805Timo Sirainen *p2 = '\0';
c96a1bff0db10e7f7e1d50bc434c95bf1f071805Timo Sirainen args[i] = p_strconcat(pool_datastack_create(),
c96a1bff0db10e7f7e1d50bc434c95bf1f071805Timo Sirainen args[i], "=<hidden>", NULL);
c96a1bff0db10e7f7e1d50bc434c95bf1f071805Timo Sirainen }
c96a1bff0db10e7f7e1d50bc434c95bf1f071805Timo Sirainen }
c96a1bff0db10e7f7e1d50bc434c95bf1f071805Timo Sirainen return t_strarray_join((void *)args, "\t");
c96a1bff0db10e7f7e1d50bc434c95bf1f071805Timo Sirainen}
c96a1bff0db10e7f7e1d50bc434c95bf1f071805Timo Sirainen
6aafdd81aa1e12c127941c1ebd87e8ee4697ec3eTimo Sirainenvoid auth_master_request_callback(const char *reply, struct auth_master_connection *conn)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen{
657afb33796f8216c568ad813627da89970760beTimo Sirainen struct const_iovec iov[2];
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
c96a1bff0db10e7f7e1d50bc434c95bf1f071805Timo Sirainen if (conn->auth->set->debug) {
d85f713cc9f9ddaa2b591169f79df70e764fbe05Timo Sirainen i_debug("master userdb out: %s",
eb7b8855cc45292334056f425645215e348ec493Timo Sirainen auth_master_reply_hide_passwords(conn, reply));
c96a1bff0db10e7f7e1d50bc434c95bf1f071805Timo Sirainen }
9f431ccfb6932746db56245c8a3d3415717ef545Timo Sirainen
eb7b8855cc45292334056f425645215e348ec493Timo Sirainen iov[0].iov_base = reply;
eb7b8855cc45292334056f425645215e348ec493Timo Sirainen iov[0].iov_len = strlen(reply);
657afb33796f8216c568ad813627da89970760beTimo Sirainen iov[1].iov_base = "\n";
657afb33796f8216c568ad813627da89970760beTimo Sirainen iov[1].iov_len = 1;
a7bee3930831a9261fa6180d02af29c484d862e9Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsendv(conn->output, iov, 2);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen}
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenstatic bool
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainenmaster_input_request(struct auth_master_connection *conn, const char *args)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen{
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen struct auth_client_connection *client_conn;
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch const char *const *list, *const *params;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen unsigned int id, client_pid, client_id;
419baa2c17c63ae516b2df6cc5695f15aaccbff8Timo Sirainen uint8_t cookie[MASTER_AUTH_COOKIE_SIZE];
419baa2c17c63ae516b2df6cc5695f15aaccbff8Timo Sirainen buffer_t buf;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch /* <id> <client-pid> <client-id> <cookie> [<parameters>] */
7a60e1dc9e93ef3f7c7fe1af6385a0bfa1e31bc3Timo Sirainen list = t_strsplit_tabescaped(args);
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen if (str_array_length(list) < 4 ||
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen str_to_uint(list[0], &id) < 0 ||
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen str_to_uint(list[1], &client_pid) < 0 ||
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen str_to_uint(list[2], &client_id) < 0) {
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen i_error("BUG: Master sent broken REQUEST");
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen return FALSE;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen }
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen
3281669db44d09a087a203201248abbc81b3cc1aTimo Sirainen buffer_create_from_data(&buf, cookie, sizeof(cookie));
419baa2c17c63ae516b2df6cc5695f15aaccbff8Timo Sirainen if (hex_to_binary(list[3], &buf) < 0) {
419baa2c17c63ae516b2df6cc5695f15aaccbff8Timo Sirainen i_error("BUG: Master sent broken REQUEST cookie");
419baa2c17c63ae516b2df6cc5695f15aaccbff8Timo Sirainen return FALSE;
419baa2c17c63ae516b2df6cc5695f15aaccbff8Timo Sirainen }
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch params = list + 4;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen client_conn = auth_client_connection_lookup(client_pid);
657afb33796f8216c568ad813627da89970760beTimo Sirainen if (client_conn == NULL) {
7fc0f80480063a9d4cb9e8c07b50db2a5627799eTimo Sirainen i_error("Master requested auth for nonexistent client %u",
657afb33796f8216c568ad813627da89970760beTimo Sirainen client_pid);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend_str(conn->output,
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen t_strdup_printf("FAIL\t%u\n", id));
ace06232cfa0e99ecca1040e8553b3216d025768Timo Sirainen } else if (!mem_equals_timing_safe(client_conn->cookie, cookie, sizeof(cookie))) {
419baa2c17c63ae516b2df6cc5695f15aaccbff8Timo Sirainen i_error("Master requested auth for client %u with invalid cookie",
419baa2c17c63ae516b2df6cc5695f15aaccbff8Timo Sirainen client_pid);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend_str(conn->output,
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen t_strdup_printf("FAIL\t%u\n", id));
daa7e7459749ae8f82cd3eed9c44522d81c609a3Timo Sirainen } else if (!auth_request_handler_master_request(
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch client_conn->request_handler, conn, id, client_id, params)) {
daa7e7459749ae8f82cd3eed9c44522d81c609a3Timo Sirainen i_error("Master requested auth for non-login client %u",
daa7e7459749ae8f82cd3eed9c44522d81c609a3Timo Sirainen client_pid);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend_str(conn->output,
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen t_strdup_printf("FAIL\t%u\n", id));
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen }
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen return TRUE;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen}
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen
d9a7e950a9cd21f2b4a90ec7759fca9e8fcc7995Timo Sirainenstatic bool
39dcbe101c4538ee25d8b196eab30e5f0faa22eeTimo Sirainenmaster_input_cache_flush(struct auth_master_connection *conn, const char *args)
39dcbe101c4538ee25d8b196eab30e5f0faa22eeTimo Sirainen{
39dcbe101c4538ee25d8b196eab30e5f0faa22eeTimo Sirainen const char *const *list;
39dcbe101c4538ee25d8b196eab30e5f0faa22eeTimo Sirainen unsigned int count;
39dcbe101c4538ee25d8b196eab30e5f0faa22eeTimo Sirainen
39dcbe101c4538ee25d8b196eab30e5f0faa22eeTimo Sirainen /* <id> [<user> [<user> [..]] */
7a60e1dc9e93ef3f7c7fe1af6385a0bfa1e31bc3Timo Sirainen list = t_strsplit_tabescaped(args);
39dcbe101c4538ee25d8b196eab30e5f0faa22eeTimo Sirainen if (list[0] == NULL) {
39dcbe101c4538ee25d8b196eab30e5f0faa22eeTimo Sirainen i_error("BUG: doveadm sent broken CACHE-FLUSH");
39dcbe101c4538ee25d8b196eab30e5f0faa22eeTimo Sirainen return FALSE;
39dcbe101c4538ee25d8b196eab30e5f0faa22eeTimo Sirainen }
39dcbe101c4538ee25d8b196eab30e5f0faa22eeTimo Sirainen
f205e138634bd4269fa095463938cccf3970954dTimo Sirainen if (passdb_cache == NULL) {
f205e138634bd4269fa095463938cccf3970954dTimo Sirainen /* cache disabled */
f205e138634bd4269fa095463938cccf3970954dTimo Sirainen count = 0;
56ffe7c9356544aa228ef6760f9fa08ec2c8c9c1Timo Sirainen } else if (list[1] == NULL) {
39dcbe101c4538ee25d8b196eab30e5f0faa22eeTimo Sirainen /* flush the whole cache */
39dcbe101c4538ee25d8b196eab30e5f0faa22eeTimo Sirainen count = auth_cache_clear(passdb_cache);
39dcbe101c4538ee25d8b196eab30e5f0faa22eeTimo Sirainen } else {
39dcbe101c4538ee25d8b196eab30e5f0faa22eeTimo Sirainen count = auth_cache_clear_users(passdb_cache, list+1);
39dcbe101c4538ee25d8b196eab30e5f0faa22eeTimo Sirainen }
39dcbe101c4538ee25d8b196eab30e5f0faa22eeTimo Sirainen (void)o_stream_send_str(conn->output,
39dcbe101c4538ee25d8b196eab30e5f0faa22eeTimo Sirainen t_strdup_printf("OK\t%s\t%u\n", list[0], count));
39dcbe101c4538ee25d8b196eab30e5f0faa22eeTimo Sirainen return TRUE;
39dcbe101c4538ee25d8b196eab30e5f0faa22eeTimo Sirainen}
39dcbe101c4538ee25d8b196eab30e5f0faa22eeTimo Sirainen
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainenstatic int
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainenmaster_input_auth_request(struct auth_master_connection *conn, const char *args,
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen const char *cmd, struct auth_request **request_r,
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen const char **error_r)
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen{
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen struct auth_request *auth_request;
b8a6abfd2bc86118f54f59ee71005f634f45cdfcTimo Sirainen const char *const *list, *name, *arg, *username;
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen unsigned int id;
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen /* <id> <userid> [<parameters>] */
7a60e1dc9e93ef3f7c7fe1af6385a0bfa1e31bc3Timo Sirainen list = t_strsplit_tabescaped(args);
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen if (list[0] == NULL || list[1] == NULL ||
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen str_to_uint(list[0], &id) < 0) {
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen i_error("BUG: Master sent broken %s", cmd);
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen return -1;
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen }
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen auth_request = auth_request_new_dummy();
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen auth_request->id = id;
0602c7dee8ceda2d7c7e5723f18c56698ac5a76dTimo Sirainen auth_request->master = conn;
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen auth_master_connection_ref(conn);
b8a6abfd2bc86118f54f59ee71005f634f45cdfcTimo Sirainen username = list[1];
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen for (list += 2; *list != NULL; list++) {
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen arg = strchr(*list, '=');
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen if (arg == NULL) {
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen name = *list;
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen arg = "";
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen } else {
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen name = t_strdup_until(*list, arg);
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen arg++;
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen }
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen
ab122a3bbae3b5fd2aad66e2f2840149d98cee52Timo Sirainen (void)auth_request_import_info(auth_request, name, arg);
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen }
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen if (auth_request->service == NULL) {
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen i_error("BUG: Master sent %s request without service", cmd);
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen auth_request_unref(&auth_request);
0602c7dee8ceda2d7c7e5723f18c56698ac5a76dTimo Sirainen auth_master_connection_unref(&conn);
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen return -1;
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen }
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen auth_request_init(auth_request);
b8a6abfd2bc86118f54f59ee71005f634f45cdfcTimo Sirainen
b8a6abfd2bc86118f54f59ee71005f634f45cdfcTimo Sirainen if (!auth_request_set_username(auth_request, username, error_r)) {
b8a6abfd2bc86118f54f59ee71005f634f45cdfcTimo Sirainen *request_r = auth_request;
b8a6abfd2bc86118f54f59ee71005f634f45cdfcTimo Sirainen return 0;
b8a6abfd2bc86118f54f59ee71005f634f45cdfcTimo Sirainen }
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen *request_r = auth_request;
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen return 1;
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen}
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainenstatic int
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainenuser_verify_restricted_uid(struct auth_request *auth_request)
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen{
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen struct auth_master_connection *conn = auth_request->master;
ee6df9526e9716b3f1734d85b566e00fc41208bcTimo Sirainen struct auth_fields *reply = auth_request->userdb_reply;
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen const char *value, *reason;
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen uid_t uid;
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen if (conn->userdb_restricted_uid == 0)
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen return 0;
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen
ee6df9526e9716b3f1734d85b566e00fc41208bcTimo Sirainen value = auth_fields_find(reply, "uid");
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen if (value == NULL)
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen reason = "userdb reply doesn't contain uid";
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen else if (str_to_uid(value, &uid) < 0)
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen reason = "userdb reply contains invalid uid";
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen else if (uid != conn->userdb_restricted_uid) {
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen reason = t_strdup_printf(
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen "userdb uid (%s) doesn't match peer uid (%s)",
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen dec2str(uid), dec2str(conn->userdb_restricted_uid));
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen } else {
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen return 0;
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen }
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen auth_request_log_error(auth_request, "userdb",
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen "client doesn't have lookup permissions for this user: %s "
4240acc84d065472e5b21becd6481553fc38fe38Timo Sirainen "(to bypass this check, set: service auth { unix_listener %s { mode=0777 } })",
4240acc84d065472e5b21becd6481553fc38fe38Timo Sirainen reason, conn->path);
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen return -1;
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen}
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainenstatic void
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainenuser_callback(enum userdb_result result,
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen struct auth_request *auth_request)
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen{
0602c7dee8ceda2d7c7e5723f18c56698ac5a76dTimo Sirainen struct auth_master_connection *conn = auth_request->master;
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen string_t *str;
3313a51ef9b245248d672c20f930c52a577a42f7Timo Sirainen const char *value;
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen
cd75c360f244c96b9ee10e01ee3a66fad13183c8Timo Sirainen if (auth_request->userdb_lookup_tempfailed)
6fabfb7bbfd88d0c1de66981e52850f26067623bTimo Sirainen result = USERDB_RESULT_INTERNAL_FAILURE;
6fabfb7bbfd88d0c1de66981e52850f26067623bTimo Sirainen
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen if (result == USERDB_RESULT_OK) {
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen if (user_verify_restricted_uid(auth_request) < 0)
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen result = USERDB_RESULT_INTERNAL_FAILURE;
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen }
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen str = t_str_new(128);
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen switch (result) {
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen case USERDB_RESULT_INTERNAL_FAILURE:
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen str_printfa(str, "FAIL\t%u", auth_request->id);
cd75c360f244c96b9ee10e01ee3a66fad13183c8Timo Sirainen if (auth_request->userdb_lookup_tempfailed) {
ee6df9526e9716b3f1734d85b566e00fc41208bcTimo Sirainen value = auth_fields_find(auth_request->userdb_reply,
ee6df9526e9716b3f1734d85b566e00fc41208bcTimo Sirainen "reason");
3313a51ef9b245248d672c20f930c52a577a42f7Timo Sirainen if (value != NULL)
3313a51ef9b245248d672c20f930c52a577a42f7Timo Sirainen str_printfa(str, "\treason=%s", value);
3313a51ef9b245248d672c20f930c52a577a42f7Timo Sirainen }
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen break;
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen case USERDB_RESULT_USER_UNKNOWN:
3ee2da6133bd7773961d1f3f3ac531448a5158b9Timo Sirainen str_printfa(str, "NOTFOUND\t%u", auth_request->id);
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen break;
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen case USERDB_RESULT_OK:
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen str_printfa(str, "USER\t%u\t", auth_request->id);
548193b7d6c19a14eff810202cd334f364b75e36Timo Sirainen str_append_tabescaped(str, auth_request->user);
548193b7d6c19a14eff810202cd334f364b75e36Timo Sirainen str_append_c(str, '\t');
559f278a4c54d9fa7e0f2e96ebceda30562f9009Timo Sirainen auth_fields_append(auth_request->userdb_reply, str,
559f278a4c54d9fa7e0f2e96ebceda30562f9009Timo Sirainen AUTH_FIELD_FLAG_HIDDEN, 0);
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen break;
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen }
397165dbd694272487e29c8d48d619822da52abcTimo Sirainen
c96a1bff0db10e7f7e1d50bc434c95bf1f071805Timo Sirainen if (conn->auth->set->debug) {
d85f713cc9f9ddaa2b591169f79df70e764fbe05Timo Sirainen i_debug("userdb out: %s",
c96a1bff0db10e7f7e1d50bc434c95bf1f071805Timo Sirainen auth_master_reply_hide_passwords(conn, str_c(str)));
c96a1bff0db10e7f7e1d50bc434c95bf1f071805Timo Sirainen }
397165dbd694272487e29c8d48d619822da52abcTimo Sirainen
3ee2da6133bd7773961d1f3f3ac531448a5158b9Timo Sirainen str_append_c(str, '\n');
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend(conn->output, str_data(str), str_len(str));
0602c7dee8ceda2d7c7e5723f18c56698ac5a76dTimo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen auth_request_unref(&auth_request);
451254b8f080792f1e6f11639a9e8be663a108c0Timo Sirainen auth_master_connection_unref(&conn);
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen}
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenstatic bool
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainenmaster_input_user(struct auth_master_connection *conn, const char *args)
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen{
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen struct auth_request *auth_request;
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen const char *error;
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen int ret;
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen ret = master_input_auth_request(conn, args, "USER",
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen &auth_request, &error);
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen if (ret <= 0) {
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen if (ret < 0)
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen return FALSE;
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen auth_request_log_info(auth_request, "userdb", "%s", error);
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen user_callback(USERDB_RESULT_USER_UNKNOWN, auth_request);
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen } else {
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen auth_request_set_state(auth_request, AUTH_REQUEST_STATE_USERDB);
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen auth_request_lookup_user(auth_request, user_callback);
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen }
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen return TRUE;
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen}
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainenstatic void pass_callback_finish(struct auth_request *auth_request,
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen enum passdb_result result)
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen{
0602c7dee8ceda2d7c7e5723f18c56698ac5a76dTimo Sirainen struct auth_master_connection *conn = auth_request->master;
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen string_t *str;
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen str = t_str_new(128);
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen switch (result) {
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen case PASSDB_RESULT_OK:
bbdd683dd23641dca779bffdf22c089b57fe5066Timo Sirainen if (auth_request->failed || !auth_request->passdb_success) {
bbdd683dd23641dca779bffdf22c089b57fe5066Timo Sirainen str_printfa(str, "FAIL\t%u", auth_request->id);
bbdd683dd23641dca779bffdf22c089b57fe5066Timo Sirainen break;
bbdd683dd23641dca779bffdf22c089b57fe5066Timo Sirainen }
76830cda2eddcb36736bbb349dcbc2e9ca032483Timo Sirainen str_printfa(str, "PASS\t%u\tuser=", auth_request->id);
d03a871a77f8ec36f48f5fea98d810e51b186fdbTimo Sirainen str_append_tabescaped(str, auth_request->user);
ee6df9526e9716b3f1734d85b566e00fc41208bcTimo Sirainen if (!auth_fields_is_empty(auth_request->extra_fields)) {
76830cda2eddcb36736bbb349dcbc2e9ca032483Timo Sirainen str_append_c(str, '\t');
ee6df9526e9716b3f1734d85b566e00fc41208bcTimo Sirainen auth_fields_append(auth_request->extra_fields,
559f278a4c54d9fa7e0f2e96ebceda30562f9009Timo Sirainen str, AUTH_FIELD_FLAG_HIDDEN, 0);
76830cda2eddcb36736bbb349dcbc2e9ca032483Timo Sirainen }
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen break;
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen case PASSDB_RESULT_USER_UNKNOWN:
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen case PASSDB_RESULT_USER_DISABLED:
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen case PASSDB_RESULT_PASS_EXPIRED:
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen str_printfa(str, "NOTFOUND\t%u", auth_request->id);
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen break;
6e5a4cdf7ef123589e2409e0012b1024c97957d5Aki Tuomi case PASSDB_RESULT_NEXT:
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen case PASSDB_RESULT_PASSWORD_MISMATCH:
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen case PASSDB_RESULT_INTERNAL_FAILURE:
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen str_printfa(str, "FAIL\t%u", auth_request->id);
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen break;
04f792b9b17210898bab55e4b6c919fe78913001Timo Sirainen case PASSDB_RESULT_SCHEME_NOT_AVAILABLE:
3cad7d3634afa649561921c54e7769528e7813f9Timo Sirainen str_printfa(str, "FAIL\t%u\treason=Configured passdbs don't support credentials lookups",
04f792b9b17210898bab55e4b6c919fe78913001Timo Sirainen auth_request->id);
04f792b9b17210898bab55e4b6c919fe78913001Timo Sirainen break;
4f17af486518a4a7526dc6c4eed702178dc0bee9Timo Sirainen }
4f17af486518a4a7526dc6c4eed702178dc0bee9Timo Sirainen
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen if (conn->auth->set->debug)
d85f713cc9f9ddaa2b591169f79df70e764fbe05Timo Sirainen i_debug("passdb out: %s", str_c(str));
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen str_append_c(str, '\n');
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend(conn->output, str_data(str), str_len(str));
0602c7dee8ceda2d7c7e5723f18c56698ac5a76dTimo Sirainen
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen auth_request_unref(&auth_request);
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen auth_master_connection_unref(&conn);
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen}
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainenstatic void
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainenauth_master_pass_proxy_finish(bool success, struct auth_request *auth_request)
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen{
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen pass_callback_finish(auth_request, success ? PASSDB_RESULT_OK :
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen PASSDB_RESULT_INTERNAL_FAILURE);
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen}
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainenstatic void
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainenpass_callback(enum passdb_result result,
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen const unsigned char *credentials ATTR_UNUSED,
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen size_t size ATTR_UNUSED,
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen struct auth_request *auth_request)
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen{
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen int ret;
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen if (result != PASSDB_RESULT_OK)
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen auth_request_proxy_finish_failure(auth_request);
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen else {
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen ret = auth_request_proxy_finish(auth_request,
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen auth_master_pass_proxy_finish);
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen if (ret == 0)
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen return;
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen if (ret < 0)
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen result = PASSDB_RESULT_INTERNAL_FAILURE;
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen }
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen pass_callback_finish(auth_request, result);
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen}
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen
86a58337862c546aa489f07e8e6d242f0180e4a0Timo Sirainenstatic const char *auth_restricted_reason(struct auth_master_connection *conn)
86a58337862c546aa489f07e8e6d242f0180e4a0Timo Sirainen{
8eefc42b2559db19d06d7ad7b8ad9d1cd2a09178Timo Sirainen struct passwd pw;
8eefc42b2559db19d06d7ad7b8ad9d1cd2a09178Timo Sirainen const char *namestr;
8eefc42b2559db19d06d7ad7b8ad9d1cd2a09178Timo Sirainen
8eefc42b2559db19d06d7ad7b8ad9d1cd2a09178Timo Sirainen if (i_getpwuid(conn->userdb_restricted_uid, &pw) <= 0)
8eefc42b2559db19d06d7ad7b8ad9d1cd2a09178Timo Sirainen namestr = "";
8eefc42b2559db19d06d7ad7b8ad9d1cd2a09178Timo Sirainen else
8eefc42b2559db19d06d7ad7b8ad9d1cd2a09178Timo Sirainen namestr = t_strdup_printf("(%s)", pw.pw_name);
8eefc42b2559db19d06d7ad7b8ad9d1cd2a09178Timo Sirainen return t_strdup_printf("%s mode=0666, but not owned by UID %lu%s",
86a58337862c546aa489f07e8e6d242f0180e4a0Timo Sirainen conn->path,
8eefc42b2559db19d06d7ad7b8ad9d1cd2a09178Timo Sirainen (unsigned long)conn->userdb_restricted_uid,
8eefc42b2559db19d06d7ad7b8ad9d1cd2a09178Timo Sirainen namestr);
86a58337862c546aa489f07e8e6d242f0180e4a0Timo Sirainen}
86a58337862c546aa489f07e8e6d242f0180e4a0Timo Sirainen
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainenstatic bool
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainenmaster_input_pass(struct auth_master_connection *conn, const char *args)
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen{
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen struct auth_request *auth_request;
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen const char *error;
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen int ret;
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen ret = master_input_auth_request(conn, args, "PASS",
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen &auth_request, &error);
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen if (ret <= 0) {
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen if (ret < 0)
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen return FALSE;
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen auth_request_log_info(auth_request, "passdb", "%s", error);
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen pass_callback(PASSDB_RESULT_USER_UNKNOWN,
5965eaa2d972e6264cecaf54091cd43019bc7d1fTimo Sirainen uchar_empty_ptr, 0, auth_request);
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen } else if (conn->userdb_restricted_uid != 0) {
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen /* no permissions to do this lookup */
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen auth_request_log_error(auth_request, "passdb",
86a58337862c546aa489f07e8e6d242f0180e4a0Timo Sirainen "Auth client doesn't have permissions to do "
86a58337862c546aa489f07e8e6d242f0180e4a0Timo Sirainen "a PASS lookup: %s", auth_restricted_reason(conn));
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen pass_callback(PASSDB_RESULT_INTERNAL_FAILURE,
5965eaa2d972e6264cecaf54091cd43019bc7d1fTimo Sirainen uchar_empty_ptr, 0, auth_request);
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen } else {
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen auth_request_set_state(auth_request,
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen AUTH_REQUEST_STATE_MECH_CONTINUE);
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen auth_request_lookup_credentials(auth_request, "",
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen pass_callback);
1862352e2ef8ed1ef824368d9c0c2c0fce89962eTimo Sirainen }
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen return TRUE;
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen}
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainenstatic void master_input_list_finish(struct master_list_iter_ctx *ctx)
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen{
47b5ef748f34ca194419befab4f7450002f4e85dTimo Sirainen i_assert(ctx->conn->iter_ctx == ctx);
47b5ef748f34ca194419befab4f7450002f4e85dTimo Sirainen
47b5ef748f34ca194419befab4f7450002f4e85dTimo Sirainen ctx->conn->iter_ctx = NULL;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen ctx->conn->io = io_add(ctx->conn->fd, IO_READ, master_input, ctx->conn);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if (ctx->iter != NULL)
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen (void)userdb_blocking_iter_deinit(&ctx->iter);
1ce47e48d7231da6f18f02eab6bab6451b4ef12aTimo Sirainen o_stream_uncork(ctx->conn->output);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen o_stream_unset_flush_callback(ctx->conn->output);
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen auth_request_unref(&ctx->auth_request);
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen auth_master_connection_unref(&ctx->conn);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen i_free(ctx);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen}
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainenstatic int master_output_list(struct master_list_iter_ctx *ctx)
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen{
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen int ret;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if ((ret = o_stream_flush(ctx->conn->output)) < 0) {
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen master_input_list_finish(ctx);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen return 1;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen }
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen if (ret > 0) {
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen o_stream_cork(ctx->conn->output);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen userdb_blocking_iter_next(ctx->iter);
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen }
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen return 1;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen}
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainenstatic void master_input_list_callback(const char *user, void *context)
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen{
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen struct master_list_iter_ctx *ctx = context;
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen struct auth_userdb *userdb = ctx->auth_request->userdb;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen int ret;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if (user == NULL) {
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if (userdb_blocking_iter_deinit(&ctx->iter) < 0)
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen ctx->failed = TRUE;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen do {
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen userdb = userdb->next;
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen } while (userdb != NULL &&
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen userdb->userdb->iface->iterate_init == NULL);
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen if (userdb == NULL) {
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen /* iteration is finished */
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen const char *str;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen str = t_strdup_printf("DONE\t%u\t%s\n",
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen ctx->auth_request->id,
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen ctx->failed ? "fail" : "");
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend_str(ctx->conn->output, str);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen master_input_list_finish(ctx);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen return;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen }
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen /* continue iterating next userdb */
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen ctx->auth_request->userdb = userdb;
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen ctx->iter = userdb_blocking_iter_init(ctx->auth_request,
550034b94a58491a08a620c8e392fd3087551e7aTimo Sirainen master_input_list_callback, ctx);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen userdb_blocking_iter_next(ctx->iter);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen return;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen }
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen T_BEGIN {
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen const char *str;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen str = t_strdup_printf("LIST\t%u\t%s\n", ctx->auth_request->id,
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen str_tabescape(user));
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen ret = o_stream_send_str(ctx->conn->output, str);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen } T_END;
1ce47e48d7231da6f18f02eab6bab6451b4ef12aTimo Sirainen if (o_stream_get_buffer_used_size(ctx->conn->output) >= MAX_OUTBUF_SIZE)
1ce47e48d7231da6f18f02eab6bab6451b4ef12aTimo Sirainen ret = o_stream_flush(ctx->conn->output);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if (ret < 0) {
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen /* disconnected, don't bother finishing */
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen master_input_list_finish(ctx);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen return;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen }
1ce47e48d7231da6f18f02eab6bab6451b4ef12aTimo Sirainen if (o_stream_get_buffer_used_size(ctx->conn->output) < MAX_OUTBUF_SIZE)
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen userdb_blocking_iter_next(ctx->iter);
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen else
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen o_stream_uncork(ctx->conn->output);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen}
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainenstatic bool
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainenmaster_input_list(struct auth_master_connection *conn, const char *args)
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen{
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen struct auth_userdb *userdb = conn->auth->userdbs;
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen struct auth_request *auth_request;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen struct master_list_iter_ctx *ctx;
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen const char *str, *name, *arg, *const *list;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen unsigned int id;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen /* <id> [<parameters>] */
7a60e1dc9e93ef3f7c7fe1af6385a0bfa1e31bc3Timo Sirainen list = t_strsplit_tabescaped(args);
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen if (list[0] == NULL || str_to_uint(list[0], &id) < 0) {
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen i_error("BUG: Master sent broken LIST");
6094fe2df0a7efe28d45fa37b59755a2bee695e1Phil Carmody return FALSE;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen }
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen list++;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
47b5ef748f34ca194419befab4f7450002f4e85dTimo Sirainen if (conn->iter_ctx != NULL) {
47b5ef748f34ca194419befab4f7450002f4e85dTimo Sirainen i_error("Auth client is already iterating users");
47b5ef748f34ca194419befab4f7450002f4e85dTimo Sirainen str = t_strdup_printf("DONE\t%u\tfail\n", id);
47b5ef748f34ca194419befab4f7450002f4e85dTimo Sirainen o_stream_nsend_str(conn->output, str);
47b5ef748f34ca194419befab4f7450002f4e85dTimo Sirainen return TRUE;
47b5ef748f34ca194419befab4f7450002f4e85dTimo Sirainen }
47b5ef748f34ca194419befab4f7450002f4e85dTimo Sirainen
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen if (conn->userdb_restricted_uid != 0) {
86a58337862c546aa489f07e8e6d242f0180e4a0Timo Sirainen i_error("Auth client doesn't have permissions to list users: %s",
86a58337862c546aa489f07e8e6d242f0180e4a0Timo Sirainen auth_restricted_reason(conn));
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen str = t_strdup_printf("DONE\t%u\tfail\n", id);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend_str(conn->output, str);
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen return TRUE;
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen }
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen while (userdb != NULL && userdb->userdb->iface->iterate_init == NULL)
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen userdb = userdb->next;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if (userdb == NULL) {
3278289d240da169166de8aa785273c5df904e64Timo Sirainen i_error("Trying to iterate users, but userdbs don't support it");
5f618705ebdfa8220a98a5cbb4a561e5e335cfffTimo Sirainen str = t_strdup_printf("DONE\t%u\tfail\n", id);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend_str(conn->output, str);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen return TRUE;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen }
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen auth_request = auth_request_new_dummy();
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen auth_request->id = id;
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen auth_request->master = conn;
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen auth_master_connection_ref(conn);
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen for (; *list != NULL; list++) {
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen arg = strchr(*list, '=');
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen if (arg == NULL) {
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen name = *list;
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen arg = "";
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen } else {
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen name = t_strdup_until(*list, arg);
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen arg++;
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen }
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen if (!auth_request_import_info(auth_request, name, arg) &&
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen strcmp(name, "user") == 0) {
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen /* username mask */
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen auth_request->user = p_strdup(auth_request->pool, arg);
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen }
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen }
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen /* rest of the code doesn't like NULL user or service */
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen if (auth_request->user == NULL)
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen auth_request->user = "";
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen if (auth_request->service == NULL)
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen auth_request->service = "";
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen ctx = i_new(struct master_list_iter_ctx, 1);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen ctx->conn = conn;
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen ctx->auth_request = auth_request;
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen ctx->auth_request->userdb = userdb;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen io_remove(&conn->io);
1ce47e48d7231da6f18f02eab6bab6451b4ef12aTimo Sirainen o_stream_cork(conn->output);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen o_stream_set_flush_callback(conn->output, master_output_list, ctx);
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen ctx->iter = userdb_blocking_iter_init(auth_request,
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen master_input_list_callback, ctx);
47b5ef748f34ca194419befab4f7450002f4e85dTimo Sirainen conn->iter_ctx = ctx;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen return TRUE;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen}
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainenstatic bool
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainenauth_master_input_line(struct auth_master_connection *conn, const char *line)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (conn->auth->set->debug)
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk i_debug("master in: %s", line);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
3278289d240da169166de8aa785273c5df904e64Timo Sirainen if (strncmp(line, "USER\t", 5) == 0)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen return master_input_user(conn, line + 5);
3278289d240da169166de8aa785273c5df904e64Timo Sirainen if (strncmp(line, "LIST\t", 5) == 0)
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen return master_input_list(conn, line + 5);
0bb8c135a1c065655fc4d2d89b74b4f958fe4f02Timo Sirainen if (strncmp(line, "PASS\t", 5) == 0)
0bb8c135a1c065655fc4d2d89b74b4f958fe4f02Timo Sirainen return master_input_pass(conn, line + 5);
3278289d240da169166de8aa785273c5df904e64Timo Sirainen
3278289d240da169166de8aa785273c5df904e64Timo Sirainen if (!conn->userdb_only) {
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen i_assert(conn->userdb_restricted_uid == 0);
3278289d240da169166de8aa785273c5df904e64Timo Sirainen if (strncmp(line, "REQUEST\t", 8) == 0)
3278289d240da169166de8aa785273c5df904e64Timo Sirainen return master_input_request(conn, line + 8);
39dcbe101c4538ee25d8b196eab30e5f0faa22eeTimo Sirainen if (strncmp(line, "CACHE-FLUSH\t", 12) == 0)
39dcbe101c4538ee25d8b196eab30e5f0faa22eeTimo Sirainen return master_input_cache_flush(conn, line + 12);
3278289d240da169166de8aa785273c5df904e64Timo Sirainen if (strncmp(line, "CPID\t", 5) == 0) {
3278289d240da169166de8aa785273c5df904e64Timo Sirainen i_error("Authentication client trying to connect to "
3278289d240da169166de8aa785273c5df904e64Timo Sirainen "master socket");
3278289d240da169166de8aa785273c5df904e64Timo Sirainen return FALSE;
3278289d240da169166de8aa785273c5df904e64Timo Sirainen }
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen }
3278289d240da169166de8aa785273c5df904e64Timo Sirainen
0bb8c135a1c065655fc4d2d89b74b4f958fe4f02Timo Sirainen i_error("BUG: Unknown command in %s socket: %s",
0bb8c135a1c065655fc4d2d89b74b4f958fe4f02Timo Sirainen conn->userdb_only ? "userdb" : "master",
3278289d240da169166de8aa785273c5df904e64Timo Sirainen str_sanitize(line, 80));
3278289d240da169166de8aa785273c5df904e64Timo Sirainen return FALSE;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen}
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainenstatic void master_input(struct auth_master_connection *conn)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen{
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen char *line;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen bool ret;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen switch (i_stream_read(conn->input)) {
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen case 0:
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen return;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen case -1:
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen /* disconnected */
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen auth_master_connection_destroy(&conn);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen return;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen case -2:
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen /* buffer full */
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen i_error("BUG: Master sent us more than %d bytes",
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen (int)MAX_INBUF_SIZE);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen auth_master_connection_destroy(&conn);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen return;
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen }
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen if (!conn->version_received) {
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen line = i_stream_next_line(conn->input);
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen if (line == NULL)
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen return;
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen /* make sure the major version matches */
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen if (strncmp(line, "VERSION\t", 8) != 0 ||
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen !str_uint_equals(t_strcut(line + 8, '\t'),
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen AUTH_MASTER_PROTOCOL_MAJOR_VERSION)) {
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen i_error("Master not compatible with this server "
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen "(mixed old and new binaries?)");
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen auth_master_connection_destroy(&conn);
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen return;
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen }
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen conn->version_received = TRUE;
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen }
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen while ((line = i_stream_next_line(conn->input)) != NULL) {
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen T_BEGIN {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen ret = auth_master_input_line(conn, line);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen } T_END;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen if (!ret) {
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen auth_master_connection_destroy(&conn);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen return;
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen }
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen }
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen}
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainenstatic int master_output(struct auth_master_connection *conn)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen{
8bb360f9e5de1c25e4f875205bb06e8bf15dae14Timo Sirainen if (o_stream_flush(conn->output) < 0) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* transmit error, probably master died */
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen auth_master_connection_destroy(&conn);
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen return 1;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
e5a776932f62d971766d55b6bcc42d2824fa05a3Timo Sirainen if (conn->io == NULL &&
e5a776932f62d971766d55b6bcc42d2824fa05a3Timo Sirainen o_stream_get_buffer_used_size(conn->output) <= MAX_OUTBUF_SIZE/2) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* allow input again */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen conn->io = io_add(conn->fd, IO_READ, master_input, conn);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen return 1;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainenstatic int
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainenauth_master_connection_set_permissions(struct auth_master_connection *conn,
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen const struct stat *st)
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen{
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen struct net_unix_cred cred;
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen if (st == NULL)
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen return 0;
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen /* figure out what permissions we want to give to this client */
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen if ((st->st_mode & 0777) != 0666) {
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen /* permissions were already restricted by the socket
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen permissions. also +x bit indicates that we shouldn't do
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen any permission checks. */
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen return 0;
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen }
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen if (net_getunixcred(conn->fd, &cred) < 0) {
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen i_error("userdb connection: Failed to get peer's credentials");
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen return -1;
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen }
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen if (cred.uid == st->st_uid || cred.gid == st->st_gid) {
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen /* full permissions */
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen return 0;
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen } else {
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen /* restrict permissions: return only lookups whose returned
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen uid matches the peer's uid */
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen conn->userdb_restricted_uid = cred.uid;
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen return 0;
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen }
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen}
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen
ad49932dae8ba31e07544b66bbc4f4de707a751cTimo Sirainenstruct auth_master_connection *
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainenauth_master_connection_create(struct auth *auth, int fd,
86a58337862c546aa489f07e8e6d242f0180e4a0Timo Sirainen const char *path, const struct stat *socket_st,
86a58337862c546aa489f07e8e6d242f0180e4a0Timo Sirainen bool userdb_only)
6b46a500174ace25494b8f0547283eb60dc13756Timo Sirainen{
ad49932dae8ba31e07544b66bbc4f4de707a751cTimo Sirainen struct auth_master_connection *conn;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *line;
6b46a500174ace25494b8f0547283eb60dc13756Timo Sirainen
86a58337862c546aa489f07e8e6d242f0180e4a0Timo Sirainen i_assert(path != NULL);
86a58337862c546aa489f07e8e6d242f0180e4a0Timo Sirainen
ad49932dae8ba31e07544b66bbc4f4de707a751cTimo Sirainen conn = i_new(struct auth_master_connection, 1);
ecb1b2d6236942bf82f822e8d0167f0e160b206dTimo Sirainen conn->refcount = 1;
ad49932dae8ba31e07544b66bbc4f4de707a751cTimo Sirainen conn->fd = fd;
86a58337862c546aa489f07e8e6d242f0180e4a0Timo Sirainen conn->path = i_strdup(path);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen conn->auth = auth;
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi conn->input = i_stream_create_fd(fd, MAX_INBUF_SIZE);
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi conn->output = o_stream_create_fd(fd, (size_t)-1);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_set_no_error_handling(conn->output, TRUE);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen o_stream_set_flush_callback(conn->output, master_output, conn);
6b46a500174ace25494b8f0547283eb60dc13756Timo Sirainen conn->io = io_add(fd, IO_READ, master_input, conn);
3278289d240da169166de8aa785273c5df904e64Timo Sirainen conn->userdb_only = userdb_only;
6b46a500174ace25494b8f0547283eb60dc13756Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen line = t_strdup_printf("VERSION\t%u\t%u\nSPID\t%s\n",
657afb33796f8216c568ad813627da89970760beTimo Sirainen AUTH_MASTER_PROTOCOL_MAJOR_VERSION,
ad49932dae8ba31e07544b66bbc4f4de707a751cTimo Sirainen AUTH_MASTER_PROTOCOL_MINOR_VERSION,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen my_pid);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend_str(conn->output, line);
29d4c6eac14a0b3d79656eb6b206a102fd09d24aTimo Sirainen DLLIST_PREPEND(&auth_master_connections, conn);
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen if (auth_master_connection_set_permissions(conn, socket_st) < 0) {
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen auth_master_connection_destroy(&conn);
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen return NULL;
c95b7ce6c3ebf84a9ef20320b9f11ef2129e1f1aTimo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return conn;
6b46a500174ace25494b8f0547283eb60dc13756Timo Sirainen}
6b46a500174ace25494b8f0547283eb60dc13756Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenvoid auth_master_connection_destroy(struct auth_master_connection **_conn)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen{
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen struct auth_master_connection *conn = *_conn;
76213404317a7ed17bec0beadb5137c82785d816Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen *_conn = NULL;
76213404317a7ed17bec0beadb5137c82785d816Timo Sirainen if (conn->destroyed)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen return;
76213404317a7ed17bec0beadb5137c82785d816Timo Sirainen conn->destroyed = TRUE;
76213404317a7ed17bec0beadb5137c82785d816Timo Sirainen
29d4c6eac14a0b3d79656eb6b206a102fd09d24aTimo Sirainen DLLIST_REMOVE(&auth_master_connections, conn);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
47b5ef748f34ca194419befab4f7450002f4e85dTimo Sirainen if (conn->iter_ctx != NULL)
47b5ef748f34ca194419befab4f7450002f4e85dTimo Sirainen master_input_list_finish(conn->iter_ctx);
9a84b90d894a741ae6e090de104d31382a41d0aaJosef 'Jeff' Sipek i_stream_close(conn->input);
9a84b90d894a741ae6e090de104d31382a41d0aaJosef 'Jeff' Sipek o_stream_close(conn->output);
5f1d689131a75c39f064cbd4202373e7edf78f18Josef 'Jeff' Sipek io_remove(&conn->io);
a943ed0f901e312445fd393249b91932797bba79Josef 'Jeff' Sipek i_close_fd_path(&conn->fd, conn->path);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen master_service_client_connection_destroyed(master_service);
ecb1b2d6236942bf82f822e8d0167f0e160b206dTimo Sirainen auth_master_connection_unref(&conn);
ecb1b2d6236942bf82f822e8d0167f0e160b206dTimo Sirainen}
ecb1b2d6236942bf82f822e8d0167f0e160b206dTimo Sirainen
ecb1b2d6236942bf82f822e8d0167f0e160b206dTimo Sirainenvoid auth_master_connection_ref(struct auth_master_connection *conn)
ecb1b2d6236942bf82f822e8d0167f0e160b206dTimo Sirainen{
ecb1b2d6236942bf82f822e8d0167f0e160b206dTimo Sirainen i_assert(conn->refcount > 0);
ecb1b2d6236942bf82f822e8d0167f0e160b206dTimo Sirainen
ecb1b2d6236942bf82f822e8d0167f0e160b206dTimo Sirainen conn->refcount++;
ecb1b2d6236942bf82f822e8d0167f0e160b206dTimo Sirainen}
ecb1b2d6236942bf82f822e8d0167f0e160b206dTimo Sirainen
ecb1b2d6236942bf82f822e8d0167f0e160b206dTimo Sirainenvoid auth_master_connection_unref(struct auth_master_connection **_conn)
ecb1b2d6236942bf82f822e8d0167f0e160b206dTimo Sirainen{
ecb1b2d6236942bf82f822e8d0167f0e160b206dTimo Sirainen struct auth_master_connection *conn = *_conn;
ecb1b2d6236942bf82f822e8d0167f0e160b206dTimo Sirainen
ecb1b2d6236942bf82f822e8d0167f0e160b206dTimo Sirainen *_conn = NULL;
ecb1b2d6236942bf82f822e8d0167f0e160b206dTimo Sirainen i_assert(conn->refcount > 0);
ecb1b2d6236942bf82f822e8d0167f0e160b206dTimo Sirainen
ecb1b2d6236942bf82f822e8d0167f0e160b206dTimo Sirainen if (--conn->refcount > 0)
ecb1b2d6236942bf82f822e8d0167f0e160b206dTimo Sirainen return;
ecb1b2d6236942bf82f822e8d0167f0e160b206dTimo Sirainen
204ee6ed414f5e4eeb6f6c10763b55daf56f11acJosef 'Jeff' Sipek i_stream_unref(&conn->input);
204ee6ed414f5e4eeb6f6c10763b55daf56f11acJosef 'Jeff' Sipek o_stream_unref(&conn->output);
ecb1b2d6236942bf82f822e8d0167f0e160b206dTimo Sirainen
86a58337862c546aa489f07e8e6d242f0180e4a0Timo Sirainen i_free(conn->path);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen i_free(conn);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
29d4c6eac14a0b3d79656eb6b206a102fd09d24aTimo Sirainenvoid auth_master_connections_destroy_all(void)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
29d4c6eac14a0b3d79656eb6b206a102fd09d24aTimo Sirainen struct auth_master_connection *conn;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
29d4c6eac14a0b3d79656eb6b206a102fd09d24aTimo Sirainen while (auth_master_connections != NULL) {
29d4c6eac14a0b3d79656eb6b206a102fd09d24aTimo Sirainen conn = auth_master_connections;
29d4c6eac14a0b3d79656eb6b206a102fd09d24aTimo Sirainen auth_master_connection_destroy(&conn);
29d4c6eac14a0b3d79656eb6b206a102fd09d24aTimo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}