From 96f60a37f6d6f1ad4baf3e441e14091046516d48 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 27 Jul 2006 13:02:27 +0000 Subject: r17273: add an async version of auth_check_password() on the public auth interface and implement the sync version as wrapper to auth_check_password_send/recv() as next all callers need to be converted to the async interface and then the modules metze (This used to be commit ed40bb3c16279f9727be67e889270da5efb8ddb9) --- source4/auth/auth.c | 215 ++++++++++++++++++++++++++++++++++++++++++++-------- source4/auth/auth.h | 1 + 2 files changed, 185 insertions(+), 31 deletions(-) diff --git a/source4/auth/auth.c b/source4/auth/auth.c index 0b044af495..d3b9e28f7b 100644 --- a/source4/auth/auth.c +++ b/source4/auth/auth.c @@ -21,7 +21,6 @@ #include "includes.h" #include "dlinklist.h" -#include "lib/ldb/include/ldb.h" #include "auth/auth.h" #include "lib/events/events.h" #include "build.h" @@ -104,8 +103,25 @@ NTSTATUS auth_get_challenge(struct auth_context *auth_ctx, const uint8_t **_chal return NT_STATUS_OK; } +struct auth_check_password_sync_state { + BOOL finished; + NTSTATUS status; + struct auth_serversupplied_info *server_info; +}; + +static void auth_check_password_sync_callback(struct auth_check_password_request *req, + void *private_data) +{ + struct auth_check_password_sync_state *s = talloc_get_type(private_data, + struct auth_check_password_sync_state); + + s->finished = True; + s->status = auth_check_password_recv(req, s, &s->server_info); +} + /** * Check a user's Plaintext, LM or NTLM password. + * (sync version) * * Check a user's password, as given in the user_info struct and return various * interesting details in the server_info struct. @@ -114,13 +130,15 @@ NTSTATUS auth_get_challenge(struct auth_context *auth_ctx, const uint8_t **_chal * struct. When the return is other than NT_STATUS_OK the contents * of that structure is undefined. * - * @param user_info Contains the user supplied components, including the passwords. - * - * @param auth_context Supplies the challenges and some other data. - * Must be created with make_auth_context(), and the challenges should be + * @param auth_ctx Supplies the challenges and some other data. + * Must be created with auth_context_create(), and the challenges should be * filled in, either at creation or by calling the challenge geneation * function auth_get_challenge(). * + * @param user_info Contains the user supplied components, including the passwords. + * + * @param mem_ctx The parent memory context for the server_info structure + * * @param server_info If successful, contains information about the authentication, * including a SAM_ACCOUNT struct describing the user. * @@ -132,75 +150,210 @@ NTSTATUS auth_check_password(struct auth_context *auth_ctx, TALLOC_CTX *mem_ctx, const struct auth_usersupplied_info *user_info, struct auth_serversupplied_info **server_info) +{ + struct auth_check_password_sync_state *sync_state; + NTSTATUS status; + + DEBUG(3, ("auth_check_password: Checking password for unmapped user [%s]\\[%s]@[%s]\n", + user_info->client.domain_name, user_info->client.account_name, user_info->workstation_name)); + + sync_state = talloc_zero(auth_ctx, struct auth_check_password_sync_state); + NT_STATUS_HAVE_NO_MEMORY(sync_state); + + auth_check_password_send(auth_ctx, user_info, auth_check_password_sync_callback, sync_state); + + while (!sync_state->finished) { + event_loop_once(auth_ctx->event_ctx); + } + + status = sync_state->status; + + if (NT_STATUS_IS_OK(status)) { + *server_info = talloc_steal(mem_ctx, sync_state->server_info); + + DEBUG(5,("auth_check_password: authentication for user [%s\\%s] succeeded\n", + (*server_info)->domain_name, (*server_info)->account_name)); + } else { + DEBUG(2,("auth_check_password: authentication for user [%s\\%s] FAILED with error %s\n", + user_info->mapped.domain_name, user_info->mapped.account_name, + nt_errstr(status))); + } + + talloc_free(sync_state); + return status; +} + +struct auth_check_password_request { + struct auth_context *auth_ctx; + const struct auth_usersupplied_info *user_info; + struct auth_serversupplied_info *server_info; + struct auth_method_context *method; + NTSTATUS status; + struct { + void (*fn)(struct auth_check_password_request *req, void *private_data); + void *private_data; + } callback; +}; + +static void auth_check_password_async_timed_handler(struct event_context *ev, struct timed_event *te, + struct timeval t, void *ptr) +{ + struct auth_check_password_request *req = talloc_get_type(ptr, struct auth_check_password_request); + req->status = req->method->ops->check_password(req->method, req, req->user_info, &req->server_info); + req->callback.fn(req, req->callback.private_data); +} + +/** + * Check a user's Plaintext, LM or NTLM password. + * async send hook + * + * Check a user's password, as given in the user_info struct and return various + * interesting details in the server_info struct. + * + * The return value takes precedence over the contents of the server_info + * struct. When the return is other than NT_STATUS_OK the contents + * of that structure is undefined. + * + * @param auth_ctx Supplies the challenges and some other data. + * Must be created with make_auth_context(), and the challenges should be + * filled in, either at creation or by calling the challenge geneation + * function auth_get_challenge(). + * + * @param user_info Contains the user supplied components, including the passwords. + * + * @param callback A callback function which will be called when the operation is finished. + * The callback function needs to call auth_check_password_recv() to get the return values + * + * @param private_data A private pointer which will ba passed to the callback function + * + **/ + +void auth_check_password_send(struct auth_context *auth_ctx, + const struct auth_usersupplied_info *user_info, + void (*callback)(struct auth_check_password_request *req, void *private_data), + void *private_data) { /* if all the modules say 'not for me' this is reasonable */ NTSTATUS nt_status; struct auth_method_context *method; - const char *method_name = "NO METHOD"; const uint8_t *challenge; - struct auth_usersupplied_info *user_info_tmp; + struct auth_usersupplied_info *user_info_tmp; + struct auth_check_password_request *req = NULL; - DEBUG(3, ("auth_check_password: Checking password for unmapped user [%s]\\[%s]@[%s]\n", + DEBUG(3, ("auth_check_password_send: Checking password for unmapped user [%s]\\[%s]@[%s]\n", user_info->client.domain_name, user_info->client.account_name, user_info->workstation_name)); + req = talloc_zero(auth_ctx, struct auth_check_password_request); + if (!req) { + callback(NULL, private_data); + return; + } + req->auth_ctx = auth_ctx; + req->user_info = user_info; + req->callback.fn = callback; + req->callback.private_data = private_data; + if (!user_info->mapped_state) { - nt_status = map_user_info(mem_ctx, user_info, &user_info_tmp); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } + nt_status = map_user_info(req, user_info, &user_info_tmp); + if (!NT_STATUS_IS_OK(nt_status)) goto failed; user_info = user_info_tmp; + req->user_info = user_info_tmp; } - DEBUGADD(3,("auth_check_password: mapped user is: [%s]\\[%s]@[%s]\n", + DEBUGADD(3,("auth_check_password_send: mapped user is: [%s]\\[%s]@[%s]\n", user_info->mapped.domain_name, user_info->mapped.account_name, user_info->workstation_name)); nt_status = auth_get_challenge(auth_ctx, &challenge); - if (!NT_STATUS_IS_OK(nt_status)) { - DEBUG(0, ("auth_check_password: Invalid challenge (length %u) stored for this auth context set_by %s - cannot continue: %s\n", + DEBUG(0, ("auth_check_password_send: Invalid challenge (length %u) stored for this auth context set_by %s - cannot continue: %s\n", (unsigned)auth_ctx->challenge.data.length, auth_ctx->challenge.set_by, nt_errstr(nt_status))); - return nt_status; + goto failed; } if (auth_ctx->challenge.set_by) { - DEBUG(10, ("auth_check_password: auth_context challenge created by %s\n", + DEBUG(10, ("auth_check_password_send: auth_context challenge created by %s\n", auth_ctx->challenge.set_by)); } - DEBUG(10, ("challenge is: \n")); + DEBUG(10, ("auth_check_password_send: challenge is: \n")); dump_data(5, auth_ctx->challenge.data.data, auth_ctx->challenge.data.length); nt_status = NT_STATUS_NO_SUCH_USER; /* If all the modules say 'not for me', then this is reasonable */ for (method = auth_ctx->methods; method; method = method->next) { NTSTATUS result; + struct timed_event *te = NULL; /* check if the module wants to chek the password */ - result = method->ops->want_check(method, mem_ctx, user_info); + result = method->ops->want_check(method, req, user_info); if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) { - DEBUG(11,("auth_check_password: %s had nothing to say\n", method->ops->name)); + DEBUG(11,("auth_check_password_send: %s had nothing to say\n", method->ops->name)); continue; } - method_name = method->ops->name; nt_status = result; + req->method = method; if (!NT_STATUS_IS_OK(nt_status)) break; - nt_status = method->ops->check_password(method, mem_ctx, user_info, server_info); - break; + te = event_add_timed(auth_ctx->event_ctx, req, + timeval_zero(), + auth_check_password_async_timed_handler, req); + if (!te) { + nt_status = NT_STATUS_NO_MEMORY; + goto failed; + } + return; } - if (!NT_STATUS_IS_OK(nt_status)) { +failed: + req->status = nt_status; + req->callback.fn(req, req->callback.private_data); +} + +/** + * Check a user's Plaintext, LM or NTLM password. + * async receive function + * + * The return value takes precedence over the contents of the server_info + * struct. When the return is other than NT_STATUS_OK the contents + * of that structure is undefined. + * + * + * @param req The async auth_check_password state, passes to the callers callback function + * + * @param mem_ctx The parent memory context for the server_info structure + * + * @param server_info If successful, contains information about the authentication, + * including a SAM_ACCOUNT struct describing the user. + * + * @return An NTSTATUS with NT_STATUS_OK or an appropriate error. + * + **/ + +NTSTATUS auth_check_password_recv(struct auth_check_password_request *req, + TALLOC_CTX *mem_ctx, + struct auth_serversupplied_info **server_info) +{ + NTSTATUS status; + + NT_STATUS_HAVE_NO_MEMORY(req); + + if (NT_STATUS_IS_OK(req->status)) { + DEBUG(5,("auth_check_password: %s authentication for user [%s\\%s] succeeded\n", + req->method->ops->name, req->server_info->domain_name, req->server_info->account_name)); + + *server_info = talloc_steal(mem_ctx, req->server_info); + } else { DEBUG(2,("auth_check_password: %s authentication for user [%s\\%s] FAILED with error %s\n", - method_name, user_info->mapped.domain_name, user_info->mapped.account_name, - nt_errstr(nt_status))); - return nt_status; + (req->method ? req->method->ops->name : "NO_METHOD"), + req->user_info->mapped.domain_name, + req->user_info->mapped.account_name, + nt_errstr(req->status))); } - DEBUG(5,("auth_check_password: %s authentication for user [%s\\%s] succeeded\n", - method_name, (*server_info)->domain_name, (*server_info)->account_name)); - - return nt_status; + status = req->status; + talloc_free(req); + return status; } /*************************************************************************** diff --git a/source4/auth/auth.h b/source4/auth/auth.h index 20a91efc10..7ebab9c8e1 100644 --- a/source4/auth/auth.h +++ b/source4/auth/auth.h @@ -124,6 +124,7 @@ struct auth_session_info { }; struct auth_method_context; +struct auth_check_password_request; struct auth_operations { const char *name; -- cgit