s3-auth Hook checking passwords and generating session_info via the auth4_context
authorAndrew Bartlett <abartlet@samba.org>
Mon, 30 Jan 2012 11:11:41 +0000 (22:11 +1100)
committerStefan Metzmacher <metze@samba.org>
Fri, 17 Feb 2012 09:48:09 +0000 (10:48 +0100)
This avoids creating a second auth_context, as it is a private pointer
in the auth4_context that has already been passed in, and makes the
gensec_ntlmssp code agnostic to the type of authentication backend
behind it. This will in turn allow the ntlmssp server code to be
further merged.

Andrew Bartlett

Signed-off-by: Stefan Metzmacher <metze@samba.org>
auth/ntlmssp/ntlmssp.h
source3/auth/auth_generic.c
source3/auth/auth_ntlmssp.c
source3/auth/proto.h

index 54d3e53526a91aab035d76990eb269d416b4ed36..2fed2b1f510ca95dd26228b030fd65af0bda86d4 100644 (file)
@@ -32,9 +32,6 @@ struct gensec_security;
 struct ntlmssp_state;
 
 struct gensec_ntlmssp_context {
-       /* used only by s3 server implementation */
-       struct auth_context *auth_context;
-
        /* For GENSEC users */
        struct gensec_security *gensec_security;
        void *server_returned_info;
index ca5a2afd47fd68d2ecd32b84f954c2044518aab6..b76dcd7e8fe244412e2b7d60a42a65b45c33c477 100644 (file)
@@ -190,6 +190,12 @@ NTSTATUS auth_generic_prepare(TALLOC_CTX *mem_ctx,
                        return NT_STATUS_NO_MEMORY;
                }
                auth4_context->generate_session_info_pac = auth3_generate_session_info_pac;
+               auth4_context->generate_session_info = auth3_generate_session_info;
+               auth4_context->get_challenge = auth3_get_challenge;
+               auth4_context->set_challenge = auth3_set_challenge;
+               auth4_context->challenge_may_be_modified = auth3_may_set_challenge;
+               auth4_context->check_password = auth3_check_password;
+               auth4_context->private_data = talloc_steal(auth4_context, auth_context);
 
                lp_ctx = loadparm_init_s3(tmp_ctx, loadparm_s3_context());
                if (lp_ctx == NULL) {
index b5935e6b282783cac6c43348c4e97480d49423c1..3e809a7a2151878b3fa5cce52cd2b415aab92004 100644 (file)
@@ -4,7 +4,8 @@
    handle NLTMSSP, server side
 
    Copyright (C) Andrew Tridgell      2001
-   Copyright (C) Andrew Bartlett 2001-2003,2011
+   Copyright (C) Andrew Bartlett 2001-2005,2011
+   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
 #include "librpc/rpc/dcerpc.h"
 #include "lib/param/param.h"
 
-static NTSTATUS gensec_ntlmssp3_server_session_info(struct gensec_security *gensec_security,
-                                       TALLOC_CTX *mem_ctx,
-                                       struct auth_session_info **session_info)
+NTSTATUS auth3_generate_session_info(TALLOC_CTX *mem_ctx,
+                                    struct auth4_context *auth_context,
+                                    void *server_returned_info,
+                                    const char *original_user_name,
+                                    uint32_t session_info_flags,
+                                    struct auth_session_info **session_info)
 {
-       struct gensec_ntlmssp_context *gensec_ntlmssp =
-               talloc_get_type_abort(gensec_security->private_data,
-                                     struct gensec_ntlmssp_context);
-       struct auth_serversupplied_info *server_info = talloc_get_type_abort(gensec_ntlmssp->server_returned_info, 
+       struct auth_serversupplied_info *server_info = talloc_get_type_abort(server_returned_info,
                                                                             struct auth_serversupplied_info);
        NTSTATUS nt_status;
 
        nt_status = create_local_token(mem_ctx,
                                       server_info,
-                                      &gensec_ntlmssp->ntlmssp_state->session_key,
-                                      gensec_ntlmssp->ntlmssp_state->user,
+                                      NULL,
+                                      original_user_name,
                                       session_info);
        if (!NT_STATUS_IS_OK(nt_status)) {
                DEBUG(10, ("create_local_token failed: %s\n",
@@ -80,13 +81,12 @@ static NTSTATUS gensec_ntlmssp3_server_update(struct gensec_security *gensec_sec
  * @return an 8 byte random challenge
  */
 
-static NTSTATUS auth_ntlmssp_get_challenge(const struct ntlmssp_state *ntlmssp_state,
+NTSTATUS auth3_get_challenge(struct auth4_context *auth4_context,
                                           uint8_t chal[8])
 {
-       struct gensec_ntlmssp_context *gensec_ntlmssp =
-               (struct gensec_ntlmssp_context *)ntlmssp_state->callback_private;
-       gensec_ntlmssp->auth_context->get_ntlm_challenge(
-               gensec_ntlmssp->auth_context, chal);
+       struct auth_context *auth_context = talloc_get_type_abort(auth4_context->private_data,
+                                                                 struct auth_context);
+       auth_context->get_ntlm_challenge(auth_context, chal);
        return NT_STATUS_OK;
 }
 
@@ -95,12 +95,10 @@ static NTSTATUS auth_ntlmssp_get_challenge(const struct ntlmssp_state *ntlmssp_s
  *
  * @return If the effective challenge used by the auth subsystem may be modified
  */
-static bool auth_ntlmssp_may_set_challenge(const struct ntlmssp_state *ntlmssp_state)
+bool auth3_may_set_challenge(struct auth4_context *auth4_context)
 {
-       struct gensec_ntlmssp_context *gensec_ntlmssp =
-               (struct gensec_ntlmssp_context *)ntlmssp_state->callback_private;
-       struct auth_context *auth_context = gensec_ntlmssp->auth_context;
-
+       struct auth_context *auth_context = talloc_get_type_abort(auth4_context->private_data,
+                                                                 struct auth_context);
        return auth_context->challenge_may_be_modified;
 }
 
@@ -108,18 +106,18 @@ static bool auth_ntlmssp_may_set_challenge(const struct ntlmssp_state *ntlmssp_s
  * NTLM2 authentication modifies the effective challenge, 
  * @param challenge The new challenge value
  */
-static NTSTATUS auth_ntlmssp_set_challenge(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *challenge)
+NTSTATUS auth3_set_challenge(struct auth4_context *auth4_context, const uint8_t *chal,
+                            const char *challenge_set_by)
 {
-       struct gensec_ntlmssp_context *gensec_ntlmssp =
-               (struct gensec_ntlmssp_context *)ntlmssp_state->callback_private;
-       struct auth_context *auth_context = gensec_ntlmssp->auth_context;
-
-       SMB_ASSERT(challenge->length == 8);
+       struct auth_context *auth_context = talloc_get_type_abort(auth4_context->private_data,
+                                                                 struct auth_context);
 
        auth_context->challenge = data_blob_talloc(auth_context,
-                                                  challenge->data, challenge->length);
+                                                  chal, 8);
+       NT_STATUS_HAVE_NO_MEMORY(auth_context->challenge.data);
 
-       auth_context->challenge_set_by = "NTLMSSP callback (NTLM2)";
+       auth_context->challenge_set_by = talloc_strdup(auth_context, challenge_set_by);
+       NT_STATUS_HAVE_NO_MEMORY(auth_context->challenge_set_by);
 
        DEBUG(5, ("auth_context challenge set by %s\n", auth_context->challenge_set_by));
        DEBUG(5, ("challenge is: \n"));
@@ -133,12 +131,15 @@ static NTSTATUS auth_ntlmssp_set_challenge(struct ntlmssp_state *ntlmssp_state,
  * Return the session keys used on the connection.
  */
 
-static NTSTATUS auth_ntlmssp_check_password(struct ntlmssp_state *ntlmssp_state, TALLOC_CTX *mem_ctx,
-                                           DATA_BLOB *session_key, DATA_BLOB *lm_session_key)
+NTSTATUS auth3_check_password(struct auth4_context *auth4_context,
+                             TALLOC_CTX *mem_ctx,
+                             const struct auth_usersupplied_info *user_info,
+                             void **server_returned_info,
+                             DATA_BLOB *session_key, DATA_BLOB *lm_session_key)
 {
-       struct gensec_ntlmssp_context *gensec_ntlmssp =
-               (struct gensec_ntlmssp_context *)ntlmssp_state->callback_private;
-       struct auth_usersupplied_info *user_info = NULL;
+       struct auth_context *auth_context = talloc_get_type_abort(auth4_context->private_data,
+                                                                 struct auth_context);
+       struct auth_usersupplied_info *mapped_user_info = NULL;
        struct auth_serversupplied_info *server_info;
        NTSTATUS nt_status;
        bool username_was_mapped;
@@ -146,21 +147,21 @@ static NTSTATUS auth_ntlmssp_check_password(struct ntlmssp_state *ntlmssp_state,
        /* The client has given us its machine name (which we only get over NBT transport).
           We need to possibly reload smb.conf if smb.conf includes depend on the machine name. */
 
-       set_remote_machine_name(gensec_ntlmssp->ntlmssp_state->client.netbios_name, True);
+       set_remote_machine_name(user_info->workstation_name, True);
 
        /* setup the string used by %U */
        /* sub_set_smb_name checks for weird internally */
-       sub_set_smb_name(gensec_ntlmssp->ntlmssp_state->user);
+       sub_set_smb_name(user_info->client.account_name);
 
        lp_load(get_dyn_CONFIGFILE(), false, false, true, true);
 
-       nt_status = make_user_info_map(&user_info,
-                                      gensec_ntlmssp->ntlmssp_state->user,
-                                      gensec_ntlmssp->ntlmssp_state->domain,
-                                      gensec_ntlmssp->ntlmssp_state->client.netbios_name,
-                                      gensec_get_remote_address(gensec_ntlmssp->gensec_security),
-                                      gensec_ntlmssp->ntlmssp_state->lm_resp.data ? &gensec_ntlmssp->ntlmssp_state->lm_resp : NULL,
-                                      gensec_ntlmssp->ntlmssp_state->nt_resp.data ? &gensec_ntlmssp->ntlmssp_state->nt_resp : NULL,
+       nt_status = make_user_info_map(&mapped_user_info,
+                                      user_info->client.account_name,
+                                      user_info->client.domain_name,
+                                      user_info->workstation_name,
+                                      user_info->remote_host,
+                                      user_info->password.response.lanman.data ? &user_info->password.response.lanman : NULL,
+                                      user_info->password.response.nt.data ? &user_info->password.response.nt : NULL,
                                       NULL, NULL, NULL,
                                       AUTH_PASSWORD_RESPONSE);
 
@@ -168,21 +169,23 @@ static NTSTATUS auth_ntlmssp_check_password(struct ntlmssp_state *ntlmssp_state,
                return nt_status;
        }
 
-       user_info->logon_parameters = MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT;
+       mapped_user_info->logon_parameters = user_info->logon_parameters;
 
-       nt_status = gensec_ntlmssp->auth_context->check_ntlm_password(gensec_ntlmssp->auth_context,
-                                                                         user_info, &server_info);
+       mapped_user_info->flags = user_info->flags;
 
-       username_was_mapped = user_info->was_mapped;
+       nt_status = auth_context->check_ntlm_password(auth_context,
+                                                     mapped_user_info, &server_info);
 
-       free_user_info(&user_info);
+       username_was_mapped = mapped_user_info->was_mapped;
+
+       free_user_info(&mapped_user_info);
 
        if (!NT_STATUS_IS_OK(nt_status)) {
                nt_status = do_map_to_guest_server_info(nt_status,
                                                        &server_info,
-                                                       gensec_ntlmssp->ntlmssp_state->user,
-                                                       gensec_ntlmssp->ntlmssp_state->domain);
-               gensec_ntlmssp->server_returned_info = server_info;
+                                                       user_info->client.account_name,
+                                                       user_info->client.domain_name);
+               *server_returned_info = talloc_steal(mem_ctx, server_info);
                return nt_status;
        }
 
@@ -192,21 +195,194 @@ static NTSTATUS auth_ntlmssp_check_password(struct ntlmssp_state *ntlmssp_state,
         * They will not be used in this form again - instead the
         * NTLMSSP code will decide on the final correct session key,
         * and supply it to create_local_token() */
-       if (server_info->session_key.length) {
+       if (session_key) {
                DEBUG(10, ("Got NT session key of length %u\n",
                        (unsigned int)server_info->session_key.length));
                *session_key = server_info->session_key;
                talloc_steal(mem_ctx, server_info->session_key.data);
                server_info->session_key = data_blob_null;
        }
-       if (server_info->lm_session_key.length) {
+       if (lm_session_key) {
                DEBUG(10, ("Got LM session key of length %u\n",
                        (unsigned int)server_info->lm_session_key.length));
                *lm_session_key = server_info->lm_session_key;
                talloc_steal(mem_ctx, server_info->lm_session_key.data);
                server_info->lm_session_key = data_blob_null;
        }
-       gensec_ntlmssp->server_returned_info = server_info;
+
+       *server_returned_info = talloc_steal(mem_ctx, server_info);
+       return nt_status;
+}
+
+/**
+ * Return the challenge as determined by the authentication subsystem
+ * @return an 8 byte random challenge
+ */
+
+static NTSTATUS auth_ntlmssp_get_challenge(const struct ntlmssp_state *ntlmssp_state,
+                                          uint8_t chal[8])
+{
+       struct gensec_ntlmssp_context *gensec_ntlmssp =
+               talloc_get_type_abort(ntlmssp_state->callback_private,
+                                     struct gensec_ntlmssp_context);
+       struct auth4_context *auth_context = gensec_ntlmssp->gensec_security->auth_context;
+       NTSTATUS status = NT_STATUS_NOT_IMPLEMENTED;
+
+       if (auth_context->get_challenge) {
+               status = auth_context->get_challenge(auth_context, chal);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(1, ("auth_ntlmssp_get_challenge: failed to get challenge: %s\n",
+                                 nt_errstr(status)));
+                       return status;
+               }
+       }
+
+       return status;
+}
+
+/**
+ * Some authentication methods 'fix' the challenge, so we may not be able to set it
+ *
+ * @return If the effective challenge used by the auth subsystem may be modified
+ */
+static bool auth_ntlmssp_may_set_challenge(const struct ntlmssp_state *ntlmssp_state)
+{
+       struct gensec_ntlmssp_context *gensec_ntlmssp =
+               talloc_get_type_abort(ntlmssp_state->callback_private,
+                                     struct gensec_ntlmssp_context);
+       struct auth4_context *auth_context = gensec_ntlmssp->gensec_security->auth_context;
+
+       if (auth_context->challenge_may_be_modified) {
+               return auth_context->challenge_may_be_modified(auth_context);
+       }
+       return false;
+}
+
+/**
+ * NTLM2 authentication modifies the effective challenge,
+ * @param challenge The new challenge value
+ */
+static NTSTATUS auth_ntlmssp_set_challenge(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *challenge)
+{
+       struct gensec_ntlmssp_context *gensec_ntlmssp =
+               talloc_get_type_abort(ntlmssp_state->callback_private,
+                                     struct gensec_ntlmssp_context);
+       struct auth4_context *auth_context = gensec_ntlmssp->gensec_security->auth_context;
+       NTSTATUS nt_status = NT_STATUS_NOT_IMPLEMENTED;
+       const uint8_t *chal;
+
+       if (challenge->length != 8) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       chal = challenge->data;
+
+       if (auth_context->set_challenge) {
+               nt_status = auth_context->set_challenge(auth_context,
+                                                       chal,
+                                                       "NTLMSSP callback (NTLM2)");
+       }
+       return nt_status;
+}
+
+/**
+ * Check the password on an NTLMSSP login.
+ *
+ * Return the session keys used on the connection.
+ */
+
+static NTSTATUS auth_ntlmssp_check_password(struct ntlmssp_state *ntlmssp_state,
+                                           TALLOC_CTX *mem_ctx,
+                                           DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key)
+{
+       struct gensec_ntlmssp_context *gensec_ntlmssp =
+               talloc_get_type_abort(ntlmssp_state->callback_private,
+                                     struct gensec_ntlmssp_context);
+       struct auth4_context *auth_context = gensec_ntlmssp->gensec_security->auth_context;
+       NTSTATUS nt_status = NT_STATUS_NOT_IMPLEMENTED;
+       struct auth_usersupplied_info *user_info;
+
+       user_info = talloc_zero(ntlmssp_state, struct auth_usersupplied_info);
+       if (!user_info) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       user_info->logon_parameters = MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT;
+       user_info->flags = 0;
+       user_info->mapped_state = false;
+       user_info->client.account_name = ntlmssp_state->user;
+       user_info->client.domain_name = ntlmssp_state->domain;
+       user_info->workstation_name = ntlmssp_state->client.netbios_name;
+       user_info->remote_host = gensec_get_remote_address(gensec_ntlmssp->gensec_security);
+
+       user_info->password_state = AUTH_PASSWORD_RESPONSE;
+       user_info->password.response.lanman = ntlmssp_state->lm_resp;
+       user_info->password.response.lanman.data = talloc_steal(user_info, ntlmssp_state->lm_resp.data);
+       user_info->password.response.nt = ntlmssp_state->nt_resp;
+       user_info->password.response.nt.data = talloc_steal(user_info, ntlmssp_state->nt_resp.data);
+
+       if (auth_context->check_password) {
+               nt_status = auth_context->check_password(auth_context,
+                                                        gensec_ntlmssp,
+                                                        user_info,
+                                                        &gensec_ntlmssp->server_returned_info,
+                                                        user_session_key, lm_session_key);
+       }
+       talloc_free(user_info);
+       NT_STATUS_NOT_OK_RETURN(nt_status);
+
+       talloc_steal(mem_ctx, user_session_key->data);
+       talloc_steal(mem_ctx, lm_session_key->data);
+
+       return nt_status;
+}
+
+/**
+ * Return the credentials of a logged on user, including session keys
+ * etc.
+ *
+ * Only valid after a successful authentication
+ *
+ * May only be called once per authentication.
+ *
+ */
+
+static NTSTATUS gensec_ntlmssp3_server_session_info(struct gensec_security *gensec_security,
+                                                   TALLOC_CTX *mem_ctx,
+                                                   struct auth_session_info **session_info)
+{
+       NTSTATUS nt_status;
+       struct gensec_ntlmssp_context *gensec_ntlmssp =
+               talloc_get_type_abort(gensec_security->private_data,
+                                     struct gensec_ntlmssp_context);
+       uint32_t session_info_flags = 0;
+
+       if (gensec_security->want_features & GENSEC_FEATURE_UNIX_TOKEN) {
+               session_info_flags |= AUTH_SESSION_INFO_UNIX_TOKEN;
+       }
+
+       session_info_flags |= AUTH_SESSION_INFO_DEFAULT_GROUPS;
+
+       if (gensec_security->auth_context && gensec_security->auth_context->generate_session_info) {
+               nt_status = gensec_security->auth_context->generate_session_info(mem_ctx, gensec_security->auth_context,
+                                                                                gensec_ntlmssp->server_returned_info,
+                                                                                gensec_ntlmssp->ntlmssp_state->user,
+                                                                                session_info_flags,
+                                                                                session_info);
+       } else {
+               DEBUG(0, ("Cannot generate a session_info without the auth_context\n"));
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+
+       NT_STATUS_NOT_OK_RETURN(nt_status);
+
+       nt_status = gensec_ntlmssp_session_key(gensec_security, *session_info,
+                                         &(*session_info)->session_key);
+
+       if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_USER_SESSION_KEY)) {
+               (*session_info)->session_key = data_blob_null;
+               nt_status = NT_STATUS_OK;
+       }
        return nt_status;
 }
 
@@ -242,11 +418,6 @@ static NTSTATUS gensec_ntlmssp3_server_start(struct gensec_security *gensec_secu
                talloc_get_type_abort(gensec_security->private_data,
                                      struct gensec_ntlmssp_context);
 
-       nt_status = make_auth_context_subsystem(gensec_ntlmssp, &gensec_ntlmssp->auth_context);
-       if (!NT_STATUS_IS_OK(nt_status)) {
-               return nt_status;
-       }
-
        nt_status = ntlmssp_server_start(gensec_ntlmssp,
                                         is_standalone,
                                         netbios_name,
index 82d6018556c5205da4ee4b5247be59f3f96172e8..bb25fedce6e4a4e388b3670676095cca2a92d30d 100644 (file)
@@ -67,11 +67,33 @@ NTSTATUS auth_domain_init(void);
 
 NTSTATUS auth_netlogond_init(void);
 
-/* The following definitions come from auth/auth_ntlmssp.c  */
+/* The following definitions come from auth/auth_generic.c  */
 
 NTSTATUS auth_generic_prepare(TALLOC_CTX *mem_ctx, const struct tsocket_address *remote_address,
                              struct gensec_security **gensec_security_out);
 
+/* The following definitions come from auth/auth_ntlmssp.c  */
+
+NTSTATUS auth3_generate_session_info(TALLOC_CTX *mem_ctx,
+                                    struct auth4_context *auth_context,
+                                    void *server_returned_info,
+                                    const char *original_user_name,
+                                    uint32_t session_info_flags,
+                                    struct auth_session_info **session_info);
+
+NTSTATUS auth3_get_challenge(struct auth4_context *auth4_context,
+                            uint8_t chal[8]);
+
+bool auth3_may_set_challenge(struct auth4_context *auth4_context);
+NTSTATUS auth3_set_challenge(struct auth4_context *auth4_context, const uint8_t *chal,
+                            const char *challenge_set_by);
+
+NTSTATUS auth3_check_password(struct auth4_context *auth4_context,
+                             TALLOC_CTX *mem_ctx,
+                             const struct auth_usersupplied_info *user_info,
+                             void **server_returned_info,
+                             DATA_BLOB *session_key, DATA_BLOB *lm_session_key);
+
 /* The following definitions come from auth/auth_sam.c  */
 
 NTSTATUS check_sam_security(const DATA_BLOB *challenge,
@@ -320,4 +342,5 @@ NTSTATUS make_session_info_krb5(TALLOC_CTX *mem_ctx,
                                DATA_BLOB *session_key,
                                struct auth_session_info **session_info);
 
+
 #endif /* _AUTH_PROTO_H_ */