s3-auth: Fix a possible null pointer dereference
[kai/samba.git] / source3 / auth / auth_ntlmssp.c
index 61029bc95d8cb540256e2e93951d479b5ae6f797..a0e49027af999f92dac1fcd68fc27c42ee754871 100644 (file)
@@ -4,7 +4,8 @@
    handle NLTMSSP, server side
 
    Copyright (C) Andrew Tridgell      2001
-   Copyright (C) Andrew Bartlett 2001-2003
+   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 "includes.h"
 #include "auth.h"
-#include "../libcli/auth/ntlmssp.h"
-#include "ntlmssp_wrap.h"
-#include "../librpc/gen_ndr/netlogon.h"
-#include "../lib/tsocket/tsocket.h"
-
-NTSTATUS auth_ntlmssp_steal_session_info(TALLOC_CTX *mem_ctx,
-                                       struct auth_ntlmssp_state *auth_ntlmssp_state,
-                                       struct auth_session_info **session_info)
+#include "libcli/security/security.h"
+
+NTSTATUS auth3_generate_session_info(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 nt_status = create_local_token(mem_ctx,
-                                               auth_ntlmssp_state->server_info,
-                                               &auth_ntlmssp_state->ntlmssp_state->session_key,
-                                               session_info);
+       struct auth_user_info_dc *user_info = NULL;
+       struct auth_serversupplied_info *server_info = NULL;
+       NTSTATUS nt_status;
+
+       /*
+        * This is a hack, some callers...
+        *
+        * Some callers pass auth_user_info_dc, the SCHANNEL and
+        * NCALRPC_AS_SYSTEM gensec modules.
+        *
+        * While the reset passes auth3_check_password() returned.
+        */
+       user_info = talloc_get_type(server_returned_info,
+                                   struct auth_user_info_dc);
+       if (user_info != NULL) {
+               const struct dom_sid *sid;
+               int cmp;
+
+               /*
+                * This should only be called from SCHANNEL or NCALRPC_AS_SYSTEM
+                */
+               if (user_info->num_sids != 1) {
+                       return NT_STATUS_INTERNAL_ERROR;
+               }
+               sid = &user_info->sids[PRIMARY_USER_SID_INDEX];
+
+               cmp = dom_sid_compare(sid, &global_sid_System);
+               if (cmp == 0) {
+                       return make_session_info_system(mem_ctx, session_info);
+               }
+
+               cmp = dom_sid_compare(sid, &global_sid_Anonymous);
+               if (cmp == 0) {
+                       /*
+                        * TODO: use auth_anonymous_session_info() here?
+                        */
+                       return make_session_info_guest(mem_ctx, session_info);
+               }
+
+               return NT_STATUS_INTERNAL_ERROR;
+       }
 
+       server_info = talloc_get_type_abort(server_returned_info,
+                                           struct auth_serversupplied_info);
+       nt_status = create_local_token(mem_ctx,
+                                      server_info,
+                                      NULL,
+                                      original_user_name,
+                                      session_info);
        if (!NT_STATUS_IS_OK(nt_status)) {
                DEBUG(10, ("create_local_token failed: %s\n",
                           nt_errstr(nt_status)));
+               return nt_status;
        }
-       return nt_status;
+
+       return NT_STATUS_OK;
 }
 
 /**
@@ -48,46 +95,31 @@ NTSTATUS auth_ntlmssp_steal_session_info(TALLOC_CTX *mem_ctx,
  * @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 auth_ntlmssp_state *auth_ntlmssp_state =
-               (struct auth_ntlmssp_state *)ntlmssp_state->callback_private;
-       auth_ntlmssp_state->auth_context->get_ntlm_challenge(
-               auth_ntlmssp_state->auth_context, chal);
+       struct auth_context *auth_context = talloc_get_type_abort(auth4_context->private_data,
+                                                                 struct auth_context);
+       auth_get_ntlm_challenge(auth_context, chal);
        return NT_STATUS_OK;
 }
 
-/**
- * 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 auth_ntlmssp_state *auth_ntlmssp_state =
-               (struct auth_ntlmssp_state *)ntlmssp_state->callback_private;
-       struct auth_context *auth_context = auth_ntlmssp_state->auth_context;
-
-       return auth_context->challenge_may_be_modified;
-}
-
 /**
  * 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 auth_ntlmssp_state *auth_ntlmssp_state =
-               (struct auth_ntlmssp_state *)ntlmssp_state->callback_private;
-       struct auth_context *auth_context = auth_ntlmssp_state->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"));
@@ -101,33 +133,38 @@ 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 auth_ntlmssp_state *auth_ntlmssp_state =
-               (struct auth_ntlmssp_state *)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;
 
-       /* the client has given us its machine name (which we otherwise would not get on port 445).
-          we need to possibly reload smb.conf if smb.conf includes depend on the machine name */
+       /* 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(auth_ntlmssp_state->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(auth_ntlmssp_state->ntlmssp_state->user);
-
-       lp_load(get_dyn_CONFIGFILE(), false, false, true, true);
-
-       nt_status = make_user_info_map(&user_info,
-                                      auth_ntlmssp_state->ntlmssp_state->user, 
-                                      auth_ntlmssp_state->ntlmssp_state->domain, 
-                                      auth_ntlmssp_state->ntlmssp_state->client.netbios_name,
-                                      auth_ntlmssp_state->remote_address,
-                                      auth_ntlmssp_state->ntlmssp_state->lm_resp.data ? &auth_ntlmssp_state->ntlmssp_state->lm_resp : NULL, 
-                                      auth_ntlmssp_state->ntlmssp_state->nt_resp.data ? &auth_ntlmssp_state->ntlmssp_state->nt_resp : NULL, 
+       sub_set_smb_name(user_info->client.account_name);
+
+       lp_load_with_shares(get_dyn_CONFIGFILE());
+
+       nt_status = make_user_info_map(talloc_tos(),
+                                       &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);
 
@@ -135,121 +172,59 @@ 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 = auth_ntlmssp_state->auth_context->check_ntlm_password(auth_ntlmssp_state->auth_context, 
-                                                                         user_info, &auth_ntlmssp_state->server_info); 
+       mapped_user_info->flags = user_info->flags;
 
-       username_was_mapped = user_info->was_mapped;
+       nt_status = auth_check_ntlm_password(mem_ctx,
+                                            auth_context,
+                                            mapped_user_info,
+                                            &server_info);
+
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               DEBUG(5,("Checking NTLMSSP password for %s\\%s failed: %s\n",
+                        user_info->client.domain_name,
+                        user_info->client.account_name,
+                        nt_errstr(nt_status)));
+       }
 
-       free_user_info(&user_info);
+       username_was_mapped = mapped_user_info->was_mapped;
+
+       TALLOC_FREE(mapped_user_info);
 
        if (!NT_STATUS_IS_OK(nt_status)) {
+               nt_status = do_map_to_guest_server_info(mem_ctx,
+                                                       nt_status,
+                                                       user_info->client.account_name,
+                                                       user_info->client.domain_name,
+                                                       &server_info);
+               if (NT_STATUS_IS_OK(nt_status)) {
+                       *server_returned_info = talloc_steal(mem_ctx, server_info);
+               }
                return nt_status;
        }
 
-       auth_ntlmssp_state->server_info->nss_token |= username_was_mapped;
+       server_info->nss_token |= username_was_mapped;
 
        /* Clear out the session keys, and pass them to the caller.
         * They will not be used in this form again - instead the
         * NTLMSSP code will decide on the final correct session key,
-        * and put it back here at the end of
-        * auth_ntlmssp_steal_server_info */
-       if (auth_ntlmssp_state->server_info->session_key.length) {
+        * and supply it to create_local_token() */
+       if (session_key) {
                DEBUG(10, ("Got NT session key of length %u\n",
-                       (unsigned int)auth_ntlmssp_state->server_info->session_key.length));
-               *session_key = auth_ntlmssp_state->server_info->session_key;
-               talloc_steal(mem_ctx, auth_ntlmssp_state->server_info->session_key.data);
-               auth_ntlmssp_state->server_info->session_key = data_blob_null;
+                       (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 (auth_ntlmssp_state->server_info->lm_session_key.length) {
+       if (lm_session_key) {
                DEBUG(10, ("Got LM session key of length %u\n",
-                       (unsigned int)auth_ntlmssp_state->server_info->lm_session_key.length));
-               *lm_session_key = auth_ntlmssp_state->server_info->lm_session_key;
-               talloc_steal(mem_ctx, auth_ntlmssp_state->server_info->lm_session_key.data);
-               auth_ntlmssp_state->server_info->lm_session_key = data_blob_null;
+                       (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;
        }
-       return nt_status;
-}
 
-static int auth_ntlmssp_state_destructor(void *ptr);
-
-NTSTATUS auth_ntlmssp_start(const struct tsocket_address *remote_address,
-                           struct auth_ntlmssp_state **auth_ntlmssp_state)
-{
-       NTSTATUS nt_status;
-       bool is_standalone;
-       const char *netbios_name;
-       const char *netbios_domain;
-       const char *dns_name;
-       char *dns_domain;
-       struct auth_ntlmssp_state *ans;
-       struct auth_context *auth_context;
-
-       if ((enum server_role)lp_server_role() == ROLE_STANDALONE) {
-               is_standalone = true;
-       } else {
-               is_standalone = false;
-       }
-
-       netbios_name = lp_netbios_name();
-       netbios_domain = lp_workgroup();
-       /* This should be a 'netbios domain -> DNS domain' mapping */
-       dns_domain = get_mydnsdomname(talloc_tos());
-       if (dns_domain) {
-               strlower_m(dns_domain);
-       }
-       dns_name = get_mydnsfullname();
-
-       ans = talloc_zero(NULL, struct auth_ntlmssp_state);
-       if (!ans) {
-               DEBUG(0,("auth_ntlmssp_start: talloc failed!\n"));
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       ans->remote_address = tsocket_address_copy(remote_address, ans);
-       if (ans->remote_address == NULL) {
-               DEBUG(0,("auth_ntlmssp_start: talloc failed!\n"));
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       nt_status = ntlmssp_server_start(ans,
-                                        is_standalone,
-                                        netbios_name,
-                                        netbios_domain,
-                                        dns_name,
-                                        dns_domain,
-                                        &ans->ntlmssp_state);
-       if (!NT_STATUS_IS_OK(nt_status)) {
-               return nt_status;
-       }
-
-       nt_status = make_auth_context_subsystem(talloc_tos(), &auth_context);
-       if (!NT_STATUS_IS_OK(nt_status)) {
-               return nt_status;
-       }
-       ans->auth_context = talloc_steal(ans, auth_context);
-
-       ans->ntlmssp_state->callback_private = ans;
-       ans->ntlmssp_state->get_challenge = auth_ntlmssp_get_challenge;
-       ans->ntlmssp_state->may_set_challenge = auth_ntlmssp_may_set_challenge;
-       ans->ntlmssp_state->set_challenge = auth_ntlmssp_set_challenge;
-       ans->ntlmssp_state->check_password = auth_ntlmssp_check_password;
-
-       talloc_set_destructor((TALLOC_CTX *)ans, auth_ntlmssp_state_destructor);
-
-       *auth_ntlmssp_state = ans;
-       return NT_STATUS_OK;
-}
-
-static int auth_ntlmssp_state_destructor(void *ptr)
-{
-       struct auth_ntlmssp_state *ans;
-
-       ans = talloc_get_type(ptr, struct auth_ntlmssp_state);
-
-       TALLOC_FREE(ans->remote_address);
-       TALLOC_FREE(ans->server_info);
-       TALLOC_FREE(ans->ntlmssp_state);
-       return 0;
+       *server_returned_info = talloc_steal(mem_ctx, server_info);
+       return nt_status;
 }