From 7ee76eeae5b3e9e5f5b226039e7276897f5e6764 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 5 May 2008 15:23:57 +1000 Subject: Move NTLM authentication details into auth/ntlm This should help clarify the role of the various files around here (done on Jelmer's request). Andrew Bartlett (This used to be commit efa399037511ced8978f2e7661a71aac7a384883) --- source4/auth/auth.c | 539 ----------------------- source4/auth/auth_anonymous.c | 78 ---- source4/auth/auth_developer.c | 207 --------- source4/auth/auth_sam.c | 448 -------------------- source4/auth/auth_server.c | 225 ---------- source4/auth/auth_simple.c | 103 ----- source4/auth/auth_unix.c | 844 ------------------------------------- source4/auth/auth_util.c | 260 ------------ source4/auth/auth_winbind.c | 282 ------------- source4/auth/config.mk | 83 +--- source4/auth/ntlm/auth.c | 539 +++++++++++++++++++++++ source4/auth/ntlm/auth_anonymous.c | 78 ++++ source4/auth/ntlm/auth_developer.c | 207 +++++++++ source4/auth/ntlm/auth_proto.h | 50 +++ source4/auth/ntlm/auth_sam.c | 449 ++++++++++++++++++++ source4/auth/ntlm/auth_server.c | 225 ++++++++++ source4/auth/ntlm/auth_simple.c | 103 +++++ source4/auth/ntlm/auth_unix.c | 844 +++++++++++++++++++++++++++++++++++++ source4/auth/ntlm/auth_util.c | 260 ++++++++++++ source4/auth/ntlm/auth_winbind.c | 282 +++++++++++++ source4/auth/ntlm/config.mk | 87 ++++ source4/auth/ntlm/ntlm_check.c | 603 ++++++++++++++++++++++++++ source4/auth/ntlm/ntlm_check.h | 75 ++++ source4/auth/ntlm/pam_errors.c | 125 ++++++ source4/auth/ntlm/pam_errors.h | 39 ++ source4/auth/ntlm_check.c | 602 -------------------------- source4/auth/pam_errors.c | 125 ------ source4/utils/config.mk | 1 + source4/utils/ntlm_auth.c | 1 + 29 files changed, 3970 insertions(+), 3794 deletions(-) delete mode 100644 source4/auth/auth.c delete mode 100644 source4/auth/auth_anonymous.c delete mode 100644 source4/auth/auth_developer.c delete mode 100644 source4/auth/auth_sam.c delete mode 100644 source4/auth/auth_server.c delete mode 100644 source4/auth/auth_simple.c delete mode 100644 source4/auth/auth_unix.c delete mode 100644 source4/auth/auth_util.c delete mode 100644 source4/auth/auth_winbind.c create mode 100644 source4/auth/ntlm/auth.c create mode 100644 source4/auth/ntlm/auth_anonymous.c create mode 100644 source4/auth/ntlm/auth_developer.c create mode 100644 source4/auth/ntlm/auth_proto.h create mode 100644 source4/auth/ntlm/auth_sam.c create mode 100644 source4/auth/ntlm/auth_server.c create mode 100644 source4/auth/ntlm/auth_simple.c create mode 100644 source4/auth/ntlm/auth_unix.c create mode 100644 source4/auth/ntlm/auth_util.c create mode 100644 source4/auth/ntlm/auth_winbind.c create mode 100644 source4/auth/ntlm/config.mk create mode 100644 source4/auth/ntlm/ntlm_check.c create mode 100644 source4/auth/ntlm/ntlm_check.h create mode 100644 source4/auth/ntlm/pam_errors.c create mode 100644 source4/auth/ntlm/pam_errors.h delete mode 100644 source4/auth/ntlm_check.c delete mode 100644 source4/auth/pam_errors.c (limited to 'source4') diff --git a/source4/auth/auth.c b/source4/auth/auth.c deleted file mode 100644 index b74a438962..0000000000 --- a/source4/auth/auth.c +++ /dev/null @@ -1,539 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Password and authentication handling - Copyright (C) Andrew Bartlett 2001-2002 - Copyright (C) Stefan Metzmacher 2005 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "includes.h" -#include "lib/util/dlinklist.h" -#include "auth/auth.h" -#include "auth/auth_proto.h" -#include "lib/events/events.h" -#include "build.h" -#include "param/param.h" - -/*************************************************************************** - Set a fixed challenge -***************************************************************************/ -_PUBLIC_ NTSTATUS auth_context_set_challenge(struct auth_context *auth_ctx, const uint8_t chal[8], const char *set_by) -{ - auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by); - NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by); - - auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8); - NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data); - - return NT_STATUS_OK; -} - -/*************************************************************************** - Set a fixed challenge -***************************************************************************/ -bool auth_challenge_may_be_modified(struct auth_context *auth_ctx) -{ - return auth_ctx->challenge.may_be_modified; -} - -/**************************************************************************** - Try to get a challenge out of the various authentication modules. - Returns a const char of length 8 bytes. -****************************************************************************/ -_PUBLIC_ NTSTATUS auth_get_challenge(struct auth_context *auth_ctx, const uint8_t **_chal) -{ - NTSTATUS nt_status; - struct auth_method_context *method; - - if (auth_ctx->challenge.data.length) { - DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n", - auth_ctx->challenge.set_by)); - *_chal = auth_ctx->challenge.data.data; - return NT_STATUS_OK; - } - - for (method = auth_ctx->methods; method; method = method->next) { - DATA_BLOB challenge = data_blob(NULL,0); - - nt_status = method->ops->get_challenge(method, auth_ctx, &challenge); - if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) { - continue; - } - - NT_STATUS_NOT_OK_RETURN(nt_status); - - if (challenge.length != 8) { - DEBUG(0, ("auth_get_challenge: invalid challenge (length %u) by mothod [%s]\n", - (unsigned)challenge.length, method->ops->name)); - return NT_STATUS_INTERNAL_ERROR; - } - - auth_ctx->challenge.data = challenge; - auth_ctx->challenge.set_by = method->ops->name; - - break; - } - - if (!auth_ctx->challenge.set_by) { - uint8_t chal[8]; - generate_random_buffer(chal, 8); - - auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8); - NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data); - auth_ctx->challenge.set_by = "random"; - - auth_ctx->challenge.may_be_modified = true; - } - - DEBUG(10,("auth_get_challenge: challenge set by %s\n", - auth_ctx->challenge.set_by)); - - *_chal = auth_ctx->challenge.data.data; - 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. - * - * 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 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. - * - * @return An NTSTATUS with NT_STATUS_OK or an appropriate error. - * - **/ - -_PUBLIC_ 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; - - 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); - } - - 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 - * - **/ - -_PUBLIC_ 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 uint8_t *challenge; - struct auth_usersupplied_info *user_info_tmp; - struct auth_check_password_request *req = NULL; - - 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(req, lp_workgroup(auth_ctx->lp_ctx), 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_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_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))); - goto failed; - } - - if (auth_ctx->challenge.set_by) { - DEBUG(10, ("auth_check_password_send: auth_context challenge created by %s\n", - auth_ctx->challenge.set_by)); - } - - 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, req, user_info); - if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) { - DEBUG(11,("auth_check_password_send: %s had nothing to say\n", method->ops->name)); - continue; - } - - nt_status = result; - req->method = method; - - if (!NT_STATUS_IS_OK(nt_status)) 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; - } - -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. - * - **/ - -_PUBLIC_ 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_recv: %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_recv: %s authentication for user [%s\\%s] FAILED with error %s\n", - (req->method ? req->method->ops->name : "NO_METHOD"), - req->user_info->mapped.domain_name, - req->user_info->mapped.account_name, - nt_errstr(req->status))); - } - - status = req->status; - talloc_free(req); - return status; -} - -/*************************************************************************** - Make a auth_info struct for the auth subsystem - - Allow the caller to specify the methods to use -***************************************************************************/ -_PUBLIC_ NTSTATUS auth_context_create_methods(TALLOC_CTX *mem_ctx, const char **methods, - struct event_context *ev, - struct messaging_context *msg, - struct loadparm_context *lp_ctx, - struct auth_context **auth_ctx) -{ - int i; - struct auth_context *ctx; - - if (!methods) { - DEBUG(0,("auth_context_create: No auth method list!?\n")); - return NT_STATUS_INTERNAL_ERROR; - } - - if (!ev) { - DEBUG(0,("auth_context_create: called with out event context\n")); - return NT_STATUS_INTERNAL_ERROR; - } - - if (!msg) { - DEBUG(0,("auth_context_create: called with out messaging context\n")); - return NT_STATUS_INTERNAL_ERROR; - } - - ctx = talloc(mem_ctx, struct auth_context); - NT_STATUS_HAVE_NO_MEMORY(ctx); - ctx->challenge.set_by = NULL; - ctx->challenge.may_be_modified = false; - ctx->challenge.data = data_blob(NULL, 0); - ctx->methods = NULL; - ctx->event_ctx = ev; - ctx->msg_ctx = msg; - ctx->lp_ctx = lp_ctx; - - for (i=0; methods[i] ; i++) { - struct auth_method_context *method; - - method = talloc(ctx, struct auth_method_context); - NT_STATUS_HAVE_NO_MEMORY(method); - - method->ops = auth_backend_byname(methods[i]); - if (!method->ops) { - DEBUG(1,("auth_context_create: failed to find method=%s\n", - methods[i])); - return NT_STATUS_INTERNAL_ERROR; - } - method->auth_ctx = ctx; - method->depth = i; - DLIST_ADD_END(ctx->methods, method, struct auth_method_context *); - } - - if (!ctx->methods) { - return NT_STATUS_INTERNAL_ERROR; - } - - *auth_ctx = ctx; - - return NT_STATUS_OK; -} -/*************************************************************************** - Make a auth_info struct for the auth subsystem - - Uses default auth_methods, depending on server role and smb.conf settings -***************************************************************************/ -_PUBLIC_ NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx, - struct event_context *ev, - struct messaging_context *msg, - struct loadparm_context *lp_ctx, - struct auth_context **auth_ctx) -{ - const char **auth_methods = NULL; - switch (lp_server_role(lp_ctx)) { - case ROLE_STANDALONE: - auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "standalone", NULL); - break; - case ROLE_DOMAIN_MEMBER: - auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "member server", NULL); - break; - case ROLE_DOMAIN_CONTROLLER: - auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "domain controller", NULL); - break; - } - return auth_context_create_methods(mem_ctx, auth_methods, ev, msg, lp_ctx, auth_ctx); -} - - -/* the list of currently registered AUTH backends */ -static struct auth_backend { - const struct auth_operations *ops; -} *backends = NULL; -static int num_backends; - -/* - register a AUTH backend. - - The 'name' can be later used by other backends to find the operations - structure for this backend. -*/ -_PUBLIC_ NTSTATUS auth_register(const struct auth_operations *ops) -{ - struct auth_operations *new_ops; - - if (auth_backend_byname(ops->name) != NULL) { - /* its already registered! */ - DEBUG(0,("AUTH backend '%s' already registered\n", - ops->name)); - return NT_STATUS_OBJECT_NAME_COLLISION; - } - - backends = talloc_realloc(talloc_autofree_context(), backends, - struct auth_backend, num_backends+1); - NT_STATUS_HAVE_NO_MEMORY(backends); - - new_ops = talloc_memdup(backends, ops, sizeof(*ops)); - NT_STATUS_HAVE_NO_MEMORY(new_ops); - new_ops->name = talloc_strdup(new_ops, ops->name); - NT_STATUS_HAVE_NO_MEMORY(new_ops->name); - - backends[num_backends].ops = new_ops; - - num_backends++; - - DEBUG(3,("AUTH backend '%s' registered\n", - ops->name)); - - return NT_STATUS_OK; -} - -/* - return the operations structure for a named backend of the specified type -*/ -const struct auth_operations *auth_backend_byname(const char *name) -{ - int i; - - for (i=0;iname, name) == 0) { - return backends[i].ops; - } - } - - return NULL; -} - -/* - return the AUTH interface version, and the size of some critical types - This can be used by backends to either detect compilation errors, or provide - multiple implementations for different smbd compilation options in one module -*/ -const struct auth_critical_sizes *auth_interface_version(void) -{ - static const struct auth_critical_sizes critical_sizes = { - AUTH_INTERFACE_VERSION, - sizeof(struct auth_operations), - sizeof(struct auth_method_context), - sizeof(struct auth_context), - sizeof(struct auth_usersupplied_info), - sizeof(struct auth_serversupplied_info) - }; - - return &critical_sizes; -} - -_PUBLIC_ NTSTATUS auth_init(void) -{ - static bool initialized = false; - extern NTSTATUS auth_developer_init(void); - extern NTSTATUS auth_winbind_init(void); - extern NTSTATUS auth_anonymous_init(void); - extern NTSTATUS auth_unix_init(void); - extern NTSTATUS auth_sam_init(void); - extern NTSTATUS auth_server_init(void); - - init_module_fn static_init[] = { STATIC_auth_MODULES }; - - if (initialized) return NT_STATUS_OK; - initialized = true; - - run_init_functions(static_init); - - return NT_STATUS_OK; -} - -NTSTATUS server_service_auth_init(void) -{ - return auth_init(); -} diff --git a/source4/auth/auth_anonymous.c b/source4/auth/auth_anonymous.c deleted file mode 100644 index b93c7c2008..0000000000 --- a/source4/auth/auth_anonymous.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - Anonymous Authentification - - Copyright (C) Stefan Metzmacher 2004-2005 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "includes.h" -#include "auth/auth.h" -#include "auth/auth_proto.h" -#include "param/param.h" - -/** - * Return a anonymous logon for anonymous users (username = "") - * - * Typically used as the first module in the auth chain, this allows - * anonymou logons to be dealt with in one place. Non-anonymou logons 'fail' - * and pass onto the next module. - **/ -static NTSTATUS anonymous_want_check(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info) -{ - if (user_info->client.account_name && *user_info->client.account_name) { - return NT_STATUS_NOT_IMPLEMENTED; - } - - return NT_STATUS_OK; -} - -/** - * Return a anonymous logon for anonymous users (username = "") - * - * Typically used as the first module in the auth chain, this allows - * anonymou logons to be dealt with in one place. Non-anonymou logons 'fail' - * and pass onto the next module. - **/ -static NTSTATUS anonymous_check_password(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info, - struct auth_serversupplied_info **_server_info) -{ - return auth_anonymous_server_info(mem_ctx, lp_netbios_name(ctx->auth_ctx->lp_ctx), _server_info); -} - -static const struct auth_operations anonymous_auth_ops = { - .name = "anonymous", - .get_challenge = auth_get_challenge_not_implemented, - .want_check = anonymous_want_check, - .check_password = anonymous_check_password -}; - -_PUBLIC_ NTSTATUS auth_anonymous_init(void) -{ - NTSTATUS ret; - - ret = auth_register(&anonymous_auth_ops); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register 'anonymous' auth backend!\n")); - return ret; - } - - return ret; -} diff --git a/source4/auth/auth_developer.c b/source4/auth/auth_developer.c deleted file mode 100644 index a2c9cbc828..0000000000 --- a/source4/auth/auth_developer.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Generic authentication types - Copyright (C) Andrew Bartlett 2001-2002 - Copyright (C) Jelmer Vernooij 2002 - Copyright (C) Stefan Metzmacher 2005 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "includes.h" -#include "auth/auth.h" -#include "auth/auth_proto.h" -#include "libcli/security/security.h" -#include "librpc/gen_ndr/ndr_samr.h" - -static NTSTATUS name_to_ntstatus_want_check(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info) -{ - return NT_STATUS_OK; -} - -/** - * Return an error based on username - * - * This function allows the testing of obsure errors, as well as the generation - * of NT_STATUS -> DOS error mapping tables. - * - * This module is of no value to end-users. - * - * The password is ignored. - * - * @return An NTSTATUS value based on the username - **/ - -static NTSTATUS name_to_ntstatus_check_password(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info, - struct auth_serversupplied_info **_server_info) -{ - NTSTATUS nt_status; - struct auth_serversupplied_info *server_info; - uint32_t error_num; - const char *user; - - user = user_info->client.account_name; - - if (strncasecmp("NT_STATUS", user, strlen("NT_STATUS")) == 0) { - nt_status = nt_status_string_to_code(user); - } else { - error_num = strtoul(user, NULL, 16); - DEBUG(5,("name_to_ntstatus_check_password: Error for user %s was 0x%08X\n", user, error_num)); - nt_status = NT_STATUS(error_num); - } - NT_STATUS_NOT_OK_RETURN(nt_status); - - server_info = talloc(mem_ctx, struct auth_serversupplied_info); - NT_STATUS_HAVE_NO_MEMORY(server_info); - - server_info->account_sid = dom_sid_parse_talloc(server_info, SID_NT_ANONYMOUS); - NT_STATUS_HAVE_NO_MEMORY(server_info->account_sid); - - /* is this correct? */ - server_info->primary_group_sid = dom_sid_parse_talloc(server_info, SID_BUILTIN_GUESTS); - NT_STATUS_HAVE_NO_MEMORY(server_info->primary_group_sid); - - server_info->n_domain_groups = 0; - server_info->domain_groups = NULL; - - /* annoying, but the Anonymous really does have a session key, - and it is all zeros! */ - server_info->user_session_key = data_blob_talloc(server_info, NULL, 16); - NT_STATUS_HAVE_NO_MEMORY(server_info->user_session_key.data); - - server_info->lm_session_key = data_blob_talloc(server_info, NULL, 16); - NT_STATUS_HAVE_NO_MEMORY(server_info->lm_session_key.data); - - data_blob_clear(&server_info->user_session_key); - data_blob_clear(&server_info->lm_session_key); - - server_info->account_name = talloc_asprintf(server_info, "NAME TO NTSTATUS %s ANONYMOUS LOGON", user); - NT_STATUS_HAVE_NO_MEMORY(server_info->account_name); - - server_info->domain_name = talloc_strdup(server_info, "NT AUTHORITY"); - NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name); - - server_info->full_name = talloc_asprintf(server_info, "NAME TO NTSTATUS %s Anonymous Logon", user); - NT_STATUS_HAVE_NO_MEMORY(server_info->full_name); - - server_info->logon_script = talloc_strdup(server_info, ""); - NT_STATUS_HAVE_NO_MEMORY(server_info->logon_script); - - server_info->profile_path = talloc_strdup(server_info, ""); - NT_STATUS_HAVE_NO_MEMORY(server_info->profile_path); - - server_info->home_directory = talloc_strdup(server_info, ""); - NT_STATUS_HAVE_NO_MEMORY(server_info->home_directory); - - server_info->home_drive = talloc_strdup(server_info, ""); - NT_STATUS_HAVE_NO_MEMORY(server_info->home_drive); - - server_info->last_logon = 0; - server_info->last_logoff = 0; - server_info->acct_expiry = 0; - server_info->last_password_change = 0; - server_info->allow_password_change = 0; - server_info->force_password_change = 0; - - server_info->logon_count = 0; - server_info->bad_password_count = 0; - - server_info->acct_flags = ACB_NORMAL; - - server_info->authenticated = false; - - *_server_info = server_info; - - return nt_status; -} - -static const struct auth_operations name_to_ntstatus_auth_ops = { - .name = "name_to_ntstatus", - .get_challenge = auth_get_challenge_not_implemented, - .want_check = name_to_ntstatus_want_check, - .check_password = name_to_ntstatus_check_password -}; - -/** - * Return a 'fixed' challenge instead of a variable one. - * - * The idea of this function is to make packet snifs consistant - * with a fixed challenge, so as to aid debugging. - * - * This module is of no value to end-users. - * - * This module does not actually authenticate the user, but - * just pretenteds to need a specified challenge. - * This module removes *all* security from the challenge-response system - * - * @return NT_STATUS_UNSUCCESSFUL - **/ -static NTSTATUS fixed_challenge_get_challenge(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, DATA_BLOB *_blob) -{ - DATA_BLOB blob; - const char *challenge = "I am a teapot"; - - blob = data_blob_talloc(mem_ctx, challenge, 8); - NT_STATUS_HAVE_NO_MEMORY(blob.data); - - *_blob = blob; - return NT_STATUS_OK; -} - -static NTSTATUS fixed_challenge_want_check(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info) -{ - /* don't handle any users */ - return NT_STATUS_NOT_IMPLEMENTED; -} - -static NTSTATUS fixed_challenge_check_password(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info, - struct auth_serversupplied_info **_server_info) -{ - /* don't handle any users */ - return NT_STATUS_NO_SUCH_USER; -} - -static const struct auth_operations fixed_challenge_auth_ops = { - .name = "fixed_challenge", - .get_challenge = fixed_challenge_get_challenge, - .want_check = fixed_challenge_want_check, - .check_password = fixed_challenge_check_password -}; - -_PUBLIC_ NTSTATUS auth_developer_init(void) -{ - NTSTATUS ret; - - ret = auth_register(&name_to_ntstatus_auth_ops); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register 'name_to_ntstatus' auth backend!\n")); - return ret; - } - - ret = auth_register(&fixed_challenge_auth_ops); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register 'fixed_challenge' auth backend!\n")); - return ret; - } - - return ret; -} diff --git a/source4/auth/auth_sam.c b/source4/auth/auth_sam.c deleted file mode 100644 index 731e489ba0..0000000000 --- a/source4/auth/auth_sam.c +++ /dev/null @@ -1,448 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Password and authentication handling - Copyright (C) Andrew Bartlett 2001-2004 - Copyright (C) Gerald Carter 2003 - Copyright (C) Stefan Metzmacher 2005 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "includes.h" -#include "librpc/gen_ndr/ndr_netlogon.h" -#include "system/time.h" -#include "lib/ldb/include/ldb.h" -#include "util/util_ldb.h" -#include "auth/auth.h" -#include "auth/auth_proto.h" -#include "auth/auth_sam.h" -#include "dsdb/samdb/samdb.h" -#include "libcli/security/security.h" -#include "libcli/ldap/ldap_ndr.h" -#include "param/param.h" - -extern const char *user_attrs[]; -extern const char *domain_ref_attrs[]; - -/**************************************************************************** - Look for the specified user in the sam, return ldb result structures -****************************************************************************/ - -static NTSTATUS authsam_search_account(TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx, - const char *account_name, - const char *domain_name, - struct ldb_message ***ret_msgs, - struct ldb_message ***ret_msgs_domain_ref) -{ - struct ldb_message **msgs_tmp; - struct ldb_message **msgs; - struct ldb_message **msgs_domain_ref; - struct ldb_dn *partitions_basedn = samdb_partitions_dn(sam_ctx, mem_ctx); - - int ret; - int ret_domain; - - struct ldb_dn *domain_dn = NULL; - - if (domain_name) { - domain_dn = samdb_domain_to_dn(sam_ctx, mem_ctx, domain_name); - if (!domain_dn) { - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - } - - /* pull the user attributes */ - ret = gendb_search(sam_ctx, mem_ctx, domain_dn, &msgs, user_attrs, - "(&(sAMAccountName=%s)(objectclass=user))", - ldb_binary_encode_string(mem_ctx, account_name)); - if (ret == -1) { - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - - if (ret == 0) { - DEBUG(3,("sam_search_user: Couldn't find user [%s\\%s] in samdb, under %s\n", - domain_name, account_name, ldb_dn_get_linearized(domain_dn))); - return NT_STATUS_NO_SUCH_USER; - } - - if (ret > 1) { - DEBUG(0,("Found %d records matching user [%s]\n", ret, account_name)); - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - - if (!domain_dn) { - struct dom_sid *domain_sid; - - domain_sid = samdb_result_sid_prefix(mem_ctx, msgs[0], "objectSid"); - if (!domain_sid) { - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - - /* find the domain's DN */ - ret = gendb_search(sam_ctx, mem_ctx, NULL, &msgs_tmp, NULL, - "(&(objectSid=%s)(objectClass=domain))", - ldap_encode_ndr_dom_sid(mem_ctx, domain_sid)); - if (ret == -1) { - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - - if (ret == 0) { - DEBUG(3,("check_sam_security: Couldn't find domain_sid [%s] in passdb file.\n", - dom_sid_string(mem_ctx, domain_sid))); - return NT_STATUS_NO_SUCH_USER; - } - - if (ret > 1) { - DEBUG(0,("Found %d records matching domain_sid [%s]\n", - ret, dom_sid_string(mem_ctx, domain_sid))); - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - - domain_dn = msgs_tmp[0]->dn; - } - - ret_domain = gendb_search(sam_ctx, mem_ctx, partitions_basedn, &msgs_domain_ref, domain_ref_attrs, - "(nCName=%s)", ldb_dn_get_linearized(domain_dn)); - if (ret_domain == -1) { - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - - if (ret_domain == 0) { - DEBUG(3,("check_sam_security: Couldn't find domain [%s] in passdb file.\n", - ldb_dn_get_linearized(msgs_tmp[0]->dn))); - return NT_STATUS_NO_SUCH_USER; - } - - if (ret_domain > 1) { - DEBUG(0,("Found %d records matching domain [%s]\n", - ret_domain, ldb_dn_get_linearized(msgs_tmp[0]->dn))); - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - - *ret_msgs = msgs; - *ret_msgs_domain_ref = msgs_domain_ref; - - return NT_STATUS_OK; -} - -/**************************************************************************** - Do a specific test for an smb password being correct, given a smb_password and - the lanman and NT responses. -****************************************************************************/ -static NTSTATUS authsam_password_ok(struct auth_context *auth_context, - TALLOC_CTX *mem_ctx, - uint16_t acct_flags, - const struct samr_Password *lm_pwd, - const struct samr_Password *nt_pwd, - const struct auth_usersupplied_info *user_info, - DATA_BLOB *user_sess_key, - DATA_BLOB *lm_sess_key) -{ - NTSTATUS status; - - if (acct_flags & ACB_PWNOTREQ) { - if (lp_null_passwords(auth_context->lp_ctx)) { - DEBUG(3,("Account for user '%s' has no password and null passwords are allowed.\n", - user_info->mapped.account_name)); - return NT_STATUS_OK; - } else { - DEBUG(3,("Account for user '%s' has no password and null passwords are NOT allowed.\n", - user_info->mapped.account_name)); - return NT_STATUS_LOGON_FAILURE; - } - } - - switch (user_info->password_state) { - case AUTH_PASSWORD_PLAIN: - { - const struct auth_usersupplied_info *user_info_temp; - status = encrypt_user_info(mem_ctx, auth_context, - AUTH_PASSWORD_HASH, - user_info, &user_info_temp); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Failed to convert plaintext password to password HASH: %s\n", nt_errstr(status))); - return status; - } - user_info = user_info_temp; - - /*fall through*/ - } - case AUTH_PASSWORD_HASH: - *lm_sess_key = data_blob(NULL, 0); - *user_sess_key = data_blob(NULL, 0); - status = hash_password_check(mem_ctx, - auth_context->lp_ctx, - user_info->password.hash.lanman, - user_info->password.hash.nt, - user_info->mapped.account_name, - lm_pwd, nt_pwd); - NT_STATUS_NOT_OK_RETURN(status); - break; - - case AUTH_PASSWORD_RESPONSE: - status = ntlm_password_check(mem_ctx, - auth_context->lp_ctx, - user_info->logon_parameters, - &auth_context->challenge.data, - &user_info->password.response.lanman, - &user_info->password.response.nt, - user_info->mapped.account_name, - user_info->client.account_name, - user_info->client.domain_name, - lm_pwd, nt_pwd, - user_sess_key, lm_sess_key); - NT_STATUS_NOT_OK_RETURN(status); - break; - } - - if (user_sess_key && user_sess_key->data) { - talloc_steal(auth_context, user_sess_key->data); - } - if (lm_sess_key && lm_sess_key->data) { - talloc_steal(auth_context, lm_sess_key->data); - } - - return NT_STATUS_OK; -} - - - -static NTSTATUS authsam_authenticate(struct auth_context *auth_context, - TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx, - struct ldb_message **msgs, - struct ldb_message **msgs_domain_ref, - const struct auth_usersupplied_info *user_info, - DATA_BLOB *user_sess_key, DATA_BLOB *lm_sess_key) -{ - struct samr_Password *lm_pwd, *nt_pwd; - NTSTATUS nt_status; - struct ldb_dn *domain_dn = samdb_result_dn(sam_ctx, mem_ctx, msgs_domain_ref[0], "nCName", NULL); - - uint16_t acct_flags = samdb_result_acct_flags(sam_ctx, mem_ctx, msgs[0], domain_dn); - - /* Quit if the account was locked out. */ - if (acct_flags & ACB_AUTOLOCK) { - DEBUG(3,("check_sam_security: Account for user %s was locked out.\n", - user_info->mapped.account_name)); - return NT_STATUS_ACCOUNT_LOCKED_OUT; - } - - /* You can only do an interactive login to normal accounts */ - if (user_info->flags & USER_INFO_INTERACTIVE_LOGON) { - if (!(acct_flags & ACB_NORMAL)) { - return NT_STATUS_NO_SUCH_USER; - } - } - - nt_status = samdb_result_passwords(mem_ctx, msgs[0], &lm_pwd, &nt_pwd); - NT_STATUS_NOT_OK_RETURN(nt_status); - - nt_status = authsam_password_ok(auth_context, mem_ctx, - acct_flags, lm_pwd, nt_pwd, - user_info, user_sess_key, lm_sess_key); - NT_STATUS_NOT_OK_RETURN(nt_status); - - nt_status = authsam_account_ok(mem_ctx, sam_ctx, - user_info->logon_parameters, - msgs[0], - msgs_domain_ref[0], - user_info->workstation_name, - user_info->mapped.account_name); - - return nt_status; -} - - - -static NTSTATUS authsam_check_password_internals(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const char *domain, - const struct auth_usersupplied_info *user_info, - struct auth_serversupplied_info **server_info) -{ - NTSTATUS nt_status; - const char *account_name = user_info->mapped.account_name; - struct ldb_message **msgs; - struct ldb_message **domain_ref_msgs; - struct ldb_context *sam_ctx; - DATA_BLOB user_sess_key, lm_sess_key; - TALLOC_CTX *tmp_ctx; - - if (!account_name || !*account_name) { - /* 'not for me' */ - return NT_STATUS_NOT_IMPLEMENTED; - } - - tmp_ctx = talloc_new(mem_ctx); - if (!tmp_ctx) { - return NT_STATUS_NO_MEMORY; - } - - sam_ctx = samdb_connect(tmp_ctx, ctx->auth_ctx->event_ctx, ctx->auth_ctx->lp_ctx, system_session(mem_ctx, ctx->auth_ctx->lp_ctx)); - if (sam_ctx == NULL) { - talloc_free(tmp_ctx); - return NT_STATUS_INVALID_SYSTEM_SERVICE; - } - - nt_status = authsam_search_account(tmp_ctx, sam_ctx, account_name, domain, &msgs, &domain_ref_msgs); - if (!NT_STATUS_IS_OK(nt_status)) { - talloc_free(tmp_ctx); - return nt_status; - } - - nt_status = authsam_authenticate(ctx->auth_ctx, tmp_ctx, sam_ctx, msgs, domain_ref_msgs, user_info, - &user_sess_key, &lm_sess_key); - if (!NT_STATUS_IS_OK(nt_status)) { - talloc_free(tmp_ctx); - return nt_status; - } - - nt_status = authsam_make_server_info(tmp_ctx, sam_ctx, lp_netbios_name(ctx->auth_ctx->lp_ctx), - msgs[0], domain_ref_msgs[0], - user_sess_key, lm_sess_key, - server_info); - if (!NT_STATUS_IS_OK(nt_status)) { - talloc_free(tmp_ctx); - return nt_status; - } - - talloc_steal(mem_ctx, *server_info); - talloc_free(tmp_ctx); - - return NT_STATUS_OK; -} - -static NTSTATUS authsam_ignoredomain_want_check(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info) -{ - if (!user_info->mapped.account_name || !*user_info->mapped.account_name) { - return NT_STATUS_NOT_IMPLEMENTED; - } - - return NT_STATUS_OK; -} - -static NTSTATUS authsam_ignoredomain_check_password(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info, - struct auth_serversupplied_info **server_info) -{ - return authsam_check_password_internals(ctx, mem_ctx, NULL, user_info, server_info); -} - -/**************************************************************************** -Check SAM security (above) but with a few extra checks. -****************************************************************************/ -static NTSTATUS authsam_want_check(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info) -{ - bool is_local_name, is_my_domain; - - if (!user_info->mapped.account_name || !*user_info->mapped.account_name) { - return NT_STATUS_NOT_IMPLEMENTED; - } - - is_local_name = lp_is_myname(ctx->auth_ctx->lp_ctx, - user_info->mapped.domain_name); - is_my_domain = lp_is_mydomain(ctx->auth_ctx->lp_ctx, - user_info->mapped.domain_name); - - /* check whether or not we service this domain/workgroup name */ - switch (lp_server_role(ctx->auth_ctx->lp_ctx)) { - case ROLE_STANDALONE: - return NT_STATUS_OK; - - case ROLE_DOMAIN_MEMBER: - if (!is_local_name) { - DEBUG(6,("authsam_check_password: %s is not one of my local names (DOMAIN_MEMBER)\n", - user_info->mapped.domain_name)); - return NT_STATUS_NOT_IMPLEMENTED; - } - return NT_STATUS_OK; - - case ROLE_DOMAIN_CONTROLLER: - if (!is_local_name && !is_my_domain) { - DEBUG(6,("authsam_check_password: %s is not one of my local names or domain name (DC)\n", - user_info->mapped.domain_name)); - return NT_STATUS_NOT_IMPLEMENTED; - } - return NT_STATUS_OK; - } - - DEBUG(6,("authsam_check_password: lp_server_role() has an undefined value\n")); - return NT_STATUS_NOT_IMPLEMENTED; -} - -/**************************************************************************** -Check SAM security (above) but with a few extra checks. -****************************************************************************/ -static NTSTATUS authsam_check_password(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info, - struct auth_serversupplied_info **server_info) -{ - const char *domain; - - /* check whether or not we service this domain/workgroup name */ - switch (lp_server_role(ctx->auth_ctx->lp_ctx)) { - case ROLE_STANDALONE: - case ROLE_DOMAIN_MEMBER: - domain = lp_netbios_name(ctx->auth_ctx->lp_ctx); - break; - - case ROLE_DOMAIN_CONTROLLER: - domain = lp_workgroup(ctx->auth_ctx->lp_ctx); - break; - - default: - return NT_STATUS_NO_SUCH_USER; - } - - return authsam_check_password_internals(ctx, mem_ctx, domain, user_info, server_info); -} - -static const struct auth_operations sam_ignoredomain_ops = { - .name = "sam_ignoredomain", - .get_challenge = auth_get_challenge_not_implemented, - .want_check = authsam_ignoredomain_want_check, - .check_password = authsam_ignoredomain_check_password -}; - -static const struct auth_operations sam_ops = { - .name = "sam", - .get_challenge = auth_get_challenge_not_implemented, - .want_check = authsam_want_check, - .check_password = authsam_check_password -}; - -_PUBLIC_ NTSTATUS auth_sam_init(void) -{ - NTSTATUS ret; - - ret = auth_register(&sam_ops); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register 'sam' auth backend!\n")); - return ret; - } - - ret = auth_register(&sam_ignoredomain_ops); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register 'sam_ignoredomain' auth backend!\n")); - return ret; - } - - return ret; -} diff --git a/source4/auth/auth_server.c b/source4/auth/auth_server.c deleted file mode 100644 index be5f84fe39..0000000000 --- a/source4/auth/auth_server.c +++ /dev/null @@ -1,225 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Authenticate by using a remote server - Copyright (C) Andrew Bartlett 2001-2002, 2008 - Copyright (C) Jelmer Vernooij 2002 - Copyright (C) Stefan Metzmacher 2005 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "includes.h" -#include "auth/auth.h" -#include "auth/auth_proto.h" -#include "auth/credentials/credentials.h" -#include "libcli/security/security.h" -#include "librpc/gen_ndr/ndr_samr.h" -#include "libcli/smb_composite/smb_composite.h" -#include "param/param.h" -#include "libcli/resolve/resolve.h" - -/* This version of 'security=server' rewirtten from scratch for Samba4 - * libraries in 2008 */ - - -static NTSTATUS server_want_check(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info) -{ - return NT_STATUS_OK; -} -/** - * The challenge from the target server, when operating in security=server - **/ -static NTSTATUS server_get_challenge(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, DATA_BLOB *_blob) -{ - struct smb_composite_connect io; - struct smbcli_options smb_options; - const char **host_list; - NTSTATUS status; - - /* Make a connection to the target server, found by 'password server' in smb.conf */ - - lp_smbcli_options(ctx->auth_ctx->lp_ctx, &smb_options); - - /* Make a negprot, WITHOUT SPNEGO, so we get a challenge nice an easy */ - io.in.options.use_spnego = false; - - /* Hope we don't get * (the default), as this won't work... */ - host_list = lp_passwordserver(ctx->auth_ctx->lp_ctx); - if (!host_list) { - return NT_STATUS_INTERNAL_ERROR; - } - io.in.dest_host = host_list[0]; - if (strequal(io.in.dest_host, "*")) { - return NT_STATUS_INTERNAL_ERROR; - } - io.in.dest_ports = lp_smb_ports(ctx->auth_ctx->lp_ctx); - - io.in.called_name = strupper_talloc(mem_ctx, io.in.dest_host); - - /* We don't want to get as far as the session setup */ - io.in.credentials = NULL; - io.in.service = NULL; - - io.in.workgroup = ""; /* only used with SPNEGO, disabled above */ - - io.in.options = smb_options; - - status = smb_composite_connect(&io, mem_ctx, lp_resolve_context(ctx->auth_ctx->lp_ctx), - ctx->auth_ctx->event_ctx); - if (!NT_STATUS_IS_OK(status)) { - *_blob = io.out.tree->session->transport->negotiate.secblob; - ctx->private_data = talloc_steal(ctx, io.out.tree->session); - } - return NT_STATUS_OK; -} - -/** - * Return an error based on username - * - * This function allows the testing of obsure errors, as well as the generation - * of NT_STATUS -> DOS error mapping tables. - * - * This module is of no value to end-users. - * - * The password is ignored. - * - * @return An NTSTATUS value based on the username - **/ - -static NTSTATUS server_check_password(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info, - struct auth_serversupplied_info **_server_info) -{ - NTSTATUS nt_status; - struct auth_serversupplied_info *server_info; - struct cli_credentials *creds; - const char *user; - struct smb_composite_sesssetup session_setup; - - struct smbcli_session *session = talloc_get_type(ctx->private_data, struct smbcli_session); - - creds = cli_credentials_init(mem_ctx); - - NT_STATUS_HAVE_NO_MEMORY(creds); - - cli_credentials_set_username(creds, user_info->client.account_name, CRED_SPECIFIED); - cli_credentials_set_domain(creds, user_info->client.domain_name, CRED_SPECIFIED); - - switch (user_info->password_state) { - case AUTH_PASSWORD_PLAIN: - cli_credentials_set_password(creds, user_info->password.plaintext, - CRED_SPECIFIED); - break; - case AUTH_PASSWORD_HASH: - cli_credentials_set_nt_hash(creds, user_info->password.hash.nt, - CRED_SPECIFIED); - break; - - case AUTH_PASSWORD_RESPONSE: - cli_credentials_set_ntlm_response(creds, &user_info->password.response.lanman, &user_info->password.response.nt, CRED_SPECIFIED); - break; - } - - session_setup.in.sesskey = session->transport->negotiate.sesskey; - session_setup.in.capabilities = session->transport->negotiate.capabilities; - - session_setup.in.credentials = creds; - session_setup.in.workgroup = ""; /* Only used with SPNEGO, which we are not doing */ - - /* Check password with remove server - this should be async some day */ - nt_status = smb_composite_sesssetup(session, &session_setup); - - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - - server_info = talloc(mem_ctx, struct auth_serversupplied_info); - NT_STATUS_HAVE_NO_MEMORY(server_info); - - server_info->account_sid = dom_sid_parse_talloc(server_info, SID_NT_ANONYMOUS); - NT_STATUS_HAVE_NO_MEMORY(server_info->account_sid); - - /* is this correct? */ - server_info->primary_group_sid = dom_sid_parse_talloc(server_info, SID_BUILTIN_GUESTS); - NT_STATUS_HAVE_NO_MEMORY(server_info->primary_group_sid); - - server_info->n_domain_groups = 0; - server_info->domain_groups = NULL; - - /* annoying, but the Anonymous really does have a session key, - and it is all zeros! */ - server_info->user_session_key = data_blob(NULL, 0); - server_info->lm_session_key = data_blob(NULL, 0); - - server_info->account_name = talloc_strdup(server_info, user_info->client.account_name); - NT_STATUS_HAVE_NO_MEMORY(server_info->account_name); - - server_info->domain_name = talloc_strdup(server_info, user_info->client.domain_name); - NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name); - - server_info->full_name = NULL; - - server_info->logon_script = talloc_strdup(server_info, ""); - NT_STATUS_HAVE_NO_MEMORY(server_info->logon_script); - - server_info->profile_path = talloc_strdup(server_info, ""); - NT_STATUS_HAVE_NO_MEMORY(server_info->profile_path); - - server_info->home_directory = talloc_strdup(server_info, ""); - NT_STATUS_HAVE_NO_MEMORY(server_info->home_directory); - - server_info->home_drive = talloc_strdup(server_info, ""); - NT_STATUS_HAVE_NO_MEMORY(server_info->home_drive); - - server_info->last_logon = 0; - server_info->last_logoff = 0; - server_info->acct_expiry = 0; - server_info->last_password_change = 0; - server_info->allow_password_change = 0; - server_info->force_password_change = 0; - - server_info->logon_count = 0; - server_info->bad_password_count = 0; - - server_info->acct_flags = ACB_NORMAL; - - server_info->authenticated = false; - - *_server_info = server_info; - - return nt_status; -} - -static const struct auth_operations server_auth_ops = { - .name = "server", - .get_challenge = server_get_challenge, - .want_check = server_want_check, - .check_password = server_check_password -}; - -_PUBLIC_ NTSTATUS auth_server_init(void) -{ - NTSTATUS ret; - - ret = auth_register(&server_auth_ops); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register 'server' auth backend!\n")); - return ret; - } - - return ret; -} diff --git a/source4/auth/auth_simple.c b/source4/auth/auth_simple.c deleted file mode 100644 index e7039c3657..0000000000 --- a/source4/auth/auth_simple.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - auth functions - - Copyright (C) Simo Sorce 2005 - Copyright (C) Andrew Tridgell 2005 - Copyright (C) Andrew Bartlett 2005 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "includes.h" -#include "auth/auth.h" -#include "lib/events/events.h" -#include "param/param.h" -#include "auth/session_proto.h" - -/* - It's allowed to pass NULL as session_info, - when the caller doesn't need a session_info -*/ -_PUBLIC_ NTSTATUS authenticate_username_pw(TALLOC_CTX *mem_ctx, - struct event_context *ev, - struct messaging_context *msg, - struct loadparm_context *lp_ctx, - const char *nt4_domain, - const char *nt4_username, - const char *password, - struct auth_session_info **session_info) -{ - struct auth_context *auth_context; - struct auth_usersupplied_info *user_info; - struct auth_serversupplied_info *server_info; - NTSTATUS nt_status; - TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); - - if (!tmp_ctx) { - return NT_STATUS_NO_MEMORY; - } - - nt_status = auth_context_create(tmp_ctx, - ev, msg, - lp_ctx, - &auth_context); - if (!NT_STATUS_IS_OK(nt_status)) { - talloc_free(tmp_ctx); - return nt_status; - } - - user_info = talloc(tmp_ctx, struct auth_usersupplied_info); - if (!user_info) { - talloc_free(tmp_ctx); - return NT_STATUS_NO_MEMORY; - } - - user_info->mapped_state = true; - user_info->client.account_name = nt4_username; - user_info->mapped.account_name = nt4_username; - user_info->client.domain_name = nt4_domain; - user_info->mapped.domain_name = nt4_domain; - - user_info->workstation_name = NULL; - - user_info->remote_host = NULL; - - user_info->password_state = AUTH_PASSWORD_PLAIN; - user_info->password.plaintext = talloc_strdup(user_info, password); - - user_info->flags = USER_INFO_CASE_INSENSITIVE_USERNAME | - USER_INFO_DONT_CHECK_UNIX_ACCOUNT; - - user_info->logon_parameters = 0; - - nt_status = auth_check_password(auth_context, tmp_ctx, user_info, &server_info); - if (!NT_STATUS_IS_OK(nt_status)) { - talloc_free(tmp_ctx); - return nt_status; - } - - if (session_info) { - nt_status = auth_generate_session_info(tmp_ctx, ev, lp_ctx, server_info, session_info); - - if (NT_STATUS_IS_OK(nt_status)) { - talloc_steal(mem_ctx, *session_info); - } - } - - talloc_free(tmp_ctx); - return nt_status; -} - diff --git a/source4/auth/auth_unix.c b/source4/auth/auth_unix.c deleted file mode 100644 index a417107025..0000000000 --- a/source4/auth/auth_unix.c +++ /dev/null @@ -1,844 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Password and authentication handling - Copyright (C) Andrew Bartlett 2001 - Copyright (C) Jeremy Allison 2001 - Copyright (C) Simo Sorce 2005 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "includes.h" -#include "auth/auth.h" -#include "auth/auth_proto.h" -#include "system/passwd.h" /* needed by some systems for struct passwd */ -#include "lib/socket/socket.h" -#include "auth/pam_errors.h" -#include "param/param.h" - -/* TODO: look at how to best fill in parms retrieveing a struct passwd info - * except in case USER_INFO_DONT_CHECK_UNIX_ACCOUNT is set - */ -static NTSTATUS authunix_make_server_info(TALLOC_CTX *mem_ctx, - const char *netbios_name, - const struct auth_usersupplied_info *user_info, - struct passwd *pwd, - struct auth_serversupplied_info **_server_info) -{ - struct auth_serversupplied_info *server_info; - NTSTATUS status; - - /* This is a real, real hack */ - if (pwd->pw_uid == 0) { - status = auth_system_server_info(mem_ctx, netbios_name, &server_info); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - server_info->account_name = talloc_steal(server_info, pwd->pw_name); - NT_STATUS_HAVE_NO_MEMORY(server_info->account_name); - - server_info->domain_name = talloc_strdup(server_info, "unix"); - NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name); - } else { - server_info = talloc(mem_ctx, struct auth_serversupplied_info); - NT_STATUS_HAVE_NO_MEMORY(server_info); - - server_info->authenticated = true; - - server_info->account_name = talloc_steal(server_info, pwd->pw_name); - NT_STATUS_HAVE_NO_MEMORY(server_info->account_name); - - server_info->domain_name = talloc_strdup(server_info, "unix"); - NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name); - - /* This isn't in any way correct.. */ - server_info->account_sid = NULL; - server_info->primary_group_sid = NULL; - server_info->n_domain_groups = 0; - server_info->domain_groups = NULL; - } - server_info->user_session_key = data_blob(NULL,0); - server_info->lm_session_key = data_blob(NULL,0); - - server_info->full_name = talloc_steal(server_info, pwd->pw_gecos); - NT_STATUS_HAVE_NO_MEMORY(server_info->full_name); - server_info->logon_script = talloc_strdup(server_info, ""); - NT_STATUS_HAVE_NO_MEMORY(server_info->logon_script); - server_info->profile_path = talloc_strdup(server_info, ""); - NT_STATUS_HAVE_NO_MEMORY(server_info->profile_path); - server_info->home_directory = talloc_strdup(server_info, ""); - NT_STATUS_HAVE_NO_MEMORY(server_info->home_directory); - server_info->home_drive = talloc_strdup(server_info, ""); - NT_STATUS_HAVE_NO_MEMORY(server_info->home_drive); - - server_info->last_logon = 0; - server_info->last_logoff = 0; - server_info->acct_expiry = 0; - server_info->last_password_change = 0; - server_info->allow_password_change = 0; - server_info->force_password_change = 0; - server_info->logon_count = 0; - server_info->bad_password_count = 0; - server_info->acct_flags = 0; - - *_server_info = server_info; - - return NT_STATUS_OK; -} - -static NTSTATUS talloc_getpwnam(TALLOC_CTX *ctx, const char *username, struct passwd **pws) -{ - struct passwd *ret; - struct passwd *from; - - *pws = NULL; - - ret = talloc(ctx, struct passwd); - NT_STATUS_HAVE_NO_MEMORY(ret); - - from = getpwnam(username); - if (!from) { - return NT_STATUS_NO_SUCH_USER; - } - - ret->pw_name = talloc_strdup(ctx, from->pw_name); - NT_STATUS_HAVE_NO_MEMORY(ret->pw_name); - - ret->pw_passwd = talloc_strdup(ctx, from->pw_passwd); - NT_STATUS_HAVE_NO_MEMORY(ret->pw_passwd); - - ret->pw_uid = from->pw_uid; - ret->pw_gid = from->pw_gid; - ret->pw_gecos = talloc_strdup(ctx, from->pw_gecos); - NT_STATUS_HAVE_NO_MEMORY(ret->pw_gecos); - - ret->pw_dir = talloc_strdup(ctx, from->pw_dir); - NT_STATUS_HAVE_NO_MEMORY(ret->pw_dir); - - ret->pw_shell = talloc_strdup(ctx, from->pw_shell); - NT_STATUS_HAVE_NO_MEMORY(ret->pw_shell); - - *pws = ret; - - return NT_STATUS_OK; -} - - -#ifdef HAVE_SECURITY_PAM_APPL_H -#include - -struct smb_pam_user_info { - const char *account_name; - const char *plaintext_password; -}; - -#define COPY_STRING(s) (s) ? strdup(s) : NULL - -/* - * Check user password - * Currently it uses PAM only and fails on systems without PAM - * Samba3 code located in pass_check.c is to ugly to be used directly it will - * need major rework that's why pass_check.c is still there. -*/ - -static int smb_pam_conv(int num_msg, const struct pam_message **msg, - struct pam_response **reply, void *appdata_ptr) -{ - struct smb_pam_user_info *info = (struct smb_pam_user_info *)appdata_ptr; - int num; - - if (num_msg <= 0) { - *reply = NULL; - return PAM_CONV_ERR; - } - - /* - * Apparantly HPUX has a buggy PAM that doesn't support the - * data pointer. Fail if this is the case. JRA. - */ - - if (info == NULL) { - *reply = NULL; - return PAM_CONV_ERR; - } - - /* - * PAM frees memory in reply messages by itself - * so use malloc instead of talloc here. - */ - *reply = malloc_array_p(struct pam_response, num_msg); - if (*reply == NULL) { - return PAM_CONV_ERR; - } - - for (num = 0; num < num_msg; num++) { - switch (msg[num]->msg_style) { - case PAM_PROMPT_ECHO_ON: - (*reply)[num].resp_retcode = PAM_SUCCESS; - (*reply)[num].resp = COPY_STRING(info->account_name); - break; - - case PAM_PROMPT_ECHO_OFF: - (*reply)[num].resp_retcode = PAM_SUCCESS; - (*reply)[num].resp = COPY_STRING(info->plaintext_password); - break; - - case PAM_TEXT_INFO: - (*reply)[num].resp_retcode = PAM_SUCCESS; - (*reply)[num].resp = NULL; - DEBUG(4,("PAM Info message in conversation function: %s\n", (msg[num]->msg))); - break; - - case PAM_ERROR_MSG: - (*reply)[num].resp_retcode = PAM_SUCCESS; - (*reply)[num].resp = NULL; - DEBUG(4,("PAM Error message in conversation function: %s\n", (msg[num]->msg))); - break; - - default: - while (num > 0) { - SAFE_FREE((*reply)[num-1].resp); - num--; - } - SAFE_FREE(*reply); - *reply = NULL; - DEBUG(1,("Error: PAM subsystme sent an UNKNOWN message type to the conversation function!\n")); - return PAM_CONV_ERR; - } - } - - return PAM_SUCCESS; -} - -/* - * Start PAM authentication for specified account - */ - -static NTSTATUS smb_pam_start(pam_handle_t **pamh, const char *account_name, const char *remote_host, struct pam_conv *pconv) -{ - int pam_error; - - if (account_name == NULL || remote_host == NULL) { - return NT_STATUS_INVALID_PARAMETER; - } - - DEBUG(4,("smb_pam_start: PAM: Init user: %s\n", account_name)); - - pam_error = pam_start("samba", account_name, pconv, pamh); - if (pam_error != PAM_SUCCESS) { - /* no valid pamh here, can we reliably call pam_strerror ? */ - DEBUG(4,("smb_pam_start: pam_start failed!\n")); - return NT_STATUS_UNSUCCESSFUL; - } - -#ifdef PAM_RHOST - DEBUG(4,("smb_pam_start: PAM: setting rhost to: %s\n", remote_host)); - pam_error = pam_set_item(*pamh, PAM_RHOST, remote_host); - if (pam_error != PAM_SUCCESS) { - NTSTATUS nt_status; - - DEBUG(4,("smb_pam_start: setting rhost failed with error: %s\n", - pam_strerror(*pamh, pam_error))); - nt_status = pam_to_nt_status(pam_error); - - pam_error = pam_end(*pamh, 0); - if (pam_error != PAM_SUCCESS) { - /* no vaild pamh here, can we reliably call pam_strerror ? */ - DEBUG(4,("smb_pam_start: clean up failed, pam_end gave error %d.\n", - pam_error)); - return pam_to_nt_status(pam_error); - } - return nt_status; - } -#endif -#ifdef PAM_TTY - DEBUG(4,("smb_pam_start: PAM: setting tty\n")); - pam_error = pam_set_item(*pamh, PAM_TTY, "samba"); - if (pam_error != PAM_SUCCESS) { - NTSTATUS nt_status; - - DEBUG(4,("smb_pam_start: setting tty failed with error: %s\n", - pam_strerror(*pamh, pam_error))); - nt_status = pam_to_nt_status(pam_error); - - pam_error = pam_end(*pamh, 0); - if (pam_error != PAM_SUCCESS) { - /* no vaild pamh here, can we reliably call pam_strerror ? */ - DEBUG(4,("smb_pam_start: clean up failed, pam_end gave error %d.\n", - pam_error)); - return pam_to_nt_status(pam_error); - } - return nt_status; - } -#endif - DEBUG(4,("smb_pam_start: PAM: Init passed for user: %s\n", account_name)); - - return NT_STATUS_OK; -} - -static NTSTATUS smb_pam_end(pam_handle_t *pamh) -{ - int pam_error; - - if (pamh != NULL) { - pam_error = pam_end(pamh, 0); - if (pam_error != PAM_SUCCESS) { - /* no vaild pamh here, can we reliably call pam_strerror ? */ - DEBUG(4,("smb_pam_end: clean up failed, pam_end gave error %d.\n", - pam_error)); - return pam_to_nt_status(pam_error); - } - return NT_STATUS_OK; - } - - DEBUG(2,("smb_pam_end: pamh is NULL, PAM not initialized ?\n")); - return NT_STATUS_UNSUCCESSFUL; -} - -/* - * PAM Authentication Handler - */ -static NTSTATUS smb_pam_auth(pam_handle_t *pamh, bool allow_null_passwords, const char *user) -{ - int pam_error; - - /* - * To enable debugging set in /etc/pam.d/samba: - * auth required /lib/security/pam_pwdb.so nullok shadow audit - */ - - DEBUG(4,("smb_pam_auth: PAM: Authenticate User: %s\n", user)); - - pam_error = pam_authenticate(pamh, PAM_SILENT | allow_null_passwords ? 0 : PAM_DISALLOW_NULL_AUTHTOK); - switch( pam_error ){ - case PAM_AUTH_ERR: - DEBUG(2, ("smb_pam_auth: PAM: Authentication Error for user %s\n", user)); - break; - case PAM_CRED_INSUFFICIENT: - DEBUG(2, ("smb_pam_auth: PAM: Insufficient Credentials for user %s\n", user)); - break; - case PAM_AUTHINFO_UNAVAIL: - DEBUG(2, ("smb_pam_auth: PAM: Authentication Information Unavailable for user %s\n", user)); - break; - case PAM_USER_UNKNOWN: - DEBUG(2, ("smb_pam_auth: PAM: Username %s NOT known to Authentication system\n", user)); - break; - case PAM_MAXTRIES: - DEBUG(2, ("smb_pam_auth: PAM: One or more authentication modules reports user limit for user %s exceeeded\n", user)); - break; - case PAM_ABORT: - DEBUG(0, ("smb_pam_auth: PAM: One or more PAM modules failed to load for user %s\n", user)); - break; - case PAM_SUCCESS: - DEBUG(4, ("smb_pam_auth: PAM: User %s Authenticated OK\n", user)); - break; - default: - DEBUG(0, ("smb_pam_auth: PAM: UNKNOWN ERROR while authenticating user %s\n", user)); - break; - } - - return pam_to_nt_status(pam_error); -} - -/* - * PAM Account Handler - */ -static NTSTATUS smb_pam_account(pam_handle_t *pamh, const char * user) -{ - int pam_error; - - DEBUG(4,("smb_pam_account: PAM: Account Management for User: %s\n", user)); - - pam_error = pam_acct_mgmt(pamh, PAM_SILENT); /* Is user account enabled? */ - switch( pam_error ) { - case PAM_AUTHTOK_EXPIRED: - DEBUG(2, ("smb_pam_account: PAM: User %s is valid but password is expired\n", user)); - break; - case PAM_ACCT_EXPIRED: - DEBUG(2, ("smb_pam_account: PAM: User %s no longer permitted to access system\n", user)); - break; - case PAM_AUTH_ERR: - DEBUG(2, ("smb_pam_account: PAM: There was an authentication error for user %s\n", user)); - break; - case PAM_PERM_DENIED: - DEBUG(0, ("smb_pam_account: PAM: User %s is NOT permitted to access system at this time\n", user)); - break; - case PAM_USER_UNKNOWN: - DEBUG(0, ("smb_pam_account: PAM: User \"%s\" is NOT known to account management\n", user)); - break; - case PAM_SUCCESS: - DEBUG(4, ("smb_pam_account: PAM: Account OK for User: %s\n", user)); - break; - default: - DEBUG(0, ("smb_pam_account: PAM: UNKNOWN PAM ERROR (%d) during Account Management for User: %s\n", pam_error, user)); - break; - } - - return pam_to_nt_status(pam_error); -} - -/* - * PAM Credential Setting - */ - -static NTSTATUS smb_pam_setcred(pam_handle_t *pamh, const char * user) -{ - int pam_error; - - /* - * This will allow samba to aquire a kerberos token. And, when - * exporting an AFS cell, be able to /write/ to this cell. - */ - - DEBUG(4,("PAM: Account Management SetCredentials for User: %s\n", user)); - - pam_error = pam_setcred(pamh, (PAM_ESTABLISH_CRED|PAM_SILENT)); - switch( pam_error ) { - case PAM_CRED_UNAVAIL: - DEBUG(0, ("smb_pam_setcred: PAM: Credentials not found for user:%s\n", user )); - break; - case PAM_CRED_EXPIRED: - DEBUG(0, ("smb_pam_setcred: PAM: Credentials for user: \"%s\" EXPIRED!\n", user )); - break; - case PAM_USER_UNKNOWN: - DEBUG(0, ("smb_pam_setcred: PAM: User: \"%s\" is NOT known so can not set credentials!\n", user )); - break; - case PAM_CRED_ERR: - DEBUG(0, ("smb_pam_setcred: PAM: Unknown setcredentials error - unable to set credentials for %s\n", user )); - break; - case PAM_SUCCESS: - DEBUG(4, ("smb_pam_setcred: PAM: SetCredentials OK for User: %s\n", user)); - break; - default: - DEBUG(0, ("smb_pam_setcred: PAM: UNKNOWN PAM ERROR (%d) during SetCredentials for User: %s\n", pam_error, user)); - break; - } - - return pam_to_nt_status(pam_error); -} - -static NTSTATUS check_unix_password(TALLOC_CTX *ctx, struct loadparm_context *lp_ctx, - const struct auth_usersupplied_info *user_info, struct passwd **pws) -{ - struct smb_pam_user_info *info; - struct pam_conv *pamconv; - pam_handle_t *pamh; - NTSTATUS nt_status; - - info = talloc(ctx, struct smb_pam_user_info); - if (info == NULL) { - return NT_STATUS_NO_MEMORY; - } - - info->account_name = user_info->mapped.account_name; - info->plaintext_password = user_info->password.plaintext; - - pamconv = talloc(ctx, struct pam_conv); - if (pamconv == NULL) { - return NT_STATUS_NO_MEMORY; - } - - pamconv->conv = smb_pam_conv; - pamconv->appdata_ptr = (void *)info; - - /* TODO: - * check for user_info->flags & USER_INFO_CASE_INSENSITIVE_USERNAME - * if true set up a crack name routine. - */ - - nt_status = smb_pam_start(&pamh, user_info->mapped.account_name, user_info->remote_host ? user_info->remote_host->addr : NULL, pamconv); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - - nt_status = smb_pam_auth(pamh, lp_null_passwords(lp_ctx), user_info->mapped.account_name); - if (!NT_STATUS_IS_OK(nt_status)) { - smb_pam_end(pamh); - return nt_status; - } - - if ( ! (user_info->flags & USER_INFO_DONT_CHECK_UNIX_ACCOUNT)) { - - nt_status = smb_pam_account(pamh, user_info->mapped.account_name); - if (!NT_STATUS_IS_OK(nt_status)) { - smb_pam_end(pamh); - return nt_status; - } - - nt_status = smb_pam_setcred(pamh, user_info->mapped.account_name); - if (!NT_STATUS_IS_OK(nt_status)) { - smb_pam_end(pamh); - return nt_status; - } - } - - smb_pam_end(pamh); - - nt_status = talloc_getpwnam(ctx, user_info->mapped.account_name, pws); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - - return NT_STATUS_OK; -} - -#else - -/**************************************************************************** -core of password checking routine -****************************************************************************/ -static NTSTATUS password_check(const char *username, const char *password, - const char *crypted, const char *salt) -{ - bool ret; - -#ifdef WITH_AFS - if (afs_auth(username, password)) - return NT_STATUS_OK; -#endif /* WITH_AFS */ - -#ifdef WITH_DFS - if (dfs_auth(username, password)) - return NT_STATUS_OK; -#endif /* WITH_DFS */ - -#ifdef OSF1_ENH_SEC - - ret = (strcmp(osf1_bigcrypt(password, salt), crypted) == 0); - - if (!ret) { - DEBUG(2, - ("OSF1_ENH_SEC failed. Trying normal crypt.\n")); - ret = (strcmp((char *)crypt(password, salt), crypted) == 0); - } - if (ret) { - return NT_STATUS_OK; - } else { - return NT_STATUS_WRONG_PASSWORD; - } - -#endif /* OSF1_ENH_SEC */ - -#ifdef ULTRIX_AUTH - ret = (strcmp((char *)crypt16(password, salt), crypted) == 0); - if (ret) { - return NT_STATUS_OK; - } else { - return NT_STATUS_WRONG_PASSWORD; - } - -#endif /* ULTRIX_AUTH */ - -#ifdef LINUX_BIGCRYPT - ret = (linux_bigcrypt(password, salt, crypted)); - if (ret) { - return NT_STATUS_OK; - } else { - return NT_STATUS_WRONG_PASSWORD; - } -#endif /* LINUX_BIGCRYPT */ - -#if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS) - - /* - * Some systems have bigcrypt in the C library but might not - * actually use it for the password hashes (HPUX 10.20) is - * a noteable example. So we try bigcrypt first, followed - * by crypt. - */ - - if (strcmp(bigcrypt(password, salt), crypted) == 0) - return NT_STATUS_OK; - else - ret = (strcmp((char *)crypt(password, salt), crypted) == 0); - if (ret) { - return NT_STATUS_OK; - } else { - return NT_STATUS_WRONG_PASSWORD; - } -#else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */ - -#ifdef HAVE_BIGCRYPT - ret = (strcmp(bigcrypt(password, salt), crypted) == 0); - if (ret) { - return NT_STATUS_OK; - } else { - return NT_STATUS_WRONG_PASSWORD; - } -#endif /* HAVE_BIGCRYPT */ - -#ifndef HAVE_CRYPT - DEBUG(1, ("Warning - no crypt available\n")); - return NT_STATUS_LOGON_FAILURE; -#else /* HAVE_CRYPT */ - ret = (strcmp((char *)crypt(password, salt), crypted) == 0); - if (ret) { - return NT_STATUS_OK; - } else { - return NT_STATUS_WRONG_PASSWORD; - } -#endif /* HAVE_CRYPT */ -#endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */ -} - -static NTSTATUS check_unix_password(TALLOC_CTX *ctx, struct loadparm_context *lp_ctx, - const struct auth_usersupplied_info *user_info, struct passwd **ret_passwd) -{ - char *username; - char *password; - char *pwcopy; - char *salt; - char *crypted; - struct passwd *pws; - NTSTATUS nt_status; - int level = lp_passwordlevel(lp_ctx); - - *ret_passwd = NULL; - - username = talloc_strdup(ctx, user_info->mapped.account_name); - password = talloc_strdup(ctx, user_info->password.plaintext); - - nt_status = talloc_getpwnam(ctx, username, &pws); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - - crypted = pws->pw_passwd; - salt = pws->pw_passwd; - -#ifdef HAVE_GETSPNAM - { - struct spwd *spass; - - /* many shadow systems require you to be root to get - the password, in most cases this should already be - the case when this function is called, except - perhaps for IPC password changing requests */ - - spass = getspnam(pws->pw_name); - if (spass && spass->sp_pwdp) { - crypted = talloc_strdup(ctx, spass->sp_pwdp); - NT_STATUS_HAVE_NO_MEMORY(crypted); - salt = talloc_strdup(ctx, spass->sp_pwdp); - NT_STATUS_HAVE_NO_MEMORY(salt); - } - } -#elif defined(IA_UINFO) - { - char *ia_password; - /* Need to get password with SVR4.2's ia_ functions - instead of get{sp,pw}ent functions. Required by - UnixWare 2.x, tested on version - 2.1. (tangent@cyberport.com) */ - uinfo_t uinfo; - if (ia_openinfo(pws->pw_name, &uinfo) != -1) { - ia_get_logpwd(uinfo, &ia_password); - crypted = talloc_strdup(ctx, ia_password); - NT_STATUS_HAVE_NO_MEMORY(crypted); - } - } -#endif - -#ifdef HAVE_GETPRPWNAM - { - struct pr_passwd *pr_pw = getprpwnam(pws->pw_name); - if (pr_pw && pr_pw->ufld.fd_encrypt) { - crypted = talloc_strdup(ctx, pr_pw->ufld.fd_encrypt); - NT_STATUS_HAVE_NO_MEMORY(crypted); - } - } -#endif - -#ifdef HAVE_GETPWANAM - { - struct passwd_adjunct *pwret; - pwret = getpwanam(s); - if (pwret && pwret->pwa_passwd) { - crypted = talloc_strdup(ctx, pwret->pwa_passwd); - NT_STATUS_HAVE_NO_MEMORY(crypted); - } - } -#endif - -#ifdef OSF1_ENH_SEC - { - struct pr_passwd *mypasswd; - DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n", username)); - mypasswd = getprpwnam(username); - if (mypasswd) { - username = talloc_strdup(ctx, mypasswd->ufld.fd_name); - NT_STATUS_HAVE_NO_MEMORY(username); - crypted = talloc_strdup(ctx, mypasswd->ufld.fd_encrypt); - NT_STATUS_HAVE_NO_MEMORY(crypted); - } else { - DEBUG(5,("OSF1_ENH_SEC: No entry for user %s in protected database !\n", username)); - } - } -#endif - -#ifdef ULTRIX_AUTH - { - AUTHORIZATION *ap = getauthuid(pws->pw_uid); - if (ap) { - crypted = talloc_strdup(ctx, ap->a_password); - endauthent(); - NT_STATUS_HAVE_NO_MEMORY(crypted); - } - } -#endif - -#if defined(HAVE_TRUNCATED_SALT) - /* crypt on some platforms (HPUX in particular) - won't work with more than 2 salt characters. */ - salt[2] = 0; -#endif - - if (crypted[0] == '\0') { - if (!lp_null_passwords(lp_ctx)) { - DEBUG(2, ("Disallowing %s with null password\n", username)); - return NT_STATUS_LOGON_FAILURE; - } - if (password == NULL) { - DEBUG(3, ("Allowing access to %s with null password\n", username)); - *ret_passwd = pws; - return NT_STATUS_OK; - } - } - - /* try it as it came to us */ - nt_status = password_check(username, password, crypted, salt); - if (NT_STATUS_IS_OK(nt_status)) { - *ret_passwd = pws; - return nt_status; - } - else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) { - /* No point continuing if its not the password thats to blame (ie PAM disabled). */ - return nt_status; - } - - if ( user_info->flags | USER_INFO_CASE_INSENSITIVE_PASSWORD) { - return nt_status; - } - - /* if the password was given to us with mixed case then we don't - * need to proceed as we know it hasn't been case modified by the - * client */ - if (strhasupper(password) && strhaslower(password)) { - return nt_status; - } - - /* make a copy of it */ - pwcopy = talloc_strdup(ctx, password); - if (!pwcopy) - return NT_STATUS_NO_MEMORY; - - /* try all lowercase if it's currently all uppercase */ - if (strhasupper(pwcopy)) { - strlower(pwcopy); - nt_status = password_check(username, pwcopy, crypted, salt); - if NT_STATUS_IS_OK(nt_status) { - *ret_passwd = pws; - return nt_status; - } - } - - /* give up? */ - if (level < 1) { - return NT_STATUS_WRONG_PASSWORD; - } - - /* last chance - all combinations of up to level chars upper! */ - strlower(pwcopy); - -#if 0 - if (NT_STATUS_IS_OK(nt_status = string_combinations(pwcopy, password_check, level))) { - *ret_passwd = pws; - return nt_status; - } -#endif - return NT_STATUS_WRONG_PASSWORD; -} - -#endif - -/** Check a plaintext username/password - * - **/ - -static NTSTATUS authunix_want_check(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info) -{ - if (!user_info->mapped.account_name || !*user_info->mapped.account_name) { - return NT_STATUS_NOT_IMPLEMENTED; - } - - return NT_STATUS_OK; -} - -static NTSTATUS authunix_check_password(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info, - struct auth_serversupplied_info **server_info) -{ - TALLOC_CTX *check_ctx; - NTSTATUS nt_status; - struct passwd *pwd; - - if (user_info->password_state != AUTH_PASSWORD_PLAIN) { - return NT_STATUS_INVALID_PARAMETER; - } - - check_ctx = talloc_named_const(mem_ctx, 0, "check_unix_password"); - if (check_ctx == NULL) { - return NT_STATUS_NO_MEMORY; - } - - nt_status = check_unix_password(check_ctx, ctx->auth_ctx->lp_ctx, user_info, &pwd); - if (!NT_STATUS_IS_OK(nt_status)) { - talloc_free(check_ctx); - return nt_status; - } - - nt_status = authunix_make_server_info(mem_ctx, lp_netbios_name(ctx->auth_ctx->lp_ctx), - user_info, pwd, server_info); - if (!NT_STATUS_IS_OK(nt_status)) { - talloc_free(check_ctx); - return nt_status; - } - - talloc_free(check_ctx); - return NT_STATUS_OK; -} - -static const struct auth_operations unix_ops = { - .name = "unix", - .get_challenge = auth_get_challenge_not_implemented, - .want_check = authunix_want_check, - .check_password = authunix_check_password -}; - -_PUBLIC_ NTSTATUS auth_unix_init(void) -{ - NTSTATUS ret; - - ret = auth_register(&unix_ops); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register unix auth backend!\n")); - return ret; - } - - return ret; -} diff --git a/source4/auth/auth_util.c b/source4/auth/auth_util.c deleted file mode 100644 index 1d86b858cf..0000000000 --- a/source4/auth/auth_util.c +++ /dev/null @@ -1,260 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Authentication utility functions - Copyright (C) Andrew Tridgell 1992-1998 - Copyright (C) Andrew Bartlett 2001 - Copyright (C) Jeremy Allison 2000-2001 - Copyright (C) Rafal Szczesniak 2002 - Copyright (C) Stefan Metzmacher 2005 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "includes.h" -#include "auth/auth.h" -#include "libcli/security/security.h" -#include "libcli/auth/libcli_auth.h" -#include "dsdb/samdb/samdb.h" -#include "auth/credentials/credentials.h" -#include "param/param.h" - -/* this default function can be used by mostly all backends - * which don't want to set a challenge - */ -NTSTATUS auth_get_challenge_not_implemented(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, DATA_BLOB *challenge) -{ - /* we don't want to set a challenge */ - return NT_STATUS_NOT_IMPLEMENTED; -} - -/**************************************************************************** - Create an auth_usersupplied_data structure after appropriate mapping. -****************************************************************************/ - -NTSTATUS map_user_info(TALLOC_CTX *mem_ctx, - const char *default_domain, - const struct auth_usersupplied_info *user_info, - struct auth_usersupplied_info **user_info_mapped) -{ - const char *domain; - char *account_name; - char *d; - DEBUG(5,("map_user_info: Mapping user [%s]\\[%s] from workstation [%s]\n", - user_info->client.domain_name, user_info->client.account_name, user_info->workstation_name)); - - account_name = talloc_strdup(mem_ctx, user_info->client.account_name); - if (!account_name) { - return NT_STATUS_NO_MEMORY; - } - - /* don't allow "" as a domain, fixes a Win9X bug - where it doesn't supply a domain for logon script - 'net use' commands. */ - - /* Split user@realm names into user and realm components. This is TODO to fix with proper userprincipalname support */ - if (user_info->client.domain_name && *user_info->client.domain_name) { - domain = user_info->client.domain_name; - } else if (strchr_m(user_info->client.account_name, '@')) { - d = strchr_m(account_name, '@'); - if (!d) { - return NT_STATUS_INTERNAL_ERROR; - } - d[0] = '\0'; - d++; - domain = d; - } else { - domain = default_domain; - } - - *user_info_mapped = talloc(mem_ctx, struct auth_usersupplied_info); - if (!*user_info_mapped) { - return NT_STATUS_NO_MEMORY; - } - if (!talloc_reference(*user_info_mapped, user_info)) { - return NT_STATUS_NO_MEMORY; - } - **user_info_mapped = *user_info; - (*user_info_mapped)->mapped_state = true; - (*user_info_mapped)->mapped.domain_name = talloc_strdup(*user_info_mapped, domain); - (*user_info_mapped)->mapped.account_name = talloc_strdup(*user_info_mapped, account_name); - talloc_free(account_name); - if (!(*user_info_mapped)->mapped.domain_name - || !(*user_info_mapped)->mapped.account_name) { - return NT_STATUS_NO_MEMORY; - } - - return NT_STATUS_OK; -} - -/**************************************************************************** - Create an auth_usersupplied_data structure after appropriate mapping. -****************************************************************************/ - -NTSTATUS encrypt_user_info(TALLOC_CTX *mem_ctx, struct auth_context *auth_context, - enum auth_password_state to_state, - const struct auth_usersupplied_info *user_info_in, - const struct auth_usersupplied_info **user_info_encrypted) -{ - NTSTATUS nt_status; - struct auth_usersupplied_info *user_info_temp; - switch (to_state) { - case AUTH_PASSWORD_RESPONSE: - switch (user_info_in->password_state) { - case AUTH_PASSWORD_PLAIN: - { - const struct auth_usersupplied_info *user_info_temp2; - nt_status = encrypt_user_info(mem_ctx, auth_context, - AUTH_PASSWORD_HASH, - user_info_in, &user_info_temp2); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - user_info_in = user_info_temp2; - /* fall through */ - } - case AUTH_PASSWORD_HASH: - { - const uint8_t *challenge; - DATA_BLOB chall_blob; - user_info_temp = talloc(mem_ctx, struct auth_usersupplied_info); - if (!user_info_temp) { - return NT_STATUS_NO_MEMORY; - } - if (!talloc_reference(user_info_temp, user_info_in)) { - return NT_STATUS_NO_MEMORY; - } - *user_info_temp = *user_info_in; - user_info_temp->mapped_state = to_state; - - nt_status = auth_get_challenge(auth_context, &challenge); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - - chall_blob = data_blob_talloc(mem_ctx, challenge, 8); - if (lp_client_ntlmv2_auth(auth_context->lp_ctx)) { - DATA_BLOB names_blob = NTLMv2_generate_names_blob(mem_ctx, lp_iconv_convenience(auth_context->lp_ctx), lp_netbios_name(auth_context->lp_ctx), lp_workgroup(auth_context->lp_ctx)); - DATA_BLOB lmv2_response, ntlmv2_response, lmv2_session_key, ntlmv2_session_key; - - if (!SMBNTLMv2encrypt_hash(user_info_temp, - user_info_in->client.account_name, - user_info_in->client.domain_name, - user_info_in->password.hash.nt->hash, &chall_blob, - &names_blob, - &lmv2_response, &ntlmv2_response, - &lmv2_session_key, &ntlmv2_session_key)) { - data_blob_free(&names_blob); - return NT_STATUS_NO_MEMORY; - } - data_blob_free(&names_blob); - user_info_temp->password.response.lanman = lmv2_response; - user_info_temp->password.response.nt = ntlmv2_response; - - data_blob_free(&lmv2_session_key); - data_blob_free(&ntlmv2_session_key); - } else { - DATA_BLOB blob = data_blob_talloc(mem_ctx, NULL, 24); - SMBOWFencrypt(user_info_in->password.hash.nt->hash, challenge, blob.data); - - user_info_temp->password.response.nt = blob; - if (lp_client_lanman_auth(auth_context->lp_ctx) && user_info_in->password.hash.lanman) { - DATA_BLOB lm_blob = data_blob_talloc(mem_ctx, NULL, 24); - SMBOWFencrypt(user_info_in->password.hash.lanman->hash, challenge, blob.data); - user_info_temp->password.response.lanman = lm_blob; - } else { - /* if not sending the LM password, send the NT password twice */ - user_info_temp->password.response.lanman = user_info_temp->password.response.nt; - } - } - - user_info_in = user_info_temp; - /* fall through */ - } - case AUTH_PASSWORD_RESPONSE: - *user_info_encrypted = user_info_in; - } - break; - case AUTH_PASSWORD_HASH: - { - switch (user_info_in->password_state) { - case AUTH_PASSWORD_PLAIN: - { - struct samr_Password lanman; - struct samr_Password nt; - - user_info_temp = talloc(mem_ctx, struct auth_usersupplied_info); - if (!user_info_temp) { - return NT_STATUS_NO_MEMORY; - } - if (!talloc_reference(user_info_temp, user_info_in)) { - return NT_STATUS_NO_MEMORY; - } - *user_info_temp = *user_info_in; - user_info_temp->mapped_state = to_state; - - if (E_deshash(user_info_in->password.plaintext, lanman.hash)) { - user_info_temp->password.hash.lanman = talloc(user_info_temp, - struct samr_Password); - *user_info_temp->password.hash.lanman = lanman; - } else { - user_info_temp->password.hash.lanman = NULL; - } - - E_md4hash(user_info_in->password.plaintext, nt.hash); - user_info_temp->password.hash.nt = talloc(user_info_temp, - struct samr_Password); - *user_info_temp->password.hash.nt = nt; - - user_info_in = user_info_temp; - /* fall through */ - } - case AUTH_PASSWORD_HASH: - *user_info_encrypted = user_info_in; - break; - default: - return NT_STATUS_INVALID_PARAMETER; - break; - } - break; - } - default: - return NT_STATUS_INVALID_PARAMETER; - } - - return NT_STATUS_OK; -} - - -/** - * Squash an NT_STATUS in line with security requirements. - * In an attempt to avoid giving the whole game away when users - * are authenticating, NT replaces both NT_STATUS_NO_SUCH_USER and - * NT_STATUS_WRONG_PASSWORD with NT_STATUS_LOGON_FAILURE in certain situations - * (session setups in particular). - * - * @param nt_status NTSTATUS input for squashing. - * @return the 'squashed' nt_status - **/ -_PUBLIC_ NTSTATUS auth_nt_status_squash(NTSTATUS nt_status) -{ - if NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER) { - /* Match WinXP and don't give the game away */ - return NT_STATUS_LOGON_FAILURE; - } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD) { - /* Match WinXP and don't give the game away */ - return NT_STATUS_LOGON_FAILURE; - } - - return nt_status; -} diff --git a/source4/auth/auth_winbind.c b/source4/auth/auth_winbind.c deleted file mode 100644 index 149f549afa..0000000000 --- a/source4/auth/auth_winbind.c +++ /dev/null @@ -1,282 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - Winbind authentication mechnism - - Copyright (C) Tim Potter 2000 - Copyright (C) Andrew Bartlett 2001 - 2002 - Copyright (C) Stefan Metzmacher 2005 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "includes.h" -#include "auth/auth.h" -#include "auth/auth_proto.h" -#include "auth/session_proto.h" -#include "nsswitch/winbind_client.h" -#include "librpc/gen_ndr/ndr_netlogon.h" -#include "librpc/gen_ndr/ndr_winbind.h" -#include "lib/messaging/irpc.h" -#include "param/param.h" - -static NTSTATUS get_info3_from_ndr(TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience, struct winbindd_response *response, struct netr_SamInfo3 *info3) -{ - size_t len = response->length - sizeof(struct winbindd_response); - if (len > 4) { - enum ndr_err_code ndr_err; - DATA_BLOB blob; - blob.length = len - 4; - blob.data = (uint8_t *)(((char *)response->extra_data.data) + 4); - - ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, - iconv_convenience, info3, - (ndr_pull_flags_fn_t)ndr_pull_netr_SamInfo3); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return ndr_map_error2ntstatus(ndr_err); - } - - return NT_STATUS_OK; - } else { - DEBUG(2, ("get_info3_from_ndr: No info3 struct found!\n")); - return NT_STATUS_UNSUCCESSFUL; - } -} - -static NTSTATUS winbind_want_check(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info) -{ - if (!user_info->mapped.account_name || !*user_info->mapped.account_name) { - return NT_STATUS_NOT_IMPLEMENTED; - } - - /* TODO: maybe limit the user scope to remote users only */ - return NT_STATUS_OK; -} - -/* - Authenticate a user with a challenge/response - using the samba3 winbind protocol -*/ -static NTSTATUS winbind_check_password_samba3(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info, - struct auth_serversupplied_info **server_info) -{ - struct winbindd_request request; - struct winbindd_response response; - NSS_STATUS result; - NTSTATUS nt_status; - struct netr_SamInfo3 info3; - - /* Send off request */ - const struct auth_usersupplied_info *user_info_temp; - nt_status = encrypt_user_info(mem_ctx, ctx->auth_ctx, - AUTH_PASSWORD_RESPONSE, - user_info, &user_info_temp); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - user_info = user_info_temp; - - ZERO_STRUCT(request); - ZERO_STRUCT(response); - request.flags = WBFLAG_PAM_INFO3_NDR; - - request.data.auth_crap.logon_parameters = user_info->logon_parameters; - - safe_strcpy(request.data.auth_crap.user, - user_info->client.account_name, sizeof(fstring)); - safe_strcpy(request.data.auth_crap.domain, - user_info->client.domain_name, sizeof(fstring)); - safe_strcpy(request.data.auth_crap.workstation, - user_info->workstation_name, sizeof(fstring)); - - memcpy(request.data.auth_crap.chal, ctx->auth_ctx->challenge.data.data, sizeof(request.data.auth_crap.chal)); - - request.data.auth_crap.lm_resp_len = MIN(user_info->password.response.lanman.length, - sizeof(request.data.auth_crap.lm_resp)); - request.data.auth_crap.nt_resp_len = MIN(user_info->password.response.nt.length, - sizeof(request.data.auth_crap.nt_resp)); - - memcpy(request.data.auth_crap.lm_resp, user_info->password.response.lanman.data, - request.data.auth_crap.lm_resp_len); - memcpy(request.data.auth_crap.nt_resp, user_info->password.response.nt.data, - request.data.auth_crap.nt_resp_len); - - result = winbindd_request_response(WINBINDD_PAM_AUTH_CRAP, &request, &response); - - nt_status = NT_STATUS(response.data.auth.nt_status); - NT_STATUS_NOT_OK_RETURN(nt_status); - - if (result == NSS_STATUS_SUCCESS && response.extra_data.data) { - union netr_Validation validation; - - nt_status = get_info3_from_ndr(mem_ctx, lp_iconv_convenience(ctx->auth_ctx->lp_ctx), &response, &info3); - SAFE_FREE(response.extra_data.data); - NT_STATUS_NOT_OK_RETURN(nt_status); - - validation.sam3 = &info3; - nt_status = make_server_info_netlogon_validation(mem_ctx, - user_info->client.account_name, - 3, &validation, - server_info); - return nt_status; - } else if (result == NSS_STATUS_SUCCESS && !response.extra_data.data) { - DEBUG(0, ("Winbindd authenticated the user [%s]\\[%s], " - "but did not include the required info3 reply!\n", - user_info->client.domain_name, user_info->client.account_name)); - return NT_STATUS_INSUFFICIENT_LOGON_INFO; - } else if (NT_STATUS_IS_OK(nt_status)) { - DEBUG(1, ("Winbindd authentication for [%s]\\[%s] failed, " - "but no error code is available!\n", - user_info->client.domain_name, user_info->client.account_name)); - return NT_STATUS_NO_LOGON_SERVERS; - } - - return nt_status; -} - -struct winbind_check_password_state { - struct winbind_SamLogon req; -}; - -/* - Authenticate a user with a challenge/response - using IRPC to the winbind task -*/ -static NTSTATUS winbind_check_password(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info, - struct auth_serversupplied_info **server_info) -{ - NTSTATUS status; - struct server_id *winbind_servers; - struct winbind_check_password_state *s; - const struct auth_usersupplied_info *user_info_new; - struct netr_IdentityInfo *identity_info; - - s = talloc(mem_ctx, struct winbind_check_password_state); - NT_STATUS_HAVE_NO_MEMORY(s); - - winbind_servers = irpc_servers_byname(ctx->auth_ctx->msg_ctx, s, "winbind_server"); - if ((winbind_servers == NULL) || (winbind_servers[0].id == 0)) { - DEBUG(0, ("Winbind authentication for [%s]\\[%s] failed, " - "no winbind_server running!\n", - user_info->client.domain_name, user_info->client.account_name)); - return NT_STATUS_NO_LOGON_SERVERS; - } - - if (user_info->flags & USER_INFO_INTERACTIVE_LOGON) { - struct netr_PasswordInfo *password_info; - - status = encrypt_user_info(s, ctx->auth_ctx, AUTH_PASSWORD_HASH, - user_info, &user_info_new); - NT_STATUS_NOT_OK_RETURN(status); - user_info = user_info_new; - - password_info = talloc(s, struct netr_PasswordInfo); - NT_STATUS_HAVE_NO_MEMORY(password_info); - - password_info->lmpassword = *user_info->password.hash.lanman; - password_info->ntpassword = *user_info->password.hash.nt; - - identity_info = &password_info->identity_info; - s->req.in.logon_level = 1; - s->req.in.logon.password= password_info; - } else { - struct netr_NetworkInfo *network_info; - const uint8_t *challenge; - - status = encrypt_user_info(s, ctx->auth_ctx, AUTH_PASSWORD_RESPONSE, - user_info, &user_info_new); - NT_STATUS_NOT_OK_RETURN(status); - user_info = user_info_new; - - network_info = talloc(s, struct netr_NetworkInfo); - NT_STATUS_HAVE_NO_MEMORY(network_info); - - status = auth_get_challenge(ctx->auth_ctx, &challenge); - NT_STATUS_NOT_OK_RETURN(status); - - memcpy(network_info->challenge, challenge, sizeof(network_info->challenge)); - - network_info->nt.length = user_info->password.response.nt.length; - network_info->nt.data = user_info->password.response.nt.data; - - network_info->lm.length = user_info->password.response.lanman.length; - network_info->lm.data = user_info->password.response.lanman.data; - - identity_info = &network_info->identity_info; - s->req.in.logon_level = 2; - s->req.in.logon.network = network_info; - } - - identity_info->domain_name.string = user_info->client.domain_name; - identity_info->parameter_control = user_info->logon_parameters; /* see MSV1_0_* */ - identity_info->logon_id_low = 0; - identity_info->logon_id_high = 0; - identity_info->account_name.string = user_info->client.account_name; - identity_info->workstation.string = user_info->workstation_name; - - s->req.in.validation_level = 3; - - status = IRPC_CALL(ctx->auth_ctx->msg_ctx, winbind_servers[0], - winbind, WINBIND_SAMLOGON, - &s->req, s); - NT_STATUS_NOT_OK_RETURN(status); - - status = make_server_info_netlogon_validation(mem_ctx, - user_info->client.account_name, - s->req.in.validation_level, - &s->req.out.validation, - server_info); - NT_STATUS_NOT_OK_RETURN(status); - - return NT_STATUS_OK; -} - -static const struct auth_operations winbind_samba3_ops = { - .name = "winbind_samba3", - .get_challenge = auth_get_challenge_not_implemented, - .want_check = winbind_want_check, - .check_password = winbind_check_password_samba3 -}; - -static const struct auth_operations winbind_ops = { - .name = "winbind", - .get_challenge = auth_get_challenge_not_implemented, - .want_check = winbind_want_check, - .check_password = winbind_check_password -}; - -_PUBLIC_ NTSTATUS auth_winbind_init(void) -{ - NTSTATUS ret; - - ret = auth_register(&winbind_samba3_ops); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register 'winbind_samba3' auth backend!\n")); - return ret; - } - - ret = auth_register(&winbind_ops); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register 'winbind' auth backend!\n")); - return ret; - } - - return NT_STATUS_OK; -} diff --git a/source4/auth/config.mk b/source4/auth/config.mk index 0acb9e30ba..87b796288d 100644 --- a/source4/auth/config.mk +++ b/source4/auth/config.mk @@ -2,6 +2,7 @@ mkinclude gensec/config.mk mkinclude kerberos/config.mk mkinclude ntlmssp/config.mk +mkinclude ntlm/config.mk mkinclude credentials/config.mk [SUBSYSTEM::auth_session] @@ -24,93 +25,13 @@ PRIVATE_PROTO_HEADER = auth_sam.h PUBLIC_DEPENDENCIES = SAMDB UTIL_LDB LIBSECURITY PRIVATE_DEPENDENCIES = LDAP_ENCODE -auth_sam_OBJ_FILES = $(addprefix auth/, sam.o ntlm_check.o) +auth_sam_OBJ_FILES = $(addprefix auth/, sam.o) [SUBSYSTEM::auth_sam_reply] PRIVATE_PROTO_HEADER = auth_sam_reply.h auth_sam_reply_OBJ_FILES = $(addprefix auth/, auth_sam_reply.o) -####################### -# Start MODULE auth_sam -[MODULE::auth_sam_module] -# gensec_krb5 and gensec_gssapi depend on it -INIT_FUNCTION = auth_sam_init -SUBSYSTEM = auth -PRIVATE_DEPENDENCIES = \ - SAMDB auth_sam -# End MODULE auth_sam -####################### - -auth_sam_module_OBJ_FILES = $(addprefix auth/, auth_sam.o) - -####################### -# Start MODULE auth_anonymous -[MODULE::auth_anonymous] -INIT_FUNCTION = auth_anonymous_init -SUBSYSTEM = auth -# End MODULE auth_anonymous -####################### - -auth_anonymous_OBJ_FILES = $(addprefix auth/, auth_anonymous.o) - -####################### -# Start MODULE auth_anonymous -[MODULE::auth_server] -INIT_FUNCTION = auth_server_init -SUBSYSTEM = auth -PRIVATE_DEPENDENCIES = LIBSAMBA-UTIL LIBCLI_SMB -OUTPUT_TYPE = SHARED_LIBRARY -# End MODULE auth_server -####################### - -auth_server_OBJ_FILES = $(addprefix auth/, auth_server.o) - -####################### -# Start MODULE auth_winbind -[MODULE::auth_winbind] -INIT_FUNCTION = auth_winbind_init -SUBSYSTEM = auth -PRIVATE_DEPENDENCIES = NDR_WINBIND MESSAGING LIBWINBIND-CLIENT -# End MODULE auth_winbind -####################### - -auth_winbind_OBJ_FILES = $(addprefix auth/, auth_winbind.o) - -####################### -# Start MODULE auth_developer -[MODULE::auth_developer] -INIT_FUNCTION = auth_developer_init -SUBSYSTEM = auth -# End MODULE auth_developer -####################### - -auth_developer_OBJ_FILES = $(addprefix auth/, auth_developer.o) - -[MODULE::auth_unix] -INIT_FUNCTION = auth_unix_init -SUBSYSTEM = auth -PRIVATE_DEPENDENCIES = CRYPT PAM PAM_ERRORS NSS_WRAPPER - -auth_unix_OBJ_FILES = $(addprefix auth/, auth_unix.o) - -[SUBSYSTEM::PAM_ERRORS] -PRIVATE_PROTO_HEADER = pam_errors.h - -#VERSION = 0.0.1 -#SO_VERSION = 0 -PAM_ERRORS_OBJ_FILES = $(addprefix auth/, pam_errors.o) - -[MODULE::auth] -INIT_FUNCTION = server_service_auth_init -SUBSYSTEM = service -PRIVATE_PROTO_HEADER = auth_proto.h -PRIVATE_DEPENDENCIES = LIBSAMBA-UTIL LIBSECURITY SAMDB CREDENTIALS - -auth_OBJ_FILES = $(addprefix auth/, auth.o auth_util.o auth_simple.o) - -# PUBLIC_HEADERS += auth/auth.h - [PYTHON::swig_auth] PUBLIC_DEPENDENCIES = auth_system_session PRIVATE_DEPENDENCIES = SAMDB diff --git a/source4/auth/ntlm/auth.c b/source4/auth/ntlm/auth.c new file mode 100644 index 0000000000..b74a438962 --- /dev/null +++ b/source4/auth/ntlm/auth.c @@ -0,0 +1,539 @@ +/* + Unix SMB/CIFS implementation. + Password and authentication handling + Copyright (C) Andrew Bartlett 2001-2002 + Copyright (C) Stefan Metzmacher 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "includes.h" +#include "lib/util/dlinklist.h" +#include "auth/auth.h" +#include "auth/auth_proto.h" +#include "lib/events/events.h" +#include "build.h" +#include "param/param.h" + +/*************************************************************************** + Set a fixed challenge +***************************************************************************/ +_PUBLIC_ NTSTATUS auth_context_set_challenge(struct auth_context *auth_ctx, const uint8_t chal[8], const char *set_by) +{ + auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by); + NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by); + + auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8); + NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data); + + return NT_STATUS_OK; +} + +/*************************************************************************** + Set a fixed challenge +***************************************************************************/ +bool auth_challenge_may_be_modified(struct auth_context *auth_ctx) +{ + return auth_ctx->challenge.may_be_modified; +} + +/**************************************************************************** + Try to get a challenge out of the various authentication modules. + Returns a const char of length 8 bytes. +****************************************************************************/ +_PUBLIC_ NTSTATUS auth_get_challenge(struct auth_context *auth_ctx, const uint8_t **_chal) +{ + NTSTATUS nt_status; + struct auth_method_context *method; + + if (auth_ctx->challenge.data.length) { + DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n", + auth_ctx->challenge.set_by)); + *_chal = auth_ctx->challenge.data.data; + return NT_STATUS_OK; + } + + for (method = auth_ctx->methods; method; method = method->next) { + DATA_BLOB challenge = data_blob(NULL,0); + + nt_status = method->ops->get_challenge(method, auth_ctx, &challenge); + if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) { + continue; + } + + NT_STATUS_NOT_OK_RETURN(nt_status); + + if (challenge.length != 8) { + DEBUG(0, ("auth_get_challenge: invalid challenge (length %u) by mothod [%s]\n", + (unsigned)challenge.length, method->ops->name)); + return NT_STATUS_INTERNAL_ERROR; + } + + auth_ctx->challenge.data = challenge; + auth_ctx->challenge.set_by = method->ops->name; + + break; + } + + if (!auth_ctx->challenge.set_by) { + uint8_t chal[8]; + generate_random_buffer(chal, 8); + + auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8); + NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data); + auth_ctx->challenge.set_by = "random"; + + auth_ctx->challenge.may_be_modified = true; + } + + DEBUG(10,("auth_get_challenge: challenge set by %s\n", + auth_ctx->challenge.set_by)); + + *_chal = auth_ctx->challenge.data.data; + 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. + * + * 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 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. + * + * @return An NTSTATUS with NT_STATUS_OK or an appropriate error. + * + **/ + +_PUBLIC_ 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; + + 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); + } + + 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 + * + **/ + +_PUBLIC_ 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 uint8_t *challenge; + struct auth_usersupplied_info *user_info_tmp; + struct auth_check_password_request *req = NULL; + + 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(req, lp_workgroup(auth_ctx->lp_ctx), 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_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_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))); + goto failed; + } + + if (auth_ctx->challenge.set_by) { + DEBUG(10, ("auth_check_password_send: auth_context challenge created by %s\n", + auth_ctx->challenge.set_by)); + } + + 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, req, user_info); + if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) { + DEBUG(11,("auth_check_password_send: %s had nothing to say\n", method->ops->name)); + continue; + } + + nt_status = result; + req->method = method; + + if (!NT_STATUS_IS_OK(nt_status)) 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; + } + +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. + * + **/ + +_PUBLIC_ 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_recv: %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_recv: %s authentication for user [%s\\%s] FAILED with error %s\n", + (req->method ? req->method->ops->name : "NO_METHOD"), + req->user_info->mapped.domain_name, + req->user_info->mapped.account_name, + nt_errstr(req->status))); + } + + status = req->status; + talloc_free(req); + return status; +} + +/*************************************************************************** + Make a auth_info struct for the auth subsystem + - Allow the caller to specify the methods to use +***************************************************************************/ +_PUBLIC_ NTSTATUS auth_context_create_methods(TALLOC_CTX *mem_ctx, const char **methods, + struct event_context *ev, + struct messaging_context *msg, + struct loadparm_context *lp_ctx, + struct auth_context **auth_ctx) +{ + int i; + struct auth_context *ctx; + + if (!methods) { + DEBUG(0,("auth_context_create: No auth method list!?\n")); + return NT_STATUS_INTERNAL_ERROR; + } + + if (!ev) { + DEBUG(0,("auth_context_create: called with out event context\n")); + return NT_STATUS_INTERNAL_ERROR; + } + + if (!msg) { + DEBUG(0,("auth_context_create: called with out messaging context\n")); + return NT_STATUS_INTERNAL_ERROR; + } + + ctx = talloc(mem_ctx, struct auth_context); + NT_STATUS_HAVE_NO_MEMORY(ctx); + ctx->challenge.set_by = NULL; + ctx->challenge.may_be_modified = false; + ctx->challenge.data = data_blob(NULL, 0); + ctx->methods = NULL; + ctx->event_ctx = ev; + ctx->msg_ctx = msg; + ctx->lp_ctx = lp_ctx; + + for (i=0; methods[i] ; i++) { + struct auth_method_context *method; + + method = talloc(ctx, struct auth_method_context); + NT_STATUS_HAVE_NO_MEMORY(method); + + method->ops = auth_backend_byname(methods[i]); + if (!method->ops) { + DEBUG(1,("auth_context_create: failed to find method=%s\n", + methods[i])); + return NT_STATUS_INTERNAL_ERROR; + } + method->auth_ctx = ctx; + method->depth = i; + DLIST_ADD_END(ctx->methods, method, struct auth_method_context *); + } + + if (!ctx->methods) { + return NT_STATUS_INTERNAL_ERROR; + } + + *auth_ctx = ctx; + + return NT_STATUS_OK; +} +/*************************************************************************** + Make a auth_info struct for the auth subsystem + - Uses default auth_methods, depending on server role and smb.conf settings +***************************************************************************/ +_PUBLIC_ NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct messaging_context *msg, + struct loadparm_context *lp_ctx, + struct auth_context **auth_ctx) +{ + const char **auth_methods = NULL; + switch (lp_server_role(lp_ctx)) { + case ROLE_STANDALONE: + auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "standalone", NULL); + break; + case ROLE_DOMAIN_MEMBER: + auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "member server", NULL); + break; + case ROLE_DOMAIN_CONTROLLER: + auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "domain controller", NULL); + break; + } + return auth_context_create_methods(mem_ctx, auth_methods, ev, msg, lp_ctx, auth_ctx); +} + + +/* the list of currently registered AUTH backends */ +static struct auth_backend { + const struct auth_operations *ops; +} *backends = NULL; +static int num_backends; + +/* + register a AUTH backend. + + The 'name' can be later used by other backends to find the operations + structure for this backend. +*/ +_PUBLIC_ NTSTATUS auth_register(const struct auth_operations *ops) +{ + struct auth_operations *new_ops; + + if (auth_backend_byname(ops->name) != NULL) { + /* its already registered! */ + DEBUG(0,("AUTH backend '%s' already registered\n", + ops->name)); + return NT_STATUS_OBJECT_NAME_COLLISION; + } + + backends = talloc_realloc(talloc_autofree_context(), backends, + struct auth_backend, num_backends+1); + NT_STATUS_HAVE_NO_MEMORY(backends); + + new_ops = talloc_memdup(backends, ops, sizeof(*ops)); + NT_STATUS_HAVE_NO_MEMORY(new_ops); + new_ops->name = talloc_strdup(new_ops, ops->name); + NT_STATUS_HAVE_NO_MEMORY(new_ops->name); + + backends[num_backends].ops = new_ops; + + num_backends++; + + DEBUG(3,("AUTH backend '%s' registered\n", + ops->name)); + + return NT_STATUS_OK; +} + +/* + return the operations structure for a named backend of the specified type +*/ +const struct auth_operations *auth_backend_byname(const char *name) +{ + int i; + + for (i=0;iname, name) == 0) { + return backends[i].ops; + } + } + + return NULL; +} + +/* + return the AUTH interface version, and the size of some critical types + This can be used by backends to either detect compilation errors, or provide + multiple implementations for different smbd compilation options in one module +*/ +const struct auth_critical_sizes *auth_interface_version(void) +{ + static const struct auth_critical_sizes critical_sizes = { + AUTH_INTERFACE_VERSION, + sizeof(struct auth_operations), + sizeof(struct auth_method_context), + sizeof(struct auth_context), + sizeof(struct auth_usersupplied_info), + sizeof(struct auth_serversupplied_info) + }; + + return &critical_sizes; +} + +_PUBLIC_ NTSTATUS auth_init(void) +{ + static bool initialized = false; + extern NTSTATUS auth_developer_init(void); + extern NTSTATUS auth_winbind_init(void); + extern NTSTATUS auth_anonymous_init(void); + extern NTSTATUS auth_unix_init(void); + extern NTSTATUS auth_sam_init(void); + extern NTSTATUS auth_server_init(void); + + init_module_fn static_init[] = { STATIC_auth_MODULES }; + + if (initialized) return NT_STATUS_OK; + initialized = true; + + run_init_functions(static_init); + + return NT_STATUS_OK; +} + +NTSTATUS server_service_auth_init(void) +{ + return auth_init(); +} diff --git a/source4/auth/ntlm/auth_anonymous.c b/source4/auth/ntlm/auth_anonymous.c new file mode 100644 index 0000000000..b93c7c2008 --- /dev/null +++ b/source4/auth/ntlm/auth_anonymous.c @@ -0,0 +1,78 @@ +/* + Unix SMB/CIFS implementation. + + Anonymous Authentification + + Copyright (C) Stefan Metzmacher 2004-2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "includes.h" +#include "auth/auth.h" +#include "auth/auth_proto.h" +#include "param/param.h" + +/** + * Return a anonymous logon for anonymous users (username = "") + * + * Typically used as the first module in the auth chain, this allows + * anonymou logons to be dealt with in one place. Non-anonymou logons 'fail' + * and pass onto the next module. + **/ +static NTSTATUS anonymous_want_check(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info) +{ + if (user_info->client.account_name && *user_info->client.account_name) { + return NT_STATUS_NOT_IMPLEMENTED; + } + + return NT_STATUS_OK; +} + +/** + * Return a anonymous logon for anonymous users (username = "") + * + * Typically used as the first module in the auth chain, this allows + * anonymou logons to be dealt with in one place. Non-anonymou logons 'fail' + * and pass onto the next module. + **/ +static NTSTATUS anonymous_check_password(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info, + struct auth_serversupplied_info **_server_info) +{ + return auth_anonymous_server_info(mem_ctx, lp_netbios_name(ctx->auth_ctx->lp_ctx), _server_info); +} + +static const struct auth_operations anonymous_auth_ops = { + .name = "anonymous", + .get_challenge = auth_get_challenge_not_implemented, + .want_check = anonymous_want_check, + .check_password = anonymous_check_password +}; + +_PUBLIC_ NTSTATUS auth_anonymous_init(void) +{ + NTSTATUS ret; + + ret = auth_register(&anonymous_auth_ops); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(0,("Failed to register 'anonymous' auth backend!\n")); + return ret; + } + + return ret; +} diff --git a/source4/auth/ntlm/auth_developer.c b/source4/auth/ntlm/auth_developer.c new file mode 100644 index 0000000000..a2c9cbc828 --- /dev/null +++ b/source4/auth/ntlm/auth_developer.c @@ -0,0 +1,207 @@ +/* + Unix SMB/CIFS implementation. + Generic authentication types + Copyright (C) Andrew Bartlett 2001-2002 + Copyright (C) Jelmer Vernooij 2002 + Copyright (C) Stefan Metzmacher 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "includes.h" +#include "auth/auth.h" +#include "auth/auth_proto.h" +#include "libcli/security/security.h" +#include "librpc/gen_ndr/ndr_samr.h" + +static NTSTATUS name_to_ntstatus_want_check(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info) +{ + return NT_STATUS_OK; +} + +/** + * Return an error based on username + * + * This function allows the testing of obsure errors, as well as the generation + * of NT_STATUS -> DOS error mapping tables. + * + * This module is of no value to end-users. + * + * The password is ignored. + * + * @return An NTSTATUS value based on the username + **/ + +static NTSTATUS name_to_ntstatus_check_password(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info, + struct auth_serversupplied_info **_server_info) +{ + NTSTATUS nt_status; + struct auth_serversupplied_info *server_info; + uint32_t error_num; + const char *user; + + user = user_info->client.account_name; + + if (strncasecmp("NT_STATUS", user, strlen("NT_STATUS")) == 0) { + nt_status = nt_status_string_to_code(user); + } else { + error_num = strtoul(user, NULL, 16); + DEBUG(5,("name_to_ntstatus_check_password: Error for user %s was 0x%08X\n", user, error_num)); + nt_status = NT_STATUS(error_num); + } + NT_STATUS_NOT_OK_RETURN(nt_status); + + server_info = talloc(mem_ctx, struct auth_serversupplied_info); + NT_STATUS_HAVE_NO_MEMORY(server_info); + + server_info->account_sid = dom_sid_parse_talloc(server_info, SID_NT_ANONYMOUS); + NT_STATUS_HAVE_NO_MEMORY(server_info->account_sid); + + /* is this correct? */ + server_info->primary_group_sid = dom_sid_parse_talloc(server_info, SID_BUILTIN_GUESTS); + NT_STATUS_HAVE_NO_MEMORY(server_info->primary_group_sid); + + server_info->n_domain_groups = 0; + server_info->domain_groups = NULL; + + /* annoying, but the Anonymous really does have a session key, + and it is all zeros! */ + server_info->user_session_key = data_blob_talloc(server_info, NULL, 16); + NT_STATUS_HAVE_NO_MEMORY(server_info->user_session_key.data); + + server_info->lm_session_key = data_blob_talloc(server_info, NULL, 16); + NT_STATUS_HAVE_NO_MEMORY(server_info->lm_session_key.data); + + data_blob_clear(&server_info->user_session_key); + data_blob_clear(&server_info->lm_session_key); + + server_info->account_name = talloc_asprintf(server_info, "NAME TO NTSTATUS %s ANONYMOUS LOGON", user); + NT_STATUS_HAVE_NO_MEMORY(server_info->account_name); + + server_info->domain_name = talloc_strdup(server_info, "NT AUTHORITY"); + NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name); + + server_info->full_name = talloc_asprintf(server_info, "NAME TO NTSTATUS %s Anonymous Logon", user); + NT_STATUS_HAVE_NO_MEMORY(server_info->full_name); + + server_info->logon_script = talloc_strdup(server_info, ""); + NT_STATUS_HAVE_NO_MEMORY(server_info->logon_script); + + server_info->profile_path = talloc_strdup(server_info, ""); + NT_STATUS_HAVE_NO_MEMORY(server_info->profile_path); + + server_info->home_directory = talloc_strdup(server_info, ""); + NT_STATUS_HAVE_NO_MEMORY(server_info->home_directory); + + server_info->home_drive = talloc_strdup(server_info, ""); + NT_STATUS_HAVE_NO_MEMORY(server_info->home_drive); + + server_info->last_logon = 0; + server_info->last_logoff = 0; + server_info->acct_expiry = 0; + server_info->last_password_change = 0; + server_info->allow_password_change = 0; + server_info->force_password_change = 0; + + server_info->logon_count = 0; + server_info->bad_password_count = 0; + + server_info->acct_flags = ACB_NORMAL; + + server_info->authenticated = false; + + *_server_info = server_info; + + return nt_status; +} + +static const struct auth_operations name_to_ntstatus_auth_ops = { + .name = "name_to_ntstatus", + .get_challenge = auth_get_challenge_not_implemented, + .want_check = name_to_ntstatus_want_check, + .check_password = name_to_ntstatus_check_password +}; + +/** + * Return a 'fixed' challenge instead of a variable one. + * + * The idea of this function is to make packet snifs consistant + * with a fixed challenge, so as to aid debugging. + * + * This module is of no value to end-users. + * + * This module does not actually authenticate the user, but + * just pretenteds to need a specified challenge. + * This module removes *all* security from the challenge-response system + * + * @return NT_STATUS_UNSUCCESSFUL + **/ +static NTSTATUS fixed_challenge_get_challenge(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, DATA_BLOB *_blob) +{ + DATA_BLOB blob; + const char *challenge = "I am a teapot"; + + blob = data_blob_talloc(mem_ctx, challenge, 8); + NT_STATUS_HAVE_NO_MEMORY(blob.data); + + *_blob = blob; + return NT_STATUS_OK; +} + +static NTSTATUS fixed_challenge_want_check(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info) +{ + /* don't handle any users */ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS fixed_challenge_check_password(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info, + struct auth_serversupplied_info **_server_info) +{ + /* don't handle any users */ + return NT_STATUS_NO_SUCH_USER; +} + +static const struct auth_operations fixed_challenge_auth_ops = { + .name = "fixed_challenge", + .get_challenge = fixed_challenge_get_challenge, + .want_check = fixed_challenge_want_check, + .check_password = fixed_challenge_check_password +}; + +_PUBLIC_ NTSTATUS auth_developer_init(void) +{ + NTSTATUS ret; + + ret = auth_register(&name_to_ntstatus_auth_ops); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(0,("Failed to register 'name_to_ntstatus' auth backend!\n")); + return ret; + } + + ret = auth_register(&fixed_challenge_auth_ops); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(0,("Failed to register 'fixed_challenge' auth backend!\n")); + return ret; + } + + return ret; +} diff --git a/source4/auth/ntlm/auth_proto.h b/source4/auth/ntlm/auth_proto.h new file mode 100644 index 0000000000..572c1a4ca7 --- /dev/null +++ b/source4/auth/ntlm/auth_proto.h @@ -0,0 +1,50 @@ +#ifndef __AUTH_NTLM_AUTH_PROTO_H__ +#define __AUTH_NTLM_AUTH_PROTO_H__ + +#undef _PRINTF_ATTRIBUTE +#define _PRINTF_ATTRIBUTE(a1, a2) PRINTF_ATTRIBUTE(a1, a2) +/* This file was automatically generated by mkproto.pl. DO NOT EDIT */ + +/* this file contains prototypes for functions that are private + * to this subsystem or library. These functions should not be + * used outside this particular subsystem! */ + + +/* The following definitions come from auth/ntlm/auth.c */ + + +/*************************************************************************** + Set a fixed challenge +***************************************************************************/ +bool auth_challenge_may_be_modified(struct auth_context *auth_ctx) ; +const struct auth_operations *auth_backend_byname(const char *name); +const struct auth_critical_sizes *auth_interface_version(void); +NTSTATUS server_service_auth_init(void); + +/* The following definitions come from auth/ntlm/auth_util.c */ + +NTSTATUS auth_get_challenge_not_implemented(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, DATA_BLOB *challenge); + +/**************************************************************************** + Create an auth_usersupplied_data structure after appropriate mapping. +****************************************************************************/ +NTSTATUS map_user_info(TALLOC_CTX *mem_ctx, + const char *default_domain, + const struct auth_usersupplied_info *user_info, + struct auth_usersupplied_info **user_info_mapped); + +/**************************************************************************** + Create an auth_usersupplied_data structure after appropriate mapping. +****************************************************************************/ +NTSTATUS encrypt_user_info(TALLOC_CTX *mem_ctx, struct auth_context *auth_context, + enum auth_password_state to_state, + const struct auth_usersupplied_info *user_info_in, + const struct auth_usersupplied_info **user_info_encrypted); + +/* The following definitions come from auth/ntlm/auth_simple.c */ + +#undef _PRINTF_ATTRIBUTE +#define _PRINTF_ATTRIBUTE(a1, a2) + +#endif /* __AUTH_NTLM_AUTH_PROTO_H__ */ + diff --git a/source4/auth/ntlm/auth_sam.c b/source4/auth/ntlm/auth_sam.c new file mode 100644 index 0000000000..2c13cd963d --- /dev/null +++ b/source4/auth/ntlm/auth_sam.c @@ -0,0 +1,449 @@ +/* + Unix SMB/CIFS implementation. + Password and authentication handling + Copyright (C) Andrew Bartlett 2001-2004 + Copyright (C) Gerald Carter 2003 + Copyright (C) Stefan Metzmacher 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "includes.h" +#include "librpc/gen_ndr/ndr_netlogon.h" +#include "system/time.h" +#include "lib/ldb/include/ldb.h" +#include "util/util_ldb.h" +#include "auth/auth.h" +#include "auth/ntlm/ntlm_check.h" +#include "auth/ntlm/auth_proto.h" +#include "auth/auth_sam.h" +#include "dsdb/samdb/samdb.h" +#include "libcli/security/security.h" +#include "libcli/ldap/ldap_ndr.h" +#include "param/param.h" + +extern const char *user_attrs[]; +extern const char *domain_ref_attrs[]; + +/**************************************************************************** + Look for the specified user in the sam, return ldb result structures +****************************************************************************/ + +static NTSTATUS authsam_search_account(TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx, + const char *account_name, + const char *domain_name, + struct ldb_message ***ret_msgs, + struct ldb_message ***ret_msgs_domain_ref) +{ + struct ldb_message **msgs_tmp; + struct ldb_message **msgs; + struct ldb_message **msgs_domain_ref; + struct ldb_dn *partitions_basedn = samdb_partitions_dn(sam_ctx, mem_ctx); + + int ret; + int ret_domain; + + struct ldb_dn *domain_dn = NULL; + + if (domain_name) { + domain_dn = samdb_domain_to_dn(sam_ctx, mem_ctx, domain_name); + if (!domain_dn) { + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + } + + /* pull the user attributes */ + ret = gendb_search(sam_ctx, mem_ctx, domain_dn, &msgs, user_attrs, + "(&(sAMAccountName=%s)(objectclass=user))", + ldb_binary_encode_string(mem_ctx, account_name)); + if (ret == -1) { + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + if (ret == 0) { + DEBUG(3,("sam_search_user: Couldn't find user [%s\\%s] in samdb, under %s\n", + domain_name, account_name, ldb_dn_get_linearized(domain_dn))); + return NT_STATUS_NO_SUCH_USER; + } + + if (ret > 1) { + DEBUG(0,("Found %d records matching user [%s]\n", ret, account_name)); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + if (!domain_dn) { + struct dom_sid *domain_sid; + + domain_sid = samdb_result_sid_prefix(mem_ctx, msgs[0], "objectSid"); + if (!domain_sid) { + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + /* find the domain's DN */ + ret = gendb_search(sam_ctx, mem_ctx, NULL, &msgs_tmp, NULL, + "(&(objectSid=%s)(objectClass=domain))", + ldap_encode_ndr_dom_sid(mem_ctx, domain_sid)); + if (ret == -1) { + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + if (ret == 0) { + DEBUG(3,("check_sam_security: Couldn't find domain_sid [%s] in passdb file.\n", + dom_sid_string(mem_ctx, domain_sid))); + return NT_STATUS_NO_SUCH_USER; + } + + if (ret > 1) { + DEBUG(0,("Found %d records matching domain_sid [%s]\n", + ret, dom_sid_string(mem_ctx, domain_sid))); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + domain_dn = msgs_tmp[0]->dn; + } + + ret_domain = gendb_search(sam_ctx, mem_ctx, partitions_basedn, &msgs_domain_ref, domain_ref_attrs, + "(nCName=%s)", ldb_dn_get_linearized(domain_dn)); + if (ret_domain == -1) { + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + if (ret_domain == 0) { + DEBUG(3,("check_sam_security: Couldn't find domain [%s] in passdb file.\n", + ldb_dn_get_linearized(msgs_tmp[0]->dn))); + return NT_STATUS_NO_SUCH_USER; + } + + if (ret_domain > 1) { + DEBUG(0,("Found %d records matching domain [%s]\n", + ret_domain, ldb_dn_get_linearized(msgs_tmp[0]->dn))); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + *ret_msgs = msgs; + *ret_msgs_domain_ref = msgs_domain_ref; + + return NT_STATUS_OK; +} + +/**************************************************************************** + Do a specific test for an smb password being correct, given a smb_password and + the lanman and NT responses. +****************************************************************************/ +static NTSTATUS authsam_password_ok(struct auth_context *auth_context, + TALLOC_CTX *mem_ctx, + uint16_t acct_flags, + const struct samr_Password *lm_pwd, + const struct samr_Password *nt_pwd, + const struct auth_usersupplied_info *user_info, + DATA_BLOB *user_sess_key, + DATA_BLOB *lm_sess_key) +{ + NTSTATUS status; + + if (acct_flags & ACB_PWNOTREQ) { + if (lp_null_passwords(auth_context->lp_ctx)) { + DEBUG(3,("Account for user '%s' has no password and null passwords are allowed.\n", + user_info->mapped.account_name)); + return NT_STATUS_OK; + } else { + DEBUG(3,("Account for user '%s' has no password and null passwords are NOT allowed.\n", + user_info->mapped.account_name)); + return NT_STATUS_LOGON_FAILURE; + } + } + + switch (user_info->password_state) { + case AUTH_PASSWORD_PLAIN: + { + const struct auth_usersupplied_info *user_info_temp; + status = encrypt_user_info(mem_ctx, auth_context, + AUTH_PASSWORD_HASH, + user_info, &user_info_temp); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Failed to convert plaintext password to password HASH: %s\n", nt_errstr(status))); + return status; + } + user_info = user_info_temp; + + /*fall through*/ + } + case AUTH_PASSWORD_HASH: + *lm_sess_key = data_blob(NULL, 0); + *user_sess_key = data_blob(NULL, 0); + status = hash_password_check(mem_ctx, + auth_context->lp_ctx, + user_info->password.hash.lanman, + user_info->password.hash.nt, + user_info->mapped.account_name, + lm_pwd, nt_pwd); + NT_STATUS_NOT_OK_RETURN(status); + break; + + case AUTH_PASSWORD_RESPONSE: + status = ntlm_password_check(mem_ctx, + auth_context->lp_ctx, + user_info->logon_parameters, + &auth_context->challenge.data, + &user_info->password.response.lanman, + &user_info->password.response.nt, + user_info->mapped.account_name, + user_info->client.account_name, + user_info->client.domain_name, + lm_pwd, nt_pwd, + user_sess_key, lm_sess_key); + NT_STATUS_NOT_OK_RETURN(status); + break; + } + + if (user_sess_key && user_sess_key->data) { + talloc_steal(auth_context, user_sess_key->data); + } + if (lm_sess_key && lm_sess_key->data) { + talloc_steal(auth_context, lm_sess_key->data); + } + + return NT_STATUS_OK; +} + + + +static NTSTATUS authsam_authenticate(struct auth_context *auth_context, + TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx, + struct ldb_message **msgs, + struct ldb_message **msgs_domain_ref, + const struct auth_usersupplied_info *user_info, + DATA_BLOB *user_sess_key, DATA_BLOB *lm_sess_key) +{ + struct samr_Password *lm_pwd, *nt_pwd; + NTSTATUS nt_status; + struct ldb_dn *domain_dn = samdb_result_dn(sam_ctx, mem_ctx, msgs_domain_ref[0], "nCName", NULL); + + uint16_t acct_flags = samdb_result_acct_flags(sam_ctx, mem_ctx, msgs[0], domain_dn); + + /* Quit if the account was locked out. */ + if (acct_flags & ACB_AUTOLOCK) { + DEBUG(3,("check_sam_security: Account for user %s was locked out.\n", + user_info->mapped.account_name)); + return NT_STATUS_ACCOUNT_LOCKED_OUT; + } + + /* You can only do an interactive login to normal accounts */ + if (user_info->flags & USER_INFO_INTERACTIVE_LOGON) { + if (!(acct_flags & ACB_NORMAL)) { + return NT_STATUS_NO_SUCH_USER; + } + } + + nt_status = samdb_result_passwords(mem_ctx, msgs[0], &lm_pwd, &nt_pwd); + NT_STATUS_NOT_OK_RETURN(nt_status); + + nt_status = authsam_password_ok(auth_context, mem_ctx, + acct_flags, lm_pwd, nt_pwd, + user_info, user_sess_key, lm_sess_key); + NT_STATUS_NOT_OK_RETURN(nt_status); + + nt_status = authsam_account_ok(mem_ctx, sam_ctx, + user_info->logon_parameters, + msgs[0], + msgs_domain_ref[0], + user_info->workstation_name, + user_info->mapped.account_name); + + return nt_status; +} + + + +static NTSTATUS authsam_check_password_internals(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const char *domain, + const struct auth_usersupplied_info *user_info, + struct auth_serversupplied_info **server_info) +{ + NTSTATUS nt_status; + const char *account_name = user_info->mapped.account_name; + struct ldb_message **msgs; + struct ldb_message **domain_ref_msgs; + struct ldb_context *sam_ctx; + DATA_BLOB user_sess_key, lm_sess_key; + TALLOC_CTX *tmp_ctx; + + if (!account_name || !*account_name) { + /* 'not for me' */ + return NT_STATUS_NOT_IMPLEMENTED; + } + + tmp_ctx = talloc_new(mem_ctx); + if (!tmp_ctx) { + return NT_STATUS_NO_MEMORY; + } + + sam_ctx = samdb_connect(tmp_ctx, ctx->auth_ctx->event_ctx, ctx->auth_ctx->lp_ctx, system_session(mem_ctx, ctx->auth_ctx->lp_ctx)); + if (sam_ctx == NULL) { + talloc_free(tmp_ctx); + return NT_STATUS_INVALID_SYSTEM_SERVICE; + } + + nt_status = authsam_search_account(tmp_ctx, sam_ctx, account_name, domain, &msgs, &domain_ref_msgs); + if (!NT_STATUS_IS_OK(nt_status)) { + talloc_free(tmp_ctx); + return nt_status; + } + + nt_status = authsam_authenticate(ctx->auth_ctx, tmp_ctx, sam_ctx, msgs, domain_ref_msgs, user_info, + &user_sess_key, &lm_sess_key); + if (!NT_STATUS_IS_OK(nt_status)) { + talloc_free(tmp_ctx); + return nt_status; + } + + nt_status = authsam_make_server_info(tmp_ctx, sam_ctx, lp_netbios_name(ctx->auth_ctx->lp_ctx), + msgs[0], domain_ref_msgs[0], + user_sess_key, lm_sess_key, + server_info); + if (!NT_STATUS_IS_OK(nt_status)) { + talloc_free(tmp_ctx); + return nt_status; + } + + talloc_steal(mem_ctx, *server_info); + talloc_free(tmp_ctx); + + return NT_STATUS_OK; +} + +static NTSTATUS authsam_ignoredomain_want_check(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info) +{ + if (!user_info->mapped.account_name || !*user_info->mapped.account_name) { + return NT_STATUS_NOT_IMPLEMENTED; + } + + return NT_STATUS_OK; +} + +static NTSTATUS authsam_ignoredomain_check_password(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info, + struct auth_serversupplied_info **server_info) +{ + return authsam_check_password_internals(ctx, mem_ctx, NULL, user_info, server_info); +} + +/**************************************************************************** +Check SAM security (above) but with a few extra checks. +****************************************************************************/ +static NTSTATUS authsam_want_check(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info) +{ + bool is_local_name, is_my_domain; + + if (!user_info->mapped.account_name || !*user_info->mapped.account_name) { + return NT_STATUS_NOT_IMPLEMENTED; + } + + is_local_name = lp_is_myname(ctx->auth_ctx->lp_ctx, + user_info->mapped.domain_name); + is_my_domain = lp_is_mydomain(ctx->auth_ctx->lp_ctx, + user_info->mapped.domain_name); + + /* check whether or not we service this domain/workgroup name */ + switch (lp_server_role(ctx->auth_ctx->lp_ctx)) { + case ROLE_STANDALONE: + return NT_STATUS_OK; + + case ROLE_DOMAIN_MEMBER: + if (!is_local_name) { + DEBUG(6,("authsam_check_password: %s is not one of my local names (DOMAIN_MEMBER)\n", + user_info->mapped.domain_name)); + return NT_STATUS_NOT_IMPLEMENTED; + } + return NT_STATUS_OK; + + case ROLE_DOMAIN_CONTROLLER: + if (!is_local_name && !is_my_domain) { + DEBUG(6,("authsam_check_password: %s is not one of my local names or domain name (DC)\n", + user_info->mapped.domain_name)); + return NT_STATUS_NOT_IMPLEMENTED; + } + return NT_STATUS_OK; + } + + DEBUG(6,("authsam_check_password: lp_server_role() has an undefined value\n")); + return NT_STATUS_NOT_IMPLEMENTED; +} + +/**************************************************************************** +Check SAM security (above) but with a few extra checks. +****************************************************************************/ +static NTSTATUS authsam_check_password(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info, + struct auth_serversupplied_info **server_info) +{ + const char *domain; + + /* check whether or not we service this domain/workgroup name */ + switch (lp_server_role(ctx->auth_ctx->lp_ctx)) { + case ROLE_STANDALONE: + case ROLE_DOMAIN_MEMBER: + domain = lp_netbios_name(ctx->auth_ctx->lp_ctx); + break; + + case ROLE_DOMAIN_CONTROLLER: + domain = lp_workgroup(ctx->auth_ctx->lp_ctx); + break; + + default: + return NT_STATUS_NO_SUCH_USER; + } + + return authsam_check_password_internals(ctx, mem_ctx, domain, user_info, server_info); +} + +static const struct auth_operations sam_ignoredomain_ops = { + .name = "sam_ignoredomain", + .get_challenge = auth_get_challenge_not_implemented, + .want_check = authsam_ignoredomain_want_check, + .check_password = authsam_ignoredomain_check_password +}; + +static const struct auth_operations sam_ops = { + .name = "sam", + .get_challenge = auth_get_challenge_not_implemented, + .want_check = authsam_want_check, + .check_password = authsam_check_password +}; + +_PUBLIC_ NTSTATUS auth_sam_init(void) +{ + NTSTATUS ret; + + ret = auth_register(&sam_ops); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(0,("Failed to register 'sam' auth backend!\n")); + return ret; + } + + ret = auth_register(&sam_ignoredomain_ops); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(0,("Failed to register 'sam_ignoredomain' auth backend!\n")); + return ret; + } + + return ret; +} diff --git a/source4/auth/ntlm/auth_server.c b/source4/auth/ntlm/auth_server.c new file mode 100644 index 0000000000..be5f84fe39 --- /dev/null +++ b/source4/auth/ntlm/auth_server.c @@ -0,0 +1,225 @@ +/* + Unix SMB/CIFS implementation. + Authenticate by using a remote server + Copyright (C) Andrew Bartlett 2001-2002, 2008 + Copyright (C) Jelmer Vernooij 2002 + Copyright (C) Stefan Metzmacher 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "includes.h" +#include "auth/auth.h" +#include "auth/auth_proto.h" +#include "auth/credentials/credentials.h" +#include "libcli/security/security.h" +#include "librpc/gen_ndr/ndr_samr.h" +#include "libcli/smb_composite/smb_composite.h" +#include "param/param.h" +#include "libcli/resolve/resolve.h" + +/* This version of 'security=server' rewirtten from scratch for Samba4 + * libraries in 2008 */ + + +static NTSTATUS server_want_check(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info) +{ + return NT_STATUS_OK; +} +/** + * The challenge from the target server, when operating in security=server + **/ +static NTSTATUS server_get_challenge(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, DATA_BLOB *_blob) +{ + struct smb_composite_connect io; + struct smbcli_options smb_options; + const char **host_list; + NTSTATUS status; + + /* Make a connection to the target server, found by 'password server' in smb.conf */ + + lp_smbcli_options(ctx->auth_ctx->lp_ctx, &smb_options); + + /* Make a negprot, WITHOUT SPNEGO, so we get a challenge nice an easy */ + io.in.options.use_spnego = false; + + /* Hope we don't get * (the default), as this won't work... */ + host_list = lp_passwordserver(ctx->auth_ctx->lp_ctx); + if (!host_list) { + return NT_STATUS_INTERNAL_ERROR; + } + io.in.dest_host = host_list[0]; + if (strequal(io.in.dest_host, "*")) { + return NT_STATUS_INTERNAL_ERROR; + } + io.in.dest_ports = lp_smb_ports(ctx->auth_ctx->lp_ctx); + + io.in.called_name = strupper_talloc(mem_ctx, io.in.dest_host); + + /* We don't want to get as far as the session setup */ + io.in.credentials = NULL; + io.in.service = NULL; + + io.in.workgroup = ""; /* only used with SPNEGO, disabled above */ + + io.in.options = smb_options; + + status = smb_composite_connect(&io, mem_ctx, lp_resolve_context(ctx->auth_ctx->lp_ctx), + ctx->auth_ctx->event_ctx); + if (!NT_STATUS_IS_OK(status)) { + *_blob = io.out.tree->session->transport->negotiate.secblob; + ctx->private_data = talloc_steal(ctx, io.out.tree->session); + } + return NT_STATUS_OK; +} + +/** + * Return an error based on username + * + * This function allows the testing of obsure errors, as well as the generation + * of NT_STATUS -> DOS error mapping tables. + * + * This module is of no value to end-users. + * + * The password is ignored. + * + * @return An NTSTATUS value based on the username + **/ + +static NTSTATUS server_check_password(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info, + struct auth_serversupplied_info **_server_info) +{ + NTSTATUS nt_status; + struct auth_serversupplied_info *server_info; + struct cli_credentials *creds; + const char *user; + struct smb_composite_sesssetup session_setup; + + struct smbcli_session *session = talloc_get_type(ctx->private_data, struct smbcli_session); + + creds = cli_credentials_init(mem_ctx); + + NT_STATUS_HAVE_NO_MEMORY(creds); + + cli_credentials_set_username(creds, user_info->client.account_name, CRED_SPECIFIED); + cli_credentials_set_domain(creds, user_info->client.domain_name, CRED_SPECIFIED); + + switch (user_info->password_state) { + case AUTH_PASSWORD_PLAIN: + cli_credentials_set_password(creds, user_info->password.plaintext, + CRED_SPECIFIED); + break; + case AUTH_PASSWORD_HASH: + cli_credentials_set_nt_hash(creds, user_info->password.hash.nt, + CRED_SPECIFIED); + break; + + case AUTH_PASSWORD_RESPONSE: + cli_credentials_set_ntlm_response(creds, &user_info->password.response.lanman, &user_info->password.response.nt, CRED_SPECIFIED); + break; + } + + session_setup.in.sesskey = session->transport->negotiate.sesskey; + session_setup.in.capabilities = session->transport->negotiate.capabilities; + + session_setup.in.credentials = creds; + session_setup.in.workgroup = ""; /* Only used with SPNEGO, which we are not doing */ + + /* Check password with remove server - this should be async some day */ + nt_status = smb_composite_sesssetup(session, &session_setup); + + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + + server_info = talloc(mem_ctx, struct auth_serversupplied_info); + NT_STATUS_HAVE_NO_MEMORY(server_info); + + server_info->account_sid = dom_sid_parse_talloc(server_info, SID_NT_ANONYMOUS); + NT_STATUS_HAVE_NO_MEMORY(server_info->account_sid); + + /* is this correct? */ + server_info->primary_group_sid = dom_sid_parse_talloc(server_info, SID_BUILTIN_GUESTS); + NT_STATUS_HAVE_NO_MEMORY(server_info->primary_group_sid); + + server_info->n_domain_groups = 0; + server_info->domain_groups = NULL; + + /* annoying, but the Anonymous really does have a session key, + and it is all zeros! */ + server_info->user_session_key = data_blob(NULL, 0); + server_info->lm_session_key = data_blob(NULL, 0); + + server_info->account_name = talloc_strdup(server_info, user_info->client.account_name); + NT_STATUS_HAVE_NO_MEMORY(server_info->account_name); + + server_info->domain_name = talloc_strdup(server_info, user_info->client.domain_name); + NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name); + + server_info->full_name = NULL; + + server_info->logon_script = talloc_strdup(server_info, ""); + NT_STATUS_HAVE_NO_MEMORY(server_info->logon_script); + + server_info->profile_path = talloc_strdup(server_info, ""); + NT_STATUS_HAVE_NO_MEMORY(server_info->profile_path); + + server_info->home_directory = talloc_strdup(server_info, ""); + NT_STATUS_HAVE_NO_MEMORY(server_info->home_directory); + + server_info->home_drive = talloc_strdup(server_info, ""); + NT_STATUS_HAVE_NO_MEMORY(server_info->home_drive); + + server_info->last_logon = 0; + server_info->last_logoff = 0; + server_info->acct_expiry = 0; + server_info->last_password_change = 0; + server_info->allow_password_change = 0; + server_info->force_password_change = 0; + + server_info->logon_count = 0; + server_info->bad_password_count = 0; + + server_info->acct_flags = ACB_NORMAL; + + server_info->authenticated = false; + + *_server_info = server_info; + + return nt_status; +} + +static const struct auth_operations server_auth_ops = { + .name = "server", + .get_challenge = server_get_challenge, + .want_check = server_want_check, + .check_password = server_check_password +}; + +_PUBLIC_ NTSTATUS auth_server_init(void) +{ + NTSTATUS ret; + + ret = auth_register(&server_auth_ops); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(0,("Failed to register 'server' auth backend!\n")); + return ret; + } + + return ret; +} diff --git a/source4/auth/ntlm/auth_simple.c b/source4/auth/ntlm/auth_simple.c new file mode 100644 index 0000000000..e7039c3657 --- /dev/null +++ b/source4/auth/ntlm/auth_simple.c @@ -0,0 +1,103 @@ +/* + Unix SMB/CIFS implementation. + + auth functions + + Copyright (C) Simo Sorce 2005 + Copyright (C) Andrew Tridgell 2005 + Copyright (C) Andrew Bartlett 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "includes.h" +#include "auth/auth.h" +#include "lib/events/events.h" +#include "param/param.h" +#include "auth/session_proto.h" + +/* + It's allowed to pass NULL as session_info, + when the caller doesn't need a session_info +*/ +_PUBLIC_ NTSTATUS authenticate_username_pw(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct messaging_context *msg, + struct loadparm_context *lp_ctx, + const char *nt4_domain, + const char *nt4_username, + const char *password, + struct auth_session_info **session_info) +{ + struct auth_context *auth_context; + struct auth_usersupplied_info *user_info; + struct auth_serversupplied_info *server_info; + NTSTATUS nt_status; + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + + if (!tmp_ctx) { + return NT_STATUS_NO_MEMORY; + } + + nt_status = auth_context_create(tmp_ctx, + ev, msg, + lp_ctx, + &auth_context); + if (!NT_STATUS_IS_OK(nt_status)) { + talloc_free(tmp_ctx); + return nt_status; + } + + user_info = talloc(tmp_ctx, struct auth_usersupplied_info); + if (!user_info) { + talloc_free(tmp_ctx); + return NT_STATUS_NO_MEMORY; + } + + user_info->mapped_state = true; + user_info->client.account_name = nt4_username; + user_info->mapped.account_name = nt4_username; + user_info->client.domain_name = nt4_domain; + user_info->mapped.domain_name = nt4_domain; + + user_info->workstation_name = NULL; + + user_info->remote_host = NULL; + + user_info->password_state = AUTH_PASSWORD_PLAIN; + user_info->password.plaintext = talloc_strdup(user_info, password); + + user_info->flags = USER_INFO_CASE_INSENSITIVE_USERNAME | + USER_INFO_DONT_CHECK_UNIX_ACCOUNT; + + user_info->logon_parameters = 0; + + nt_status = auth_check_password(auth_context, tmp_ctx, user_info, &server_info); + if (!NT_STATUS_IS_OK(nt_status)) { + talloc_free(tmp_ctx); + return nt_status; + } + + if (session_info) { + nt_status = auth_generate_session_info(tmp_ctx, ev, lp_ctx, server_info, session_info); + + if (NT_STATUS_IS_OK(nt_status)) { + talloc_steal(mem_ctx, *session_info); + } + } + + talloc_free(tmp_ctx); + return nt_status; +} + diff --git a/source4/auth/ntlm/auth_unix.c b/source4/auth/ntlm/auth_unix.c new file mode 100644 index 0000000000..a417107025 --- /dev/null +++ b/source4/auth/ntlm/auth_unix.c @@ -0,0 +1,844 @@ +/* + Unix SMB/CIFS implementation. + Password and authentication handling + Copyright (C) Andrew Bartlett 2001 + Copyright (C) Jeremy Allison 2001 + Copyright (C) Simo Sorce 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "includes.h" +#include "auth/auth.h" +#include "auth/auth_proto.h" +#include "system/passwd.h" /* needed by some systems for struct passwd */ +#include "lib/socket/socket.h" +#include "auth/pam_errors.h" +#include "param/param.h" + +/* TODO: look at how to best fill in parms retrieveing a struct passwd info + * except in case USER_INFO_DONT_CHECK_UNIX_ACCOUNT is set + */ +static NTSTATUS authunix_make_server_info(TALLOC_CTX *mem_ctx, + const char *netbios_name, + const struct auth_usersupplied_info *user_info, + struct passwd *pwd, + struct auth_serversupplied_info **_server_info) +{ + struct auth_serversupplied_info *server_info; + NTSTATUS status; + + /* This is a real, real hack */ + if (pwd->pw_uid == 0) { + status = auth_system_server_info(mem_ctx, netbios_name, &server_info); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + server_info->account_name = talloc_steal(server_info, pwd->pw_name); + NT_STATUS_HAVE_NO_MEMORY(server_info->account_name); + + server_info->domain_name = talloc_strdup(server_info, "unix"); + NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name); + } else { + server_info = talloc(mem_ctx, struct auth_serversupplied_info); + NT_STATUS_HAVE_NO_MEMORY(server_info); + + server_info->authenticated = true; + + server_info->account_name = talloc_steal(server_info, pwd->pw_name); + NT_STATUS_HAVE_NO_MEMORY(server_info->account_name); + + server_info->domain_name = talloc_strdup(server_info, "unix"); + NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name); + + /* This isn't in any way correct.. */ + server_info->account_sid = NULL; + server_info->primary_group_sid = NULL; + server_info->n_domain_groups = 0; + server_info->domain_groups = NULL; + } + server_info->user_session_key = data_blob(NULL,0); + server_info->lm_session_key = data_blob(NULL,0); + + server_info->full_name = talloc_steal(server_info, pwd->pw_gecos); + NT_STATUS_HAVE_NO_MEMORY(server_info->full_name); + server_info->logon_script = talloc_strdup(server_info, ""); + NT_STATUS_HAVE_NO_MEMORY(server_info->logon_script); + server_info->profile_path = talloc_strdup(server_info, ""); + NT_STATUS_HAVE_NO_MEMORY(server_info->profile_path); + server_info->home_directory = talloc_strdup(server_info, ""); + NT_STATUS_HAVE_NO_MEMORY(server_info->home_directory); + server_info->home_drive = talloc_strdup(server_info, ""); + NT_STATUS_HAVE_NO_MEMORY(server_info->home_drive); + + server_info->last_logon = 0; + server_info->last_logoff = 0; + server_info->acct_expiry = 0; + server_info->last_password_change = 0; + server_info->allow_password_change = 0; + server_info->force_password_change = 0; + server_info->logon_count = 0; + server_info->bad_password_count = 0; + server_info->acct_flags = 0; + + *_server_info = server_info; + + return NT_STATUS_OK; +} + +static NTSTATUS talloc_getpwnam(TALLOC_CTX *ctx, const char *username, struct passwd **pws) +{ + struct passwd *ret; + struct passwd *from; + + *pws = NULL; + + ret = talloc(ctx, struct passwd); + NT_STATUS_HAVE_NO_MEMORY(ret); + + from = getpwnam(username); + if (!from) { + return NT_STATUS_NO_SUCH_USER; + } + + ret->pw_name = talloc_strdup(ctx, from->pw_name); + NT_STATUS_HAVE_NO_MEMORY(ret->pw_name); + + ret->pw_passwd = talloc_strdup(ctx, from->pw_passwd); + NT_STATUS_HAVE_NO_MEMORY(ret->pw_passwd); + + ret->pw_uid = from->pw_uid; + ret->pw_gid = from->pw_gid; + ret->pw_gecos = talloc_strdup(ctx, from->pw_gecos); + NT_STATUS_HAVE_NO_MEMORY(ret->pw_gecos); + + ret->pw_dir = talloc_strdup(ctx, from->pw_dir); + NT_STATUS_HAVE_NO_MEMORY(ret->pw_dir); + + ret->pw_shell = talloc_strdup(ctx, from->pw_shell); + NT_STATUS_HAVE_NO_MEMORY(ret->pw_shell); + + *pws = ret; + + return NT_STATUS_OK; +} + + +#ifdef HAVE_SECURITY_PAM_APPL_H +#include + +struct smb_pam_user_info { + const char *account_name; + const char *plaintext_password; +}; + +#define COPY_STRING(s) (s) ? strdup(s) : NULL + +/* + * Check user password + * Currently it uses PAM only and fails on systems without PAM + * Samba3 code located in pass_check.c is to ugly to be used directly it will + * need major rework that's why pass_check.c is still there. +*/ + +static int smb_pam_conv(int num_msg, const struct pam_message **msg, + struct pam_response **reply, void *appdata_ptr) +{ + struct smb_pam_user_info *info = (struct smb_pam_user_info *)appdata_ptr; + int num; + + if (num_msg <= 0) { + *reply = NULL; + return PAM_CONV_ERR; + } + + /* + * Apparantly HPUX has a buggy PAM that doesn't support the + * data pointer. Fail if this is the case. JRA. + */ + + if (info == NULL) { + *reply = NULL; + return PAM_CONV_ERR; + } + + /* + * PAM frees memory in reply messages by itself + * so use malloc instead of talloc here. + */ + *reply = malloc_array_p(struct pam_response, num_msg); + if (*reply == NULL) { + return PAM_CONV_ERR; + } + + for (num = 0; num < num_msg; num++) { + switch (msg[num]->msg_style) { + case PAM_PROMPT_ECHO_ON: + (*reply)[num].resp_retcode = PAM_SUCCESS; + (*reply)[num].resp = COPY_STRING(info->account_name); + break; + + case PAM_PROMPT_ECHO_OFF: + (*reply)[num].resp_retcode = PAM_SUCCESS; + (*reply)[num].resp = COPY_STRING(info->plaintext_password); + break; + + case PAM_TEXT_INFO: + (*reply)[num].resp_retcode = PAM_SUCCESS; + (*reply)[num].resp = NULL; + DEBUG(4,("PAM Info message in conversation function: %s\n", (msg[num]->msg))); + break; + + case PAM_ERROR_MSG: + (*reply)[num].resp_retcode = PAM_SUCCESS; + (*reply)[num].resp = NULL; + DEBUG(4,("PAM Error message in conversation function: %s\n", (msg[num]->msg))); + break; + + default: + while (num > 0) { + SAFE_FREE((*reply)[num-1].resp); + num--; + } + SAFE_FREE(*reply); + *reply = NULL; + DEBUG(1,("Error: PAM subsystme sent an UNKNOWN message type to the conversation function!\n")); + return PAM_CONV_ERR; + } + } + + return PAM_SUCCESS; +} + +/* + * Start PAM authentication for specified account + */ + +static NTSTATUS smb_pam_start(pam_handle_t **pamh, const char *account_name, const char *remote_host, struct pam_conv *pconv) +{ + int pam_error; + + if (account_name == NULL || remote_host == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + DEBUG(4,("smb_pam_start: PAM: Init user: %s\n", account_name)); + + pam_error = pam_start("samba", account_name, pconv, pamh); + if (pam_error != PAM_SUCCESS) { + /* no valid pamh here, can we reliably call pam_strerror ? */ + DEBUG(4,("smb_pam_start: pam_start failed!\n")); + return NT_STATUS_UNSUCCESSFUL; + } + +#ifdef PAM_RHOST + DEBUG(4,("smb_pam_start: PAM: setting rhost to: %s\n", remote_host)); + pam_error = pam_set_item(*pamh, PAM_RHOST, remote_host); + if (pam_error != PAM_SUCCESS) { + NTSTATUS nt_status; + + DEBUG(4,("smb_pam_start: setting rhost failed with error: %s\n", + pam_strerror(*pamh, pam_error))); + nt_status = pam_to_nt_status(pam_error); + + pam_error = pam_end(*pamh, 0); + if (pam_error != PAM_SUCCESS) { + /* no vaild pamh here, can we reliably call pam_strerror ? */ + DEBUG(4,("smb_pam_start: clean up failed, pam_end gave error %d.\n", + pam_error)); + return pam_to_nt_status(pam_error); + } + return nt_status; + } +#endif +#ifdef PAM_TTY + DEBUG(4,("smb_pam_start: PAM: setting tty\n")); + pam_error = pam_set_item(*pamh, PAM_TTY, "samba"); + if (pam_error != PAM_SUCCESS) { + NTSTATUS nt_status; + + DEBUG(4,("smb_pam_start: setting tty failed with error: %s\n", + pam_strerror(*pamh, pam_error))); + nt_status = pam_to_nt_status(pam_error); + + pam_error = pam_end(*pamh, 0); + if (pam_error != PAM_SUCCESS) { + /* no vaild pamh here, can we reliably call pam_strerror ? */ + DEBUG(4,("smb_pam_start: clean up failed, pam_end gave error %d.\n", + pam_error)); + return pam_to_nt_status(pam_error); + } + return nt_status; + } +#endif + DEBUG(4,("smb_pam_start: PAM: Init passed for user: %s\n", account_name)); + + return NT_STATUS_OK; +} + +static NTSTATUS smb_pam_end(pam_handle_t *pamh) +{ + int pam_error; + + if (pamh != NULL) { + pam_error = pam_end(pamh, 0); + if (pam_error != PAM_SUCCESS) { + /* no vaild pamh here, can we reliably call pam_strerror ? */ + DEBUG(4,("smb_pam_end: clean up failed, pam_end gave error %d.\n", + pam_error)); + return pam_to_nt_status(pam_error); + } + return NT_STATUS_OK; + } + + DEBUG(2,("smb_pam_end: pamh is NULL, PAM not initialized ?\n")); + return NT_STATUS_UNSUCCESSFUL; +} + +/* + * PAM Authentication Handler + */ +static NTSTATUS smb_pam_auth(pam_handle_t *pamh, bool allow_null_passwords, const char *user) +{ + int pam_error; + + /* + * To enable debugging set in /etc/pam.d/samba: + * auth required /lib/security/pam_pwdb.so nullok shadow audit + */ + + DEBUG(4,("smb_pam_auth: PAM: Authenticate User: %s\n", user)); + + pam_error = pam_authenticate(pamh, PAM_SILENT | allow_null_passwords ? 0 : PAM_DISALLOW_NULL_AUTHTOK); + switch( pam_error ){ + case PAM_AUTH_ERR: + DEBUG(2, ("smb_pam_auth: PAM: Authentication Error for user %s\n", user)); + break; + case PAM_CRED_INSUFFICIENT: + DEBUG(2, ("smb_pam_auth: PAM: Insufficient Credentials for user %s\n", user)); + break; + case PAM_AUTHINFO_UNAVAIL: + DEBUG(2, ("smb_pam_auth: PAM: Authentication Information Unavailable for user %s\n", user)); + break; + case PAM_USER_UNKNOWN: + DEBUG(2, ("smb_pam_auth: PAM: Username %s NOT known to Authentication system\n", user)); + break; + case PAM_MAXTRIES: + DEBUG(2, ("smb_pam_auth: PAM: One or more authentication modules reports user limit for user %s exceeeded\n", user)); + break; + case PAM_ABORT: + DEBUG(0, ("smb_pam_auth: PAM: One or more PAM modules failed to load for user %s\n", user)); + break; + case PAM_SUCCESS: + DEBUG(4, ("smb_pam_auth: PAM: User %s Authenticated OK\n", user)); + break; + default: + DEBUG(0, ("smb_pam_auth: PAM: UNKNOWN ERROR while authenticating user %s\n", user)); + break; + } + + return pam_to_nt_status(pam_error); +} + +/* + * PAM Account Handler + */ +static NTSTATUS smb_pam_account(pam_handle_t *pamh, const char * user) +{ + int pam_error; + + DEBUG(4,("smb_pam_account: PAM: Account Management for User: %s\n", user)); + + pam_error = pam_acct_mgmt(pamh, PAM_SILENT); /* Is user account enabled? */ + switch( pam_error ) { + case PAM_AUTHTOK_EXPIRED: + DEBUG(2, ("smb_pam_account: PAM: User %s is valid but password is expired\n", user)); + break; + case PAM_ACCT_EXPIRED: + DEBUG(2, ("smb_pam_account: PAM: User %s no longer permitted to access system\n", user)); + break; + case PAM_AUTH_ERR: + DEBUG(2, ("smb_pam_account: PAM: There was an authentication error for user %s\n", user)); + break; + case PAM_PERM_DENIED: + DEBUG(0, ("smb_pam_account: PAM: User %s is NOT permitted to access system at this time\n", user)); + break; + case PAM_USER_UNKNOWN: + DEBUG(0, ("smb_pam_account: PAM: User \"%s\" is NOT known to account management\n", user)); + break; + case PAM_SUCCESS: + DEBUG(4, ("smb_pam_account: PAM: Account OK for User: %s\n", user)); + break; + default: + DEBUG(0, ("smb_pam_account: PAM: UNKNOWN PAM ERROR (%d) during Account Management for User: %s\n", pam_error, user)); + break; + } + + return pam_to_nt_status(pam_error); +} + +/* + * PAM Credential Setting + */ + +static NTSTATUS smb_pam_setcred(pam_handle_t *pamh, const char * user) +{ + int pam_error; + + /* + * This will allow samba to aquire a kerberos token. And, when + * exporting an AFS cell, be able to /write/ to this cell. + */ + + DEBUG(4,("PAM: Account Management SetCredentials for User: %s\n", user)); + + pam_error = pam_setcred(pamh, (PAM_ESTABLISH_CRED|PAM_SILENT)); + switch( pam_error ) { + case PAM_CRED_UNAVAIL: + DEBUG(0, ("smb_pam_setcred: PAM: Credentials not found for user:%s\n", user )); + break; + case PAM_CRED_EXPIRED: + DEBUG(0, ("smb_pam_setcred: PAM: Credentials for user: \"%s\" EXPIRED!\n", user )); + break; + case PAM_USER_UNKNOWN: + DEBUG(0, ("smb_pam_setcred: PAM: User: \"%s\" is NOT known so can not set credentials!\n", user )); + break; + case PAM_CRED_ERR: + DEBUG(0, ("smb_pam_setcred: PAM: Unknown setcredentials error - unable to set credentials for %s\n", user )); + break; + case PAM_SUCCESS: + DEBUG(4, ("smb_pam_setcred: PAM: SetCredentials OK for User: %s\n", user)); + break; + default: + DEBUG(0, ("smb_pam_setcred: PAM: UNKNOWN PAM ERROR (%d) during SetCredentials for User: %s\n", pam_error, user)); + break; + } + + return pam_to_nt_status(pam_error); +} + +static NTSTATUS check_unix_password(TALLOC_CTX *ctx, struct loadparm_context *lp_ctx, + const struct auth_usersupplied_info *user_info, struct passwd **pws) +{ + struct smb_pam_user_info *info; + struct pam_conv *pamconv; + pam_handle_t *pamh; + NTSTATUS nt_status; + + info = talloc(ctx, struct smb_pam_user_info); + if (info == NULL) { + return NT_STATUS_NO_MEMORY; + } + + info->account_name = user_info->mapped.account_name; + info->plaintext_password = user_info->password.plaintext; + + pamconv = talloc(ctx, struct pam_conv); + if (pamconv == NULL) { + return NT_STATUS_NO_MEMORY; + } + + pamconv->conv = smb_pam_conv; + pamconv->appdata_ptr = (void *)info; + + /* TODO: + * check for user_info->flags & USER_INFO_CASE_INSENSITIVE_USERNAME + * if true set up a crack name routine. + */ + + nt_status = smb_pam_start(&pamh, user_info->mapped.account_name, user_info->remote_host ? user_info->remote_host->addr : NULL, pamconv); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + + nt_status = smb_pam_auth(pamh, lp_null_passwords(lp_ctx), user_info->mapped.account_name); + if (!NT_STATUS_IS_OK(nt_status)) { + smb_pam_end(pamh); + return nt_status; + } + + if ( ! (user_info->flags & USER_INFO_DONT_CHECK_UNIX_ACCOUNT)) { + + nt_status = smb_pam_account(pamh, user_info->mapped.account_name); + if (!NT_STATUS_IS_OK(nt_status)) { + smb_pam_end(pamh); + return nt_status; + } + + nt_status = smb_pam_setcred(pamh, user_info->mapped.account_name); + if (!NT_STATUS_IS_OK(nt_status)) { + smb_pam_end(pamh); + return nt_status; + } + } + + smb_pam_end(pamh); + + nt_status = talloc_getpwnam(ctx, user_info->mapped.account_name, pws); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + + return NT_STATUS_OK; +} + +#else + +/**************************************************************************** +core of password checking routine +****************************************************************************/ +static NTSTATUS password_check(const char *username, const char *password, + const char *crypted, const char *salt) +{ + bool ret; + +#ifdef WITH_AFS + if (afs_auth(username, password)) + return NT_STATUS_OK; +#endif /* WITH_AFS */ + +#ifdef WITH_DFS + if (dfs_auth(username, password)) + return NT_STATUS_OK; +#endif /* WITH_DFS */ + +#ifdef OSF1_ENH_SEC + + ret = (strcmp(osf1_bigcrypt(password, salt), crypted) == 0); + + if (!ret) { + DEBUG(2, + ("OSF1_ENH_SEC failed. Trying normal crypt.\n")); + ret = (strcmp((char *)crypt(password, salt), crypted) == 0); + } + if (ret) { + return NT_STATUS_OK; + } else { + return NT_STATUS_WRONG_PASSWORD; + } + +#endif /* OSF1_ENH_SEC */ + +#ifdef ULTRIX_AUTH + ret = (strcmp((char *)crypt16(password, salt), crypted) == 0); + if (ret) { + return NT_STATUS_OK; + } else { + return NT_STATUS_WRONG_PASSWORD; + } + +#endif /* ULTRIX_AUTH */ + +#ifdef LINUX_BIGCRYPT + ret = (linux_bigcrypt(password, salt, crypted)); + if (ret) { + return NT_STATUS_OK; + } else { + return NT_STATUS_WRONG_PASSWORD; + } +#endif /* LINUX_BIGCRYPT */ + +#if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS) + + /* + * Some systems have bigcrypt in the C library but might not + * actually use it for the password hashes (HPUX 10.20) is + * a noteable example. So we try bigcrypt first, followed + * by crypt. + */ + + if (strcmp(bigcrypt(password, salt), crypted) == 0) + return NT_STATUS_OK; + else + ret = (strcmp((char *)crypt(password, salt), crypted) == 0); + if (ret) { + return NT_STATUS_OK; + } else { + return NT_STATUS_WRONG_PASSWORD; + } +#else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */ + +#ifdef HAVE_BIGCRYPT + ret = (strcmp(bigcrypt(password, salt), crypted) == 0); + if (ret) { + return NT_STATUS_OK; + } else { + return NT_STATUS_WRONG_PASSWORD; + } +#endif /* HAVE_BIGCRYPT */ + +#ifndef HAVE_CRYPT + DEBUG(1, ("Warning - no crypt available\n")); + return NT_STATUS_LOGON_FAILURE; +#else /* HAVE_CRYPT */ + ret = (strcmp((char *)crypt(password, salt), crypted) == 0); + if (ret) { + return NT_STATUS_OK; + } else { + return NT_STATUS_WRONG_PASSWORD; + } +#endif /* HAVE_CRYPT */ +#endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */ +} + +static NTSTATUS check_unix_password(TALLOC_CTX *ctx, struct loadparm_context *lp_ctx, + const struct auth_usersupplied_info *user_info, struct passwd **ret_passwd) +{ + char *username; + char *password; + char *pwcopy; + char *salt; + char *crypted; + struct passwd *pws; + NTSTATUS nt_status; + int level = lp_passwordlevel(lp_ctx); + + *ret_passwd = NULL; + + username = talloc_strdup(ctx, user_info->mapped.account_name); + password = talloc_strdup(ctx, user_info->password.plaintext); + + nt_status = talloc_getpwnam(ctx, username, &pws); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + + crypted = pws->pw_passwd; + salt = pws->pw_passwd; + +#ifdef HAVE_GETSPNAM + { + struct spwd *spass; + + /* many shadow systems require you to be root to get + the password, in most cases this should already be + the case when this function is called, except + perhaps for IPC password changing requests */ + + spass = getspnam(pws->pw_name); + if (spass && spass->sp_pwdp) { + crypted = talloc_strdup(ctx, spass->sp_pwdp); + NT_STATUS_HAVE_NO_MEMORY(crypted); + salt = talloc_strdup(ctx, spass->sp_pwdp); + NT_STATUS_HAVE_NO_MEMORY(salt); + } + } +#elif defined(IA_UINFO) + { + char *ia_password; + /* Need to get password with SVR4.2's ia_ functions + instead of get{sp,pw}ent functions. Required by + UnixWare 2.x, tested on version + 2.1. (tangent@cyberport.com) */ + uinfo_t uinfo; + if (ia_openinfo(pws->pw_name, &uinfo) != -1) { + ia_get_logpwd(uinfo, &ia_password); + crypted = talloc_strdup(ctx, ia_password); + NT_STATUS_HAVE_NO_MEMORY(crypted); + } + } +#endif + +#ifdef HAVE_GETPRPWNAM + { + struct pr_passwd *pr_pw = getprpwnam(pws->pw_name); + if (pr_pw && pr_pw->ufld.fd_encrypt) { + crypted = talloc_strdup(ctx, pr_pw->ufld.fd_encrypt); + NT_STATUS_HAVE_NO_MEMORY(crypted); + } + } +#endif + +#ifdef HAVE_GETPWANAM + { + struct passwd_adjunct *pwret; + pwret = getpwanam(s); + if (pwret && pwret->pwa_passwd) { + crypted = talloc_strdup(ctx, pwret->pwa_passwd); + NT_STATUS_HAVE_NO_MEMORY(crypted); + } + } +#endif + +#ifdef OSF1_ENH_SEC + { + struct pr_passwd *mypasswd; + DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n", username)); + mypasswd = getprpwnam(username); + if (mypasswd) { + username = talloc_strdup(ctx, mypasswd->ufld.fd_name); + NT_STATUS_HAVE_NO_MEMORY(username); + crypted = talloc_strdup(ctx, mypasswd->ufld.fd_encrypt); + NT_STATUS_HAVE_NO_MEMORY(crypted); + } else { + DEBUG(5,("OSF1_ENH_SEC: No entry for user %s in protected database !\n", username)); + } + } +#endif + +#ifdef ULTRIX_AUTH + { + AUTHORIZATION *ap = getauthuid(pws->pw_uid); + if (ap) { + crypted = talloc_strdup(ctx, ap->a_password); + endauthent(); + NT_STATUS_HAVE_NO_MEMORY(crypted); + } + } +#endif + +#if defined(HAVE_TRUNCATED_SALT) + /* crypt on some platforms (HPUX in particular) + won't work with more than 2 salt characters. */ + salt[2] = 0; +#endif + + if (crypted[0] == '\0') { + if (!lp_null_passwords(lp_ctx)) { + DEBUG(2, ("Disallowing %s with null password\n", username)); + return NT_STATUS_LOGON_FAILURE; + } + if (password == NULL) { + DEBUG(3, ("Allowing access to %s with null password\n", username)); + *ret_passwd = pws; + return NT_STATUS_OK; + } + } + + /* try it as it came to us */ + nt_status = password_check(username, password, crypted, salt); + if (NT_STATUS_IS_OK(nt_status)) { + *ret_passwd = pws; + return nt_status; + } + else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) { + /* No point continuing if its not the password thats to blame (ie PAM disabled). */ + return nt_status; + } + + if ( user_info->flags | USER_INFO_CASE_INSENSITIVE_PASSWORD) { + return nt_status; + } + + /* if the password was given to us with mixed case then we don't + * need to proceed as we know it hasn't been case modified by the + * client */ + if (strhasupper(password) && strhaslower(password)) { + return nt_status; + } + + /* make a copy of it */ + pwcopy = talloc_strdup(ctx, password); + if (!pwcopy) + return NT_STATUS_NO_MEMORY; + + /* try all lowercase if it's currently all uppercase */ + if (strhasupper(pwcopy)) { + strlower(pwcopy); + nt_status = password_check(username, pwcopy, crypted, salt); + if NT_STATUS_IS_OK(nt_status) { + *ret_passwd = pws; + return nt_status; + } + } + + /* give up? */ + if (level < 1) { + return NT_STATUS_WRONG_PASSWORD; + } + + /* last chance - all combinations of up to level chars upper! */ + strlower(pwcopy); + +#if 0 + if (NT_STATUS_IS_OK(nt_status = string_combinations(pwcopy, password_check, level))) { + *ret_passwd = pws; + return nt_status; + } +#endif + return NT_STATUS_WRONG_PASSWORD; +} + +#endif + +/** Check a plaintext username/password + * + **/ + +static NTSTATUS authunix_want_check(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info) +{ + if (!user_info->mapped.account_name || !*user_info->mapped.account_name) { + return NT_STATUS_NOT_IMPLEMENTED; + } + + return NT_STATUS_OK; +} + +static NTSTATUS authunix_check_password(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info, + struct auth_serversupplied_info **server_info) +{ + TALLOC_CTX *check_ctx; + NTSTATUS nt_status; + struct passwd *pwd; + + if (user_info->password_state != AUTH_PASSWORD_PLAIN) { + return NT_STATUS_INVALID_PARAMETER; + } + + check_ctx = talloc_named_const(mem_ctx, 0, "check_unix_password"); + if (check_ctx == NULL) { + return NT_STATUS_NO_MEMORY; + } + + nt_status = check_unix_password(check_ctx, ctx->auth_ctx->lp_ctx, user_info, &pwd); + if (!NT_STATUS_IS_OK(nt_status)) { + talloc_free(check_ctx); + return nt_status; + } + + nt_status = authunix_make_server_info(mem_ctx, lp_netbios_name(ctx->auth_ctx->lp_ctx), + user_info, pwd, server_info); + if (!NT_STATUS_IS_OK(nt_status)) { + talloc_free(check_ctx); + return nt_status; + } + + talloc_free(check_ctx); + return NT_STATUS_OK; +} + +static const struct auth_operations unix_ops = { + .name = "unix", + .get_challenge = auth_get_challenge_not_implemented, + .want_check = authunix_want_check, + .check_password = authunix_check_password +}; + +_PUBLIC_ NTSTATUS auth_unix_init(void) +{ + NTSTATUS ret; + + ret = auth_register(&unix_ops); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(0,("Failed to register unix auth backend!\n")); + return ret; + } + + return ret; +} diff --git a/source4/auth/ntlm/auth_util.c b/source4/auth/ntlm/auth_util.c new file mode 100644 index 0000000000..1d86b858cf --- /dev/null +++ b/source4/auth/ntlm/auth_util.c @@ -0,0 +1,260 @@ +/* + Unix SMB/CIFS implementation. + Authentication utility functions + Copyright (C) Andrew Tridgell 1992-1998 + Copyright (C) Andrew Bartlett 2001 + Copyright (C) Jeremy Allison 2000-2001 + Copyright (C) Rafal Szczesniak 2002 + Copyright (C) Stefan Metzmacher 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "includes.h" +#include "auth/auth.h" +#include "libcli/security/security.h" +#include "libcli/auth/libcli_auth.h" +#include "dsdb/samdb/samdb.h" +#include "auth/credentials/credentials.h" +#include "param/param.h" + +/* this default function can be used by mostly all backends + * which don't want to set a challenge + */ +NTSTATUS auth_get_challenge_not_implemented(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, DATA_BLOB *challenge) +{ + /* we don't want to set a challenge */ + return NT_STATUS_NOT_IMPLEMENTED; +} + +/**************************************************************************** + Create an auth_usersupplied_data structure after appropriate mapping. +****************************************************************************/ + +NTSTATUS map_user_info(TALLOC_CTX *mem_ctx, + const char *default_domain, + const struct auth_usersupplied_info *user_info, + struct auth_usersupplied_info **user_info_mapped) +{ + const char *domain; + char *account_name; + char *d; + DEBUG(5,("map_user_info: Mapping user [%s]\\[%s] from workstation [%s]\n", + user_info->client.domain_name, user_info->client.account_name, user_info->workstation_name)); + + account_name = talloc_strdup(mem_ctx, user_info->client.account_name); + if (!account_name) { + return NT_STATUS_NO_MEMORY; + } + + /* don't allow "" as a domain, fixes a Win9X bug + where it doesn't supply a domain for logon script + 'net use' commands. */ + + /* Split user@realm names into user and realm components. This is TODO to fix with proper userprincipalname support */ + if (user_info->client.domain_name && *user_info->client.domain_name) { + domain = user_info->client.domain_name; + } else if (strchr_m(user_info->client.account_name, '@')) { + d = strchr_m(account_name, '@'); + if (!d) { + return NT_STATUS_INTERNAL_ERROR; + } + d[0] = '\0'; + d++; + domain = d; + } else { + domain = default_domain; + } + + *user_info_mapped = talloc(mem_ctx, struct auth_usersupplied_info); + if (!*user_info_mapped) { + return NT_STATUS_NO_MEMORY; + } + if (!talloc_reference(*user_info_mapped, user_info)) { + return NT_STATUS_NO_MEMORY; + } + **user_info_mapped = *user_info; + (*user_info_mapped)->mapped_state = true; + (*user_info_mapped)->mapped.domain_name = talloc_strdup(*user_info_mapped, domain); + (*user_info_mapped)->mapped.account_name = talloc_strdup(*user_info_mapped, account_name); + talloc_free(account_name); + if (!(*user_info_mapped)->mapped.domain_name + || !(*user_info_mapped)->mapped.account_name) { + return NT_STATUS_NO_MEMORY; + } + + return NT_STATUS_OK; +} + +/**************************************************************************** + Create an auth_usersupplied_data structure after appropriate mapping. +****************************************************************************/ + +NTSTATUS encrypt_user_info(TALLOC_CTX *mem_ctx, struct auth_context *auth_context, + enum auth_password_state to_state, + const struct auth_usersupplied_info *user_info_in, + const struct auth_usersupplied_info **user_info_encrypted) +{ + NTSTATUS nt_status; + struct auth_usersupplied_info *user_info_temp; + switch (to_state) { + case AUTH_PASSWORD_RESPONSE: + switch (user_info_in->password_state) { + case AUTH_PASSWORD_PLAIN: + { + const struct auth_usersupplied_info *user_info_temp2; + nt_status = encrypt_user_info(mem_ctx, auth_context, + AUTH_PASSWORD_HASH, + user_info_in, &user_info_temp2); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + user_info_in = user_info_temp2; + /* fall through */ + } + case AUTH_PASSWORD_HASH: + { + const uint8_t *challenge; + DATA_BLOB chall_blob; + user_info_temp = talloc(mem_ctx, struct auth_usersupplied_info); + if (!user_info_temp) { + return NT_STATUS_NO_MEMORY; + } + if (!talloc_reference(user_info_temp, user_info_in)) { + return NT_STATUS_NO_MEMORY; + } + *user_info_temp = *user_info_in; + user_info_temp->mapped_state = to_state; + + nt_status = auth_get_challenge(auth_context, &challenge); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + + chall_blob = data_blob_talloc(mem_ctx, challenge, 8); + if (lp_client_ntlmv2_auth(auth_context->lp_ctx)) { + DATA_BLOB names_blob = NTLMv2_generate_names_blob(mem_ctx, lp_iconv_convenience(auth_context->lp_ctx), lp_netbios_name(auth_context->lp_ctx), lp_workgroup(auth_context->lp_ctx)); + DATA_BLOB lmv2_response, ntlmv2_response, lmv2_session_key, ntlmv2_session_key; + + if (!SMBNTLMv2encrypt_hash(user_info_temp, + user_info_in->client.account_name, + user_info_in->client.domain_name, + user_info_in->password.hash.nt->hash, &chall_blob, + &names_blob, + &lmv2_response, &ntlmv2_response, + &lmv2_session_key, &ntlmv2_session_key)) { + data_blob_free(&names_blob); + return NT_STATUS_NO_MEMORY; + } + data_blob_free(&names_blob); + user_info_temp->password.response.lanman = lmv2_response; + user_info_temp->password.response.nt = ntlmv2_response; + + data_blob_free(&lmv2_session_key); + data_blob_free(&ntlmv2_session_key); + } else { + DATA_BLOB blob = data_blob_talloc(mem_ctx, NULL, 24); + SMBOWFencrypt(user_info_in->password.hash.nt->hash, challenge, blob.data); + + user_info_temp->password.response.nt = blob; + if (lp_client_lanman_auth(auth_context->lp_ctx) && user_info_in->password.hash.lanman) { + DATA_BLOB lm_blob = data_blob_talloc(mem_ctx, NULL, 24); + SMBOWFencrypt(user_info_in->password.hash.lanman->hash, challenge, blob.data); + user_info_temp->password.response.lanman = lm_blob; + } else { + /* if not sending the LM password, send the NT password twice */ + user_info_temp->password.response.lanman = user_info_temp->password.response.nt; + } + } + + user_info_in = user_info_temp; + /* fall through */ + } + case AUTH_PASSWORD_RESPONSE: + *user_info_encrypted = user_info_in; + } + break; + case AUTH_PASSWORD_HASH: + { + switch (user_info_in->password_state) { + case AUTH_PASSWORD_PLAIN: + { + struct samr_Password lanman; + struct samr_Password nt; + + user_info_temp = talloc(mem_ctx, struct auth_usersupplied_info); + if (!user_info_temp) { + return NT_STATUS_NO_MEMORY; + } + if (!talloc_reference(user_info_temp, user_info_in)) { + return NT_STATUS_NO_MEMORY; + } + *user_info_temp = *user_info_in; + user_info_temp->mapped_state = to_state; + + if (E_deshash(user_info_in->password.plaintext, lanman.hash)) { + user_info_temp->password.hash.lanman = talloc(user_info_temp, + struct samr_Password); + *user_info_temp->password.hash.lanman = lanman; + } else { + user_info_temp->password.hash.lanman = NULL; + } + + E_md4hash(user_info_in->password.plaintext, nt.hash); + user_info_temp->password.hash.nt = talloc(user_info_temp, + struct samr_Password); + *user_info_temp->password.hash.nt = nt; + + user_info_in = user_info_temp; + /* fall through */ + } + case AUTH_PASSWORD_HASH: + *user_info_encrypted = user_info_in; + break; + default: + return NT_STATUS_INVALID_PARAMETER; + break; + } + break; + } + default: + return NT_STATUS_INVALID_PARAMETER; + } + + return NT_STATUS_OK; +} + + +/** + * Squash an NT_STATUS in line with security requirements. + * In an attempt to avoid giving the whole game away when users + * are authenticating, NT replaces both NT_STATUS_NO_SUCH_USER and + * NT_STATUS_WRONG_PASSWORD with NT_STATUS_LOGON_FAILURE in certain situations + * (session setups in particular). + * + * @param nt_status NTSTATUS input for squashing. + * @return the 'squashed' nt_status + **/ +_PUBLIC_ NTSTATUS auth_nt_status_squash(NTSTATUS nt_status) +{ + if NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER) { + /* Match WinXP and don't give the game away */ + return NT_STATUS_LOGON_FAILURE; + } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD) { + /* Match WinXP and don't give the game away */ + return NT_STATUS_LOGON_FAILURE; + } + + return nt_status; +} diff --git a/source4/auth/ntlm/auth_winbind.c b/source4/auth/ntlm/auth_winbind.c new file mode 100644 index 0000000000..149f549afa --- /dev/null +++ b/source4/auth/ntlm/auth_winbind.c @@ -0,0 +1,282 @@ +/* + Unix SMB/CIFS implementation. + + Winbind authentication mechnism + + Copyright (C) Tim Potter 2000 + Copyright (C) Andrew Bartlett 2001 - 2002 + Copyright (C) Stefan Metzmacher 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "includes.h" +#include "auth/auth.h" +#include "auth/auth_proto.h" +#include "auth/session_proto.h" +#include "nsswitch/winbind_client.h" +#include "librpc/gen_ndr/ndr_netlogon.h" +#include "librpc/gen_ndr/ndr_winbind.h" +#include "lib/messaging/irpc.h" +#include "param/param.h" + +static NTSTATUS get_info3_from_ndr(TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience, struct winbindd_response *response, struct netr_SamInfo3 *info3) +{ + size_t len = response->length - sizeof(struct winbindd_response); + if (len > 4) { + enum ndr_err_code ndr_err; + DATA_BLOB blob; + blob.length = len - 4; + blob.data = (uint8_t *)(((char *)response->extra_data.data) + 4); + + ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, + iconv_convenience, info3, + (ndr_pull_flags_fn_t)ndr_pull_netr_SamInfo3); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return ndr_map_error2ntstatus(ndr_err); + } + + return NT_STATUS_OK; + } else { + DEBUG(2, ("get_info3_from_ndr: No info3 struct found!\n")); + return NT_STATUS_UNSUCCESSFUL; + } +} + +static NTSTATUS winbind_want_check(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info) +{ + if (!user_info->mapped.account_name || !*user_info->mapped.account_name) { + return NT_STATUS_NOT_IMPLEMENTED; + } + + /* TODO: maybe limit the user scope to remote users only */ + return NT_STATUS_OK; +} + +/* + Authenticate a user with a challenge/response + using the samba3 winbind protocol +*/ +static NTSTATUS winbind_check_password_samba3(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info, + struct auth_serversupplied_info **server_info) +{ + struct winbindd_request request; + struct winbindd_response response; + NSS_STATUS result; + NTSTATUS nt_status; + struct netr_SamInfo3 info3; + + /* Send off request */ + const struct auth_usersupplied_info *user_info_temp; + nt_status = encrypt_user_info(mem_ctx, ctx->auth_ctx, + AUTH_PASSWORD_RESPONSE, + user_info, &user_info_temp); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + user_info = user_info_temp; + + ZERO_STRUCT(request); + ZERO_STRUCT(response); + request.flags = WBFLAG_PAM_INFO3_NDR; + + request.data.auth_crap.logon_parameters = user_info->logon_parameters; + + safe_strcpy(request.data.auth_crap.user, + user_info->client.account_name, sizeof(fstring)); + safe_strcpy(request.data.auth_crap.domain, + user_info->client.domain_name, sizeof(fstring)); + safe_strcpy(request.data.auth_crap.workstation, + user_info->workstation_name, sizeof(fstring)); + + memcpy(request.data.auth_crap.chal, ctx->auth_ctx->challenge.data.data, sizeof(request.data.auth_crap.chal)); + + request.data.auth_crap.lm_resp_len = MIN(user_info->password.response.lanman.length, + sizeof(request.data.auth_crap.lm_resp)); + request.data.auth_crap.nt_resp_len = MIN(user_info->password.response.nt.length, + sizeof(request.data.auth_crap.nt_resp)); + + memcpy(request.data.auth_crap.lm_resp, user_info->password.response.lanman.data, + request.data.auth_crap.lm_resp_len); + memcpy(request.data.auth_crap.nt_resp, user_info->password.response.nt.data, + request.data.auth_crap.nt_resp_len); + + result = winbindd_request_response(WINBINDD_PAM_AUTH_CRAP, &request, &response); + + nt_status = NT_STATUS(response.data.auth.nt_status); + NT_STATUS_NOT_OK_RETURN(nt_status); + + if (result == NSS_STATUS_SUCCESS && response.extra_data.data) { + union netr_Validation validation; + + nt_status = get_info3_from_ndr(mem_ctx, lp_iconv_convenience(ctx->auth_ctx->lp_ctx), &response, &info3); + SAFE_FREE(response.extra_data.data); + NT_STATUS_NOT_OK_RETURN(nt_status); + + validation.sam3 = &info3; + nt_status = make_server_info_netlogon_validation(mem_ctx, + user_info->client.account_name, + 3, &validation, + server_info); + return nt_status; + } else if (result == NSS_STATUS_SUCCESS && !response.extra_data.data) { + DEBUG(0, ("Winbindd authenticated the user [%s]\\[%s], " + "but did not include the required info3 reply!\n", + user_info->client.domain_name, user_info->client.account_name)); + return NT_STATUS_INSUFFICIENT_LOGON_INFO; + } else if (NT_STATUS_IS_OK(nt_status)) { + DEBUG(1, ("Winbindd authentication for [%s]\\[%s] failed, " + "but no error code is available!\n", + user_info->client.domain_name, user_info->client.account_name)); + return NT_STATUS_NO_LOGON_SERVERS; + } + + return nt_status; +} + +struct winbind_check_password_state { + struct winbind_SamLogon req; +}; + +/* + Authenticate a user with a challenge/response + using IRPC to the winbind task +*/ +static NTSTATUS winbind_check_password(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info, + struct auth_serversupplied_info **server_info) +{ + NTSTATUS status; + struct server_id *winbind_servers; + struct winbind_check_password_state *s; + const struct auth_usersupplied_info *user_info_new; + struct netr_IdentityInfo *identity_info; + + s = talloc(mem_ctx, struct winbind_check_password_state); + NT_STATUS_HAVE_NO_MEMORY(s); + + winbind_servers = irpc_servers_byname(ctx->auth_ctx->msg_ctx, s, "winbind_server"); + if ((winbind_servers == NULL) || (winbind_servers[0].id == 0)) { + DEBUG(0, ("Winbind authentication for [%s]\\[%s] failed, " + "no winbind_server running!\n", + user_info->client.domain_name, user_info->client.account_name)); + return NT_STATUS_NO_LOGON_SERVERS; + } + + if (user_info->flags & USER_INFO_INTERACTIVE_LOGON) { + struct netr_PasswordInfo *password_info; + + status = encrypt_user_info(s, ctx->auth_ctx, AUTH_PASSWORD_HASH, + user_info, &user_info_new); + NT_STATUS_NOT_OK_RETURN(status); + user_info = user_info_new; + + password_info = talloc(s, struct netr_PasswordInfo); + NT_STATUS_HAVE_NO_MEMORY(password_info); + + password_info->lmpassword = *user_info->password.hash.lanman; + password_info->ntpassword = *user_info->password.hash.nt; + + identity_info = &password_info->identity_info; + s->req.in.logon_level = 1; + s->req.in.logon.password= password_info; + } else { + struct netr_NetworkInfo *network_info; + const uint8_t *challenge; + + status = encrypt_user_info(s, ctx->auth_ctx, AUTH_PASSWORD_RESPONSE, + user_info, &user_info_new); + NT_STATUS_NOT_OK_RETURN(status); + user_info = user_info_new; + + network_info = talloc(s, struct netr_NetworkInfo); + NT_STATUS_HAVE_NO_MEMORY(network_info); + + status = auth_get_challenge(ctx->auth_ctx, &challenge); + NT_STATUS_NOT_OK_RETURN(status); + + memcpy(network_info->challenge, challenge, sizeof(network_info->challenge)); + + network_info->nt.length = user_info->password.response.nt.length; + network_info->nt.data = user_info->password.response.nt.data; + + network_info->lm.length = user_info->password.response.lanman.length; + network_info->lm.data = user_info->password.response.lanman.data; + + identity_info = &network_info->identity_info; + s->req.in.logon_level = 2; + s->req.in.logon.network = network_info; + } + + identity_info->domain_name.string = user_info->client.domain_name; + identity_info->parameter_control = user_info->logon_parameters; /* see MSV1_0_* */ + identity_info->logon_id_low = 0; + identity_info->logon_id_high = 0; + identity_info->account_name.string = user_info->client.account_name; + identity_info->workstation.string = user_info->workstation_name; + + s->req.in.validation_level = 3; + + status = IRPC_CALL(ctx->auth_ctx->msg_ctx, winbind_servers[0], + winbind, WINBIND_SAMLOGON, + &s->req, s); + NT_STATUS_NOT_OK_RETURN(status); + + status = make_server_info_netlogon_validation(mem_ctx, + user_info->client.account_name, + s->req.in.validation_level, + &s->req.out.validation, + server_info); + NT_STATUS_NOT_OK_RETURN(status); + + return NT_STATUS_OK; +} + +static const struct auth_operations winbind_samba3_ops = { + .name = "winbind_samba3", + .get_challenge = auth_get_challenge_not_implemented, + .want_check = winbind_want_check, + .check_password = winbind_check_password_samba3 +}; + +static const struct auth_operations winbind_ops = { + .name = "winbind", + .get_challenge = auth_get_challenge_not_implemented, + .want_check = winbind_want_check, + .check_password = winbind_check_password +}; + +_PUBLIC_ NTSTATUS auth_winbind_init(void) +{ + NTSTATUS ret; + + ret = auth_register(&winbind_samba3_ops); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(0,("Failed to register 'winbind_samba3' auth backend!\n")); + return ret; + } + + ret = auth_register(&winbind_ops); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(0,("Failed to register 'winbind' auth backend!\n")); + return ret; + } + + return NT_STATUS_OK; +} diff --git a/source4/auth/ntlm/config.mk b/source4/auth/ntlm/config.mk new file mode 100644 index 0000000000..319aca7318 --- /dev/null +++ b/source4/auth/ntlm/config.mk @@ -0,0 +1,87 @@ +# NTLM auth server subsystem + +[SUBSYSTEM::ntlm_check] +PRIVATE_DEPENDENCIES = LIBSAMBA-UTIL + +ntlm_check_OBJ_FILES = $(addprefix auth/ntlm/, ntlm_check.o) + +####################### +# Start MODULE auth_sam +[MODULE::auth_sam_module] +# gensec_krb5 and gensec_gssapi depend on it +INIT_FUNCTION = auth_sam_init +SUBSYSTEM = auth +PRIVATE_DEPENDENCIES = \ + SAMDB auth_sam ntlm_check +# End MODULE auth_sam +####################### + +auth_sam_module_OBJ_FILES = $(addprefix auth/ntlm/, auth_sam.o) + +####################### +# Start MODULE auth_anonymous +[MODULE::auth_anonymous] +INIT_FUNCTION = auth_anonymous_init +SUBSYSTEM = auth +# End MODULE auth_anonymous +####################### + +auth_anonymous_OBJ_FILES = $(addprefix auth/ntlm/, auth_anonymous.o) + +####################### +# Start MODULE auth_anonymous +[MODULE::auth_server] +INIT_FUNCTION = auth_server_init +SUBSYSTEM = auth +PRIVATE_DEPENDENCIES = LIBSAMBA-UTIL LIBCLI_SMB +OUTPUT_TYPE = SHARED_LIBRARY +# End MODULE auth_server +####################### + +auth_server_OBJ_FILES = $(addprefix auth/ntlm/, auth_server.o) + +####################### +# Start MODULE auth_winbind +[MODULE::auth_winbind] +INIT_FUNCTION = auth_winbind_init +SUBSYSTEM = auth +PRIVATE_DEPENDENCIES = NDR_WINBIND MESSAGING LIBWINBIND-CLIENT +# End MODULE auth_winbind +####################### + +auth_winbind_OBJ_FILES = $(addprefix auth/ntlm/, auth_winbind.o) + +####################### +# Start MODULE auth_developer +[MODULE::auth_developer] +INIT_FUNCTION = auth_developer_init +SUBSYSTEM = auth +# End MODULE auth_developer +####################### + +auth_developer_OBJ_FILES = $(addprefix auth/ntlm/, auth_developer.o) + +[MODULE::auth_unix] +INIT_FUNCTION = auth_unix_init +SUBSYSTEM = auth +PRIVATE_DEPENDENCIES = CRYPT PAM PAM_ERRORS NSS_WRAPPER + +auth_unix_OBJ_FILES = $(addprefix auth/ntlm/, auth_unix.o) + +[SUBSYSTEM::PAM_ERRORS] +PRIVATE_PROTO_HEADER = pam_errors.h + +#VERSION = 0.0.1 +#SO_VERSION = 0 +PAM_ERRORS_OBJ_FILES = $(addprefix auth/ntlm/, pam_errors.o) + +[MODULE::auth] +INIT_FUNCTION = server_service_auth_init +SUBSYSTEM = service +PRIVATE_PROTO_HEADER = auth_proto.h +PRIVATE_DEPENDENCIES = LIBSAMBA-UTIL LIBSECURITY SAMDB CREDENTIALS + +auth_OBJ_FILES = $(addprefix auth/ntlm/, auth.o auth_util.o auth_simple.o) + +# PUBLIC_HEADERS += auth/auth.h + diff --git a/source4/auth/ntlm/ntlm_check.c b/source4/auth/ntlm/ntlm_check.c new file mode 100644 index 0000000000..0dbbce0edc --- /dev/null +++ b/source4/auth/ntlm/ntlm_check.c @@ -0,0 +1,603 @@ +/* + Unix SMB/CIFS implementation. + Password and authentication handling + Copyright (C) Andrew Bartlett 2001-2004 + Copyright (C) Gerald Carter 2003 + Copyright (C) Luke Kenneth Casson Leighton 1996-2000 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "includes.h" +#include "lib/crypto/crypto.h" +#include "librpc/gen_ndr/netlogon.h" +#include "libcli/auth/libcli_auth.h" +#include "param/param.h" +#include "auth/ntlm/ntlm_check.h" + +/**************************************************************************** + Core of smb password checking routine. +****************************************************************************/ + +static bool smb_pwd_check_ntlmv1(TALLOC_CTX *mem_ctx, + const DATA_BLOB *nt_response, + const uint8_t *part_passwd, + const DATA_BLOB *sec_blob, + DATA_BLOB *user_sess_key) +{ + /* Finish the encryption of part_passwd. */ + uint8_t p24[24]; + + if (part_passwd == NULL) { + DEBUG(10,("No password set - DISALLOWING access\n")); + /* No password set - always false ! */ + return false; + } + + if (sec_blob->length != 8) { + DEBUG(0, ("smb_pwd_check_ntlmv1: incorrect challenge size (%lu)\n", + (unsigned long)sec_blob->length)); + return false; + } + + if (nt_response->length != 24) { + DEBUG(0, ("smb_pwd_check_ntlmv1: incorrect password length (%lu)\n", + (unsigned long)nt_response->length)); + return false; + } + + SMBOWFencrypt(part_passwd, sec_blob->data, p24); + +#if DEBUG_PASSWORD + DEBUG(100,("Part password (P16) was |\n")); + dump_data(100, part_passwd, 16); + DEBUGADD(100,("Password from client was |\n")); + dump_data(100, nt_response->data, nt_response->length); + DEBUGADD(100,("Given challenge was |\n")); + dump_data(100, sec_blob->data, sec_blob->length); + DEBUGADD(100,("Value from encryption was |\n")); + dump_data(100, p24, 24); +#endif + if (memcmp(p24, nt_response->data, 24) == 0) { + if (user_sess_key != NULL) { + *user_sess_key = data_blob_talloc(mem_ctx, NULL, 16); + SMBsesskeygen_ntv1(part_passwd, user_sess_key->data); + } + return true; + } + return false; +} + +/**************************************************************************** + Core of smb password checking routine. (NTLMv2, LMv2) + Note: The same code works with both NTLMv2 and LMv2. +****************************************************************************/ + +static bool smb_pwd_check_ntlmv2(TALLOC_CTX *mem_ctx, + const DATA_BLOB *ntv2_response, + const uint8_t *part_passwd, + const DATA_BLOB *sec_blob, + const char *user, const char *domain, + bool upper_case_domain, /* should the domain be transformed into upper case? */ + DATA_BLOB *user_sess_key) +{ + /* Finish the encryption of part_passwd. */ + uint8_t kr[16]; + uint8_t value_from_encryption[16]; + DATA_BLOB client_key_data; + + if (part_passwd == NULL) { + DEBUG(10,("No password set - DISALLOWING access\n")); + /* No password set - always false */ + return false; + } + + if (sec_blob->length != 8) { + DEBUG(0, ("smb_pwd_check_ntlmv2: incorrect challenge size (%lu)\n", + (unsigned long)sec_blob->length)); + return false; + } + + if (ntv2_response->length < 24) { + /* We MUST have more than 16 bytes, or the stuff below will go + crazy. No known implementation sends less than the 24 bytes + for LMv2, let alone NTLMv2. */ + DEBUG(0, ("smb_pwd_check_ntlmv2: incorrect password length (%lu)\n", + (unsigned long)ntv2_response->length)); + return false; + } + + client_key_data = data_blob_talloc(mem_ctx, ntv2_response->data+16, ntv2_response->length-16); + /* + todo: should we be checking this for anything? We can't for LMv2, + but for NTLMv2 it is meant to contain the current time etc. + */ + + if (!ntv2_owf_gen(part_passwd, user, domain, upper_case_domain, kr)) { + return false; + } + + SMBOWFencrypt_ntv2(kr, sec_blob, &client_key_data, value_from_encryption); + +#if DEBUG_PASSWORD + DEBUG(100,("Part password (P16) was |\n")); + dump_data(100, part_passwd, 16); + DEBUGADD(100,("Password from client was |\n")); + dump_data(100, ntv2_response->data, ntv2_response->length); + DEBUGADD(100,("Variable data from client was |\n")); + dump_data(100, client_key_data.data, client_key_data.length); + DEBUGADD(100,("Given challenge was |\n")); + dump_data(100, sec_blob->data, sec_blob->length); + DEBUGADD(100,("Value from encryption was |\n")); + dump_data(100, value_from_encryption, 16); +#endif + data_blob_clear_free(&client_key_data); + if (memcmp(value_from_encryption, ntv2_response->data, 16) == 0) { + if (user_sess_key != NULL) { + *user_sess_key = data_blob_talloc(mem_ctx, NULL, 16); + SMBsesskeygen_ntv2(kr, value_from_encryption, user_sess_key->data); + } + return true; + } + return false; +} + +/**************************************************************************** + Core of smb password checking routine. (NTLMv2, LMv2) + Note: The same code works with both NTLMv2 and LMv2. +****************************************************************************/ + +static bool smb_sess_key_ntlmv2(TALLOC_CTX *mem_ctx, + const DATA_BLOB *ntv2_response, + const uint8_t *part_passwd, + const DATA_BLOB *sec_blob, + const char *user, const char *domain, + bool upper_case_domain, /* should the domain be transformed into upper case? */ + DATA_BLOB *user_sess_key) +{ + /* Finish the encryption of part_passwd. */ + uint8_t kr[16]; + uint8_t value_from_encryption[16]; + DATA_BLOB client_key_data; + + if (part_passwd == NULL) { + DEBUG(10,("No password set - DISALLOWING access\n")); + /* No password set - always false */ + return false; + } + + if (sec_blob->length != 8) { + DEBUG(0, ("smb_sess_key_ntlmv2: incorrect challenge size (%lu)\n", + (unsigned long)sec_blob->length)); + return false; + } + + if (ntv2_response->length < 24) { + /* We MUST have more than 16 bytes, or the stuff below will go + crazy. No known implementation sends less than the 24 bytes + for LMv2, let alone NTLMv2. */ + DEBUG(0, ("smb_sess_key_ntlmv2: incorrect password length (%lu)\n", + (unsigned long)ntv2_response->length)); + return false; + } + + client_key_data = data_blob_talloc(mem_ctx, ntv2_response->data+16, ntv2_response->length-16); + + if (!ntv2_owf_gen(part_passwd, user, domain, upper_case_domain, kr)) { + return false; + } + + SMBOWFencrypt_ntv2(kr, sec_blob, &client_key_data, value_from_encryption); + *user_sess_key = data_blob_talloc(mem_ctx, NULL, 16); + SMBsesskeygen_ntv2(kr, value_from_encryption, user_sess_key->data); + return true; +} + +/** + * Compare password hashes against those from the SAM + * + * @param mem_ctx talloc context + * @param client_lanman LANMAN password hash, as supplied by the client + * @param client_nt NT (MD4) password hash, as supplied by the client + * @param username internal Samba username, for log messages + * @param client_username username the client used + * @param client_domain domain name the client used (may be mapped) + * @param stored_lanman LANMAN password hash, as stored on the SAM + * @param stored_nt NT (MD4) password hash, as stored on the SAM + * @param user_sess_key User session key + * @param lm_sess_key LM session key (first 8 bytes of the LM hash) + */ + +NTSTATUS hash_password_check(TALLOC_CTX *mem_ctx, + struct loadparm_context *lp_ctx, + const struct samr_Password *client_lanman, + const struct samr_Password *client_nt, + const char *username, + const struct samr_Password *stored_lanman, + const struct samr_Password *stored_nt) +{ + if (stored_nt == NULL) { + DEBUG(3,("ntlm_password_check: NO NT password stored for user %s.\n", + username)); + } + + if (client_nt && stored_nt) { + if (memcmp(client_nt->hash, stored_nt->hash, sizeof(stored_nt->hash)) == 0) { + return NT_STATUS_OK; + } else { + DEBUG(3,("ntlm_password_check: Interactive logon: NT password check failed for user %s\n", + username)); + return NT_STATUS_WRONG_PASSWORD; + } + + } else if (client_lanman && stored_lanman) { + if (!lp_lanman_auth(lp_ctx)) { + DEBUG(3,("ntlm_password_check: Interactive logon: only LANMAN password supplied for user %s, and LM passwords are disabled!\n", + username)); + return NT_STATUS_WRONG_PASSWORD; + } + if (strchr_m(username, '@')) { + return NT_STATUS_NOT_FOUND; + } + + if (memcmp(client_lanman->hash, stored_lanman->hash, sizeof(stored_lanman->hash)) == 0) { + return NT_STATUS_OK; + } else { + DEBUG(3,("ntlm_password_check: Interactive logon: LANMAN password check failed for user %s\n", + username)); + return NT_STATUS_WRONG_PASSWORD; + } + } + if (strchr_m(username, '@')) { + return NT_STATUS_NOT_FOUND; + } + return NT_STATUS_WRONG_PASSWORD; +} + +/** + * Check a challenge-response password against the value of the NT or + * LM password hash. + * + * @param mem_ctx talloc context + * @param challenge 8-byte challenge. If all zero, forces plaintext comparison + * @param nt_response 'unicode' NT response to the challenge, or unicode password + * @param lm_response ASCII or LANMAN response to the challenge, or password in DOS code page + * @param username internal Samba username, for log messages + * @param client_username username the client used + * @param client_domain domain name the client used (may be mapped) + * @param stored_lanman LANMAN ASCII password from our passdb or similar + * @param stored_nt MD4 unicode password from our passdb or similar + * @param user_sess_key User session key + * @param lm_sess_key LM session key (first 8 bytes of the LM hash) + */ + +NTSTATUS ntlm_password_check(TALLOC_CTX *mem_ctx, + struct loadparm_context *lp_ctx, + uint32_t logon_parameters, + const DATA_BLOB *challenge, + const DATA_BLOB *lm_response, + const DATA_BLOB *nt_response, + const char *username, + const char *client_username, + const char *client_domain, + const struct samr_Password *stored_lanman, + const struct samr_Password *stored_nt, + DATA_BLOB *user_sess_key, + DATA_BLOB *lm_sess_key) +{ + const static uint8_t zeros[8]; + DATA_BLOB tmp_sess_key; + + if (stored_nt == NULL) { + DEBUG(3,("ntlm_password_check: NO NT password stored for user %s.\n", + username)); + } + + *lm_sess_key = data_blob(NULL, 0); + *user_sess_key = data_blob(NULL, 0); + + /* Check for cleartext netlogon. Used by Exchange 5.5. */ + if ((logon_parameters & MSV1_0_CLEARTEXT_PASSWORD_ALLOWED) + && challenge->length == sizeof(zeros) + && (memcmp(challenge->data, zeros, challenge->length) == 0 )) { + struct samr_Password client_nt; + struct samr_Password client_lm; + char *unix_pw = NULL; + bool lm_ok; + + DEBUG(4,("ntlm_password_check: checking plaintext passwords for user %s\n", + username)); + mdfour(client_nt.hash, nt_response->data, nt_response->length); + + if (lm_response->length && + (convert_string_talloc(mem_ctx, lp_iconv_convenience(lp_ctx), CH_DOS, CH_UNIX, + lm_response->data, lm_response->length, + (void **)&unix_pw) != -1)) { + if (E_deshash(unix_pw, client_lm.hash)) { + lm_ok = true; + } else { + lm_ok = false; + } + } else { + lm_ok = false; + } + return hash_password_check(mem_ctx, + lp_ctx, + lm_ok ? &client_lm : NULL, + nt_response->length ? &client_nt : NULL, + username, + stored_lanman, stored_nt); + } + + if (nt_response->length != 0 && nt_response->length < 24) { + DEBUG(2,("ntlm_password_check: invalid NT password length (%lu) for user %s\n", + (unsigned long)nt_response->length, username)); + } + + if (nt_response->length > 24 && stored_nt) { + /* We have the NT MD4 hash challenge available - see if we can + use it + */ + DEBUG(4,("ntlm_password_check: Checking NTLMv2 password with domain [%s]\n", client_domain)); + if (smb_pwd_check_ntlmv2(mem_ctx, + nt_response, + stored_nt->hash, challenge, + client_username, + client_domain, + false, + user_sess_key)) { + *lm_sess_key = *user_sess_key; + if (user_sess_key->length) { + lm_sess_key->length = 8; + } + return NT_STATUS_OK; + } + + DEBUG(4,("ntlm_password_check: Checking NTLMv2 password with uppercased version of domain [%s]\n", client_domain)); + if (smb_pwd_check_ntlmv2(mem_ctx, + nt_response, + stored_nt->hash, challenge, + client_username, + client_domain, + true, + user_sess_key)) { + *lm_sess_key = *user_sess_key; + if (user_sess_key->length) { + lm_sess_key->length = 8; + } + return NT_STATUS_OK; + } + + DEBUG(4,("ntlm_password_check: Checking NTLMv2 password without a domain\n")); + if (smb_pwd_check_ntlmv2(mem_ctx, + nt_response, + stored_nt->hash, challenge, + client_username, + "", + false, + user_sess_key)) { + *lm_sess_key = *user_sess_key; + if (user_sess_key->length) { + lm_sess_key->length = 8; + } + return NT_STATUS_OK; + } else { + DEBUG(3,("ntlm_password_check: NTLMv2 password check failed\n")); + } + } else if (nt_response->length == 24 && stored_nt) { + if (lp_ntlm_auth(lp_ctx)) { + /* We have the NT MD4 hash challenge available - see if we can + use it (ie. does it exist in the smbpasswd file). + */ + DEBUG(4,("ntlm_password_check: Checking NT MD4 password\n")); + if (smb_pwd_check_ntlmv1(mem_ctx, + nt_response, + stored_nt->hash, challenge, + user_sess_key)) { + /* The LM session key for this response is not very secure, + so use it only if we otherwise allow LM authentication */ + + if (lp_lanman_auth(lp_ctx) && stored_lanman) { + *lm_sess_key = data_blob_talloc(mem_ctx, stored_lanman->hash, 8); + } + return NT_STATUS_OK; + } else { + DEBUG(3,("ntlm_password_check: NT MD4 password check failed for user %s\n", + username)); + return NT_STATUS_WRONG_PASSWORD; + } + } else { + DEBUG(2,("ntlm_password_check: NTLMv1 passwords NOT PERMITTED for user %s\n", + username)); + /* no return, becouse we might pick up LMv2 in the LM field */ + } + } + + if (lm_response->length == 0) { + DEBUG(3,("ntlm_password_check: NEITHER LanMan nor NT password supplied for user %s\n", + username)); + return NT_STATUS_WRONG_PASSWORD; + } + + if (lm_response->length < 24) { + DEBUG(2,("ntlm_password_check: invalid LanMan password length (%lu) for user %s\n", + (unsigned long)nt_response->length, username)); + return NT_STATUS_WRONG_PASSWORD; + } + + if (!lp_lanman_auth(lp_ctx)) { + DEBUG(3,("ntlm_password_check: Lanman passwords NOT PERMITTED for user %s\n", + username)); + } else if (!stored_lanman) { + DEBUG(3,("ntlm_password_check: NO LanMan password set for user %s (and no NT password supplied)\n", + username)); + } else if (strchr_m(username, '@')) { + DEBUG(3,("ntlm_password_check: NO LanMan password allowed for username@realm logins (user: %s)\n", + username)); + } else { + DEBUG(4,("ntlm_password_check: Checking LM password\n")); + if (smb_pwd_check_ntlmv1(mem_ctx, + lm_response, + stored_lanman->hash, challenge, + NULL)) { + /* The session key for this response is still very odd. + It not very secure, so use it only if we otherwise + allow LM authentication */ + + if (lp_lanman_auth(lp_ctx) && stored_lanman) { + uint8_t first_8_lm_hash[16]; + memcpy(first_8_lm_hash, stored_lanman->hash, 8); + memset(first_8_lm_hash + 8, '\0', 8); + *user_sess_key = data_blob_talloc(mem_ctx, first_8_lm_hash, 16); + *lm_sess_key = data_blob_talloc(mem_ctx, stored_lanman->hash, 8); + } + return NT_STATUS_OK; + } + } + + if (!stored_nt) { + DEBUG(4,("ntlm_password_check: LM password check failed for user, no NT password %s\n",username)); + return NT_STATUS_WRONG_PASSWORD; + } + + /* This is for 'LMv2' authentication. almost NTLMv2 but limited to 24 bytes. + - related to Win9X, legacy NAS pass-though authentication + */ + DEBUG(4,("ntlm_password_check: Checking LMv2 password with domain %s\n", client_domain)); + if (smb_pwd_check_ntlmv2(mem_ctx, + lm_response, + stored_nt->hash, challenge, + client_username, + client_domain, + false, + &tmp_sess_key)) { + if (nt_response->length > 24) { + /* If NTLMv2 authentication has preceeded us + * (even if it failed), then use the session + * key from that. See the RPC-SAMLOGON + * torture test */ + smb_sess_key_ntlmv2(mem_ctx, + nt_response, + stored_nt->hash, challenge, + client_username, + client_domain, + false, + user_sess_key); + } else { + /* Otherwise, use the LMv2 session key */ + *user_sess_key = tmp_sess_key; + } + *lm_sess_key = *user_sess_key; + if (user_sess_key->length) { + lm_sess_key->length = 8; + } + return NT_STATUS_OK; + } + + DEBUG(4,("ntlm_password_check: Checking LMv2 password with upper-cased version of domain %s\n", client_domain)); + if (smb_pwd_check_ntlmv2(mem_ctx, + lm_response, + stored_nt->hash, challenge, + client_username, + client_domain, + true, + &tmp_sess_key)) { + if (nt_response->length > 24) { + /* If NTLMv2 authentication has preceeded us + * (even if it failed), then use the session + * key from that. See the RPC-SAMLOGON + * torture test */ + smb_sess_key_ntlmv2(mem_ctx, + nt_response, + stored_nt->hash, challenge, + client_username, + client_domain, + true, + user_sess_key); + } else { + /* Otherwise, use the LMv2 session key */ + *user_sess_key = tmp_sess_key; + } + *lm_sess_key = *user_sess_key; + if (user_sess_key->length) { + lm_sess_key->length = 8; + } + return NT_STATUS_OK; + } + + DEBUG(4,("ntlm_password_check: Checking LMv2 password without a domain\n")); + if (smb_pwd_check_ntlmv2(mem_ctx, + lm_response, + stored_nt->hash, challenge, + client_username, + "", + false, + &tmp_sess_key)) { + if (nt_response->length > 24) { + /* If NTLMv2 authentication has preceeded us + * (even if it failed), then use the session + * key from that. See the RPC-SAMLOGON + * torture test */ + smb_sess_key_ntlmv2(mem_ctx, + nt_response, + stored_nt->hash, challenge, + client_username, + "", + false, + user_sess_key); + } else { + /* Otherwise, use the LMv2 session key */ + *user_sess_key = tmp_sess_key; + } + *lm_sess_key = *user_sess_key; + if (user_sess_key->length) { + lm_sess_key->length = 8; + } + return NT_STATUS_OK; + } + + /* Apparently NT accepts NT responses in the LM field + - I think this is related to Win9X pass-though authentication + */ + DEBUG(4,("ntlm_password_check: Checking NT MD4 password in LM field\n")); + if (lp_ntlm_auth(lp_ctx)) { + if (smb_pwd_check_ntlmv1(mem_ctx, + lm_response, + stored_nt->hash, challenge, + NULL)) { + /* The session key for this response is still very odd. + It not very secure, so use it only if we otherwise + allow LM authentication */ + + if (lp_lanman_auth(lp_ctx) && stored_lanman) { + uint8_t first_8_lm_hash[16]; + memcpy(first_8_lm_hash, stored_lanman->hash, 8); + memset(first_8_lm_hash + 8, '\0', 8); + *user_sess_key = data_blob_talloc(mem_ctx, first_8_lm_hash, 16); + *lm_sess_key = data_blob_talloc(mem_ctx, stored_lanman->hash, 8); + } + return NT_STATUS_OK; + } + DEBUG(3,("ntlm_password_check: LM password, NT MD4 password in LM field and LMv2 failed for user %s\n",username)); + } else { + DEBUG(3,("ntlm_password_check: LM password and LMv2 failed for user %s, and NT MD4 password in LM field not permitted\n",username)); + } + + /* Try and match error codes */ + if (strchr_m(username, '@')) { + return NT_STATUS_NOT_FOUND; + } + return NT_STATUS_WRONG_PASSWORD; +} + diff --git a/source4/auth/ntlm/ntlm_check.h b/source4/auth/ntlm/ntlm_check.h new file mode 100644 index 0000000000..eb115b74d6 --- /dev/null +++ b/source4/auth/ntlm/ntlm_check.h @@ -0,0 +1,75 @@ +/* + Unix SMB/CIFS implementation. + Password and authentication handling + Copyright (C) Andrew Bartlett 2001-2004 + Copyright (C) Gerald Carter 2003 + Copyright (C) Luke Kenneth Casson Leighton 1996-2000 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + + +/** + * Compare password hashes against those from the SAM + * + * @param mem_ctx talloc context + * @param client_lanman LANMAN password hash, as supplied by the client + * @param client_nt NT (MD4) password hash, as supplied by the client + * @param username internal Samba username, for log messages + * @param client_username username the client used + * @param client_domain domain name the client used (may be mapped) + * @param stored_lanman LANMAN password hash, as stored on the SAM + * @param stored_nt NT (MD4) password hash, as stored on the SAM + * @param user_sess_key User session key + * @param lm_sess_key LM session key (first 8 bytes of the LM hash) + */ + +NTSTATUS hash_password_check(TALLOC_CTX *mem_ctx, + struct loadparm_context *lp_ctx, + const struct samr_Password *client_lanman, + const struct samr_Password *client_nt, + const char *username, + const struct samr_Password *stored_lanman, + const struct samr_Password *stored_nt); + +/** + * Check a challenge-response password against the value of the NT or + * LM password hash. + * + * @param mem_ctx talloc context + * @param challenge 8-byte challenge. If all zero, forces plaintext comparison + * @param nt_response 'unicode' NT response to the challenge, or unicode password + * @param lm_response ASCII or LANMAN response to the challenge, or password in DOS code page + * @param username internal Samba username, for log messages + * @param client_username username the client used + * @param client_domain domain name the client used (may be mapped) + * @param stored_lanman LANMAN ASCII password from our passdb or similar + * @param stored_nt MD4 unicode password from our passdb or similar + * @param user_sess_key User session key + * @param lm_sess_key LM session key (first 8 bytes of the LM hash) + */ + +NTSTATUS ntlm_password_check(TALLOC_CTX *mem_ctx, + struct loadparm_context *lp_ctx, + uint32_t logon_parameters, + const DATA_BLOB *challenge, + const DATA_BLOB *lm_response, + const DATA_BLOB *nt_response, + const char *username, + const char *client_username, + const char *client_domain, + const struct samr_Password *stored_lanman, + const struct samr_Password *stored_nt, + DATA_BLOB *user_sess_key, + DATA_BLOB *lm_sess_key); diff --git a/source4/auth/ntlm/pam_errors.c b/source4/auth/ntlm/pam_errors.c new file mode 100644 index 0000000000..9774ad8727 --- /dev/null +++ b/source4/auth/ntlm/pam_errors.c @@ -0,0 +1,125 @@ +/* + * Unix SMB/CIFS implementation. + * PAM error mapping functions + * Copyright (C) Andrew Bartlett 2002 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "includes.h" + +#ifdef WITH_HAVE_SECURITY_PAM_APPL_H +#include + +#if defined(PAM_AUTHTOK_RECOVERY_ERR) && !defined(PAM_AUTHTOK_RECOVER_ERR) +#define PAM_AUTHTOK_RECOVER_ERR PAM_AUTHTOK_RECOVERY_ERR +#endif + +/* PAM -> NT_STATUS map */ +static const struct { + int pam_code; + NTSTATUS ntstatus; +} pam_to_nt_status_map[] = { + {PAM_OPEN_ERR, NT_STATUS_UNSUCCESSFUL}, + {PAM_SYMBOL_ERR, NT_STATUS_UNSUCCESSFUL}, + {PAM_SERVICE_ERR, NT_STATUS_UNSUCCESSFUL}, + {PAM_SYSTEM_ERR, NT_STATUS_UNSUCCESSFUL}, + {PAM_BUF_ERR, NT_STATUS_UNSUCCESSFUL}, + {PAM_PERM_DENIED, NT_STATUS_ACCESS_DENIED}, + {PAM_AUTH_ERR, NT_STATUS_WRONG_PASSWORD}, + {PAM_CRED_INSUFFICIENT, NT_STATUS_INSUFFICIENT_LOGON_INFO}, /* FIXME: Is this correct? */ + {PAM_AUTHINFO_UNAVAIL, NT_STATUS_LOGON_FAILURE}, + {PAM_USER_UNKNOWN, NT_STATUS_NO_SUCH_USER}, + {PAM_MAXTRIES, NT_STATUS_REMOTE_SESSION_LIMIT}, /* FIXME: Is this correct? */ + {PAM_NEW_AUTHTOK_REQD, NT_STATUS_PASSWORD_MUST_CHANGE}, + {PAM_ACCT_EXPIRED, NT_STATUS_ACCOUNT_EXPIRED}, + {PAM_SESSION_ERR, NT_STATUS_INSUFFICIENT_RESOURCES}, + {PAM_CRED_UNAVAIL, NT_STATUS_NO_TOKEN}, /* FIXME: Is this correct? */ + {PAM_CRED_EXPIRED, NT_STATUS_PASSWORD_EXPIRED}, /* FIXME: Is this correct? */ + {PAM_CRED_ERR, NT_STATUS_UNSUCCESSFUL}, + {PAM_AUTHTOK_ERR, NT_STATUS_UNSUCCESSFUL}, +#ifdef PAM_AUTHTOK_RECOVER_ERR + {PAM_AUTHTOK_RECOVER_ERR, NT_STATUS_UNSUCCESSFUL}, +#endif + {PAM_AUTHTOK_EXPIRED, NT_STATUS_PASSWORD_EXPIRED}, + {PAM_SUCCESS, NT_STATUS_OK} +}; + +/* NT_STATUS -> PAM map */ +static const struct { + NTSTATUS ntstatus; + int pam_code; +} nt_status_to_pam_map[] = { + {NT_STATUS_UNSUCCESSFUL, PAM_SYSTEM_ERR}, + {NT_STATUS_NO_SUCH_USER, PAM_USER_UNKNOWN}, + {NT_STATUS_WRONG_PASSWORD, PAM_AUTH_ERR}, + {NT_STATUS_LOGON_FAILURE, PAM_AUTH_ERR}, + {NT_STATUS_ACCOUNT_EXPIRED, PAM_ACCT_EXPIRED}, + {NT_STATUS_PASSWORD_EXPIRED, PAM_AUTHTOK_EXPIRED}, + {NT_STATUS_PASSWORD_MUST_CHANGE, PAM_NEW_AUTHTOK_REQD}, + {NT_STATUS_OK, PAM_SUCCESS} +}; + +/***************************************************************************** +convert a PAM error to a NT status32 code + *****************************************************************************/ +NTSTATUS pam_to_nt_status(int pam_error) +{ + int i; + if (pam_error == 0) return NT_STATUS_OK; + + for (i=0; NT_STATUS_V(pam_to_nt_status_map[i].ntstatus); i++) { + if (pam_error == pam_to_nt_status_map[i].pam_code) + return pam_to_nt_status_map[i].ntstatus; + } + return NT_STATUS_UNSUCCESSFUL; +} + +/***************************************************************************** +convert an NT status32 code to a PAM error + *****************************************************************************/ +int nt_status_to_pam(NTSTATUS nt_status) +{ + int i; + if NT_STATUS_IS_OK(nt_status) return PAM_SUCCESS; + + for (i=0; NT_STATUS_V(nt_status_to_pam_map[i].ntstatus); i++) { + if (NT_STATUS_EQUAL(nt_status,nt_status_to_pam_map[i].ntstatus)) + return nt_status_to_pam_map[i].pam_code; + } + return PAM_SYSTEM_ERR; +} + +#else + +/***************************************************************************** +convert a PAM error to a NT status32 code + *****************************************************************************/ +NTSTATUS pam_to_nt_status(int pam_error) +{ + if (pam_error == 0) return NT_STATUS_OK; + return NT_STATUS_UNSUCCESSFUL; +} + +/***************************************************************************** +convert an NT status32 code to a PAM error + *****************************************************************************/ +int nt_status_to_pam(NTSTATUS nt_status) +{ + if (NT_STATUS_EQUAL(nt_status, NT_STATUS_OK)) return 0; + return 4; /* PAM_SYSTEM_ERR */ +} + +#endif + diff --git a/source4/auth/ntlm/pam_errors.h b/source4/auth/ntlm/pam_errors.h new file mode 100644 index 0000000000..904950caa6 --- /dev/null +++ b/source4/auth/ntlm/pam_errors.h @@ -0,0 +1,39 @@ +#ifndef __AUTH_NTLM_PAM_ERRORS_H__ +#define __AUTH_NTLM_PAM_ERRORS_H__ + +#undef _PRINTF_ATTRIBUTE +#define _PRINTF_ATTRIBUTE(a1, a2) PRINTF_ATTRIBUTE(a1, a2) +/* This file was automatically generated by mkproto.pl. DO NOT EDIT */ + +/* this file contains prototypes for functions that are private + * to this subsystem or library. These functions should not be + * used outside this particular subsystem! */ + + +/* The following definitions come from auth/ntlm/pam_errors.c */ + + +/***************************************************************************** +convert a PAM error to a NT status32 code + *****************************************************************************/ +NTSTATUS pam_to_nt_status(int pam_error); + +/***************************************************************************** +convert an NT status32 code to a PAM error + *****************************************************************************/ +int nt_status_to_pam(NTSTATUS nt_status); + +/***************************************************************************** +convert a PAM error to a NT status32 code + *****************************************************************************/ +NTSTATUS pam_to_nt_status(int pam_error); + +/***************************************************************************** +convert an NT status32 code to a PAM error + *****************************************************************************/ +int nt_status_to_pam(NTSTATUS nt_status); +#undef _PRINTF_ATTRIBUTE +#define _PRINTF_ATTRIBUTE(a1, a2) + +#endif /* __AUTH_NTLM_PAM_ERRORS_H__ */ + diff --git a/source4/auth/ntlm_check.c b/source4/auth/ntlm_check.c deleted file mode 100644 index 55f2595f44..0000000000 --- a/source4/auth/ntlm_check.c +++ /dev/null @@ -1,602 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Password and authentication handling - Copyright (C) Andrew Bartlett 2001-2004 - Copyright (C) Gerald Carter 2003 - Copyright (C) Luke Kenneth Casson Leighton 1996-2000 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "includes.h" -#include "lib/crypto/crypto.h" -#include "librpc/gen_ndr/netlogon.h" -#include "libcli/auth/libcli_auth.h" -#include "param/param.h" - -/**************************************************************************** - Core of smb password checking routine. -****************************************************************************/ - -static bool smb_pwd_check_ntlmv1(TALLOC_CTX *mem_ctx, - const DATA_BLOB *nt_response, - const uint8_t *part_passwd, - const DATA_BLOB *sec_blob, - DATA_BLOB *user_sess_key) -{ - /* Finish the encryption of part_passwd. */ - uint8_t p24[24]; - - if (part_passwd == NULL) { - DEBUG(10,("No password set - DISALLOWING access\n")); - /* No password set - always false ! */ - return false; - } - - if (sec_blob->length != 8) { - DEBUG(0, ("smb_pwd_check_ntlmv1: incorrect challenge size (%lu)\n", - (unsigned long)sec_blob->length)); - return false; - } - - if (nt_response->length != 24) { - DEBUG(0, ("smb_pwd_check_ntlmv1: incorrect password length (%lu)\n", - (unsigned long)nt_response->length)); - return false; - } - - SMBOWFencrypt(part_passwd, sec_blob->data, p24); - -#if DEBUG_PASSWORD - DEBUG(100,("Part password (P16) was |\n")); - dump_data(100, part_passwd, 16); - DEBUGADD(100,("Password from client was |\n")); - dump_data(100, nt_response->data, nt_response->length); - DEBUGADD(100,("Given challenge was |\n")); - dump_data(100, sec_blob->data, sec_blob->length); - DEBUGADD(100,("Value from encryption was |\n")); - dump_data(100, p24, 24); -#endif - if (memcmp(p24, nt_response->data, 24) == 0) { - if (user_sess_key != NULL) { - *user_sess_key = data_blob_talloc(mem_ctx, NULL, 16); - SMBsesskeygen_ntv1(part_passwd, user_sess_key->data); - } - return true; - } - return false; -} - -/**************************************************************************** - Core of smb password checking routine. (NTLMv2, LMv2) - Note: The same code works with both NTLMv2 and LMv2. -****************************************************************************/ - -static bool smb_pwd_check_ntlmv2(TALLOC_CTX *mem_ctx, - const DATA_BLOB *ntv2_response, - const uint8_t *part_passwd, - const DATA_BLOB *sec_blob, - const char *user, const char *domain, - bool upper_case_domain, /* should the domain be transformed into upper case? */ - DATA_BLOB *user_sess_key) -{ - /* Finish the encryption of part_passwd. */ - uint8_t kr[16]; - uint8_t value_from_encryption[16]; - DATA_BLOB client_key_data; - - if (part_passwd == NULL) { - DEBUG(10,("No password set - DISALLOWING access\n")); - /* No password set - always false */ - return false; - } - - if (sec_blob->length != 8) { - DEBUG(0, ("smb_pwd_check_ntlmv2: incorrect challenge size (%lu)\n", - (unsigned long)sec_blob->length)); - return false; - } - - if (ntv2_response->length < 24) { - /* We MUST have more than 16 bytes, or the stuff below will go - crazy. No known implementation sends less than the 24 bytes - for LMv2, let alone NTLMv2. */ - DEBUG(0, ("smb_pwd_check_ntlmv2: incorrect password length (%lu)\n", - (unsigned long)ntv2_response->length)); - return false; - } - - client_key_data = data_blob_talloc(mem_ctx, ntv2_response->data+16, ntv2_response->length-16); - /* - todo: should we be checking this for anything? We can't for LMv2, - but for NTLMv2 it is meant to contain the current time etc. - */ - - if (!ntv2_owf_gen(part_passwd, user, domain, upper_case_domain, kr)) { - return false; - } - - SMBOWFencrypt_ntv2(kr, sec_blob, &client_key_data, value_from_encryption); - -#if DEBUG_PASSWORD - DEBUG(100,("Part password (P16) was |\n")); - dump_data(100, part_passwd, 16); - DEBUGADD(100,("Password from client was |\n")); - dump_data(100, ntv2_response->data, ntv2_response->length); - DEBUGADD(100,("Variable data from client was |\n")); - dump_data(100, client_key_data.data, client_key_data.length); - DEBUGADD(100,("Given challenge was |\n")); - dump_data(100, sec_blob->data, sec_blob->length); - DEBUGADD(100,("Value from encryption was |\n")); - dump_data(100, value_from_encryption, 16); -#endif - data_blob_clear_free(&client_key_data); - if (memcmp(value_from_encryption, ntv2_response->data, 16) == 0) { - if (user_sess_key != NULL) { - *user_sess_key = data_blob_talloc(mem_ctx, NULL, 16); - SMBsesskeygen_ntv2(kr, value_from_encryption, user_sess_key->data); - } - return true; - } - return false; -} - -/**************************************************************************** - Core of smb password checking routine. (NTLMv2, LMv2) - Note: The same code works with both NTLMv2 and LMv2. -****************************************************************************/ - -static bool smb_sess_key_ntlmv2(TALLOC_CTX *mem_ctx, - const DATA_BLOB *ntv2_response, - const uint8_t *part_passwd, - const DATA_BLOB *sec_blob, - const char *user, const char *domain, - bool upper_case_domain, /* should the domain be transformed into upper case? */ - DATA_BLOB *user_sess_key) -{ - /* Finish the encryption of part_passwd. */ - uint8_t kr[16]; - uint8_t value_from_encryption[16]; - DATA_BLOB client_key_data; - - if (part_passwd == NULL) { - DEBUG(10,("No password set - DISALLOWING access\n")); - /* No password set - always false */ - return false; - } - - if (sec_blob->length != 8) { - DEBUG(0, ("smb_sess_key_ntlmv2: incorrect challenge size (%lu)\n", - (unsigned long)sec_blob->length)); - return false; - } - - if (ntv2_response->length < 24) { - /* We MUST have more than 16 bytes, or the stuff below will go - crazy. No known implementation sends less than the 24 bytes - for LMv2, let alone NTLMv2. */ - DEBUG(0, ("smb_sess_key_ntlmv2: incorrect password length (%lu)\n", - (unsigned long)ntv2_response->length)); - return false; - } - - client_key_data = data_blob_talloc(mem_ctx, ntv2_response->data+16, ntv2_response->length-16); - - if (!ntv2_owf_gen(part_passwd, user, domain, upper_case_domain, kr)) { - return false; - } - - SMBOWFencrypt_ntv2(kr, sec_blob, &client_key_data, value_from_encryption); - *user_sess_key = data_blob_talloc(mem_ctx, NULL, 16); - SMBsesskeygen_ntv2(kr, value_from_encryption, user_sess_key->data); - return true; -} - -/** - * Compare password hashes against those from the SAM - * - * @param mem_ctx talloc context - * @param client_lanman LANMAN password hash, as supplied by the client - * @param client_nt NT (MD4) password hash, as supplied by the client - * @param username internal Samba username, for log messages - * @param client_username username the client used - * @param client_domain domain name the client used (may be mapped) - * @param stored_lanman LANMAN password hash, as stored on the SAM - * @param stored_nt NT (MD4) password hash, as stored on the SAM - * @param user_sess_key User session key - * @param lm_sess_key LM session key (first 8 bytes of the LM hash) - */ - -NTSTATUS hash_password_check(TALLOC_CTX *mem_ctx, - struct loadparm_context *lp_ctx, - const struct samr_Password *client_lanman, - const struct samr_Password *client_nt, - const char *username, - const struct samr_Password *stored_lanman, - const struct samr_Password *stored_nt) -{ - if (stored_nt == NULL) { - DEBUG(3,("ntlm_password_check: NO NT password stored for user %s.\n", - username)); - } - - if (client_nt && stored_nt) { - if (memcmp(client_nt->hash, stored_nt->hash, sizeof(stored_nt->hash)) == 0) { - return NT_STATUS_OK; - } else { - DEBUG(3,("ntlm_password_check: Interactive logon: NT password check failed for user %s\n", - username)); - return NT_STATUS_WRONG_PASSWORD; - } - - } else if (client_lanman && stored_lanman) { - if (!lp_lanman_auth(lp_ctx)) { - DEBUG(3,("ntlm_password_check: Interactive logon: only LANMAN password supplied for user %s, and LM passwords are disabled!\n", - username)); - return NT_STATUS_WRONG_PASSWORD; - } - if (strchr_m(username, '@')) { - return NT_STATUS_NOT_FOUND; - } - - if (memcmp(client_lanman->hash, stored_lanman->hash, sizeof(stored_lanman->hash)) == 0) { - return NT_STATUS_OK; - } else { - DEBUG(3,("ntlm_password_check: Interactive logon: LANMAN password check failed for user %s\n", - username)); - return NT_STATUS_WRONG_PASSWORD; - } - } - if (strchr_m(username, '@')) { - return NT_STATUS_NOT_FOUND; - } - return NT_STATUS_WRONG_PASSWORD; -} - -/** - * Check a challenge-response password against the value of the NT or - * LM password hash. - * - * @param mem_ctx talloc context - * @param challenge 8-byte challenge. If all zero, forces plaintext comparison - * @param nt_response 'unicode' NT response to the challenge, or unicode password - * @param lm_response ASCII or LANMAN response to the challenge, or password in DOS code page - * @param username internal Samba username, for log messages - * @param client_username username the client used - * @param client_domain domain name the client used (may be mapped) - * @param stored_lanman LANMAN ASCII password from our passdb or similar - * @param stored_nt MD4 unicode password from our passdb or similar - * @param user_sess_key User session key - * @param lm_sess_key LM session key (first 8 bytes of the LM hash) - */ - -NTSTATUS ntlm_password_check(TALLOC_CTX *mem_ctx, - struct loadparm_context *lp_ctx, - uint32_t logon_parameters, - const DATA_BLOB *challenge, - const DATA_BLOB *lm_response, - const DATA_BLOB *nt_response, - const char *username, - const char *client_username, - const char *client_domain, - const struct samr_Password *stored_lanman, - const struct samr_Password *stored_nt, - DATA_BLOB *user_sess_key, - DATA_BLOB *lm_sess_key) -{ - const static uint8_t zeros[8]; - DATA_BLOB tmp_sess_key; - - if (stored_nt == NULL) { - DEBUG(3,("ntlm_password_check: NO NT password stored for user %s.\n", - username)); - } - - *lm_sess_key = data_blob(NULL, 0); - *user_sess_key = data_blob(NULL, 0); - - /* Check for cleartext netlogon. Used by Exchange 5.5. */ - if ((logon_parameters & MSV1_0_CLEARTEXT_PASSWORD_ALLOWED) - && challenge->length == sizeof(zeros) - && (memcmp(challenge->data, zeros, challenge->length) == 0 )) { - struct samr_Password client_nt; - struct samr_Password client_lm; - char *unix_pw = NULL; - bool lm_ok; - - DEBUG(4,("ntlm_password_check: checking plaintext passwords for user %s\n", - username)); - mdfour(client_nt.hash, nt_response->data, nt_response->length); - - if (lm_response->length && - (convert_string_talloc(mem_ctx, lp_iconv_convenience(lp_ctx), CH_DOS, CH_UNIX, - lm_response->data, lm_response->length, - (void **)&unix_pw) != -1)) { - if (E_deshash(unix_pw, client_lm.hash)) { - lm_ok = true; - } else { - lm_ok = false; - } - } else { - lm_ok = false; - } - return hash_password_check(mem_ctx, - lp_ctx, - lm_ok ? &client_lm : NULL, - nt_response->length ? &client_nt : NULL, - username, - stored_lanman, stored_nt); - } - - if (nt_response->length != 0 && nt_response->length < 24) { - DEBUG(2,("ntlm_password_check: invalid NT password length (%lu) for user %s\n", - (unsigned long)nt_response->length, username)); - } - - if (nt_response->length > 24 && stored_nt) { - /* We have the NT MD4 hash challenge available - see if we can - use it - */ - DEBUG(4,("ntlm_password_check: Checking NTLMv2 password with domain [%s]\n", client_domain)); - if (smb_pwd_check_ntlmv2(mem_ctx, - nt_response, - stored_nt->hash, challenge, - client_username, - client_domain, - false, - user_sess_key)) { - *lm_sess_key = *user_sess_key; - if (user_sess_key->length) { - lm_sess_key->length = 8; - } - return NT_STATUS_OK; - } - - DEBUG(4,("ntlm_password_check: Checking NTLMv2 password with uppercased version of domain [%s]\n", client_domain)); - if (smb_pwd_check_ntlmv2(mem_ctx, - nt_response, - stored_nt->hash, challenge, - client_username, - client_domain, - true, - user_sess_key)) { - *lm_sess_key = *user_sess_key; - if (user_sess_key->length) { - lm_sess_key->length = 8; - } - return NT_STATUS_OK; - } - - DEBUG(4,("ntlm_password_check: Checking NTLMv2 password without a domain\n")); - if (smb_pwd_check_ntlmv2(mem_ctx, - nt_response, - stored_nt->hash, challenge, - client_username, - "", - false, - user_sess_key)) { - *lm_sess_key = *user_sess_key; - if (user_sess_key->length) { - lm_sess_key->length = 8; - } - return NT_STATUS_OK; - } else { - DEBUG(3,("ntlm_password_check: NTLMv2 password check failed\n")); - } - } else if (nt_response->length == 24 && stored_nt) { - if (lp_ntlm_auth(lp_ctx)) { - /* We have the NT MD4 hash challenge available - see if we can - use it (ie. does it exist in the smbpasswd file). - */ - DEBUG(4,("ntlm_password_check: Checking NT MD4 password\n")); - if (smb_pwd_check_ntlmv1(mem_ctx, - nt_response, - stored_nt->hash, challenge, - user_sess_key)) { - /* The LM session key for this response is not very secure, - so use it only if we otherwise allow LM authentication */ - - if (lp_lanman_auth(lp_ctx) && stored_lanman) { - *lm_sess_key = data_blob_talloc(mem_ctx, stored_lanman->hash, 8); - } - return NT_STATUS_OK; - } else { - DEBUG(3,("ntlm_password_check: NT MD4 password check failed for user %s\n", - username)); - return NT_STATUS_WRONG_PASSWORD; - } - } else { - DEBUG(2,("ntlm_password_check: NTLMv1 passwords NOT PERMITTED for user %s\n", - username)); - /* no return, becouse we might pick up LMv2 in the LM field */ - } - } - - if (lm_response->length == 0) { - DEBUG(3,("ntlm_password_check: NEITHER LanMan nor NT password supplied for user %s\n", - username)); - return NT_STATUS_WRONG_PASSWORD; - } - - if (lm_response->length < 24) { - DEBUG(2,("ntlm_password_check: invalid LanMan password length (%lu) for user %s\n", - (unsigned long)nt_response->length, username)); - return NT_STATUS_WRONG_PASSWORD; - } - - if (!lp_lanman_auth(lp_ctx)) { - DEBUG(3,("ntlm_password_check: Lanman passwords NOT PERMITTED for user %s\n", - username)); - } else if (!stored_lanman) { - DEBUG(3,("ntlm_password_check: NO LanMan password set for user %s (and no NT password supplied)\n", - username)); - } else if (strchr_m(username, '@')) { - DEBUG(3,("ntlm_password_check: NO LanMan password allowed for username@realm logins (user: %s)\n", - username)); - } else { - DEBUG(4,("ntlm_password_check: Checking LM password\n")); - if (smb_pwd_check_ntlmv1(mem_ctx, - lm_response, - stored_lanman->hash, challenge, - NULL)) { - /* The session key for this response is still very odd. - It not very secure, so use it only if we otherwise - allow LM authentication */ - - if (lp_lanman_auth(lp_ctx) && stored_lanman) { - uint8_t first_8_lm_hash[16]; - memcpy(first_8_lm_hash, stored_lanman->hash, 8); - memset(first_8_lm_hash + 8, '\0', 8); - *user_sess_key = data_blob_talloc(mem_ctx, first_8_lm_hash, 16); - *lm_sess_key = data_blob_talloc(mem_ctx, stored_lanman->hash, 8); - } - return NT_STATUS_OK; - } - } - - if (!stored_nt) { - DEBUG(4,("ntlm_password_check: LM password check failed for user, no NT password %s\n",username)); - return NT_STATUS_WRONG_PASSWORD; - } - - /* This is for 'LMv2' authentication. almost NTLMv2 but limited to 24 bytes. - - related to Win9X, legacy NAS pass-though authentication - */ - DEBUG(4,("ntlm_password_check: Checking LMv2 password with domain %s\n", client_domain)); - if (smb_pwd_check_ntlmv2(mem_ctx, - lm_response, - stored_nt->hash, challenge, - client_username, - client_domain, - false, - &tmp_sess_key)) { - if (nt_response->length > 24) { - /* If NTLMv2 authentication has preceeded us - * (even if it failed), then use the session - * key from that. See the RPC-SAMLOGON - * torture test */ - smb_sess_key_ntlmv2(mem_ctx, - nt_response, - stored_nt->hash, challenge, - client_username, - client_domain, - false, - user_sess_key); - } else { - /* Otherwise, use the LMv2 session key */ - *user_sess_key = tmp_sess_key; - } - *lm_sess_key = *user_sess_key; - if (user_sess_key->length) { - lm_sess_key->length = 8; - } - return NT_STATUS_OK; - } - - DEBUG(4,("ntlm_password_check: Checking LMv2 password with upper-cased version of domain %s\n", client_domain)); - if (smb_pwd_check_ntlmv2(mem_ctx, - lm_response, - stored_nt->hash, challenge, - client_username, - client_domain, - true, - &tmp_sess_key)) { - if (nt_response->length > 24) { - /* If NTLMv2 authentication has preceeded us - * (even if it failed), then use the session - * key from that. See the RPC-SAMLOGON - * torture test */ - smb_sess_key_ntlmv2(mem_ctx, - nt_response, - stored_nt->hash, challenge, - client_username, - client_domain, - true, - user_sess_key); - } else { - /* Otherwise, use the LMv2 session key */ - *user_sess_key = tmp_sess_key; - } - *lm_sess_key = *user_sess_key; - if (user_sess_key->length) { - lm_sess_key->length = 8; - } - return NT_STATUS_OK; - } - - DEBUG(4,("ntlm_password_check: Checking LMv2 password without a domain\n")); - if (smb_pwd_check_ntlmv2(mem_ctx, - lm_response, - stored_nt->hash, challenge, - client_username, - "", - false, - &tmp_sess_key)) { - if (nt_response->length > 24) { - /* If NTLMv2 authentication has preceeded us - * (even if it failed), then use the session - * key from that. See the RPC-SAMLOGON - * torture test */ - smb_sess_key_ntlmv2(mem_ctx, - nt_response, - stored_nt->hash, challenge, - client_username, - "", - false, - user_sess_key); - } else { - /* Otherwise, use the LMv2 session key */ - *user_sess_key = tmp_sess_key; - } - *lm_sess_key = *user_sess_key; - if (user_sess_key->length) { - lm_sess_key->length = 8; - } - return NT_STATUS_OK; - } - - /* Apparently NT accepts NT responses in the LM field - - I think this is related to Win9X pass-though authentication - */ - DEBUG(4,("ntlm_password_check: Checking NT MD4 password in LM field\n")); - if (lp_ntlm_auth(lp_ctx)) { - if (smb_pwd_check_ntlmv1(mem_ctx, - lm_response, - stored_nt->hash, challenge, - NULL)) { - /* The session key for this response is still very odd. - It not very secure, so use it only if we otherwise - allow LM authentication */ - - if (lp_lanman_auth(lp_ctx) && stored_lanman) { - uint8_t first_8_lm_hash[16]; - memcpy(first_8_lm_hash, stored_lanman->hash, 8); - memset(first_8_lm_hash + 8, '\0', 8); - *user_sess_key = data_blob_talloc(mem_ctx, first_8_lm_hash, 16); - *lm_sess_key = data_blob_talloc(mem_ctx, stored_lanman->hash, 8); - } - return NT_STATUS_OK; - } - DEBUG(3,("ntlm_password_check: LM password, NT MD4 password in LM field and LMv2 failed for user %s\n",username)); - } else { - DEBUG(3,("ntlm_password_check: LM password and LMv2 failed for user %s, and NT MD4 password in LM field not permitted\n",username)); - } - - /* Try and match error codes */ - if (strchr_m(username, '@')) { - return NT_STATUS_NOT_FOUND; - } - return NT_STATUS_WRONG_PASSWORD; -} - diff --git a/source4/auth/pam_errors.c b/source4/auth/pam_errors.c deleted file mode 100644 index 9774ad8727..0000000000 --- a/source4/auth/pam_errors.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * PAM error mapping functions - * Copyright (C) Andrew Bartlett 2002 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - */ - -#include "includes.h" - -#ifdef WITH_HAVE_SECURITY_PAM_APPL_H -#include - -#if defined(PAM_AUTHTOK_RECOVERY_ERR) && !defined(PAM_AUTHTOK_RECOVER_ERR) -#define PAM_AUTHTOK_RECOVER_ERR PAM_AUTHTOK_RECOVERY_ERR -#endif - -/* PAM -> NT_STATUS map */ -static const struct { - int pam_code; - NTSTATUS ntstatus; -} pam_to_nt_status_map[] = { - {PAM_OPEN_ERR, NT_STATUS_UNSUCCESSFUL}, - {PAM_SYMBOL_ERR, NT_STATUS_UNSUCCESSFUL}, - {PAM_SERVICE_ERR, NT_STATUS_UNSUCCESSFUL}, - {PAM_SYSTEM_ERR, NT_STATUS_UNSUCCESSFUL}, - {PAM_BUF_ERR, NT_STATUS_UNSUCCESSFUL}, - {PAM_PERM_DENIED, NT_STATUS_ACCESS_DENIED}, - {PAM_AUTH_ERR, NT_STATUS_WRONG_PASSWORD}, - {PAM_CRED_INSUFFICIENT, NT_STATUS_INSUFFICIENT_LOGON_INFO}, /* FIXME: Is this correct? */ - {PAM_AUTHINFO_UNAVAIL, NT_STATUS_LOGON_FAILURE}, - {PAM_USER_UNKNOWN, NT_STATUS_NO_SUCH_USER}, - {PAM_MAXTRIES, NT_STATUS_REMOTE_SESSION_LIMIT}, /* FIXME: Is this correct? */ - {PAM_NEW_AUTHTOK_REQD, NT_STATUS_PASSWORD_MUST_CHANGE}, - {PAM_ACCT_EXPIRED, NT_STATUS_ACCOUNT_EXPIRED}, - {PAM_SESSION_ERR, NT_STATUS_INSUFFICIENT_RESOURCES}, - {PAM_CRED_UNAVAIL, NT_STATUS_NO_TOKEN}, /* FIXME: Is this correct? */ - {PAM_CRED_EXPIRED, NT_STATUS_PASSWORD_EXPIRED}, /* FIXME: Is this correct? */ - {PAM_CRED_ERR, NT_STATUS_UNSUCCESSFUL}, - {PAM_AUTHTOK_ERR, NT_STATUS_UNSUCCESSFUL}, -#ifdef PAM_AUTHTOK_RECOVER_ERR - {PAM_AUTHTOK_RECOVER_ERR, NT_STATUS_UNSUCCESSFUL}, -#endif - {PAM_AUTHTOK_EXPIRED, NT_STATUS_PASSWORD_EXPIRED}, - {PAM_SUCCESS, NT_STATUS_OK} -}; - -/* NT_STATUS -> PAM map */ -static const struct { - NTSTATUS ntstatus; - int pam_code; -} nt_status_to_pam_map[] = { - {NT_STATUS_UNSUCCESSFUL, PAM_SYSTEM_ERR}, - {NT_STATUS_NO_SUCH_USER, PAM_USER_UNKNOWN}, - {NT_STATUS_WRONG_PASSWORD, PAM_AUTH_ERR}, - {NT_STATUS_LOGON_FAILURE, PAM_AUTH_ERR}, - {NT_STATUS_ACCOUNT_EXPIRED, PAM_ACCT_EXPIRED}, - {NT_STATUS_PASSWORD_EXPIRED, PAM_AUTHTOK_EXPIRED}, - {NT_STATUS_PASSWORD_MUST_CHANGE, PAM_NEW_AUTHTOK_REQD}, - {NT_STATUS_OK, PAM_SUCCESS} -}; - -/***************************************************************************** -convert a PAM error to a NT status32 code - *****************************************************************************/ -NTSTATUS pam_to_nt_status(int pam_error) -{ - int i; - if (pam_error == 0) return NT_STATUS_OK; - - for (i=0; NT_STATUS_V(pam_to_nt_status_map[i].ntstatus); i++) { - if (pam_error == pam_to_nt_status_map[i].pam_code) - return pam_to_nt_status_map[i].ntstatus; - } - return NT_STATUS_UNSUCCESSFUL; -} - -/***************************************************************************** -convert an NT status32 code to a PAM error - *****************************************************************************/ -int nt_status_to_pam(NTSTATUS nt_status) -{ - int i; - if NT_STATUS_IS_OK(nt_status) return PAM_SUCCESS; - - for (i=0; NT_STATUS_V(nt_status_to_pam_map[i].ntstatus); i++) { - if (NT_STATUS_EQUAL(nt_status,nt_status_to_pam_map[i].ntstatus)) - return nt_status_to_pam_map[i].pam_code; - } - return PAM_SYSTEM_ERR; -} - -#else - -/***************************************************************************** -convert a PAM error to a NT status32 code - *****************************************************************************/ -NTSTATUS pam_to_nt_status(int pam_error) -{ - if (pam_error == 0) return NT_STATUS_OK; - return NT_STATUS_UNSUCCESSFUL; -} - -/***************************************************************************** -convert an NT status32 code to a PAM error - *****************************************************************************/ -int nt_status_to_pam(NTSTATUS nt_status) -{ - if (NT_STATUS_EQUAL(nt_status, NT_STATUS_OK)) return 0; - return 4; /* PAM_SYSTEM_ERR */ -} - -#endif - diff --git a/source4/utils/config.mk b/source4/utils/config.mk index a7d82684e4..13f3b0a145 100644 --- a/source4/utils/config.mk +++ b/source4/utils/config.mk @@ -13,6 +13,7 @@ PRIVATE_DEPENDENCIES = \ gensec \ LIBCLI_RESOLVE \ auth \ + ntlm_check \ MESSAGING \ LIBEVENTS # End BINARY ntlm_auth diff --git a/source4/utils/ntlm_auth.c b/source4/utils/ntlm_auth.c index 07c0e4f31e..95029deffa 100644 --- a/source4/utils/ntlm_auth.c +++ b/source4/utils/ntlm_auth.c @@ -30,6 +30,7 @@ #include "auth/auth.h" #include "librpc/gen_ndr/ndr_netlogon.h" #include "auth/auth_sam.h" +#include "auth/ntlm/ntlm_check.h" #include "pstring.h" #include "libcli/auth/libcli_auth.h" #include "libcli/security/security.h" -- cgit