From: Timo Sirainen Date: Wed, 31 Mar 2010 16:22:19 +0000 (+0300) Subject: auth: If userdb lookup returns tempfail, return reason field (if any). X-Git-Tag: 2.0.beta5~255 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=3313a51ef9b245248d672c20f930c52a577a42f7;p=thirdparty%2Fdovecot%2Fcore.git auth: If userdb lookup returns tempfail, return reason field (if any). --HG-- branch : HEAD --- diff --git a/src/auth/auth-master-connection.c b/src/auth/auth-master-connection.c index f1711a6868..84f7887431 100644 --- a/src/auth/auth-master-connection.c +++ b/src/auth/auth-master-connection.c @@ -164,6 +164,7 @@ user_callback(enum userdb_result result, struct auth_master_connection *conn = auth_request->context; struct auth_stream_reply *reply = auth_request->userdb_reply; string_t *str; + const char *value; if (auth_request->userdb_lookup_failed) result = USERDB_RESULT_INTERNAL_FAILURE; @@ -172,6 +173,11 @@ user_callback(enum userdb_result result, switch (result) { case USERDB_RESULT_INTERNAL_FAILURE: str_printfa(str, "FAIL\t%u", auth_request->id); + if (auth_request->userdb_lookup_failed) { + value = auth_stream_reply_find(reply, "reason"); + if (value != NULL) + str_printfa(str, "\treason=%s", value); + } break; case USERDB_RESULT_USER_UNKNOWN: str_printfa(str, "NOTFOUND\t%u", auth_request->id); diff --git a/src/auth/auth-request-handler.c b/src/auth/auth-request-handler.c index 714836c961..2b815cf4f1 100644 --- a/src/auth/auth-request-handler.c +++ b/src/auth/auth-request-handler.c @@ -475,6 +475,7 @@ static void userdb_callback(enum userdb_result result, { struct auth_request_handler *handler = request->context; struct auth_stream_reply *reply; + const char *value; i_assert(request->state == AUTH_REQUEST_STATE_USERDB); @@ -488,6 +489,12 @@ static void userdb_callback(enum userdb_result result, case USERDB_RESULT_INTERNAL_FAILURE: auth_stream_reply_add(reply, "FAIL", NULL); auth_stream_reply_add(reply, NULL, dec2str(request->id)); + if (request->userdb_lookup_failed) { + value = auth_stream_reply_find(request->userdb_reply, + "reason"); + if (value != NULL) + auth_stream_reply_add(reply, "reason", value); + } break; case USERDB_RESULT_USER_UNKNOWN: auth_stream_reply_add(reply, "NOTFOUND", NULL); diff --git a/src/auth/auth-stream.c b/src/auth/auth-stream.c index 01f4a6fa2b..631505b9c3 100644 --- a/src/auth/auth-stream.c +++ b/src/auth/auth-stream.c @@ -40,7 +40,9 @@ void auth_stream_reply_add(struct auth_stream_reply *reply, } } -void auth_stream_reply_remove(struct auth_stream_reply *reply, const char *key) +static bool +auth_stream_reply_find_area(struct auth_stream_reply *reply, const char *key, + unsigned int *idx_r, unsigned int *len_r) { const char *str = str_c(reply->str); unsigned int i, start, key_len = strlen(key); @@ -49,21 +51,56 @@ void auth_stream_reply_remove(struct auth_stream_reply *reply, const char *key) while (str[i] != '\0') { start = i; for (; str[i] != '\0'; i++) { - if (str[i] == '\t') { - i++; + if (str[i] == '\t') break; - } } if (strncmp(str+start, key, key_len) == 0 && (str[start+key_len] == '=' || str[start+key_len] == '\t' || str[start+key_len] == '\0')) { - str_delete(reply->str, start, i-start); - if (str_len(reply->str) == start && start > 0) - str_delete(reply->str, start - 1, 1); - break; + *idx_r = start; + *len_r = i - start; + return TRUE; } + if (str[i] == '\t') + i++; + } + return FALSE; +} + +void auth_stream_reply_remove(struct auth_stream_reply *reply, const char *key) +{ + unsigned int idx, len; + + if (!auth_stream_reply_find_area(reply, key, &idx, &len)) + return; + + if (str_len(reply->str) < idx + len) { + /* remove also trailing tab */ + len++; + } else if (str_len(reply->str) == idx + len && idx > 0) { + /* removing last item, remove preceding tab */ + len++; + idx--; + } + + str_delete(reply->str, idx, len); +} + +const char *auth_stream_reply_find(struct auth_stream_reply *reply, + const char *key) +{ + unsigned int idx, len, keylen; + + if (!auth_stream_reply_find_area(reply, key, &idx, &len)) + return NULL; + else { + keylen = strlen(key); + i_assert(len > keylen); + idx += keylen + 1; + len -= keylen + 1; + return t_strndup(str_c(reply->str) + idx, len); } } diff --git a/src/auth/auth-stream.h b/src/auth/auth-stream.h index 51cb329fd6..260c65b947 100644 --- a/src/auth/auth-stream.h +++ b/src/auth/auth-stream.h @@ -9,6 +9,9 @@ void auth_stream_reply_add(struct auth_stream_reply *reply, void auth_stream_reply_reset(struct auth_stream_reply *reply); void auth_stream_reply_remove(struct auth_stream_reply *reply, const char *key); +const char *auth_stream_reply_find(struct auth_stream_reply *reply, + const char *key); + void auth_stream_reply_import(struct auth_stream_reply *reply, const char *str); const char *auth_stream_reply_export(struct auth_stream_reply *reply); bool auth_stream_is_empty(struct auth_stream_reply *reply); diff --git a/src/auth/auth-worker-client.c b/src/auth/auth-worker-client.c index 8261b6b7c5..bb8672a875 100644 --- a/src/auth/auth-worker-client.c +++ b/src/auth/auth-worker-client.c @@ -98,6 +98,7 @@ static void verify_plain_callback(enum passdb_result result, struct auth_worker_client *client = request->context; struct auth_stream_reply *reply; string_t *str; + const char *value; if (request->passdb_failure && result == PASSDB_RESULT_OK) result = PASSDB_RESULT_PASSWORD_MISMATCH; @@ -127,6 +128,13 @@ static void verify_plain_callback(enum passdb_result result, auth_stream_reply_export(request->extra_cache_fields); auth_stream_reply_import(reply, fields); } + } else if (request->userdb_lookup_failed) { + value = auth_stream_reply_find(request->extra_fields, "reason"); + if (value != NULL) { + auth_stream_reply_add(reply, NULL, ""); + auth_stream_reply_add(reply, NULL, ""); + auth_stream_reply_add(reply, "reason", value); + } } str = auth_stream_reply_get_str(reply); str_append_c(str, '\n'); @@ -200,6 +208,7 @@ lookup_credentials_callback(enum passdb_result result, struct auth_worker_client *client = request->context; struct auth_stream_reply *reply; string_t *str; + const char *value; if (request->passdb_failure && result == PASSDB_RESULT_OK) result = PASSDB_RESULT_PASSWORD_MISMATCH; @@ -211,6 +220,12 @@ lookup_credentials_callback(enum passdb_result result, auth_stream_reply_add(reply, "FAIL", NULL); auth_stream_reply_add(reply, NULL, t_strdup_printf("%d", result)); + value = auth_stream_reply_find(request->extra_fields, "reason"); + if (request->userdb_lookup_failed && value != NULL) { + auth_stream_reply_add(reply, NULL, ""); + auth_stream_reply_add(reply, NULL, ""); + auth_stream_reply_add(reply, "reason", value); + } } else { auth_stream_reply_add(reply, "OK", NULL); auth_stream_reply_add(reply, NULL, request->user); @@ -356,6 +371,7 @@ lookup_user_callback(enum userdb_result result, struct auth_worker_client *client = auth_request->context; struct auth_stream_reply *reply = auth_request->userdb_reply; string_t *str; + const char *value; if (auth_request->userdb_lookup_failed) result = USERDB_RESULT_INTERNAL_FAILURE; @@ -365,6 +381,11 @@ lookup_user_callback(enum userdb_result result, switch (result) { case USERDB_RESULT_INTERNAL_FAILURE: str_append(str, "FAIL\t"); + if (auth_request->userdb_lookup_failed) { + value = auth_stream_reply_find(reply, "reason"); + if (value != NULL) + str_printfa(str, "reason=%s", value); + } break; case USERDB_RESULT_USER_UNKNOWN: str_append(str, "NOTFOUND\t"); diff --git a/src/auth/passdb-blocking.c b/src/auth/passdb-blocking.c index 0b3f39edae..0cffe02e95 100644 --- a/src/auth/passdb-blocking.c +++ b/src/auth/passdb-blocking.c @@ -48,7 +48,10 @@ auth_worker_reply_parse(struct auth_request *request, const char *reply) /* internal failure most likely */ return ret; } else if (args[3] != NULL) { - auth_request_set_field(request, "user", args[2], NULL); + if (*args[2] != '\0') { + auth_request_set_field(request, "user", + args[2], NULL); + } auth_worker_reply_parse_args(request, args + 3); return ret; } diff --git a/src/auth/userdb-blocking.c b/src/auth/userdb-blocking.c index 6e6510c69c..90e2a03ad2 100644 --- a/src/auth/userdb-blocking.c +++ b/src/auth/userdb-blocking.c @@ -19,18 +19,26 @@ static bool user_callback(const char *reply, void *context) { struct auth_request *request = context; enum userdb_result result; + const char *args; - if (strncmp(reply, "FAIL\t", 5) == 0) + if (strncmp(reply, "FAIL\t", 5) == 0) { result = USERDB_RESULT_INTERNAL_FAILURE; - else if (strncmp(reply, "NOTFOUND\t", 9) == 0) + args = reply + 5; + } else if (strncmp(reply, "NOTFOUND\t", 9) == 0) { result = USERDB_RESULT_USER_UNKNOWN; - else if (strncmp(reply, "OK\t", 3) == 0) { + args = reply + 9; + } else if (strncmp(reply, "OK\t", 3) == 0) { result = USERDB_RESULT_OK; - request->userdb_reply = auth_stream_reply_init(request->pool); - auth_stream_reply_import(request->userdb_reply, reply + 3); + args = reply + 3; } else { result = USERDB_RESULT_INTERNAL_FAILURE; i_error("BUG: auth-worker sent invalid user reply"); + args = ""; + } + + if (*args != '\0') { + request->userdb_reply = auth_stream_reply_init(request->pool); + auth_stream_reply_import(request->userdb_reply, args); } auth_request_userdb_callback(result, request);