s3: Fix "force group" with ntlmssp guest session setup
[samba.git] / source3 / auth / auth_ntlmssp.c
index f165322f7ae3de6d15d97654f3962b0af4e24793..0e2c61af17b4b4f0eaa6607c6f5bd87dfa4b3f67 100644 (file)
@@ -8,7 +8,7 @@
 
    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 2 of the License, or
+   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,
    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, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
 
-NTSTATUS ntlmssp_server_start(NTLMSSP_STATE **ntlmssp_state)
-{
-       NTSTATUS nt_status;
-       TALLOC_CTX *mem_ctx;
-
-       mem_ctx = talloc_init("NTLMSSP context");
-       
-       *ntlmssp_state = talloc_zero(mem_ctx, sizeof(**ntlmssp_state));
-       if (!*ntlmssp_state) {
-               DEBUG(0,("ntlmssp_start: talloc failed!\n"));
-               talloc_destroy(mem_ctx);
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       ZERO_STRUCTP(*ntlmssp_state);
+/**
+ * Return the challenge as determined by the authentication subsystem 
+ * @return an 8 byte random challenge
+ */
 
-       (*ntlmssp_state)->mem_ctx = mem_ctx;
-
-       if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&(*ntlmssp_state)->auth_context))) {
-               return nt_status;
-       }
-       return NT_STATUS_OK;
-}
-
-NTSTATUS ntlmssp_server_end(NTLMSSP_STATE **ntlmssp_state)
+static void auth_ntlmssp_get_challenge(const struct ntlmssp_state *ntlmssp_state,
+                                      uint8_t chal[8])
 {
-       TALLOC_CTX *mem_ctx = (*ntlmssp_state)->mem_ctx;
-       if ((*ntlmssp_state)->auth_context) {
-               ((*ntlmssp_state)->auth_context->free)(&(*ntlmssp_state)->auth_context);
-       }
-       if ((*ntlmssp_state)->server_info) {
-               free_server_info(&(*ntlmssp_state)->server_info);
-       }
-
-       talloc_destroy(mem_ctx);
-       *ntlmssp_state = NULL;
-       return NT_STATUS_OK;
+       AUTH_NTLMSSP_STATE *auth_ntlmssp_state =
+               (AUTH_NTLMSSP_STATE *)ntlmssp_state->auth_context;
+       auth_ntlmssp_state->auth_context->get_ntlm_challenge(
+               auth_ntlmssp_state->auth_context, chal);
 }
 
-NTSTATUS ntlmssp_server_update(NTLMSSP_STATE *ntlmssp_state, 
-                              DATA_BLOB request, DATA_BLOB *reply) 
+/**
+ * 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)
 {
-       uint32 ntlmssp_command;
-               
-       if (!msrpc_parse(&request, "Cd",
-                        "NTLMSSP",
-                        &ntlmssp_command)) {
-               return NT_STATUS_LOGON_FAILURE;
-       }
+       AUTH_NTLMSSP_STATE *auth_ntlmssp_state =
+               (AUTH_NTLMSSP_STATE *)ntlmssp_state->auth_context;
+       struct auth_context *auth_context = auth_ntlmssp_state->auth_context;
 
-       if (ntlmssp_command == NTLMSSP_NEGOTIATE) {
-               return ntlmssp_negotiate(ntlmssp_state, request, reply);
-       } else if (ntlmssp_command == NTLMSSP_AUTH) {
-               return ntlmssp_auth(ntlmssp_state, request, reply);
-       } else {
-               return NT_STATUS_LOGON_FAILURE;
-       }
+       return auth_context->challenge_may_be_modified;
 }
 
-static const char *ntlmssp_target_name(uint32 neg_flags, uint32 *chal_flags) 
+/**
+ * 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)
 {
-       if (neg_flags & NTLMSSP_REQUEST_TARGET) {
-               if (lp_server_role() == ROLE_STANDALONE) {
-                       *chal_flags |= NTLMSSP_TARGET_TYPE_SERVER;
-                       return global_myname();
-               } else {
-                       *chal_flags |= NTLMSSP_TARGET_TYPE_DOMAIN;
-                       return lp_workgroup();
-               };
-       } else {
-               return "";
-       }
-}
-
-NTSTATUS ntlmssp_negotiate(NTLMSSP_STATE *ntlmssp_state, 
-                          DATA_BLOB request, DATA_BLOB *reply) 
-{
-       DATA_BLOB struct_blob;
-       fstring dnsname, dnsdomname;
-       uint32 ntlmssp_command, neg_flags, chal_flags;
-       char *cliname=NULL, *domname=NULL;
-       const uint8 *cryptkey;
-       const char *target_name;
-
-       /* parse the NTLMSSP packet */
-#if 0
-       file_save("ntlmssp_negotiate.dat", request.data, request.length);
-#endif
-
-       if (!msrpc_parse(&request, "CddAA",
-                        "NTLMSSP",
-                        &ntlmssp_command,
-                        &neg_flags,
-                        &cliname,
-                        &domname)) {
-               return NT_STATUS_LOGON_FAILURE;
-       }
+       AUTH_NTLMSSP_STATE *auth_ntlmssp_state =
+               (AUTH_NTLMSSP_STATE *)ntlmssp_state->auth_context;
+       struct auth_context *auth_context = auth_ntlmssp_state->auth_context;
 
