From: Timo Sirainen Date: Wed, 2 Jun 2010 15:48:55 +0000 (+0100) Subject: auth: Fixes to destroying pending async userdb requests at deinit. X-Git-Tag: 2.0.beta6~74 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0602c7dee8ceda2d7c7e5723f18c56698ac5a76d;p=thirdparty%2Fdovecot%2Fcore.git auth: Fixes to destroying pending async userdb requests at deinit. --HG-- branch : HEAD --- diff --git a/src/auth/auth-master-connection.c b/src/auth/auth-master-connection.c index 33245ff07c..bf16b69346 100644 --- a/src/auth/auth-master-connection.c +++ b/src/auth/auth-master-connection.c @@ -3,6 +3,7 @@ #include "auth-common.h" #include "array.h" #include "hash.h" +#include "llist.h" #include "str.h" #include "strescape.h" #include "str-sanitize.h" @@ -26,6 +27,12 @@ #define MAX_INBUF_SIZE 1024 #define MAX_OUTBUF_SIZE (1024*50) +struct auth_request_list { + struct auth_request_list *prev, *next; + + struct auth_request *auth_request; +}; + struct master_userdb_request { struct auth_master_connection *conn; unsigned int id; @@ -116,6 +123,7 @@ master_input_auth_request(struct auth_master_connection *conn, const char *args, const char **error_r) { struct auth_request *auth_request; + struct auth_request_list *request_list; const char *const *list, *name, *arg; unsigned int id; @@ -129,9 +137,14 @@ master_input_auth_request(struct auth_master_connection *conn, const char *args, auth_request = auth_request_new_dummy(); auth_request->id = id; - auth_request->context = conn; + auth_request->master = conn; auth_master_connection_ref(conn); + request_list = p_new(auth_request->pool, struct auth_request_list, 1); + request_list->auth_request = auth_request; + DLLIST_PREPEND(&conn->requests, request_list); + auth_request->context = request_list; + if (!auth_request_set_username(auth_request, list[1], error_r)) { *request_r = auth_request; return 0; @@ -152,8 +165,9 @@ master_input_auth_request(struct auth_master_connection *conn, const char *args, if (auth_request->service == NULL) { i_error("BUG: Master sent %s request without service", cmd); - auth_master_connection_unref(&conn); + DLLIST_REMOVE(&conn->requests, request_list); auth_request_unref(&auth_request); + auth_master_connection_unref(&conn); return -1; } @@ -166,7 +180,8 @@ static void user_callback(enum userdb_result result, struct auth_request *auth_request) { - struct auth_master_connection *conn = auth_request->context; + struct auth_master_connection *conn = auth_request->master; + struct auth_request_list *list = auth_request->context; struct auth_stream_reply *reply = auth_request->userdb_reply; string_t *str; const char *value; @@ -198,6 +213,8 @@ user_callback(enum userdb_result result, str_append_c(str, '\n'); (void)o_stream_send(conn->output, str_data(str), str_len(str)); + + DLLIST_REMOVE(&conn->requests, list); auth_request_unref(&auth_request); auth_master_connection_unref(&conn); } @@ -229,7 +246,8 @@ pass_callback(enum passdb_result result, size_t size ATTR_UNUSED, struct auth_request *auth_request) { - struct auth_master_connection *conn = auth_request->context; + struct auth_master_connection *conn = auth_request->master; + struct auth_request_list *list = auth_request->context; struct auth_stream_reply *reply = auth_request->extra_fields; string_t *str; @@ -257,6 +275,8 @@ pass_callback(enum passdb_result result, str_append_c(str, '\n'); (void)o_stream_send(conn->output, str_data(str), str_len(str)); + + DLLIST_REMOVE(&conn->requests, list); auth_request_unref(&auth_request); auth_master_connection_unref(&conn); } @@ -512,6 +532,7 @@ void auth_master_connection_destroy(struct auth_master_connection **_conn) { struct auth_master_connection *conn = *_conn; struct auth_master_connection *const *masters; + struct auth_request_list *list; unsigned int idx; *_conn = NULL; @@ -519,6 +540,9 @@ void auth_master_connection_destroy(struct auth_master_connection **_conn) return; conn->destroyed = TRUE; + for (list = conn->requests; list != NULL; list = list->next) + list->auth_request->destroyed = TRUE; + array_foreach(&auth_master_connections, masters) { if (*masters == conn) { idx = array_foreach_idx(&auth_master_connections, diff --git a/src/auth/auth-master-connection.h b/src/auth/auth-master-connection.h index 26d2b7266b..b0bc9aaab6 100644 --- a/src/auth/auth-master-connection.h +++ b/src/auth/auth-master-connection.h @@ -12,6 +12,8 @@ struct auth_master_connection { struct ostream *output; struct io *io; + struct auth_request_list *requests; + unsigned int version_received:1; unsigned int destroyed:1; unsigned int userdb_only:1; diff --git a/src/auth/auth-request-handler.c b/src/auth/auth-request-handler.c index feb292f970..13d8b884ae 100644 --- a/src/auth/auth-request-handler.c +++ b/src/auth/auth-request-handler.c @@ -74,6 +74,7 @@ static void auth_request_handler_unref(struct auth_request_handler **_handler) while (hash_table_iterate(iter, &key, &value)) { struct auth_request *auth_request = value; + auth_request->destroyed = TRUE; auth_request_unref(&auth_request); } hash_table_iterate_deinit(&iter); @@ -97,11 +98,6 @@ void auth_request_handler_destroy(struct auth_request_handler **_handler) auth_request_handler_unref(&handler); } -bool auth_request_handler_is_destroyed(struct auth_request_handler *handler) -{ - return handler->destroyed; -} - void auth_request_handler_set(struct auth_request_handler *handler, unsigned int connect_uid, unsigned int client_pid) diff --git a/src/auth/auth-request-handler.h b/src/auth/auth-request-handler.h index 2391282327..515b3a8267 100644 --- a/src/auth/auth-request-handler.h +++ b/src/auth/auth-request-handler.h @@ -25,8 +25,6 @@ auth_request_handler_create(auth_request_callback_t *callback, void *context, #endif void auth_request_handler_destroy(struct auth_request_handler **handler); -bool auth_request_handler_is_destroyed(struct auth_request_handler *handler); - void auth_request_handler_set(struct auth_request_handler *handler, unsigned int connect_uid, unsigned int client_pid); diff --git a/src/auth/auth-request.c b/src/auth/auth-request.c index b6ba7d3ac6..b3b4fb8d35 100644 --- a/src/auth/auth-request.c +++ b/src/auth/auth-request.c @@ -390,7 +390,7 @@ auth_request_handle_passdb_callback(enum passdb_result *result, strlen(request->passdb_password)); } - if (auth_request_handler_is_destroyed(request->handler)) { + if (request->destroyed) { /* the passdb may have been freed already. this request won't be sent anywhere anyway, so just fail it immediately. */ *result = PASSDB_RESULT_INTERNAL_FAILURE; @@ -742,6 +742,14 @@ void auth_request_userdb_callback(enum userdb_result result, { struct userdb_module *userdb = request->userdb->userdb; + if (request->destroyed) { + /* the userdb may have been freed already. this request won't + be sent anywhere anyway, so just fail it immediately. */ + request->private_callback. + userdb(USERDB_RESULT_INTERNAL_FAILURE, request); + return; + } + if (result != USERDB_RESULT_OK && request->userdb->next != NULL) { /* try next userdb. */ if (result == USERDB_RESULT_INTERNAL_FAILURE) diff --git a/src/auth/auth-request.h b/src/auth/auth-request.h index ed9d00f420..db23030273 100644 --- a/src/auth/auth-request.h +++ b/src/auth/auth-request.h @@ -108,6 +108,7 @@ struct auth_request { unsigned int userdb_lookup:1; unsigned int userdb_lookup_failed:1; unsigned int secured:1; + unsigned int destroyed:1; /* ... mechanism specific data ... */ };