summaryrefslogtreecommitdiffstats
path: root/source4/auth/ntlm/auth.c
diff options
context:
space:
mode:
Diffstat (limited to 'source4/auth/ntlm/auth.c')
-rw-r--r--source4/auth/ntlm/auth.c869
1 files changed, 869 insertions, 0 deletions
diff --git a/source4/auth/ntlm/auth.c b/source4/auth/ntlm/auth.c
new file mode 100644
index 0000000..3ad18bd
--- /dev/null
+++ b/source4/auth/ntlm/auth.c
@@ -0,0 +1,869 @@
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include <tevent.h>
+#include "../lib/util/tevent_ntstatus.h"
+#include "../lib/util/dlinklist.h"
+#include "auth/auth.h"
+#include "auth/ntlm/auth_proto.h"
+#include "param/param.h"
+#include "dsdb/samdb/samdb.h"
+#include "libcli/wbclient/wbclient.h"
+#include "lib/util/samba_modules.h"
+#include "auth/credentials/credentials.h"
+#include "system/kerberos.h"
+#include "auth/kerberos/kerberos.h"
+#include "auth/kerberos/kerberos_util.h"
+#include "libds/common/roles.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_AUTH
+
+static NTSTATUS auth_generate_session_info_wrapper(struct auth4_context *auth_context,
+ TALLOC_CTX *mem_ctx,
+ void *server_returned_info,
+ const char *original_user_name,
+ uint32_t session_info_flags,
+ struct auth_session_info **session_info);
+
+/***************************************************************************
+ Set a fixed challenge
+***************************************************************************/
+_PUBLIC_ NTSTATUS auth_context_set_challenge(struct auth4_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;
+}
+
+/****************************************************************************
+ 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 auth4_context *auth_ctx, uint8_t chal[8])
+{
+
+ if (auth_ctx->challenge.data.length == 8) {
+ DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
+ auth_ctx->challenge.set_by));
+ memcpy(chal, auth_ctx->challenge.data.data, 8);
+ return NT_STATUS_OK;
+ }
+
+ if (!auth_ctx->challenge.set_by) {
+ 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";
+ }
+
+ DEBUG(10,("auth_get_challenge: challenge set by %s\n",
+ auth_ctx->challenge.set_by));
+
+ return NT_STATUS_OK;
+}
+
+/**
+ * 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 user_info_dc struct.
+ *
+ * The return value takes precedence over the contents of the user_info_dc
+ * 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 generation
+ * function auth_get_challenge().
+ *
+ * @param user_info Contains the user supplied components, including the passwords.
+ *
+ * @param mem_ctx The parent memory context for the user_info_dc structure
+ *
+ * @param user_info_dc 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 auth4_context *auth_ctx,
+ TALLOC_CTX *mem_ctx,
+ const struct auth_usersupplied_info *user_info,
+ struct auth_user_info_dc **user_info_dc,
+ uint8_t *pauthoritative)
+{
+ struct tevent_req *subreq;
+ struct tevent_context *ev;
+ bool ok;
+ NTSTATUS status;
+
+ /*TODO: create a new event context here! */
+ ev = auth_ctx->event_ctx;
+
+ /*
+ * We are authoritative by default
+ */
+ *pauthoritative = 1;
+
+ subreq = auth_check_password_send(mem_ctx,
+ ev,
+ auth_ctx,
+ user_info);
+ if (subreq == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ok = tevent_req_poll(subreq, ev);
+ if (!ok) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ status = auth_check_password_recv(subreq, mem_ctx,
+ user_info_dc, pauthoritative);
+ TALLOC_FREE(subreq);
+
+ return status;
+}
+
+struct auth_check_password_state {
+ struct tevent_context *ev;
+ struct auth4_context *auth_ctx;
+ const struct auth_usersupplied_info *user_info;
+ struct auth_user_info_dc *user_info_dc;
+ struct auth_method_context *method;
+ const struct authn_audit_info *client_audit_info;
+ const struct authn_audit_info *server_audit_info;
+ uint8_t authoritative;
+};
+
+static void auth_check_password_next(struct tevent_req *req);
+
+/**
+ * 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 user_info_dc struct.
+ *
+ * The return value takes precedence over the contents of the user_info_dc
+ * struct. When the return is other than NT_STATUS_OK the contents
+ * of that structure is undefined.
+ *
+ * @param mem_ctx The memory context the request should operate on
+ *
+ * @param ev The tevent context the request should operate on
+ *
+ * @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 generation function
+ * auth_get_challenge().
+ *
+ * @param user_info Contains the user supplied components, including the passwords.
+ *
+ * @return The request handle or NULL on no memory error.
+ *
+ **/
+
+_PUBLIC_ struct tevent_req *auth_check_password_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct auth4_context *auth_ctx,
+ const struct auth_usersupplied_info *user_info)
+{
+ struct tevent_req *req;
+ struct auth_check_password_state *state;
+ /* if all the modules say 'not for me' this is reasonable */
+ NTSTATUS nt_status;
+ uint8_t chal[8];
+
+ 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 = tevent_req_create(mem_ctx, &state,
+ struct auth_check_password_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ /*
+ * We are authoritative by default.
+ */
+ state->ev = ev;
+ state->auth_ctx = auth_ctx;
+ state->user_info = user_info;
+ state->authoritative = 1;
+
+ if (user_info->mapped.account_name == NULL) {
+ struct auth_usersupplied_info *user_info_tmp;
+
+ /*
+ * We don't really do any mapping here.
+ *
+ * It's up to the backends to do mappings
+ * for their authentication.
+ */
+ user_info_tmp = talloc_zero(state, struct auth_usersupplied_info);
+ if (tevent_req_nomem(user_info_tmp, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ /*
+ * The lifetime of user_info is longer than
+ * user_info_tmp, so we don't need to copy the
+ * strings.
+ */
+ *user_info_tmp = *user_info;
+ user_info_tmp->mapped.domain_name = user_info->client.domain_name;
+ user_info_tmp->mapped.account_name = user_info->client.account_name;
+
+ user_info = user_info_tmp;
+ state->user_info = user_info_tmp;
+ }
+
+ DEBUGADD(3,("auth_check_password_send: "
+ "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, chal);
+ if (tevent_req_nterror(req, 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)));
+ return tevent_req_post(req, ev);
+ }
+
+ 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);
+
+ state->method = state->auth_ctx->methods;
+ auth_check_password_next(req);
+ if (!tevent_req_is_in_progress(req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ return req;
+}
+
+static void auth_check_password_done(struct tevent_req *subreq);
+
+static void auth_check_password_next(struct tevent_req *req)
+{
+ struct auth_check_password_state *state =
+ tevent_req_data(req, struct auth_check_password_state);
+ struct tevent_req *subreq = NULL;
+ NTSTATUS status;
+
+ if (state->method == NULL) {
+ state->authoritative = 0;
+ tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
+ return;
+ }
+
+ /* check if the module wants to check the password */
+ status = state->method->ops->want_check(state->method, state,
+ state->user_info);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
+ DEBUG(11,("auth_check_password_send: "
+ "%s doesn't want to check\n",
+ state->method->ops->name));
+ state->method = state->method->next;
+ auth_check_password_next(req);
+ return;
+ }
+
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ subreq = state->method->ops->check_password_send(
+ state, state->ev, state->method, state->user_info);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, auth_check_password_done, req);
+}
+
+static void auth_check_password_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct auth_check_password_state *state =
+ tevent_req_data(req,
+ struct auth_check_password_state);
+ bool authoritative = true;
+ NTSTATUS status;
+
+ status = state->method->ops->check_password_recv(subreq, state,
+ &state->user_info_dc,
+ &state->client_audit_info,
+ &state->server_audit_info,
+ &authoritative);
+ TALLOC_FREE(subreq);
+ if (!authoritative ||
+ NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
+ DEBUG(11,("auth_check_password_send: "
+ "%s passes to the next method\n",
+ state->method->ops->name));
+ state->method = state->method->next;
+ auth_check_password_next(req);
+ return;
+ }
+
+ /* the backend has handled the request */
+
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+/**
+ * Check a user's Plaintext, LM or NTLM password.
+ * async receive function
+ *
+ * The return value takes precedence over the contents of the user_info_dc
+ * struct. When the return is other than NT_STATUS_OK the contents
+ * of that structure is undefined.
+ *
+ *
+ * @param req The async request state
+ *
+ * @param mem_ctx The parent memory context for the user_info_dc structure
+ *
+ * @param user_info_dc 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 tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct auth_user_info_dc **user_info_dc,
+ uint8_t *pauthoritative)
+{
+ struct auth_check_password_state *state =
+ tevent_req_data(req, struct auth_check_password_state);
+ NTSTATUS status = NT_STATUS_OK;
+
+ *pauthoritative = state->authoritative;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ /*
+ * Please try not to change this string, it is probably in use
+ * in audit logging tools
+ */
+ DEBUG(2,("auth_check_password_recv: "
+ "%s authentication for user [%s\\%s] "
+ "FAILED with error %s, authoritative=%u\n",
+ (state->method ? state->method->ops->name : "NO_METHOD"),
+ state->user_info->mapped.domain_name,
+ state->user_info->mapped.account_name,
+ nt_errstr(status), state->authoritative));
+
+ log_authentication_event(state->auth_ctx->msg_ctx,
+ state->auth_ctx->lp_ctx,
+ &state->auth_ctx->start_time,
+ state->user_info, status,
+ NULL, NULL, NULL,
+ state->client_audit_info,
+ state->server_audit_info);
+ tevent_req_received(req);
+ return status;
+ }
+
+ DEBUG(5,("auth_check_password_recv: "
+ "%s authentication for user [%s\\%s] succeeded\n",
+ state->method->ops->name,
+ state->user_info_dc->info->domain_name,
+ state->user_info_dc->info->account_name));
+
+ log_authentication_event(state->auth_ctx->msg_ctx,
+ state->auth_ctx->lp_ctx,
+ &state->auth_ctx->start_time,
+ state->user_info, status,
+ state->user_info_dc->info->domain_name,
+ state->user_info_dc->info->account_name,
+ &state->user_info_dc->sids[PRIMARY_USER_SID_INDEX].sid,
+ state->client_audit_info,
+ state->server_audit_info);
+
+ /*
+ * Release our handle to state->user_info_dc.
+ * state->{client,server}_audit_info, if non-NULL, becomes the new
+ * parent.
+ */
+ *user_info_dc = talloc_reparent(state, mem_ctx, state->user_info_dc);
+ state->user_info_dc = NULL;
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+struct auth_check_password_wrapper_state {
+ uint8_t authoritative;
+ struct auth_user_info_dc *user_info_dc;
+};
+
+static void auth_check_password_wrapper_done(struct tevent_req *subreq);
+
+static struct tevent_req *auth_check_password_wrapper_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct auth4_context *auth_ctx,
+ const struct auth_usersupplied_info *user_info)
+{
+ struct tevent_req *req = NULL;
+ struct auth_check_password_wrapper *state = NULL;
+ struct tevent_req *subreq = NULL;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct auth_check_password_wrapper_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ subreq = auth_check_password_send(state, ev, auth_ctx, user_info);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq,
+ auth_check_password_wrapper_done,
+ req);
+
+ return req;
+}
+
+static void auth_check_password_wrapper_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct auth_check_password_wrapper_state *state =
+ tevent_req_data(req,
+ struct auth_check_password_wrapper_state);
+ NTSTATUS status;
+
+ status = auth_check_password_recv(subreq, state,
+ &state->user_info_dc,
+ &state->authoritative);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static NTSTATUS auth_check_password_wrapper_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ uint8_t *pauthoritative,
+ void **server_returned_info,
+ DATA_BLOB *user_session_key,
+ DATA_BLOB *lm_session_key)
+{
+ struct auth_check_password_wrapper_state *state =
+ tevent_req_data(req,
+ struct auth_check_password_wrapper_state);
+ struct auth_user_info_dc *user_info_dc = state->user_info_dc;
+ NTSTATUS status = NT_STATUS_OK;
+
+ *pauthoritative = state->authoritative;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ talloc_steal(mem_ctx, user_info_dc);
+ *server_returned_info = user_info_dc;
+
+ if (user_session_key) {
+ DEBUG(10, ("Got NT session key of length %u\n",
+ (unsigned)user_info_dc->user_session_key.length));
+ *user_session_key = user_info_dc->user_session_key;
+ talloc_steal(mem_ctx, user_session_key->data);
+ user_info_dc->user_session_key = data_blob_null;
+ }
+
+ if (lm_session_key) {
+ DEBUG(10, ("Got LM session key of length %u\n",
+ (unsigned)user_info_dc->lm_session_key.length));
+ *lm_session_key = user_info_dc->lm_session_key;
+ talloc_steal(mem_ctx, lm_session_key->data);
+ user_info_dc->lm_session_key = data_blob_null;
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+ /* Wrapper because we don't want to expose all callers to needing to
+ * know that session_info is generated from the main ldb, and because
+ * we need to break a dependency loop between the DCE/RPC layer and the
+ * generation of unix tokens via IRPC */
+static NTSTATUS auth_generate_session_info_wrapper(struct auth4_context *auth_context,
+ TALLOC_CTX *mem_ctx,
+ void *server_returned_info,
+ const char *original_user_name,
+ uint32_t session_info_flags,
+ struct auth_session_info **session_info)
+{
+ NTSTATUS status;
+ struct auth_user_info_dc *user_info_dc = talloc_get_type_abort(server_returned_info, struct auth_user_info_dc);
+
+ if (!(user_info_dc->info->user_flags & NETLOGON_GUEST)) {
+ session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
+ }
+
+ status = auth_generate_session_info(mem_ctx,
+ auth_context->lp_ctx,
+ auth_context->sam_ctx,
+ user_info_dc,
+ session_info_flags,
+ session_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if ((session_info_flags & AUTH_SESSION_INFO_UNIX_TOKEN)
+ && NT_STATUS_IS_OK(status)) {
+ status = auth_session_info_fill_unix(auth_context->lp_ctx,
+ original_user_name,
+ *session_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(*session_info);
+ }
+ }
+ return status;
+}
+
+/* Wrapper because we don't want to expose all callers to needing to
+ * know anything about the PAC or auth subsystem internal structures
+ * before we output a struct auth session_info */
+static NTSTATUS auth_generate_session_info_pac(struct auth4_context *auth_ctx,
+ TALLOC_CTX *mem_ctx,
+ struct smb_krb5_context *smb_krb5_context,
+ DATA_BLOB *pac_blob,
+ const char *principal_name,
+ const struct tsocket_address *remote_address,
+ uint32_t session_info_flags,
+ struct auth_session_info **session_info)
+{
+ NTSTATUS status;
+ struct auth_user_info_dc *user_info_dc;
+ TALLOC_CTX *tmp_ctx;
+
+ if (!pac_blob) {
+ /*
+ * This should already have been caught at the main
+ * gensec layer, but better check twice
+ */
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ tmp_ctx = talloc_named(mem_ctx, 0, "gensec_gssapi_session_info context");
+ NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+
+ /*
+ * FIXME: To correctly create the security token, we also need to get the
+ * claims info, device info, and device claims info from the PAC. For now,
+ * we support claims only in the KDC.
+ */
+ status = kerberos_pac_blob_to_user_info_dc(tmp_ctx,
+ *pac_blob,
+ smb_krb5_context->krb5_context,
+ &user_info_dc, NULL, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(tmp_ctx);
+ return status;
+ }
+
+ if (!(user_info_dc->info->user_flags & NETLOGON_GUEST)) {
+ session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
+ }
+
+ status = auth_generate_session_info_wrapper(auth_ctx, mem_ctx,
+ user_info_dc,
+ user_info_dc->info->account_name,
+ session_info_flags, session_info);
+ talloc_free(tmp_ctx);
+ return status;
+}
+
+/***************************************************************************
+ Make a auth_info struct for the auth subsystem
+ - Allow the caller to specify the methods to use, including optionally the SAM to use
+***************************************************************************/
+_PUBLIC_ NTSTATUS auth_context_create_methods(TALLOC_CTX *mem_ctx, const char * const *methods,
+ struct tevent_context *ev,
+ struct imessaging_context *msg,
+ struct loadparm_context *lp_ctx,
+ struct ldb_context *sam_ctx,
+ struct auth4_context **auth_ctx)
+{
+ int i;
+ struct auth4_context *ctx;
+
+ auth4_init();
+
+ if (!ev) {
+ DEBUG(0,("auth_context_create: called with out event context\n"));
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ ctx = talloc_zero(mem_ctx, struct auth4_context);
+ NT_STATUS_HAVE_NO_MEMORY(ctx);
+ ctx->challenge.data = data_blob(NULL, 0);
+ ctx->methods = NULL;
+ ctx->event_ctx = ev;
+ ctx->msg_ctx = msg;
+ ctx->lp_ctx = lp_ctx;
+ ctx->start_time = timeval_current();
+
+ if (sam_ctx) {
+ ctx->sam_ctx = sam_ctx;
+ } else {
+ ctx->sam_ctx = samdb_connect(ctx,
+ ctx->event_ctx,
+ ctx->lp_ctx,
+ system_session(ctx->lp_ctx),
+ NULL,
+ 0);
+ }
+
+ for (i=0; methods && 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);
+ }
+
+ ctx->check_ntlm_password_send = auth_check_password_wrapper_send;
+ ctx->check_ntlm_password_recv = auth_check_password_wrapper_recv;
+ ctx->get_ntlm_challenge = auth_get_challenge;
+ ctx->set_ntlm_challenge = auth_context_set_challenge;
+ ctx->generate_session_info = auth_generate_session_info_wrapper;
+ ctx->generate_session_info_pac = auth_generate_session_info_pac;
+
+ *auth_ctx = ctx;
+
+ return NT_STATUS_OK;
+}
+
+const char **auth_methods_from_lp(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
+{
+ char **auth_methods = NULL;
+
+ switch (lpcfg_server_role(lp_ctx)) {
+ case ROLE_STANDALONE:
+ auth_methods = str_list_make(mem_ctx, "anonymous sam_ignoredomain", NULL);
+ break;
+ case ROLE_DOMAIN_MEMBER:
+ case ROLE_DOMAIN_BDC:
+ case ROLE_DOMAIN_PDC:
+ case ROLE_ACTIVE_DIRECTORY_DC:
+ case ROLE_IPA_DC:
+ auth_methods = str_list_make(mem_ctx, "anonymous sam winbind sam_ignoredomain", NULL);
+ break;
+ }
+ return discard_const_p(const char *, auth_methods);
+}
+
+/***************************************************************************
+ 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 tevent_context *ev,
+ struct imessaging_context *msg,
+ struct loadparm_context *lp_ctx,
+ struct auth4_context **auth_ctx)
+{
+ NTSTATUS status;
+ const char **auth_methods;
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ if (!tmp_ctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ auth_methods = auth_methods_from_lp(tmp_ctx, lp_ctx);
+ if (!auth_methods) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ status = auth_context_create_methods(mem_ctx, auth_methods, ev, msg, lp_ctx, NULL, auth_ctx);
+ talloc_free(tmp_ctx);
+ return status;
+}
+
+_PUBLIC_ NTSTATUS auth_context_create_for_netlogon(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct imessaging_context *msg,
+ struct loadparm_context *lp_ctx,
+ struct auth4_context **auth_ctx)
+{
+ NTSTATUS status;
+ char **_auth_methods = NULL;
+ const char **auth_methods = NULL;
+
+ /*
+ * Here we only allow 'sam winbind' instead of
+ * the 'anonymous sam winbind sam_ignoredomain'
+ * we typically use for authentication from clients.
+ */
+ _auth_methods = str_list_make(mem_ctx, "sam winbind", NULL);
+ if (_auth_methods == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ auth_methods = discard_const_p(const char *, _auth_methods);
+
+ status = auth_context_create_methods(mem_ctx, auth_methods, ev, msg,
+ lp_ctx, NULL, auth_ctx);
+ talloc_free(_auth_methods);
+ return status;
+}
+
+/* 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(TALLOC_CTX *mem_ctx,
+ 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(mem_ctx, backends,
+ struct auth_backend, num_backends+1);
+ NT_STATUS_HAVE_NO_MEMORY(backends);
+
+ new_ops = (struct auth_operations *)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;i<num_backends;i++) {
+ if (strcmp(backends[i].ops->name, 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 = {
+ AUTH4_INTERFACE_VERSION,
+ sizeof(struct auth_operations),
+ sizeof(struct auth_method_context),
+ sizeof(struct auth4_context),
+ sizeof(struct auth_usersupplied_info),
+ sizeof(struct auth_user_info_dc)
+ };
+
+ return &critical_sizes;
+}
+
+_PUBLIC_ NTSTATUS auth4_init(void)
+{
+ static bool initialized = false;
+#define _MODULE_PROTO(init) extern NTSTATUS init(TALLOC_CTX *);
+ STATIC_auth4_MODULES_PROTO;
+ init_module_fn static_init[] = { STATIC_auth4_MODULES };
+
+ if (initialized) return NT_STATUS_OK;
+ initialized = true;
+
+ run_init_functions(NULL, static_init);
+
+ return NT_STATUS_OK;
+}