bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen#include "hostpid.h"
46552a931924c2d743f045e95b08c3ce6beda91aTimo Sirainen#include "login-common.h"
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen#include "array.h"
c5f932968281763df360b9c97cef60f5f80d5e3dTimo Sirainen#include "iostream.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "istream.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "ostream.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "str.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "safe-memset.h"
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen#include "time-util.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "login-proxy.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "auth-client.h"
de754cb78f75e8b3b994cddafe41c9ed1467c33dTimo Sirainen#include "dsasl-client.h"
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainen#include "master-service-ssl-settings.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "client-common.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
53dfcefa9440a49d703e49193819a79be99c9ba6Timo Sirainen#define PROXY_FAILURE_MSG "Account is temporarily unavailable."
f0d93763f210ecdb85a115fdd0210a16cfc5ff5cTimo Sirainen#define PROXY_DEFAULT_TIMEOUT_MSECS (1000*30)
53dfcefa9440a49d703e49193819a79be99c9ba6Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen/* If we've been waiting auth server to respond for over this many milliseconds,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen send a "waiting" message. */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#define AUTH_WAITING_TIMEOUT_MSECS (30*1000)
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen#define AUTH_WAITING_WARNING_TIMEOUT_MSECS (10*1000)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Boschstruct client_auth_fail_code_id {
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch const char *id;
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch enum client_auth_fail_code code;
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch};
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Boschstatic const struct client_auth_fail_code_id client_auth_fail_codes[] = {
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch { AUTH_CLIENT_FAIL_CODE_AUTHZFAILED,
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch CLIENT_AUTH_FAIL_CODE_AUTHZFAILED },
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch { AUTH_CLIENT_FAIL_CODE_TEMPFAIL,
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch CLIENT_AUTH_FAIL_CODE_TEMPFAIL },
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch { AUTH_CLIENT_FAIL_CODE_USER_DISABLED,
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch CLIENT_AUTH_FAIL_CODE_USER_DISABLED },
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch { AUTH_CLIENT_FAIL_CODE_PASS_EXPIRED,
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch CLIENT_AUTH_FAIL_CODE_PASS_EXPIRED },
8ac6623677005256bf99ab33a2ed98c69c1d656cStephan Bosch { AUTH_CLIENT_FAIL_CODE_INVALID_BASE64,
8ac6623677005256bf99ab33a2ed98c69c1d656cStephan Bosch CLIENT_AUTH_FAIL_CODE_INVALID_BASE64 },
04eb0abcf8f8b0c014499b5c5bae89484553613fStephan Bosch { AUTH_CLIENT_FAIL_CODE_MECH_INVALID,
04eb0abcf8f8b0c014499b5c5bae89484553613fStephan Bosch CLIENT_AUTH_FAIL_CODE_MECH_INVALID },
04eb0abcf8f8b0c014499b5c5bae89484553613fStephan Bosch { AUTH_CLIENT_FAIL_CODE_MECH_SSL_REQUIRED,
04eb0abcf8f8b0c014499b5c5bae89484553613fStephan Bosch CLIENT_AUTH_FAIL_CODE_MECH_SSL_REQUIRED },
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch { NULL, CLIENT_AUTH_FAIL_CODE_NONE }
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch};
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Boschstatic enum client_auth_fail_code
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Boschclient_auth_fail_code_lookup(const char *fail_code)
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch{
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch const struct client_auth_fail_code_id *fail = client_auth_fail_codes;
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch while (fail->id != NULL) {
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch if (strcmp(fail->id, fail_code) == 0)
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch return fail->code;
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch fail++;
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch }
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch return CLIENT_AUTH_FAIL_CODE_NONE;
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch}
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainenstatic void client_auth_failed(struct client *client)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_free_and_null(client->master_data_prefix);
2e78f05b11df23ec2731afaf8f19d5b5240cb29fTimo Sirainen if (client->auth_response != NULL)
2e78f05b11df23ec2731afaf8f19d5b5240cb29fTimo Sirainen str_truncate(client->auth_response, 0);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
d1e7425048c61d71f41f737ba947687198842dc2Timo Sirainen if (client->auth_initializing || client->destroyed)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
5f1d689131a75c39f064cbd4202373e7edf78f18Josef 'Jeff' Sipek io_remove(&client->io);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
a1852ab4cf0a942a3fcf4ca5636a7932ebcc7970Stephan Bosch if (!client_does_custom_io(client)) {
a1852ab4cf0a942a3fcf4ca5636a7932ebcc7970Stephan Bosch client->io = io_add(client->fd, IO_READ, client_input, client);
a1852ab4cf0a942a3fcf4ca5636a7932ebcc7970Stephan Bosch client_input(client);
a1852ab4cf0a942a3fcf4ca5636a7932ebcc7970Stephan Bosch }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void client_auth_waiting_timeout(struct client *client)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen if (!client->notified_auth_ready) {
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainen client_log_warn(client, "Auth process not responding, "
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen "delayed sending initial response (greeting)");
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainen }
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client_notify_status(client, FALSE, client->master_tag == 0 ?
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen AUTH_SERVER_WAITING_MSG : AUTH_MASTER_WAITING_MSG);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen timeout_remove(&client->to_auth_waiting);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid client_set_auth_waiting(struct client *client)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(client->to_auth_waiting == NULL);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->to_auth_waiting =
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen timeout_add(!client->notified_auth_ready ?
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen AUTH_WAITING_WARNING_TIMEOUT_MSECS :
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainen AUTH_WAITING_TIMEOUT_MSECS,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_auth_waiting_timeout, client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainenstatic void alt_username_set(ARRAY_TYPE(const_string) *alt_usernames, pool_t pool,
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen const char *key, const char *value)
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen{
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen char *const *fields;
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen unsigned int i, count;
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen fields = array_get(&global_alt_usernames, &count);
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen for (i = 0; i < count; i++) {
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen if (strcmp(fields[i], key) == 0)
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen break;
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen }
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen if (i == count) {
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen char *new_key = i_strdup(key);
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen array_append(&global_alt_usernames, &new_key, 1);
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen }
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen value = p_strdup(pool, value);
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen if (i < array_count(alt_usernames)) {
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen array_idx_set(alt_usernames, i, &value);
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen return;
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen }
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen /* array is NULL-terminated, so if there are unused fields in
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen the middle set them as "" */
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen while (array_count(alt_usernames) < i) {
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen const char *empty_str = "";
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen array_append(alt_usernames, &empty_str, 1);
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen }
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen array_append(alt_usernames, &value, 1);
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen}
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainenstatic void client_auth_parse_args(struct client *client, bool success,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *const *args,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct client_auth_reply *reply_r)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *key, *value, *p;
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen ARRAY_TYPE(const_string) alt_usernames;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen t_array_init(&alt_usernames, 4);
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(reply_r);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen for (; *args != NULL; args++) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen p = strchr(*args, '=');
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (p == NULL) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen key = *args;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen value = "";
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen } else {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen key = t_strdup_until(*args, p);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen value = p + 1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch if (strcmp(key, "nologin") == 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen reply_r->nologin = TRUE;
f32d0295c90ed810889504cdfa5e1a25a415f65fStephan Bosch reply_r->fail_code = CLIENT_AUTH_FAIL_CODE_LOGIN_DISABLED;
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch } else if (strcmp(key, "proxy") == 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen reply_r->proxy = TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen else if (strcmp(key, "reason") == 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen reply_r->reason = value;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen else if (strcmp(key, "host") == 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen reply_r->host = value;
e7dd5065d21c569e5e6ddd713bd345dadd1cf51dTimo Sirainen else if (strcmp(key, "hostip") == 0)
e7dd5065d21c569e5e6ddd713bd345dadd1cf51dTimo Sirainen reply_r->hostip = value;
d694a52bce62c52080c3f87a56dcf77030fd2712Timo Sirainen else if (strcmp(key, "source_ip") == 0)
d694a52bce62c52080c3f87a56dcf77030fd2712Timo Sirainen reply_r->source_ip = value;
009217abb57a24a4076092e8e4e165545747839eStephan Bosch else if (strcmp(key, "port") == 0) {
009217abb57a24a4076092e8e4e165545747839eStephan Bosch if (net_str2port(value, &reply_r->port) < 0) {
009217abb57a24a4076092e8e4e165545747839eStephan Bosch i_error("Auth service returned invalid "
009217abb57a24a4076092e8e4e165545747839eStephan Bosch "port number: %s", value);
009217abb57a24a4076092e8e4e165545747839eStephan Bosch }
009217abb57a24a4076092e8e4e165545747839eStephan Bosch } else if (strcmp(key, "destuser") == 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen reply_r->destuser = value;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen else if (strcmp(key, "pass") == 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen reply_r->password = value;
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch else if (strcmp(key, "proxy_timeout") == 0) {
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch if (str_to_uint(value, &reply_r->proxy_timeout_msecs) < 0) {
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch i_error("BUG: Auth service returned invalid "
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch "proxy_timeout value: %s", value);
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch }
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch reply_r->proxy_timeout_msecs *= 1000;
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch } else if (strcmp(key, "proxy_refresh") == 0) {
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch if (str_to_uint(value, &reply_r->proxy_refresh_secs) < 0) {
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch i_error("BUG: Auth service returned invalid "
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch "proxy_refresh value: %s", value);
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch }
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch } else if (strcmp(key, "proxy_mech") == 0)
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen reply_r->proxy_mech = value;
ab281fc992907b6cf6c730f672dc3aa4c6685015Timo Sirainen else if (strcmp(key, "proxy_nopipelining") == 0)
ab281fc992907b6cf6c730f672dc3aa4c6685015Timo Sirainen reply_r->proxy_nopipelining = TRUE;
6d24551e169c0808695db35d7a228f1970a84c75Timo Sirainen else if (strcmp(key, "proxy_not_trusted") == 0)
6d24551e169c0808695db35d7a228f1970a84c75Timo Sirainen reply_r->proxy_not_trusted = TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen else if (strcmp(key, "master") == 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen reply_r->master_user = value;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen else if (strcmp(key, "ssl") == 0) {
1bf5c6c20f3d51f13d3240cfb46e471074c86276Timo Sirainen reply_r->ssl_flags |= PROXY_SSL_FLAG_YES;
1bf5c6c20f3d51f13d3240cfb46e471074c86276Timo Sirainen if (strcmp(value, "any-cert") == 0)
1bf5c6c20f3d51f13d3240cfb46e471074c86276Timo Sirainen reply_r->ssl_flags |= PROXY_SSL_FLAG_ANY_CERT;
1bf5c6c20f3d51f13d3240cfb46e471074c86276Timo Sirainen if (reply_r->port == 0)
5a250816ffc4cc5db203f9410ea99b6601c7b91aTimo Sirainen reply_r->port = login_binary->default_ssl_port;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen } else if (strcmp(key, "starttls") == 0) {
1bf5c6c20f3d51f13d3240cfb46e471074c86276Timo Sirainen reply_r->ssl_flags |= PROXY_SSL_FLAG_YES |
1bf5c6c20f3d51f13d3240cfb46e471074c86276Timo Sirainen PROXY_SSL_FLAG_STARTTLS;
1bf5c6c20f3d51f13d3240cfb46e471074c86276Timo Sirainen if (strcmp(value, "any-cert") == 0)
1bf5c6c20f3d51f13d3240cfb46e471074c86276Timo Sirainen reply_r->ssl_flags |= PROXY_SSL_FLAG_ANY_CERT;
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch } else if (strcmp(key, "code") == 0) {
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch if (reply_r->fail_code != CLIENT_AUTH_FAIL_CODE_NONE) {
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch /* code already assigned */
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch } else {
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch reply_r->fail_code = client_auth_fail_code_lookup(value);
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch }
8ce3071e80b9973230048ecadfcb073fb82cc69fTimo Sirainen } else if (strcmp(key, "user") == 0 ||
8ce3071e80b9973230048ecadfcb073fb82cc69fTimo Sirainen strcmp(key, "postlogin_socket") == 0) {
8ce3071e80b9973230048ecadfcb073fb82cc69fTimo Sirainen /* already handled in sasl-server.c */
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen } else if (strncmp(key, "user_", 5) == 0) {
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen if (success) {
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen alt_username_set(&alt_usernames, client->pool,
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen key, value);
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen }
998eadc15aabe598cc9301fdb28c0fef5225b3f7Aki Tuomi } else if (strncmp(key, "forward_", 8) == 0) {
998eadc15aabe598cc9301fdb28c0fef5225b3f7Aki Tuomi /* these are passed to upstream */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen } else if (client->set->auth_debug)
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk i_debug("Ignoring unknown passdb extra field: %s", key);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen if (array_count(&alt_usernames) > 0) {
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen const char **alt;
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen alt = p_new(client->pool, const char *,
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen array_count(&alt_usernames) + 1);
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen memcpy(alt, array_idx(&alt_usernames, 0),
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen sizeof(*alt) * array_count(&alt_usernames));
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen client->alt_usernames = alt;
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen }
2e2a1d720ed53490e8e5c5031e773d395bd5683dTimo Sirainen if (reply_r->port == 0)
5a250816ffc4cc5db203f9410ea99b6601c7b91aTimo Sirainen reply_r->port = login_binary->default_port;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (reply_r->destuser == NULL)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen reply_r->destuser = client->virtual_user;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void proxy_free_password(struct client *client)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->proxy_password == NULL)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen safe_memset(client->proxy_password, 0, strlen(client->proxy_password));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_free_and_null(client->proxy_password);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid client_proxy_finish_destroy_client(struct client *client)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen string_t *str = t_str_new(128);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
b8afdaa1bffe2f27cd4b02bf3bfbd2d297c8e648Timo Sirainen if (client->input->closed) {
b8afdaa1bffe2f27cd4b02bf3bfbd2d297c8e648Timo Sirainen /* input stream got closed in client_send_raw_data().
b8afdaa1bffe2f27cd4b02bf3bfbd2d297c8e648Timo Sirainen In most places we don't have to check for this explicitly,
b8afdaa1bffe2f27cd4b02bf3bfbd2d297c8e648Timo Sirainen but login_proxy_detach() attempts to get and use the
b8afdaa1bffe2f27cd4b02bf3bfbd2d297c8e648Timo Sirainen istream's fd, which is now -1. */
b8afdaa1bffe2f27cd4b02bf3bfbd2d297c8e648Timo Sirainen client_destroy(client, "Disconnected");
b8afdaa1bffe2f27cd4b02bf3bfbd2d297c8e648Timo Sirainen return;
b8afdaa1bffe2f27cd4b02bf3bfbd2d297c8e648Timo Sirainen }
b8afdaa1bffe2f27cd4b02bf3bfbd2d297c8e648Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str_printfa(str, "proxy(%s): started proxying to %s:%u",
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->virtual_user,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen login_proxy_get_host(client->login_proxy),
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen login_proxy_get_port(client->login_proxy));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (strcmp(client->virtual_user, client->proxy_user) != 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* remote username is different, log it */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str_append_c(str, '/');
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str_append(str, client->proxy_user);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->proxy_master_user != NULL)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str_printfa(str, " (master %s)", client->proxy_master_user);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
ec23e16ed879e289d12c6e1a5f9745dd3979004aTimo Sirainen login_proxy_detach(client->login_proxy);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_destroy_success(client, str_c(str));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainenstatic void client_proxy_error(struct client *client, const char *text)
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen{
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client->v.proxy_error(client, text);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen}
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
2b96880f2d789d125aff6a95eaa7b51f558a6a1cTimo Sirainenconst char *client_proxy_get_state(struct client *client)
2b96880f2d789d125aff6a95eaa7b51f558a6a1cTimo Sirainen{
a8d3f2d03d260b55064d3be868bc06b025d6c9d3Timo Sirainen return client->v.proxy_get_state(client);
2b96880f2d789d125aff6a95eaa7b51f558a6a1cTimo Sirainen}
2b96880f2d789d125aff6a95eaa7b51f558a6a1cTimo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid client_proxy_log_failure(struct client *client, const char *line)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen string_t *str = t_str_new(128);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str_printfa(str, "proxy(%s): Login failed to %s:%u",
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->virtual_user,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen login_proxy_get_host(client->login_proxy),
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen login_proxy_get_port(client->login_proxy));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (strcmp(client->virtual_user, client->proxy_user) != 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* remote username is different, log it */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str_append_c(str, '/');
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str_append(str, client->proxy_user);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->proxy_master_user != NULL)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str_printfa(str, " (master %s)", client->proxy_master_user);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str_append(str, ": ");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str_append(str, line);
cbaac1e9a69099a2c25e09b1db19bcbf9037e342Timo Sirainen client_log(client, str_c(str));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid client_proxy_failed(struct client *client, bool send_line)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (send_line) {
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client_proxy_error(client, PROXY_FAILURE_MSG);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen if (client->proxy_sasl_client != NULL)
de754cb78f75e8b3b994cddafe41c9ed1467c33dTimo Sirainen dsasl_client_free(&client->proxy_sasl_client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen login_proxy_free(&client->login_proxy);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen proxy_free_password(client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_free_and_null(client->proxy_user);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_free_and_null(client->proxy_master_user);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* call this last - it may destroy the client */
660b99a7059824676b2b8d6f79b8e15d47df25a2Timo Sirainen client_auth_failed(client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void proxy_input(struct client *client)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct istream *input;
e911b23f3e05308df9b98b1a3fdaf72e4302d8fdTimo Sirainen struct ostream *output;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *line;
77f1da4b5e2b800197d8db548235497d5e9d6a4fTimo Sirainen unsigned int duration;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->login_proxy == NULL) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* we're just freeing the proxy */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen input = login_proxy_get_istream(client->login_proxy);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (input == NULL) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->destroyed) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* we came here from client_destroy() */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* failed for some reason, probably server disconnected */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_proxy_failed(client, TRUE);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(!client->destroyed);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen switch (i_stream_read(input)) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen case -2:
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_log_err(client, "proxy: Remote input buffer full");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_proxy_failed(client, TRUE);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen case -1:
18f1bbf05980d3c53ecae81b62574212f0891522Timo Sirainen line = i_stream_next_line(input);
77f1da4b5e2b800197d8db548235497d5e9d6a4fTimo Sirainen duration = ioloop_time - client->created;
75e46142d8fbac811df8f2ca58d9a2f48a75d65fTimo Sirainen client_log_err(client, t_strdup_printf(
77f1da4b5e2b800197d8db548235497d5e9d6a4fTimo Sirainen "proxy: Remote %s:%u disconnected: %s "
2b96880f2d789d125aff6a95eaa7b51f558a6a1cTimo Sirainen "(state=%s, duration=%us)%s",
75e46142d8fbac811df8f2ca58d9a2f48a75d65fTimo Sirainen login_proxy_get_host(client->login_proxy),
75e46142d8fbac811df8f2ca58d9a2f48a75d65fTimo Sirainen login_proxy_get_port(client->login_proxy),
c5f932968281763df360b9c97cef60f5f80d5e3dTimo Sirainen io_stream_get_disconnect_reason(input, NULL),
2b96880f2d789d125aff6a95eaa7b51f558a6a1cTimo Sirainen client_proxy_get_state(client), duration,
18f1bbf05980d3c53ecae81b62574212f0891522Timo Sirainen line == NULL ? "" : t_strdup_printf(
18f1bbf05980d3c53ecae81b62574212f0891522Timo Sirainen " - BUG: line not read: %s", line)));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_proxy_failed(client, TRUE);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e911b23f3e05308df9b98b1a3fdaf72e4302d8fdTimo Sirainen output = client->output;
e911b23f3e05308df9b98b1a3fdaf72e4302d8fdTimo Sirainen o_stream_ref(output);
e911b23f3e05308df9b98b1a3fdaf72e4302d8fdTimo Sirainen o_stream_cork(output);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen while ((line = i_stream_next_line(input)) != NULL) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->v.proxy_parse_line(client, line) != 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen break;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e911b23f3e05308df9b98b1a3fdaf72e4302d8fdTimo Sirainen o_stream_uncork(output);
e911b23f3e05308df9b98b1a3fdaf72e4302d8fdTimo Sirainen o_stream_unref(&output);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic int proxy_start(struct client *client,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const struct client_auth_reply *reply)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
2598b2f36365b52d9754b9348a5be29569293e46Timo Sirainen struct login_proxy_settings proxy_set;
de754cb78f75e8b3b994cddafe41c9ed1467c33dTimo Sirainen const struct dsasl_client_mech *sasl_mech = NULL;
2598b2f36365b52d9754b9348a5be29569293e46Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(reply->destuser != NULL);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(!client->destroyed);
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen i_assert(client->proxy_sasl_client == NULL);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen client->proxy_mech = NULL;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->v.proxy_reset(client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (reply->password == NULL) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_log_err(client, "proxy: password not given");
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client_proxy_error(client, PROXY_FAILURE_MSG);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return -1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
04b7dc631f33bf61f273138c679da9bd0910fb6dTimo Sirainen if (reply->host == NULL || *reply->host == '\0') {
04b7dc631f33bf61f273138c679da9bd0910fb6dTimo Sirainen client_log_err(client, "proxy: host not given");
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client_proxy_error(client, PROXY_FAILURE_MSG);
04b7dc631f33bf61f273138c679da9bd0910fb6dTimo Sirainen return -1;
04b7dc631f33bf61f273138c679da9bd0910fb6dTimo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen if (reply->proxy_mech != NULL) {
de754cb78f75e8b3b994cddafe41c9ed1467c33dTimo Sirainen sasl_mech = dsasl_client_mech_find(reply->proxy_mech);
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen if (sasl_mech == NULL) {
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen client_log_err(client, t_strdup_printf(
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen "proxy: Unsupported SASL mechanism %s",
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen reply->proxy_mech));
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen client_proxy_error(client, PROXY_FAILURE_MSG);
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen return -1;
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen }
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen } else if (reply->master_user != NULL) {
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen /* have to use PLAIN authentication with master user logins */
de754cb78f75e8b3b994cddafe41c9ed1467c33dTimo Sirainen sasl_mech = &dsasl_client_mech_plain;
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen }
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(client->refcount > 1);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->destroyed) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* connection_queue_add() decided that we were the oldest
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen connection and killed us. */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return -1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (login_proxy_is_ourself(client, reply->host, reply->port,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen reply->destuser)) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_log_err(client, "Proxying loops to itself");
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client_proxy_error(client, PROXY_FAILURE_MSG);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return -1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&proxy_set);
2598b2f36365b52d9754b9348a5be29569293e46Timo Sirainen proxy_set.host = reply->host;
e7dd5065d21c569e5e6ddd713bd345dadd1cf51dTimo Sirainen if (reply->hostip != NULL &&
e7dd5065d21c569e5e6ddd713bd345dadd1cf51dTimo Sirainen net_addr2ip(reply->hostip, &proxy_set.ip) < 0)
e7dd5065d21c569e5e6ddd713bd345dadd1cf51dTimo Sirainen proxy_set.ip.family = 0;
c51644e9e04effbbc9c415cadcfbcb4d9465855cTimo Sirainen if (reply->source_ip != NULL) {
c51644e9e04effbbc9c415cadcfbcb4d9465855cTimo Sirainen if (net_addr2ip(reply->source_ip, &proxy_set.source_ip) < 0)
c51644e9e04effbbc9c415cadcfbcb4d9465855cTimo Sirainen proxy_set.source_ip.family = 0;
c51644e9e04effbbc9c415cadcfbcb4d9465855cTimo Sirainen } else if (login_source_ips_count > 0) {
c51644e9e04effbbc9c415cadcfbcb4d9465855cTimo Sirainen /* select the next source IP with round robin. */
c51644e9e04effbbc9c415cadcfbcb4d9465855cTimo Sirainen proxy_set.source_ip = login_source_ips[login_source_ips_idx];
c51644e9e04effbbc9c415cadcfbcb4d9465855cTimo Sirainen login_source_ips_idx =
c51644e9e04effbbc9c415cadcfbcb4d9465855cTimo Sirainen (login_source_ips_idx + 1) % login_source_ips_count;
c51644e9e04effbbc9c415cadcfbcb4d9465855cTimo Sirainen }
2598b2f36365b52d9754b9348a5be29569293e46Timo Sirainen proxy_set.port = reply->port;
2598b2f36365b52d9754b9348a5be29569293e46Timo Sirainen proxy_set.connect_timeout_msecs = reply->proxy_timeout_msecs;
f0d93763f210ecdb85a115fdd0210a16cfc5ff5cTimo Sirainen if (proxy_set.connect_timeout_msecs == 0)
f0d93763f210ecdb85a115fdd0210a16cfc5ff5cTimo Sirainen proxy_set.connect_timeout_msecs = PROXY_DEFAULT_TIMEOUT_MSECS;
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainen proxy_set.notify_refresh_secs = reply->proxy_refresh_secs;
2598b2f36365b52d9754b9348a5be29569293e46Timo Sirainen proxy_set.ssl_flags = reply->ssl_flags;
2598b2f36365b52d9754b9348a5be29569293e46Timo Sirainen
2ef0e8ee48c9683f7bd6698798efa3328e4322d1Timo Sirainen if (login_proxy_new(client, &proxy_set, proxy_input) < 0) {
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client_proxy_error(client, PROXY_FAILURE_MSG);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return -1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen client->proxy_mech = sasl_mech;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->proxy_user = i_strdup(reply->destuser);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->proxy_master_user = i_strdup(reply->master_user);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->proxy_password = i_strdup(reply->password);
ab281fc992907b6cf6c730f672dc3aa4c6685015Timo Sirainen client->proxy_nopipelining = reply->proxy_nopipelining;
6d24551e169c0808695db35d7a228f1970a84c75Timo Sirainen client->proxy_not_trusted = reply->proxy_not_trusted;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* disable input until authentication is finished */
5f1d689131a75c39f064cbd4202373e7edf78f18Josef 'Jeff' Sipek io_remove(&client->io);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return 0;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainenstatic void ATTR_NULL(3, 4)
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainenclient_auth_result(struct client *client, enum client_auth_result result,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen const struct client_auth_reply *reply, const char *text)
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen{
280503e88a6b2f72a32a8fbe363794abaaa845d6Timo Sirainen o_stream_cork(client->output);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client->v.auth_result(client, result, reply, text);
280503e88a6b2f72a32a8fbe363794abaaa845d6Timo Sirainen o_stream_uncork(client->output);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen}
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic bool
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenclient_auth_handle_reply(struct client *client,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const struct client_auth_reply *reply, bool success)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (reply->proxy) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* we want to proxy the connection to another server.
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen don't do this unless authentication succeeded. with
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen master user proxying we can get FAIL with proxy still set.
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen proxy host=.. [port=..] [destuser=..] pass=.. */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (!success)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return FALSE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (proxy_start(client, reply) < 0)
660b99a7059824676b2b8d6f79b8e15d47df25a2Timo Sirainen client_auth_failed(client);
42fcc708268a89aa9640693e71d13a2bb76e19c8Timo Sirainen else {
42fcc708268a89aa9640693e71d13a2bb76e19c8Timo Sirainen /* this for plugins being able th hook into auth reply
42fcc708268a89aa9640693e71d13a2bb76e19c8Timo Sirainen when proxying is used */
42fcc708268a89aa9640693e71d13a2bb76e19c8Timo Sirainen client_auth_result(client, CLIENT_AUTH_RESULT_SUCCESS,
42fcc708268a89aa9640693e71d13a2bb76e19c8Timo Sirainen reply, NULL);
42fcc708268a89aa9640693e71d13a2bb76e19c8Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen if (reply->host != NULL) {
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen const char *reason;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen if (reply->reason != NULL)
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen reason = reply->reason;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen else if (reply->nologin)
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen reason = "Try this server instead.";
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen else
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen reason = "Logged in, but you should use this server instead.";
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen if (reply->nologin) {
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client_auth_result(client,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen CLIENT_AUTH_RESULT_REFERRAL_NOLOGIN,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen reply, reason);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen } else {
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client_auth_result(client,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen CLIENT_AUTH_RESULT_REFERRAL_SUCCESS,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen reply, reason);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen return TRUE;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen }
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen } else if (reply->nologin) {
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch enum client_auth_result result = CLIENT_AUTH_RESULT_AUTHFAILED;
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch const char *timestamp, *reason = reply->reason;
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch /* Either failed or user login is disabled */
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch switch (reply->fail_code) {
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch case CLIENT_AUTH_FAIL_CODE_AUTHZFAILED:
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch result = CLIENT_AUTH_RESULT_AUTHZFAILED;
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch if (reason == NULL)
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch reason = "Authorization failed";
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch break;
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch case CLIENT_AUTH_FAIL_CODE_TEMPFAIL:
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch result = CLIENT_AUTH_RESULT_TEMPFAIL;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen timestamp = t_strflocaltime("%Y-%m-%d %H:%M:%S", ioloop_time);
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch reason = t_strdup_printf(AUTH_TEMP_FAILED_MSG" [%s:%s]",
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen my_hostname, timestamp);
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch break;
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch case CLIENT_AUTH_FAIL_CODE_PASS_EXPIRED:
529944a3554da75c2e6231a25fe489d815519b22Stephan Bosch result = CLIENT_AUTH_RESULT_PASS_EXPIRED;
529944a3554da75c2e6231a25fe489d815519b22Stephan Bosch break;
8ac6623677005256bf99ab33a2ed98c69c1d656cStephan Bosch case CLIENT_AUTH_FAIL_CODE_INVALID_BASE64:
8ac6623677005256bf99ab33a2ed98c69c1d656cStephan Bosch result = CLIENT_AUTH_RESULT_INVALID_BASE64;
8ac6623677005256bf99ab33a2ed98c69c1d656cStephan Bosch break;
04eb0abcf8f8b0c014499b5c5bae89484553613fStephan Bosch case CLIENT_AUTH_FAIL_CODE_MECH_INVALID:
04eb0abcf8f8b0c014499b5c5bae89484553613fStephan Bosch result = CLIENT_AUTH_RESULT_MECH_INVALID;
04eb0abcf8f8b0c014499b5c5bae89484553613fStephan Bosch break;
04eb0abcf8f8b0c014499b5c5bae89484553613fStephan Bosch case CLIENT_AUTH_FAIL_CODE_MECH_SSL_REQUIRED:
04eb0abcf8f8b0c014499b5c5bae89484553613fStephan Bosch result = CLIENT_AUTH_RESULT_MECH_SSL_REQUIRED;
04eb0abcf8f8b0c014499b5c5bae89484553613fStephan Bosch break;
f32d0295c90ed810889504cdfa5e1a25a415f65fStephan Bosch case CLIENT_AUTH_FAIL_CODE_LOGIN_DISABLED:
f32d0295c90ed810889504cdfa5e1a25a415f65fStephan Bosch result = CLIENT_AUTH_RESULT_LOGIN_DISABLED;
f32d0295c90ed810889504cdfa5e1a25a415f65fStephan Bosch if (reason == NULL)
f32d0295c90ed810889504cdfa5e1a25a415f65fStephan Bosch reason = "Login disabled for this user";
f32d0295c90ed810889504cdfa5e1a25a415f65fStephan Bosch break;
529944a3554da75c2e6231a25fe489d815519b22Stephan Bosch case CLIENT_AUTH_FAIL_CODE_USER_DISABLED:
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch default:
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch if (reason != NULL)
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch result = CLIENT_AUTH_RESULT_AUTHFAILED_REASON;
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch else
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch result = CLIENT_AUTH_RESULT_AUTHFAILED;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen }
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch if (reason == NULL)
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch reason = AUTH_FAILED_MSG;
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch client_auth_result(client, result, reply, reason);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen } else {
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen /* normal login/failure */
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen return FALSE;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen }
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen i_assert(reply->nologin);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen if (!client->destroyed)
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client_auth_failed(client);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen return TRUE;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen}
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainenvoid client_auth_respond(struct client *client, const char *response)
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen{
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client->auth_waiting = FALSE;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client_set_auth_waiting(client);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen auth_client_request_continue(client->auth_request, response);
a1852ab4cf0a942a3fcf4ca5636a7932ebcc7970Stephan Bosch if (!client_does_custom_io(client))
a1852ab4cf0a942a3fcf4ca5636a7932ebcc7970Stephan Bosch io_remove(&client->io);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen}
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainenvoid client_auth_abort(struct client *client)
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen{
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen sasl_server_auth_abort(client);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen}
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainenvoid client_auth_fail(struct client *client, const char *text)
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen{
04eb0abcf8f8b0c014499b5c5bae89484553613fStephan Bosch sasl_server_auth_failed(client, text, NULL);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
decb23442f9e6cd5c4845a9cb162029b8c6d5f0fTimo Sirainenint client_auth_read_line(struct client *client)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen const unsigned char *data;
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen size_t i, size, len;
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen
3858a7a5da361c35f1e6e50c8e3214dc0cf379d6Phil Carmody if (i_stream_read_more(client->input, &data, &size) == -1) {
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen client_destroy(client, "Disconnected");
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen return -1;
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen }
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen /* see if we have a full line */
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen for (i = 0; i < size; i++) {
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen if (data[i] == '\n')
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen break;
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen }
decb23442f9e6cd5c4845a9cb162029b8c6d5f0fTimo Sirainen if (client->auth_response == NULL)
decb23442f9e6cd5c4845a9cb162029b8c6d5f0fTimo Sirainen client->auth_response = str_new(default_pool, I_MAX(i+1, 256));
7fa573e6ea36024f618492e7d3649a69c1b41028Timo Sirainen if (str_len(client->auth_response) + i > LOGIN_MAX_AUTH_BUF_SIZE) {
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen client_destroy(client, "Authentication response too large");
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen return -1;
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen }
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen str_append_n(client->auth_response, data, i);
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen i_stream_skip(client->input, i == size ? size : i+1);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen /* drop trailing \r */
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen len = str_len(client->auth_response);
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen if (len > 0 && str_c(client->auth_response)[len-1] == '\r')
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen str_truncate(client->auth_response, len-1);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
f0339f522dc9c8e2e8a29ef9a3f937c431c6bd1bTimo Sirainen return i < size ? 1 : 0;
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen}
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainenvoid client_auth_parse_response(struct client *client)
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen{
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen if (client_auth_read_line(client) <= 0)
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen return;
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen if (strcmp(str_c(client->auth_response), "*") == 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen sasl_server_auth_abort(client);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen return;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client_auth_respond(client, str_c(client->auth_response));
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen memset(str_c_modifiable(client->auth_response), 0,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen str_len(client->auth_response));
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainen}
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainen
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainenstatic void client_auth_input(struct client *client)
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainen{
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch i_assert(client->v.auth_parse_response != NULL);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client->v.auth_parse_response(client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainenvoid client_auth_send_challenge(struct client *client, const char *data)
4c6ddf2491104f917d00e6900e833e80ea02c7b6Timo Sirainen{
4c6ddf2491104f917d00e6900e833e80ea02c7b6Timo Sirainen struct const_iovec iov[3];
4c6ddf2491104f917d00e6900e833e80ea02c7b6Timo Sirainen
4c6ddf2491104f917d00e6900e833e80ea02c7b6Timo Sirainen iov[0].iov_base = "+ ";
4c6ddf2491104f917d00e6900e833e80ea02c7b6Timo Sirainen iov[0].iov_len = 2;
4c6ddf2491104f917d00e6900e833e80ea02c7b6Timo Sirainen iov[1].iov_base = data;
4c6ddf2491104f917d00e6900e833e80ea02c7b6Timo Sirainen iov[1].iov_len = strlen(data);
4c6ddf2491104f917d00e6900e833e80ea02c7b6Timo Sirainen iov[2].iov_base = "\r\n";
4c6ddf2491104f917d00e6900e833e80ea02c7b6Timo Sirainen iov[2].iov_len = 2;
4c6ddf2491104f917d00e6900e833e80ea02c7b6Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsendv(client->output, iov, 3);
4c6ddf2491104f917d00e6900e833e80ea02c7b6Timo Sirainen}
4c6ddf2491104f917d00e6900e833e80ea02c7b6Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainensasl_callback(struct client *client, enum sasl_server_reply sasl_reply,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *data, const char *const *args)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct client_auth_reply reply;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(!client->destroyed ||
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen sasl_reply == SASL_SERVER_REPLY_AUTH_ABORTED ||
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen sasl_reply == SASL_SERVER_REPLY_MASTER_FAILED);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch client->last_auth_fail = CLIENT_AUTH_FAIL_CODE_NONE;
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&reply);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen switch (sasl_reply) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen case SASL_SERVER_REPLY_SUCCESS:
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&client->to_auth_waiting);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (args != NULL) {
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen client_auth_parse_args(client, TRUE, args, &reply);
fd3d068169c6ec587c9c446f2ee45560a444334aTimo Sirainen reply.all_fields = args;
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch client->last_auth_fail = reply.fail_code;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client_auth_handle_reply(client, &reply, TRUE))
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen break;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client_auth_result(client, CLIENT_AUTH_RESULT_SUCCESS,
6b107c647b2120d3906ff7d368f8a16900f6833fTimo Sirainen &reply, NULL);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_destroy_success(client, "Login");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen break;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen case SASL_SERVER_REPLY_AUTH_FAILED:
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen case SASL_SERVER_REPLY_AUTH_ABORTED:
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&client->to_auth_waiting);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (args != NULL) {
ce1a6c9b82117d253df9acd77e54ac84dd8a247eTimo Sirainen client_auth_parse_args(client, FALSE, args, &reply);
36b072d84a9076c3c483bf710444a716e987ccc3Stephan Bosch client->last_auth_fail = reply.fail_code;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen reply.nologin = TRUE;
fd3d068169c6ec587c9c446f2ee45560a444334aTimo Sirainen reply.all_fields = args;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client_auth_handle_reply(client, &reply, FALSE))
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen break;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (sasl_reply == SASL_SERVER_REPLY_AUTH_ABORTED) {
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client_auth_result(client, CLIENT_AUTH_RESULT_ABORTED,
6b107c647b2120d3906ff7d368f8a16900f6833fTimo Sirainen &reply, "Authentication aborted by client.");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen } else if (data == NULL) {
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client_auth_result(client,
6b107c647b2120d3906ff7d368f8a16900f6833fTimo Sirainen CLIENT_AUTH_RESULT_AUTHFAILED, &reply,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen AUTH_FAILED_MSG);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen } else {
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client_auth_result(client,
6b107c647b2120d3906ff7d368f8a16900f6833fTimo Sirainen CLIENT_AUTH_RESULT_AUTHFAILED_REASON, &reply,
63e376747537cb2dfaa0e36d1bafd19df1443a4eTimo Sirainen data);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (!client->destroyed)
660b99a7059824676b2b8d6f79b8e15d47df25a2Timo Sirainen client_auth_failed(client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen break;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen case SASL_SERVER_REPLY_MASTER_FAILED:
7a23d586f07ec376e28e8f6f3f3392a4ac8b83bbTimo Sirainen if (data != NULL) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* authentication itself succeeded, we just hit some
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen internal failure. */
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client_auth_result(client, CLIENT_AUTH_RESULT_TEMPFAIL,
6b107c647b2120d3906ff7d368f8a16900f6833fTimo Sirainen &reply, data);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
7a23d586f07ec376e28e8f6f3f3392a4ac8b83bbTimo Sirainen
0348172a5278d1f5aa2440f30346c390ddc17318Timo Sirainen /* the fd may still be hanging somewhere in kernel or another
0348172a5278d1f5aa2440f30346c390ddc17318Timo Sirainen process. make sure the client gets disconnected. */
cb2c44f33d9d48f58e4c5e42ba2526a0c100218aTimo Sirainen if (shutdown(client->fd, SHUT_RDWR) < 0 && errno != ENOTCONN)
0348172a5278d1f5aa2440f30346c390ddc17318Timo Sirainen i_error("shutdown() failed: %m");
0348172a5278d1f5aa2440f30346c390ddc17318Timo Sirainen
86bca14f79caeff0830abd2315d8a0e5db4b979bTimo Sirainen if (data != NULL) {
1a1159e589def1e32b7dc25397f15146672ef73eTimo Sirainen /* e.g. mail_max_userip_connections is reached */
86bca14f79caeff0830abd2315d8a0e5db4b979bTimo Sirainen } else {
86bca14f79caeff0830abd2315d8a0e5db4b979bTimo Sirainen /* The error should have been logged already.
86bca14f79caeff0830abd2315d8a0e5db4b979bTimo Sirainen The client will only see a generic internal error. */
86bca14f79caeff0830abd2315d8a0e5db4b979bTimo Sirainen client_notify_disconnect(client, CLIENT_DISCONNECT_INTERNAL_ERROR,
86bca14f79caeff0830abd2315d8a0e5db4b979bTimo Sirainen "Internal login failure. "
86bca14f79caeff0830abd2315d8a0e5db4b979bTimo Sirainen "Refer to server log for more information.");
86bca14f79caeff0830abd2315d8a0e5db4b979bTimo Sirainen data = t_strdup_printf("Internal login failure (pid=%s id=%u)",
86bca14f79caeff0830abd2315d8a0e5db4b979bTimo Sirainen my_pid, client->master_auth_id);
1a1159e589def1e32b7dc25397f15146672ef73eTimo Sirainen }
86bca14f79caeff0830abd2315d8a0e5db4b979bTimo Sirainen client->no_extra_disconnect_reason = TRUE;
86bca14f79caeff0830abd2315d8a0e5db4b979bTimo Sirainen client_destroy(client, data);
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen break;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen case SASL_SERVER_REPLY_CONTINUE:
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch i_assert(client->v.auth_send_challenge != NULL);
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainen client->v.auth_send_challenge(client, data);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&client->to_auth_waiting);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
decb23442f9e6cd5c4845a9cb162029b8c6d5f0fTimo Sirainen if (client->auth_response != NULL)
decb23442f9e6cd5c4845a9cb162029b8c6d5f0fTimo Sirainen str_truncate(client->auth_response, 0);
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(client->io == NULL);
6998ca95b4947c90647ac5d4794ebd6311acada2Timo Sirainen client->auth_waiting = TRUE;
a1852ab4cf0a942a3fcf4ca5636a7932ebcc7970Stephan Bosch if (!client_does_custom_io(client)) {
a1852ab4cf0a942a3fcf4ca5636a7932ebcc7970Stephan Bosch client->io = io_add(client->fd, IO_READ,
a1852ab4cf0a942a3fcf4ca5636a7932ebcc7970Stephan Bosch client_auth_input, client);
a1852ab4cf0a942a3fcf4ca5636a7932ebcc7970Stephan Bosch client_auth_input(client);
a1852ab4cf0a942a3fcf4ca5636a7932ebcc7970Stephan Bosch }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
b66d803de86bfb411165b3465b0d9ef64ecfe2a1Timo Sirainen client_unref(&client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenint client_auth_begin(struct client *client, const char *mech_name,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *init_resp)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainen if (!client->secured && strcmp(client->ssl_set->ssl, "required") == 0) {
b11269887905780bc8cb7762bbb157aa59961cacTimo Sirainen if (client->set->auth_verbose) {
d3a7d023b47d2a137f01109e7b38702dca3f11d3Timo Sirainen client_log(client, "Login failed: "
d3a7d023b47d2a137f01109e7b38702dca3f11d3Timo Sirainen "SSL required for authentication");
d3a7d023b47d2a137f01109e7b38702dca3f11d3Timo Sirainen }
d3a7d023b47d2a137f01109e7b38702dca3f11d3Timo Sirainen client->auth_attempts++;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client_auth_result(client, CLIENT_AUTH_RESULT_SSL_REQUIRED, NULL,
d3a7d023b47d2a137f01109e7b38702dca3f11d3Timo Sirainen "Authentication not allowed until SSL/TLS is enabled.");
d3a7d023b47d2a137f01109e7b38702dca3f11d3Timo Sirainen return 1;
d3a7d023b47d2a137f01109e7b38702dca3f11d3Timo Sirainen }
d3a7d023b47d2a137f01109e7b38702dca3f11d3Timo Sirainen
d3a7d023b47d2a137f01109e7b38702dca3f11d3Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_ref(client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->auth_initializing = TRUE;
5a250816ffc4cc5db203f9410ea99b6601c7b91aTimo Sirainen sasl_server_auth_begin(client, login_binary->protocol, mech_name,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen init_resp, sasl_callback);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->auth_initializing = FALSE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (!client->authenticating)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return 1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* don't handle input until we get the initial auth reply */
5f1d689131a75c39f064cbd4202373e7edf78f18Josef 'Jeff' Sipek io_remove(&client->io);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_set_auth_waiting(client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return 0;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenbool client_check_plaintext_auth(struct client *client, bool pass_sent)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
04eb0abcf8f8b0c014499b5c5bae89484553613fStephan Bosch bool ssl_required = (strcmp(client->ssl_set->ssl, "required") == 0);
04eb0abcf8f8b0c014499b5c5bae89484553613fStephan Bosch
e2ce85866a669d1881d2d31791619d2e7c63c253Timo Sirainen if (client->secured || (!client->set->disable_plaintext_auth &&
04eb0abcf8f8b0c014499b5c5bae89484553613fStephan Bosch !ssl_required))
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
b11269887905780bc8cb7762bbb157aa59961cacTimo Sirainen if (client->set->auth_verbose) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_log(client, "Login failed: "
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "Plaintext authentication disabled");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (pass_sent) {
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client_notify_status(client, TRUE,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "Plaintext authentication not allowed "
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "without SSL/TLS, but your client did it anyway. "
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "If anyone was listening, the password was exposed.");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
04eb0abcf8f8b0c014499b5c5bae89484553613fStephan Bosch
04eb0abcf8f8b0c014499b5c5bae89484553613fStephan Bosch if (ssl_required) {
04eb0abcf8f8b0c014499b5c5bae89484553613fStephan Bosch client_auth_result(client, CLIENT_AUTH_RESULT_SSL_REQUIRED, NULL,
04eb0abcf8f8b0c014499b5c5bae89484553613fStephan Bosch AUTH_PLAINTEXT_DISABLED_MSG);
04eb0abcf8f8b0c014499b5c5bae89484553613fStephan Bosch } else {
04eb0abcf8f8b0c014499b5c5bae89484553613fStephan Bosch client_auth_result(client, CLIENT_AUTH_RESULT_MECH_SSL_REQUIRED, NULL,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen AUTH_PLAINTEXT_DISABLED_MSG);
04eb0abcf8f8b0c014499b5c5bae89484553613fStephan Bosch }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->auth_attempts++;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return FALSE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid clients_notify_auth_connected(void)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
80e461e945dd4d5b0d08535413176cf1756e8523Timo Sirainen struct client *client, *next;
80e461e945dd4d5b0d08535413176cf1756e8523Timo Sirainen
80e461e945dd4d5b0d08535413176cf1756e8523Timo Sirainen for (client = clients; client != NULL; client = next) {
80e461e945dd4d5b0d08535413176cf1756e8523Timo Sirainen next = client->next;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&client->to_auth_waiting);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client_notify_auth_ready(client);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
a1852ab4cf0a942a3fcf4ca5636a7932ebcc7970Stephan Bosch if (!client_does_custom_io(client) && client->input_blocked) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->input_blocked = FALSE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_input(client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}