]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
auth: If userdb lookup returns tempfail, return reason field (if any).
authorTimo Sirainen <tss@iki.fi>
Wed, 31 Mar 2010 16:22:19 +0000 (19:22 +0300)
committerTimo Sirainen <tss@iki.fi>
Wed, 31 Mar 2010 16:22:19 +0000 (19:22 +0300)
--HG--
branch : HEAD

src/auth/auth-master-connection.c
src/auth/auth-request-handler.c
src/auth/auth-stream.c
src/auth/auth-stream.h
src/auth/auth-worker-client.c
src/auth/passdb-blocking.c
src/auth/userdb-blocking.c

index f1711a68688c0dc5cdd9e1cc2217c752456c5115..84f78874312cd3c9aa05513d3e00c1290f6d37b0 100644 (file)
@@ -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);
index 714836c961ab0be6636680bfcd6fd6065dff95a2..2b815cf4f1544e2c2b1d009e78c4d1913e828495 100644 (file)
@@ -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);
index 01f4a6fa2b97468af71a0ef8a187cf709613a371..631505b9c315d077e4eaf9c29508cbb32f5f4a2c 100644 (file)
@@ -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);
        }
 }
 
index 51cb329fd602b046e72e06aabc225e41bbc1adca..260c65b9474caf784d927bca42f6969a874abb78 100644 (file)
@@ -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);
index 8261b6b7c59b5f7a9abd704a0593270c801825f3..bb8672a875bd675eebdd5a37a9d7cfefd4a6308b 100644 (file)
@@ -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");
index 0b3f39edae86ec975ababf832545430c97634d6e..0cffe02e95e8b5b8a20a2464315a2e47ca2f44fd 100644 (file)
@@ -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;
                }
index 6e6510c69cd1daf44ad5aba876592e7fdcc7ca1c..90e2a03ad21919d2dbb6d0858b5a4e25ec99dae6 100644 (file)
@@ -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);