-       SAFE_FREE(cliname);
-       SAFE_FREE(domname);
-  
-       debug_ntlmssp_flags(neg_flags);
+       SMB_ASSERT(challenge->length == 8);
 
-       cryptkey = ntlmssp_state->auth_context->get_ntlm_challenge(ntlmssp_state->auth_context);
+       auth_context->challenge = data_blob_talloc(auth_context->mem_ctx, 
+                                                  challenge->data, challenge->length);
 
-       /* Give them the challenge. For now, ignore neg_flags and just
-          return the flags we want. Obviously this is not correct */
-       
-       chal_flags = 
-               NTLMSSP_NEGOTIATE_128 | 
-               NTLMSSP_NEGOTIATE_NTLM |
-               NTLMSSP_CHAL_TARGET_INFO;
-       
-       if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE) {
-               chal_flags |= NTLMSSP_NEGOTIATE_UNICODE;
-               ntlmssp_state->unicode = True;
-       } else {
-               chal_flags |= NTLMSSP_NEGOTIATE_OEM;
-       }
-
-       target_name = ntlmssp_target_name(neg_flags, &chal_flags); 
-
-       dnsdomname[0] = '\0';
-       get_mydomname(dnsdomname);
-       strlower(dnsdomname);
-       
-       dnsname[0] = '\0';
-       get_myfullname(dnsname);
-       strlower(dnsname);
-       
-       /* the numbers here are the string type flags */
-       msrpc_gen(&struct_blob, "aaaaa",
-                 ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_DOMAIN, lp_workgroup(),
-                 ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_SERVER, global_myname(),
-                 ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_DOMAIN_DNS, dnsname,
-                 ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_SERVER_DNS, dnsdomname,
-                 ntlmssp_state->unicode, 0, "");
-
-       {
-               const char *gen_string;
-               if (ntlmssp_state->unicode) {
-                       gen_string = "CdUdbddB";
-               } else {
-                       gen_string = "CdAdbddB";
-               }
-               
-               msrpc_gen(reply, gen_string,
-                         "NTLMSSP", 
-                         NTLMSSP_CHALLENGE,
-                         target_name,
-                         chal_flags,
-                         cryptkey, 8,
-                         0, 0,
-                         struct_blob.data, struct_blob.length);
-       }
-               
-       data_blob_free(&struct_blob);
+       auth_context->challenge_set_by = "NTLMSSP callback (NTLM2)";
 
-       return NT_STATUS_MORE_PROCESSING_REQUIRED;
+       DEBUG(5, ("auth_context challenge set by %s\n", auth_context->challenge_set_by));
+       DEBUG(5, ("challenge is: \n"));
+       dump_data(5, auth_context->challenge.data, auth_context->challenge.length);
+       return NT_STATUS_OK;
 }
 
