client-common-auth.c revision f32d0295c90ed810889504cdfa5e1a25a415f65f
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2002-2016 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "hostpid.h"
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen#include "login-common.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "array.h"
993e6c2caaae971dd3c34913a42d854e3b623261Timo Sirainen#include "iostream.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "istream.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "ostream.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "str.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "safe-memset.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "time-util.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "login-proxy.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "auth-client.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "dsasl-client.h"
7888a9d2008eab9985096c46e1da9ee985c22a2aTimo Sirainen#include "master-service-ssl-settings.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "client-common.h"
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen#define PROXY_FAILURE_MSG "Account is temporarily unavailable."
213b139965e8bde6c8aff02ffd9fd39a74c887a9Timo Sirainen#define PROXY_DEFAULT_TIMEOUT_MSECS (1000*30)
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen/* If we've been waiting auth server to respond for over this many milliseconds,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen send a "waiting" message. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#define AUTH_WAITING_TIMEOUT_MSECS (30*1000)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#define AUTH_WAITING_WARNING_TIMEOUT_MSECS (10*1000)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct client_auth_fail_code_id {
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen const char *id;
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen enum client_auth_fail_code code;
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen};
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainenstatic const struct client_auth_fail_code_id client_auth_fail_codes[] = {
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen { AUTH_CLIENT_FAIL_CODE_AUTHZFAILED,
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen CLIENT_AUTH_FAIL_CODE_AUTHZFAILED },
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen { AUTH_CLIENT_FAIL_CODE_TEMPFAIL,
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen CLIENT_AUTH_FAIL_CODE_TEMPFAIL },
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen { AUTH_CLIENT_FAIL_CODE_USER_DISABLED,
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen CLIENT_AUTH_FAIL_CODE_USER_DISABLED },
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen { AUTH_CLIENT_FAIL_CODE_PASS_EXPIRED,
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen CLIENT_AUTH_FAIL_CODE_PASS_EXPIRED },
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen { NULL, CLIENT_AUTH_FAIL_CODE_NONE }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen};
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainenstatic enum client_auth_fail_code
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainenclient_auth_fail_code_lookup(const char *fail_code)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen{
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen const struct client_auth_fail_code_id *fail = client_auth_fail_codes;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen while (fail->id != NULL) {
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen if (strcmp(fail->id, fail_code) == 0)
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen return fail->code;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen fail++;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen }
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen return CLIENT_AUTH_FAIL_CODE_NONE;
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen}
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainenstatic void client_auth_failed(struct client *client)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_free_and_null(client->master_data_prefix);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (client->auth_response != NULL)
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen str_truncate(client->auth_response, 0);
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen if (client->auth_initializing || client->destroyed)
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen return;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen if (client->io != NULL)
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen io_remove(&client->io);
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen client->io = io_add(client->fd, IO_READ, client_input, client);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen client_input(client);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen}
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void client_auth_waiting_timeout(struct client *client)
993e6c2caaae971dd3c34913a42d854e3b623261Timo Sirainen{
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen if (!client->notified_auth_ready) {
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen client_log_warn(client, "Auth process not responding, "
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "delayed sending initial response (greeting)");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_notify_status(client, FALSE, client->master_tag == 0 ?
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen AUTH_SERVER_WAITING_MSG : AUTH_MASTER_WAITING_MSG);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen timeout_remove(&client->to_auth_waiting);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen}
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainenvoid client_set_auth_waiting(struct client *client)
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen{
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen i_assert(client->to_auth_waiting == NULL);
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen client->to_auth_waiting =
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen timeout_add(!client->notified_auth_ready ?
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen AUTH_WAITING_WARNING_TIMEOUT_MSECS :
993e6c2caaae971dd3c34913a42d854e3b623261Timo Sirainen AUTH_WAITING_TIMEOUT_MSECS,
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen client_auth_waiting_timeout, client);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen}
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
993e6c2caaae971dd3c34913a42d854e3b623261Timo Sirainenstatic void alt_username_set(ARRAY_TYPE(const_string) *alt_usernames, pool_t pool,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen const char *key, const char *value)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen{
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen char *const *fields;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen unsigned int i, count;
993e6c2caaae971dd3c34913a42d854e3b623261Timo Sirainen
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen fields = array_get(&global_alt_usernames, &count);
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen for (i = 0; i < count; i++) {
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen if (strcmp(fields[i], key) == 0)
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen break;
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen }
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen if (i == count) {
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen char *new_key = i_strdup(key);
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen array_append(&global_alt_usernames, &new_key, 1);
993e6c2caaae971dd3c34913a42d854e3b623261Timo Sirainen }
993e6c2caaae971dd3c34913a42d854e3b623261Timo Sirainen
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen value = p_strdup(pool, value);
993e6c2caaae971dd3c34913a42d854e3b623261Timo Sirainen if (i < array_count(alt_usernames)) {
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen array_idx_set(alt_usernames, i, &value);
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen return;
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen }
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen /* array is NULL-terminated, so if there are unused fields in
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen the middle set them as "" */
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen while (array_count(alt_usernames) < i) {
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen const char *empty_str = "";
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen array_append(alt_usernames, &empty_str, 1);
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen }
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen array_append(alt_usernames, &value, 1);
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen}
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainenstatic void client_auth_parse_args(struct client *client, bool success,
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen const char *const *args,
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen struct client_auth_reply *reply_r)
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen{
8eeafcb306872435f3171e6acf5a9937aec3a175Timo Sirainen const char *key, *value, *p;
993e6c2caaae971dd3c34913a42d854e3b623261Timo Sirainen ARRAY_TYPE(const_string) alt_usernames;
a4d209d480d453566d331e870b8d0c99af7716c8Timo Sirainen
a4d209d480d453566d331e870b8d0c99af7716c8Timo Sirainen t_array_init(&alt_usernames, 4);
a4d209d480d453566d331e870b8d0c99af7716c8Timo Sirainen memset(reply_r, 0, sizeof(*reply_r));
a4d209d480d453566d331e870b8d0c99af7716c8Timo Sirainen
993e6c2caaae971dd3c34913a42d854e3b623261Timo Sirainen for (; *args != NULL; args++) {
a4d209d480d453566d331e870b8d0c99af7716c8Timo Sirainen p = strchr(*args, '=');
a4d209d480d453566d331e870b8d0c99af7716c8Timo Sirainen if (p == NULL) {
a4d209d480d453566d331e870b8d0c99af7716c8Timo Sirainen key = *args;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen value = "";
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen } else {
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen key = t_strdup_until(*args, p);
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen value = p + 1;
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen }
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen if (strcmp(key, "nologin") == 0) {
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen reply_r->nologin = TRUE;
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen reply_r->fail_code = CLIENT_AUTH_FAIL_CODE_LOGIN_DISABLED;
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen } else if (strcmp(key, "proxy") == 0)
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen reply_r->proxy = TRUE;
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen else if (strcmp(key, "reason") == 0)
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen reply_r->reason = value;
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen else if (strcmp(key, "host") == 0)
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen reply_r->host = value;
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen else if (strcmp(key, "hostip") == 0)
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen reply_r->hostip = value;
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen else if (strcmp(key, "source_ip") == 0)
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen reply_r->source_ip = value;
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen else if (strcmp(key, "port") == 0) {
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen if (net_str2port(value, &reply_r->port) < 0) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen i_error("Auth service returned invalid "
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen "port number: %s", value);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen }
ccb77e2f63626ec46e5745ef4f38baa8e8e504fcTimo Sirainen } else if (strcmp(key, "destuser") == 0)
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen reply_r->destuser = value;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen else if (strcmp(key, "pass") == 0)
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen reply_r->password = value;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen else if (strcmp(key, "proxy_timeout") == 0) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (str_to_uint(value, &reply_r->proxy_timeout_msecs) < 0) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen i_error("BUG: Auth service returned invalid "
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen "proxy_timeout value: %s", value);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen reply_r->proxy_timeout_msecs *= 1000;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen } else if (strcmp(key, "proxy_refresh") == 0) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (str_to_uint(value, &reply_r->proxy_refresh_secs) < 0) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen i_error("BUG: Auth service returned invalid "
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen "proxy_refresh value: %s", value);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen } else if (strcmp(key, "proxy_mech") == 0)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen reply_r->proxy_mech = value;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen else if (strcmp(key, "proxy_nopipelining") == 0)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen reply_r->proxy_nopipelining = TRUE;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen else if (strcmp(key, "proxy_not_trusted") == 0)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen reply_r->proxy_not_trusted = TRUE;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen else if (strcmp(key, "master") == 0)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen reply_r->master_user = value;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen else if (strcmp(key, "ssl") == 0) {
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen reply_r->ssl_flags |= PROXY_SSL_FLAG_YES;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (strcmp(value, "any-cert") == 0)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen reply_r->ssl_flags |= PROXY_SSL_FLAG_ANY_CERT;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen if (reply_r->port == 0)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen reply_r->port = login_binary->default_ssl_port;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen } else if (strcmp(key, "starttls") == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen reply_r->ssl_flags |= PROXY_SSL_FLAG_YES |
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen PROXY_SSL_FLAG_STARTTLS;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (strcmp(value, "any-cert") == 0)
c21c33a8c98972c45349066fc76ac9e2c05013c1Timo Sirainen reply_r->ssl_flags |= PROXY_SSL_FLAG_ANY_CERT;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen } else if (strcmp(key, "code") == 0) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (reply_r->fail_code != CLIENT_AUTH_FAIL_CODE_NONE) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen /* code already assigned */
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen } else {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen reply_r->fail_code = client_auth_fail_code_lookup(value);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
c21c33a8c98972c45349066fc76ac9e2c05013c1Timo Sirainen } else if (strcmp(key, "user") == 0 ||
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen strcmp(key, "postlogin_socket") == 0) {
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen /* already handled in sasl-server.c */
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen } else if (strncmp(key, "user_", 5) == 0) {
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen if (success) {
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen alt_username_set(&alt_usernames, client->pool,
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen key, value);
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen }
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen } else if (client->set->auth_debug)
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen i_debug("Ignoring unknown passdb extra field: %s", key);
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen }
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen if (array_count(&alt_usernames) > 0) {
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen const char **alt;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen alt = p_new(client->pool, const char *,
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen array_count(&alt_usernames) + 1);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen memcpy(alt, array_idx(&alt_usernames, 0),
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen sizeof(*alt) * array_count(&alt_usernames));
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen client->alt_usernames = alt;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen }
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen if (reply_r->port == 0)
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen reply_r->port = login_binary->default_port;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen if (reply_r->destuser == NULL)
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen reply_r->destuser = client->virtual_user;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen}
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainenstatic void proxy_free_password(struct client *client)
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen{
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen if (client->proxy_password == NULL)
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen safe_memset(client->proxy_password, 0, strlen(client->proxy_password));
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen i_free_and_null(client->proxy_password);
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainenvoid client_proxy_finish_destroy_client(struct client *client)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen{
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen string_t *str = t_str_new(128);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (client->input->closed) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen /* input stream got closed in client_send_raw_data().
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen In most places we don't have to check for this explicitly,
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen but login_proxy_detach() attempts to get and use the
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen istream's fd, which is now -1. */
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen client_destroy(client, "Disconnected");
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen return;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen str_printfa(str, "proxy(%s): started proxying to %s:%u",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client->virtual_user,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen login_proxy_get_host(client->login_proxy),
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen login_proxy_get_port(client->login_proxy));
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen if (strcmp(client->virtual_user, client->proxy_user) != 0) {
527ed64bc924b4a13b570a8450f8be3efdf71879Timo Sirainen /* remote username is different, log it */
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen str_append_c(str, '/');
688f0fdfb7ca946e38ae34459b0ca30b71c8457cTimo Sirainen str_append(str, client->proxy_user);
688f0fdfb7ca946e38ae34459b0ca30b71c8457cTimo Sirainen }
688f0fdfb7ca946e38ae34459b0ca30b71c8457cTimo Sirainen if (client->proxy_master_user != NULL)
688f0fdfb7ca946e38ae34459b0ca30b71c8457cTimo Sirainen str_printfa(str, " (master %s)", client->proxy_master_user);
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen login_proxy_detach(client->login_proxy);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen client_destroy_success(client, str_c(str));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void client_proxy_error(struct client *client, const char *text)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen client->v.proxy_error(client, text);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainenvoid client_proxy_log_failure(struct client *client, const char *line)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen{
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen string_t *str = t_str_new(128);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen str_printfa(str, "proxy(%s): Login failed to %s:%u",
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen client->virtual_user,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen login_proxy_get_host(client->login_proxy),
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen login_proxy_get_port(client->login_proxy));
c680a6b35b459045e92814778908da5a93922107Timo Sirainen if (strcmp(client->virtual_user, client->proxy_user) != 0) {
c680a6b35b459045e92814778908da5a93922107Timo Sirainen /* remote username is different, log it */
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen str_append_c(str, '/');
c680a6b35b459045e92814778908da5a93922107Timo Sirainen str_append(str, client->proxy_user);
c680a6b35b459045e92814778908da5a93922107Timo Sirainen }
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (client->proxy_master_user != NULL)
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen str_printfa(str, " (master %s)", client->proxy_master_user);
c680a6b35b459045e92814778908da5a93922107Timo Sirainen str_append(str, ": ");
096953143c4032bad154637f687551856f7946cbTimo Sirainen str_append(str, line);
096953143c4032bad154637f687551856f7946cbTimo Sirainen client_log(client, str_c(str));
096953143c4032bad154637f687551856f7946cbTimo Sirainen}
096953143c4032bad154637f687551856f7946cbTimo Sirainen
c680a6b35b459045e92814778908da5a93922107Timo Sirainenvoid client_proxy_failed(struct client *client, bool send_line)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen{
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (send_line) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen client_proxy_error(client, PROXY_FAILURE_MSG);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (client->proxy_sasl_client != NULL)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen dsasl_client_free(&client->proxy_sasl_client);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen login_proxy_free(&client->login_proxy);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen proxy_free_password(client);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen i_free_and_null(client->proxy_user);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen i_free_and_null(client->proxy_master_user);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen /* call this last - it may destroy the client */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen client_auth_failed(client);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen}
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void proxy_input(struct client *client)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct istream *input;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct ostream *output;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *line;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int duration;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (client->login_proxy == NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* we're just freeing the proxy */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen input = login_proxy_get_istream(client->login_proxy);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (input == NULL) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (client->destroyed) {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen /* we came here from client_destroy() */
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen }
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen /* failed for some reason, probably server disconnected */
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen client_proxy_failed(client, TRUE);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen }
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen i_assert(!client->destroyed);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen switch (i_stream_read(input)) {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen case -2:
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen client_log_err(client, "proxy: Remote input buffer full");
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen client_proxy_failed(client, TRUE);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen case -1:
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen line = i_stream_next_line(input);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen duration = ioloop_time - client->created;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen client_log_err(client, t_strdup_printf(
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen "proxy: Remote %s:%u disconnected: %s "
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen "(state=%u, duration=%us)%s",
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen login_proxy_get_host(client->login_proxy),
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen login_proxy_get_port(client->login_proxy),
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen io_stream_get_disconnect_reason(input, NULL),
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen client->proxy_state, duration,
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen line == NULL ? "" : t_strdup_printf(
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen " - BUG: line not read: %s", line)));
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen client_proxy_failed(client, TRUE);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen }
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen output = client->output;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen o_stream_ref(output);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen o_stream_cork(output);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen while ((line = i_stream_next_line(input)) != NULL) {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (client->v.proxy_parse_line(client, line) != 0)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen break;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen }
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen o_stream_uncork(output);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen o_stream_unref(&output);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen}
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainenstatic int proxy_start(struct client *client,
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen const struct client_auth_reply *reply)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen{
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen struct login_proxy_settings proxy_set;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen const struct dsasl_client_mech *sasl_mech = NULL;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen i_assert(reply->destuser != NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(!client->destroyed);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(client->proxy_sasl_client == NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client->proxy_mech = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client->v.proxy_reset(client);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (reply->password == NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_log_err(client, "proxy: password not given");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_proxy_error(client, PROXY_FAILURE_MSG);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen return -1;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen }
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (reply->host == NULL || *reply->host == '\0') {
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen client_log_err(client, "proxy: host not given");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_proxy_error(client, PROXY_FAILURE_MSG);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (reply->proxy_mech != NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sasl_mech = dsasl_client_mech_find(reply->proxy_mech);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (sasl_mech == NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_log_err(client, t_strdup_printf(
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "proxy: Unsupported SASL mechanism %s",
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen reply->proxy_mech));
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen client_proxy_error(client, PROXY_FAILURE_MSG);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen return -1;
8bae533c96e129dca8ee7b494d7de5aeb4a043a2Timo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen } else if (reply->master_user != NULL) {
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen /* have to use PLAIN authentication with master user logins */
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen sasl_mech = &dsasl_client_mech_plain;
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen }
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen i_assert(client->refcount > 1);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen if (client->destroyed) {
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen /* connection_queue_add() decided that we were the oldest
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen connection and killed us. */
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen return -1;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen if (login_proxy_is_ourself(client, reply->host, reply->port,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen reply->destuser)) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen client_log_err(client, "Proxying loops to itself");
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen client_proxy_error(client, PROXY_FAILURE_MSG);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen return -1;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
37b805dfb45902b6b41c45482f67e6f98e08b0a3Timo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen memset(&proxy_set, 0, sizeof(proxy_set));
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen proxy_set.host = reply->host;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen if (reply->hostip != NULL &&
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen net_addr2ip(reply->hostip, &proxy_set.ip) < 0)
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen proxy_set.ip.family = 0;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen if (reply->source_ip != NULL) {
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen if (net_addr2ip(reply->source_ip, &proxy_set.source_ip) < 0)
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen proxy_set.source_ip.family = 0;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen } else if (login_source_ips_count > 0) {
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen /* select the next source IP with round robin. */
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen proxy_set.source_ip = login_source_ips[login_source_ips_idx];
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen login_source_ips_idx =
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen (login_source_ips_idx + 1) % login_source_ips_count;
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen }
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen proxy_set.port = reply->port;
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen proxy_set.connect_timeout_msecs = reply->proxy_timeout_msecs;
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen if (proxy_set.connect_timeout_msecs == 0)
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen proxy_set.connect_timeout_msecs = PROXY_DEFAULT_TIMEOUT_MSECS;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen proxy_set.notify_refresh_secs = reply->proxy_refresh_secs;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen proxy_set.ssl_flags = reply->ssl_flags;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen if (login_proxy_new(client, &proxy_set, proxy_input) < 0) {
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen client_proxy_error(client, PROXY_FAILURE_MSG);
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen return -1;
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen }
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen client->proxy_mech = sasl_mech;
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen client->proxy_user = i_strdup(reply->destuser);
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen client->proxy_master_user = i_strdup(reply->master_user);
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen client->proxy_password = i_strdup(reply->password);
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen client->proxy_nopipelining = reply->proxy_nopipelining;
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen client->proxy_not_trusted = reply->proxy_not_trusted;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen /* disable input until authentication is finished */
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen if (client->io != NULL)
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen io_remove(&client->io);
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen return 0;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen}
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainenstatic void ATTR_NULL(3, 4)
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainenclient_auth_result(struct client *client, enum client_auth_result result,
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen const struct client_auth_reply *reply, const char *text)
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen{
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen o_stream_cork(client->output);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen client->v.auth_result(client, result, reply, text);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen o_stream_uncork(client->output);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen}
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainenstatic bool
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainenclient_auth_handle_reply(struct client *client,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen const struct client_auth_reply *reply, bool success)
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen{
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (reply->proxy) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen /* we want to proxy the connection to another server.
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen don't do this unless authentication succeeded. with
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen master user proxying we can get FAIL with proxy still set.
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen proxy host=.. [port=..] [destuser=..] pass=.. */
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (!success)
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen return FALSE;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (proxy_start(client, reply) < 0)
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen client_auth_failed(client);
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen else {
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen /* this for plugins being able th hook into auth reply
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen when proxying is used */
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen client_auth_result(client, CLIENT_AUTH_RESULT_SUCCESS,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen reply, NULL);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen return TRUE;
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen }
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (reply->host != NULL) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen const char *reason;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (reply->reason != NULL)
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen reason = reply->reason;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen else if (reply->nologin)
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen reason = "Try this server instead.";
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen else
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen reason = "Logged in, but you should use this server instead.";
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen if (reply->nologin) {
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen client_auth_result(client,
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen CLIENT_AUTH_RESULT_REFERRAL_NOLOGIN,
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen reply, reason);
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen } else {
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen client_auth_result(client,
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen CLIENT_AUTH_RESULT_REFERRAL_SUCCESS,
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen reply, reason);
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen return TRUE;
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen }
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen } else if (reply->nologin) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen enum client_auth_result result = CLIENT_AUTH_RESULT_AUTHFAILED;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen const char *timestamp, *reason = reply->reason;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen /* Either failed or user login is disabled */
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen switch (reply->fail_code) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen case CLIENT_AUTH_FAIL_CODE_AUTHZFAILED:
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen result = CLIENT_AUTH_RESULT_AUTHZFAILED;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (reason == NULL)
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen reason = "Authorization failed";
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen break;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen case CLIENT_AUTH_FAIL_CODE_TEMPFAIL:
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen result = CLIENT_AUTH_RESULT_TEMPFAIL;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen timestamp = t_strflocaltime("%Y-%m-%d %H:%M:%S", ioloop_time);
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen reason = t_strdup_printf(AUTH_TEMP_FAILED_MSG" [%s:%s]",
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen my_hostname, timestamp);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen break;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen case CLIENT_AUTH_FAIL_CODE_PASS_EXPIRED:
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen result = CLIENT_AUTH_RESULT_PASS_EXPIRED;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen break;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen case CLIENT_AUTH_FAIL_CODE_LOGIN_DISABLED:
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen result = CLIENT_AUTH_RESULT_LOGIN_DISABLED;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (reason == NULL)
a8012fea2a7315033bc467acbf46be8e7323318cTimo Sirainen reason = "Login disabled for this user";
a8012fea2a7315033bc467acbf46be8e7323318cTimo Sirainen break;
a8012fea2a7315033bc467acbf46be8e7323318cTimo Sirainen case CLIENT_AUTH_FAIL_CODE_USER_DISABLED:
834b90e1f426d1e3308670e09c050bcdea546eb8Timo Sirainen default:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (reason != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen result = CLIENT_AUTH_RESULT_AUTHFAILED_REASON;
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen else
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen result = CLIENT_AUTH_RESULT_AUTHFAILED;
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen }
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen if (reason == NULL)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen reason = AUTH_FAILED_MSG;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_auth_result(client, result, reply, reason);
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen } else {
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen /* normal login/failure */
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen return FALSE;
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen }
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen i_assert(reply->nologin);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (!client->destroyed)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen client_auth_failed(client);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return TRUE;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen}
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainenvoid client_auth_respond(struct client *client, const char *response)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen{
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen client->auth_waiting = FALSE;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen client_set_auth_waiting(client);
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen auth_client_request_continue(client->auth_request, response);
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen io_remove(&client->io);
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen}
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen
b7cf555b699d73f2d71de0dabc088af6a7be3627Timo Sirainenvoid client_auth_abort(struct client *client)
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen{
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen sasl_server_auth_abort(client);
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen}
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid client_auth_fail(struct client *client, const char *text)
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen{
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen sasl_server_auth_failed(client, text);
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint client_auth_read_line(struct client *client)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen const unsigned char *data;
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen size_t i, size;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen unsigned int len;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen if (i_stream_read_more(client->input, &data, &size) == -1) {
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen client_destroy(client, "Disconnected");
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen return -1;
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen }
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen /* see if we have a full line */
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen for (i = 0; i < size; i++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (data[i] == '\n')
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen if (client->auth_response == NULL)
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen client->auth_response = str_new(default_pool, I_MAX(i+1, 256));
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen if (str_len(client->auth_response) + i > LOGIN_MAX_AUTH_BUF_SIZE) {
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen client_destroy(client, "Authentication response too large");
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen return -1;
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen }
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen str_append_n(client->auth_response, data, i);
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen i_stream_skip(client->input, i == size ? size : i+1);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen /* drop trailing \r */
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen len = str_len(client->auth_response);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (len > 0 && str_c(client->auth_response)[len-1] == '\r')
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen str_truncate(client->auth_response, len-1);
85144b5f0bc763de14c7d87291a90ef74ac241a2Timo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return i < size ? 1 : 0;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen}
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainenvoid client_auth_parse_response(struct client *client)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen{
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (client_auth_read_line(client) <= 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (strcmp(str_c(client->auth_response), "*") == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sasl_server_auth_abort(client);
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_auth_respond(client, str_c(client->auth_response));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen memset(str_c_modifiable(client->auth_response), 0,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str_len(client->auth_response));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void client_auth_input(struct client *client)
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen{
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen i_assert(client->v.auth_parse_response != NULL);
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen client->v.auth_parse_response(client);
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen}
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid client_auth_send_challenge(struct client *client, const char *data)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen struct const_iovec iov[3];
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen iov[0].iov_base = "+ ";
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen iov[0].iov_len = 2;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen iov[1].iov_base = data;
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen iov[1].iov_len = strlen(data);
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen iov[2].iov_base = "\r\n";
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen iov[2].iov_len = 2;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
8bae533c96e129dca8ee7b494d7de5aeb4a043a2Timo Sirainen o_stream_nsendv(client->output, iov, 3);
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen}
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainenstatic void
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainensasl_callback(struct client *client, enum sasl_server_reply sasl_reply,
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen const char *data, const char *const *args)
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct client_auth_reply reply;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen i_assert(!client->destroyed ||
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen sasl_reply == SASL_SERVER_REPLY_AUTH_ABORTED ||
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen sasl_reply == SASL_SERVER_REPLY_MASTER_FAILED);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen client->last_auth_fail = CLIENT_AUTH_FAIL_CODE_NONE;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen memset(&reply, 0, sizeof(reply));
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen switch (sasl_reply) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen case SASL_SERVER_REPLY_SUCCESS:
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (client->to_auth_waiting != NULL)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen timeout_remove(&client->to_auth_waiting);
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen if (args != NULL) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen client_auth_parse_args(client, TRUE, args, &reply);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen reply.all_fields = args;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen client->last_auth_fail = reply.fail_code;
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen if (client_auth_handle_reply(client, &reply, TRUE))
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen break;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen client_auth_result(client, CLIENT_AUTH_RESULT_SUCCESS,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen &reply, NULL);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen client_destroy_success(client, "Login");
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen break;
case SASL_SERVER_REPLY_AUTH_FAILED:
case SASL_SERVER_REPLY_AUTH_ABORTED:
if (client->to_auth_waiting != NULL)
timeout_remove(&client->to_auth_waiting);
if (args != NULL) {
client_auth_parse_args(client, FALSE, args, &reply);
client->last_auth_fail = reply.fail_code;
reply.nologin = TRUE;
reply.all_fields = args;
if (client_auth_handle_reply(client, &reply, FALSE))
break;
}
if (sasl_reply == SASL_SERVER_REPLY_AUTH_ABORTED) {
client_auth_result(client, CLIENT_AUTH_RESULT_ABORTED,
&reply, "Authentication aborted by client.");
} else if (data == NULL) {
client_auth_result(client,
CLIENT_AUTH_RESULT_AUTHFAILED, &reply,
AUTH_FAILED_MSG);
} else {
client_auth_result(client,
CLIENT_AUTH_RESULT_AUTHFAILED_REASON, &reply,
data);
}
if (!client->destroyed)
client_auth_failed(client);
break;
case SASL_SERVER_REPLY_MASTER_FAILED:
if (data != NULL) {
/* authentication itself succeeded, we just hit some
internal failure. */
client_auth_result(client, CLIENT_AUTH_RESULT_TEMPFAIL,
&reply, data);
}
/* the fd may still be hanging somewhere in kernel or another
process. make sure the client gets disconnected. */
if (shutdown(client->fd, SHUT_RDWR) < 0 && errno != ENOTCONN)
i_error("shutdown() failed: %m");
if (data == NULL)
client_destroy_internal_failure(client);
else
client_destroy_success(client, data);
break;
case SASL_SERVER_REPLY_CONTINUE:
i_assert(client->v.auth_send_challenge != NULL);
client->v.auth_send_challenge(client, data);
if (client->to_auth_waiting != NULL)
timeout_remove(&client->to_auth_waiting);
if (client->auth_response != NULL)
str_truncate(client->auth_response, 0);
i_assert(client->io == NULL);
client->auth_waiting = TRUE;
client->io = io_add(client->fd, IO_READ,
client_auth_input, client);
client_auth_input(client);
return;
}
client_unref(&client);
}
int client_auth_begin(struct client *client, const char *mech_name,
const char *init_resp)
{
if (!client->secured && strcmp(client->ssl_set->ssl, "required") == 0) {
if (client->set->auth_verbose) {
client_log(client, "Login failed: "
"SSL required for authentication");
}
client->auth_attempts++;
client_auth_result(client, CLIENT_AUTH_RESULT_SSL_REQUIRED, NULL,
"Authentication not allowed until SSL/TLS is enabled.");
return 1;
}
client_ref(client);
client->auth_initializing = TRUE;
sasl_server_auth_begin(client, login_binary->protocol, mech_name,
init_resp, sasl_callback);
client->auth_initializing = FALSE;
if (!client->authenticating)
return 1;
/* don't handle input until we get the initial auth reply */
if (client->io != NULL)
io_remove(&client->io);
client_set_auth_waiting(client);
return 0;
}
bool client_check_plaintext_auth(struct client *client, bool pass_sent)
{
if (client->secured || (!client->set->disable_plaintext_auth &&
strcmp(client->ssl_set->ssl, "required") != 0))
return TRUE;
if (client->set->auth_verbose) {
client_log(client, "Login failed: "
"Plaintext authentication disabled");
}
if (pass_sent) {
client_notify_status(client, TRUE,
"Plaintext authentication not allowed "
"without SSL/TLS, but your client did it anyway. "
"If anyone was listening, the password was exposed.");
}
client_auth_result(client, CLIENT_AUTH_RESULT_SSL_REQUIRED, NULL,
AUTH_PLAINTEXT_DISABLED_MSG);
client->auth_tried_disabled_plaintext = TRUE;
client->auth_attempts++;
return FALSE;
}
void clients_notify_auth_connected(void)
{
struct client *client, *next;
for (client = clients; client != NULL; client = next) {
next = client->next;
if (client->to_auth_waiting != NULL)
timeout_remove(&client->to_auth_waiting);
client_notify_auth_ready(client);
if (client->input_blocked) {
client->input_blocked = FALSE;
client_input(client);
}
}
}