Mercurial > dovecot > core-2.2
diff src/auth/auth-request.c @ 14155:da43dc494753
auth: Handle proxy_maybe=yes with host=hostname properly.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sat, 25 Feb 2012 05:04:15 +0200 |
parents | ba770cba5598 |
children | 8e2f395cf86c |
line wrap: on
line diff
--- a/src/auth/auth-request.c Sat Feb 25 04:38:01 2012 +0200 +++ b/src/auth/auth-request.c Sat Feb 25 05:04:15 2012 +0200 @@ -11,6 +11,7 @@ #include "str-sanitize.h" #include "strescape.h" #include "var-expand.h" +#include "dns-lookup.h" #include "auth-cache.h" #include "auth-request.h" #include "auth-request-handler.h" @@ -27,6 +28,8 @@ #include <stdlib.h> #include <sys/stat.h> +#define AUTH_DNS_SOCKET_PATH "dns-client" +#define AUTH_DNS_TIMEOUT_MSECS (1000*10) #define CACHED_PASSWORD_SCHEME "SHA1" unsigned int auth_request_state_count[AUTH_REQUEST_STATE_MAX]; @@ -158,6 +161,11 @@ auth_request_state_count[request->state]--; auth_refresh_proctitle(); + if (request->mech_password != NULL) { + safe_memset(request->mech_password, 0, + strlen(request->mech_password)); + } + if (request->to_abort != NULL) timeout_remove(&request->to_abort); if (request->to_penalty != NULL) @@ -543,8 +551,6 @@ } else { auth_request_ref(request); request->private_callback.verify_plain(result, request); - safe_memset(request->mech_password, 0, - strlen(request->mech_password)); auth_request_unref(&request); } } @@ -1410,53 +1416,144 @@ static bool auth_request_proxy_is_self(struct auth_request *request) { - const char *const *tmp, *host = NULL, *port = NULL, *destuser = NULL; - struct ip_addr ip; + const char *const *tmp, *port = NULL, *destuser = NULL; + + if (!request->proxy_host_is_self) + return FALSE; tmp = auth_stream_split(request->extra_fields); for (; *tmp != NULL; tmp++) { - if (strncmp(*tmp, "host=", 5) == 0) - host = *tmp + 5; - else if (strncmp(*tmp, "port=", 5) == 0) + if (strncmp(*tmp, "port=", 5) == 0) port = *tmp + 5; - if (strncmp(*tmp, "destuser=", 9) == 0) + else if (strncmp(*tmp, "destuser=", 9) == 0) destuser = *tmp + 9; } - if (host == NULL || net_addr2ip(host, &ip) < 0) { - /* broken setup */ - return FALSE; - } - if (!net_ip_compare(&ip, &request->local_ip)) - return FALSE; - if (port != NULL && !str_uint_equals(port, request->local_port)) return FALSE; return destuser == NULL || strcmp(destuser, request->original_username) == 0; } -void auth_request_proxy_finish(struct auth_request *request, bool success) +static bool +auth_request_proxy_ip_is_self(struct auth_request *request, + const struct ip_addr *ip) { - if (!request->proxy || request->no_login) - return; + return net_ip_compare(ip, &request->local_ip); +} - if (!success) { - /* drop all proxy fields */ - } else if (!request->proxy_maybe) { +static void auth_request_proxy_finish_ip(struct auth_request *request) +{ + if (!request->proxy_maybe) { /* proxying */ request->no_login = TRUE; - return; } else if (!auth_request_proxy_is_self(request)) { /* proxy destination isn't ourself - proxy */ auth_stream_reply_remove(request->extra_fields, "proxy_maybe"); auth_stream_reply_add(request->extra_fields, "proxy", NULL); request->no_login = TRUE; - return; } else { /* proxying to ourself - log in without proxying by dropping all the proxying fields. */ + auth_request_proxy_finish_failure(request); } +} + +struct auth_request_proxy_dns_lookup_ctx { + struct auth_request *request; + auth_request_proxy_cb_t *callback; +}; + +static void +auth_request_proxy_dns_callback(const struct dns_lookup_result *result, + void *context) +{ + struct auth_request_proxy_dns_lookup_ctx *ctx = context; + struct auth_request *request = ctx->request; + const char *host; + unsigned int i; + + if (result->ret != 0) { + host = auth_stream_reply_find(request->extra_fields, "host"); + i_assert(host != NULL); + auth_request_log_error(request, "dns", + "dns_lookup(%s) failed: %s", host, result->error); + request->internal_failure = TRUE; + auth_request_proxy_finish_failure(request); + } else { + auth_stream_reply_remove(request->extra_fields, "host"); + auth_stream_reply_add(request->extra_fields, "host", + net_ip2addr(&result->ips[0])); + for (i = 0; i < result->ips_count; i++) { + if (auth_request_proxy_ip_is_self(request, + &result->ips[i])) { + request->proxy_host_is_self = TRUE; + break; + } + } + auth_request_proxy_finish_ip(request); + } + if (ctx->callback != NULL) + ctx->callback(result->ret == 0, request); + i_free(ctx); +} + +static int auth_request_proxy_host_lookup(struct auth_request *request, + auth_request_proxy_cb_t *callback) +{ + struct auth_request_proxy_dns_lookup_ctx *ctx; + struct dns_lookup_settings dns_set; + const char *host; + struct ip_addr ip; + + host = auth_stream_reply_find(request->extra_fields, "host"); + if (host == NULL) + return 1; + if (net_addr2ip(host, &ip) == 0) { + if (auth_request_proxy_ip_is_self(request, &ip)) + request->proxy_host_is_self = TRUE; + return 1; + } + + /* need to do dns lookup for the host */ + memset(&dns_set, 0, sizeof(dns_set)); + dns_set.dns_client_socket_path = AUTH_DNS_SOCKET_PATH; + dns_set.timeout_msecs = AUTH_DNS_TIMEOUT_MSECS; + + ctx = i_new(struct auth_request_proxy_dns_lookup_ctx, 1); + ctx->request = request; + + if (dns_lookup(host, &dns_set, auth_request_proxy_dns_callback, ctx) < 0) { + /* failed early */ + request->internal_failure = TRUE; + auth_request_proxy_finish_failure(request); + return -1; + } + ctx->callback = callback; + return 0; +} + +int auth_request_proxy_finish(struct auth_request *request, + auth_request_proxy_cb_t *callback) +{ + int ret; + + if (!request->proxy) + return 1; + + if ((ret = auth_request_proxy_host_lookup(request, callback)) <= 0) + return ret; + + auth_request_proxy_finish_ip(request); + return 1; +} + +void auth_request_proxy_finish_failure(struct auth_request *request) +{ + if (!request->proxy) + return; + + /* drop all proxying fields */ auth_stream_reply_remove(request->extra_fields, "proxy"); auth_stream_reply_remove(request->extra_fields, "proxy_maybe"); auth_stream_reply_remove(request->extra_fields, "host");