-NTSTATUS ntlmssp_auth(NTLMSSP_STATE *ntlmssp_state, 
-                     DATA_BLOB request, DATA_BLOB *reply) 
+/**
+ * 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, DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key) 
 {
-       char *workgroup = NULL, *user = NULL, *machine = NULL;
-       DATA_BLOB lmhash, nthash, sess_key;
-       DATA_BLOB plaintext_password = data_blob(NULL, 0);
-       uint32 ntlmssp_command, neg_flags;
-       NTSTATUS nt_status;
-       uint32 auth_flags = AUTH_FLAG_NONE;
+       AUTH_NTLMSSP_STATE *auth_ntlmssp_state =
+               (AUTH_NTLMSSP_STATE *)ntlmssp_state->auth_context;
        auth_usersupplied_info *user_info = NULL;
+       NTSTATUS nt_status;
+       bool username_was_mapped;
 
-       const char *parse_string;
+       /* 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 */
 
-       /* parse the NTLMSSP packet */
-#if 0
-       file_save("ntlmssp_auth.dat", request.data, request.length);
-#endif
+       set_remote_machine_name(auth_ntlmssp_state->ntlmssp_state->workstation, True);
 
-       if (ntlmssp_state->unicode) {
-               parse_string = "CdBBUUUBd";
-       } else {
-               parse_string = "CdBBAAABd";
-       }
+       /* setup the string used by %U */
+       /* sub_set_smb_name checks for weird internally */
+       sub_set_smb_name(auth_ntlmssp_state->ntlmssp_state->user);
+
+       reload_services(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->workstation, 
+                                      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, 
+                                      NULL, NULL, NULL,
+                                      True);
+
+       user_info->logon_parameters = MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT;
 
-       /* now the NTLMSSP encoded auth hashes */
-       if (!msrpc_parse(&request, parse_string,
-                        "NTLMSSP", 
-                        &ntlmssp_command, 
-                        &lmhash,
-                        &nthash,
-                        &workgroup, 
-                        &user, 
-                        &machine,
-                        &sess_key,
-                        &neg_flags)) {
-               return NT_STATUS_LOGON_FAILURE;
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               return nt_status;
        }
 
-       data_blob_free(&sess_key);
-       
-       DEBUG(3,("Got user=[%s] workgroup=[%s] machine=[%s] len1=%d len2=%d\n",
-                user, workgroup, machine, lmhash.length, nthash.length));
+       nt_status = auth_ntlmssp_state->auth_context->check_ntlm_password(auth_ntlmssp_state->auth_context, 
+                                                                         user_info, &auth_ntlmssp_state->server_info); 
 
-       /* 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 */
+       username_was_mapped = user_info->was_mapped;
 
-       set_remote_machine_name(machine);
+       free_user_info(&user_info);
 
-       /* setup the string used by %U */
-       sub_set_smb_name(user);
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               return nt_status;
+       }
 
-       reload_services(True);
+       auth_ntlmssp_state->server_info->nss_token |= username_was_mapped;
 
-#if 0
-       file_save("nthash1.dat", nthash.data, nthash.length);
-       file_save("lmhash1.dat", lmhash.data, lmhash.length);
-#endif
+       if (auth_ntlmssp_state->server_info->ptok == NULL) {
+               nt_status = create_local_token(auth_ntlmssp_state->server_info);
+               if (!NT_STATUS_IS_OK(nt_status)) {
+                       DEBUG(10, ("create_local_token failed: %s\n",
+                                  nt_errstr(nt_status)));
+                       return nt_status;
+               }
+       }
 
-       if (lmhash.length) {
-               auth_flags |= AUTH_FLAG_LM_RESP;
+       if (auth_ntlmssp_state->server_info->user_session_key.length) {
+               DEBUG(10, ("Got NT session key of length %u\n",
+                       (unsigned int)auth_ntlmssp_state->server_info->user_session_key.length));
+               *user_session_key = data_blob_talloc(auth_ntlmssp_state->mem_ctx, 
+                                                  auth_ntlmssp_state->server_info->user_session_key.data,
+                                                  auth_ntlmssp_state->server_info->user_session_key.length);
+       }
+       if (auth_ntlmssp_state->server_info->lm_session_key.length) {
+               DEBUG(10, ("Got LM session key of length %u\n",
+                       (unsigned int)auth_ntlmssp_state->server_info->lm_session_key.length));
+               *lm_session_key = data_blob_talloc(auth_ntlmssp_state->mem_ctx, 
+                                                  auth_ntlmssp_state->server_info->lm_session_key.data,
+                                                  auth_ntlmssp_state->server_info->lm_session_key.length);
        }
+       return nt_status;
+}
 
-       if (nthash.length == 24) {
-               auth_flags |= AUTH_FLAG_NTLM_RESP;
-       } else if (nthash.length > 24) {
-               auth_flags |= AUTH_FLAG_NTLMv2_RESP;
-       };
+NTSTATUS auth_ntlmssp_start(AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
+{
+       NTSTATUS nt_status;
+       TALLOC_CTX *mem_ctx;
 
+       mem_ctx = talloc_init("AUTH NTLMSSP context");
        
+       *auth_ntlmssp_state = TALLOC_ZERO_P(mem_ctx, AUTH_NTLMSSP_STATE);
+       if (!*auth_ntlmssp_state) {
+               DEBUG(0,("auth_ntlmssp_start: talloc failed!\n"));
+               talloc_destroy(mem_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
 
-       nt_status = make_user_info_map(&user_info, user, workgroup, machine, 
-                                      lmhash, nthash, plaintext_password, 
-                                      auth_flags, True);
+       ZERO_STRUCTP(*auth_ntlmssp_state);
 
-       ntlmssp_state->orig_user = talloc_strdup(ntlmssp_state->mem_ctx, user);
-       ntlmssp_state->orig_domain = talloc_strdup(ntlmssp_state->mem_ctx, workgroup);
+       (*auth_ntlmssp_state)->mem_ctx = mem_ctx;
 
-       SAFE_FREE(user);
-       SAFE_FREE(workgroup);
-       SAFE_FREE(machine);
+       if (!NT_STATUS_IS_OK(nt_status = ntlmssp_server_start(&(*auth_ntlmssp_state)->ntlmssp_state))) {
+               return nt_status;
+       }
 
-       if (!NT_STATUS_IS_OK(nt_status)) {
+       if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&(*auth_ntlmssp_state)->auth_context))) {
                return nt_status;
        }
 
-       nt_status = ntlmssp_state->auth_context->check_ntlm_password(ntlmssp_state->auth_context, user_info, &ntlmssp_state->server_info); 
-                       
-       (ntlmssp_state->auth_context->free)(&ntlmssp_state->auth_context);
+       (*auth_ntlmssp_state)->ntlmssp_state->auth_context = (*auth_ntlmssp_state);
+       (*auth_ntlmssp_state)->ntlmssp_state->get_challenge = auth_ntlmssp_get_challenge;
+       (*auth_ntlmssp_state)->ntlmssp_state->may_set_challenge = auth_ntlmssp_may_set_challenge;
+       (*auth_ntlmssp_state)->ntlmssp_state->set_challenge = auth_ntlmssp_set_challenge;
+       (*auth_ntlmssp_state)->ntlmssp_state->check_password = auth_ntlmssp_check_password;
+       (*auth_ntlmssp_state)->ntlmssp_state->server_role = (enum server_types)lp_server_role();
 
-       free_user_info(&user_info);
-       
-       data_blob_free(&lmhash);
-       
-       data_blob_free(&nthash);
+       return NT_STATUS_OK;
+}
+
+void auth_ntlmssp_end(AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
+{
+       TALLOC_CTX *mem_ctx;
 
-       *reply = data_blob(NULL, 0);
+       if (*auth_ntlmssp_state == NULL) {
+               return;
+       }
 
-       return nt_status;
+       mem_ctx = (*auth_ntlmssp_state)->mem_ctx;
+       if ((*auth_ntlmssp_state)->ntlmssp_state) {
+               ntlmssp_end(&(*auth_ntlmssp_state)->ntlmssp_state);
+       }
+       if ((*auth_ntlmssp_state)->auth_context) {
+               ((*auth_ntlmssp_state)->auth_context->free)(&(*auth_ntlmssp_state)->auth_context);
+       }
+       if ((*auth_ntlmssp_state)->server_info) {
+               TALLOC_FREE((*auth_ntlmssp_state)->server_info);
+       }
+       talloc_destroy(mem_ctx);
+       *auth_ntlmssp_state = NULL;
+}
+
+NTSTATUS auth_ntlmssp_update(AUTH_NTLMSSP_STATE *auth_ntlmssp_state, 
+                            const DATA_BLOB request, DATA_BLOB *reply) 
+{
+       return ntlmssp_update(auth_ntlmssp_state->ntlmssp_state, request, reply);
 }