s3-build: avoid to globally include printing and spoolss headers.
[vlendec/samba-autobuild/.git] / source3 / smbd / smb2_sesssetup.c
index 7ac003fad6e17dd98dad063dc0109e56e7541030..f5272b35cd9c0fd08b1cdaa4a0c6fe8e4cb6d960 100644 (file)
@@ -23,7 +23,8 @@
 #include "smbd/globals.h"
 #include "../libcli/smb/smb_common.h"
 #include "../libcli/auth/spnego.h"
-#include "ntlmssp.h"
+#include "../libcli/auth/ntlmssp.h"
+#include "ntlmssp_wrap.h"
 
 static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *smb2req,
                                        uint64_t in_session_id,
@@ -143,6 +144,26 @@ static int smbd_smb2_session_destructor(struct smbd_smb2_session *session)
        return 0;
 }
 
+static NTSTATUS setup_ntlmssp_server_info(struct smbd_smb2_session *session,
+                               NTSTATUS status)
+{
+       if (NT_STATUS_IS_OK(status)) {
+               status = auth_ntlmssp_steal_server_info(session,
+                               session->auth_ntlmssp_state,
+                               &session->server_info);
+       } else {
+               /* Note that this server_info won't have a session
+                * key.  But for map to guest, that's exactly the right
+                * thing - we can't reasonably guess the key the
+                * client wants, as the password was wrong */
+               status = do_map_to_guest(status,
+                       &session->server_info,
+                       auth_ntlmssp_get_username(session->auth_ntlmssp_state),
+                       auth_ntlmssp_get_domain(session->auth_ntlmssp_state));
+       }
+       return status;
+}
+
 #ifdef HAVE_KRB5
 static NTSTATUS smbd_smb2_session_setup_krb5(struct smbd_smb2_session *session,
                                        struct smbd_smb2_request *smb2req,
@@ -170,9 +191,8 @@ static NTSTATUS smbd_smb2_session_setup_krb5(struct smbd_smb2_session *session,
        fstring tmp;
        bool username_was_mapped = false;
        bool map_domainuser_to_guest = false;
-       struct smbd_server_connection *sconn = smbd_server_conn;
 
-       if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
+       if (!spnego_parse_krb5_wrap(talloc_tos(), *secblob, &ticket, tok_id)) {
                status = NT_STATUS_LOGON_FAILURE;
                goto fail;
        }
@@ -265,7 +285,7 @@ static NTSTATUS smbd_smb2_session_setup_krb5(struct smbd_smb2_session *session,
 
        /* lookup the passwd struct, create a new user if necessary */
 
-       username_was_mapped = map_username(sconn, user);
+       username_was_mapped = map_username(user);
 
        pw = smb_getpwnam(talloc_tos(), user, real_username, true );
        if (pw) {
@@ -345,6 +365,7 @@ static NTSTATUS smbd_smb2_session_setup_krb5(struct smbd_smb2_session *session,
                        DEBUG(10, ("smb2: found user %s in passdb, calling "
                                "make_server_info_sam\n", real_username));
                        status = make_server_info_sam(&tmp_server_info, sampass);
+                       TALLOC_FREE(sampass);
                } else {
                        /*
                         * User not in passdb, make it up artificially
@@ -444,7 +465,8 @@ static NTSTATUS smbd_smb2_session_setup_krb5(struct smbd_smb2_session *session,
                        register_homes_share(session->server_info->unix_name);
        }
 
-       if (!session_claim(session->compat_vuser)) {
+       if (!session_claim(sconn_server_id(session->sconn),
+                          session->compat_vuser)) {
                DEBUG(1, ("smb2: Failed to claim session "
                        "for vuid=%d\n",
                        session->compat_vuser->vuid));
@@ -466,10 +488,11 @@ static NTSTATUS smbd_smb2_session_setup_krb5(struct smbd_smb2_session *session,
         status = NT_STATUS_OK;
 
        /* wrap that up in a nice GSS-API wrapping */
-       ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
+       ap_rep_wrapped = spnego_gen_krb5_wrap(talloc_tos(), ap_rep,
                                TOK_ID_KRB_AP_REP);
 
        secblob_out = spnego_gen_auth_response(
+                                       talloc_tos(),
                                        &ap_rep_wrapped,
                                        status,
                                        mechOID);
@@ -502,6 +525,7 @@ static NTSTATUS smbd_smb2_session_setup_krb5(struct smbd_smb2_session *session,
 
        ap_rep_wrapped = data_blob_null;
        secblob_out = spnego_gen_auth_response(
+                                       talloc_tos(),
                                        &ap_rep_wrapped,
                                        status,
                                        mechOID);
@@ -524,14 +548,13 @@ static NTSTATUS smbd_smb2_spnego_negotiate(struct smbd_smb2_session *session,
 {
        DATA_BLOB secblob_in = data_blob_null;
        DATA_BLOB chal_out = data_blob_null;
-       DATA_BLOB secblob_out = data_blob_null;
        char *kerb_mech = NULL;
        NTSTATUS status;
 
        /* Ensure we have no old NTLM state around. */
-       auth_ntlmssp_end(&session->auth_ntlmssp_state);
+       TALLOC_FREE(session->auth_ntlmssp_state);
 
-       status = parse_spnego_mechanisms(in_security_buffer,
+       status = parse_spnego_mechanisms(talloc_tos(), in_security_buffer,
                        &secblob_in, &kerb_mech);
        if (!NT_STATUS_IS_OK(status)) {
                goto out;
@@ -553,15 +576,25 @@ static NTSTATUS smbd_smb2_spnego_negotiate(struct smbd_smb2_session *session,
        }
 #endif
 
-       /* Fall back to NTLMSSP. */
-       status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
-       if (!NT_STATUS_IS_OK(status)) {
-               goto out;
-       }
+       if (kerb_mech) {
+               /* The mechtoken is a krb5 ticket, but
+                * we need to fall back to NTLM. */
 
-       status = auth_ntlmssp_update(session->auth_ntlmssp_state,
-                                    secblob_in,
-                                    &chal_out);
+               DEBUG(3,("smb2: Got krb5 ticket in SPNEGO "
+                       "but set to downgrade to NTLMSSP\n"));
+
+               status = NT_STATUS_MORE_PROCESSING_REQUIRED;
+       } else {
+               /* Fall back to NTLMSSP. */
+               status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
+               if (!NT_STATUS_IS_OK(status)) {
+                       goto out;
+               }
+
+               status = auth_ntlmssp_update(session->auth_ntlmssp_state,
+                                            secblob_in,
+                                            &chal_out);
+       }
 
        if (!NT_STATUS_IS_OK(status) &&
                        !NT_STATUS_EQUAL(status,
@@ -569,13 +602,11 @@ static NTSTATUS smbd_smb2_spnego_negotiate(struct smbd_smb2_session *session,
                goto out;
        }
 
-       secblob_out = spnego_gen_auth_response(&chal_out,
+       *out_security_buffer = spnego_gen_auth_response(smb2req,
+                                               &chal_out,
                                                status,
                                                OID_NTLMSSP);
-       *out_security_buffer = data_blob_talloc(smb2req,
-                                               secblob_out.data,
-                                               secblob_out.length);
-       if (secblob_out.data && out_security_buffer->data == NULL) {
+       if (out_security_buffer->data == NULL) {
                status = NT_STATUS_NO_MEMORY;
                goto out;
        }
@@ -584,13 +615,12 @@ static NTSTATUS smbd_smb2_spnego_negotiate(struct smbd_smb2_session *session,
   out:
 
        data_blob_free(&secblob_in);
-       data_blob_free(&secblob_out);
        data_blob_free(&chal_out);
-       SAFE_FREE(kerb_mech);
+       TALLOC_FREE(kerb_mech);
        if (!NT_STATUS_IS_OK(status) &&
                        !NT_STATUS_EQUAL(status,
                                NT_STATUS_MORE_PROCESSING_REQUIRED)) {
-               auth_ntlmssp_end(&session->auth_ntlmssp_state);
+               TALLOC_FREE(session->auth_ntlmssp_state);
                TALLOC_FREE(session);
        }
        return status;
@@ -610,7 +640,7 @@ static NTSTATUS smbd_smb2_common_ntlmssp_auth_return(struct smbd_smb2_session *s
                session->do_signing = true;
        }
 
-       if (session->auth_ntlmssp_state->server_info->guest) {
+       if (session->server_info->guest) {
                /* we map anonymous to guest internally */
                *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST;
                *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL;
@@ -618,25 +648,11 @@ static NTSTATUS smbd_smb2_common_ntlmssp_auth_return(struct smbd_smb2_session *s
                session->do_signing = false;
        }
 
-       session->server_info = session->auth_ntlmssp_state->server_info;
-       data_blob_free(&session->server_info->user_session_key);
-       session->server_info->user_session_key =
-               data_blob_talloc(
-                       session->server_info,
-                       session->auth_ntlmssp_state->ntlmssp_state->session_key.data,
-                       session->auth_ntlmssp_state->ntlmssp_state->session_key.length);
-       if (session->auth_ntlmssp_state->ntlmssp_state->session_key.length > 0) {
-               if (session->server_info->user_session_key.data == NULL) {
-                       auth_ntlmssp_end(&session->auth_ntlmssp_state);
-                       TALLOC_FREE(session);
-                       return NT_STATUS_NO_MEMORY;
-               }
-       }
        session->session_key = session->server_info->user_session_key;
 
        session->compat_vuser = talloc_zero(session, user_struct);
        if (session->compat_vuser == NULL) {
-               auth_ntlmssp_end(&session->auth_ntlmssp_state);
+               TALLOC_FREE(session->auth_ntlmssp_state);
                TALLOC_FREE(session);
                return NT_STATUS_NO_MEMORY;
        }
@@ -649,22 +665,23 @@ static NTSTATUS smbd_smb2_common_ntlmssp_auth_return(struct smbd_smb2_session *s
 
        /* This is a potentially untrusted username */
        alpha_strcpy(tmp,
-               session->auth_ntlmssp_state->ntlmssp_state->user,
-               ". _-$",
-               sizeof(tmp));
+                    auth_ntlmssp_get_username(session->auth_ntlmssp_state),
+                    ". _-$",
+                    sizeof(tmp));
        session->server_info->sanitized_username = talloc_strdup(
-                       session->server_info, tmp);
+               session->server_info, tmp);
 
        if (!session->compat_vuser->server_info->guest) {
                session->compat_vuser->homes_snum =
                        register_homes_share(session->server_info->unix_name);
        }
 
-       if (!session_claim(session->compat_vuser)) {
+       if (!session_claim(sconn_server_id(session->sconn),
+                          session->compat_vuser)) {
                DEBUG(1, ("smb2: Failed to claim session "
                        "for vuid=%d\n",
                        session->compat_vuser->vuid));
-               auth_ntlmssp_end(&session->auth_ntlmssp_state);
+               TALLOC_FREE(session->auth_ntlmssp_state);
                TALLOC_FREE(session);
                return NT_STATUS_LOGON_FAILURE;
        }
@@ -698,10 +715,9 @@ static NTSTATUS smbd_smb2_spnego_auth(struct smbd_smb2_session *session,
 {
        DATA_BLOB auth = data_blob_null;
        DATA_BLOB auth_out = data_blob_null;
-       DATA_BLOB secblob_out = data_blob_null;
        NTSTATUS status;
 
-       if (!spnego_parse_auth(in_security_buffer, &auth)) {
+       if (!spnego_parse_auth(talloc_tos(), in_security_buffer, &auth)) {
                TALLOC_FREE(session);
                return NT_STATUS_LOGON_FAILURE;
        }
@@ -711,7 +727,8 @@ static NTSTATUS smbd_smb2_spnego_auth(struct smbd_smb2_session *session,
                DATA_BLOB secblob_in = data_blob_null;
                char *kerb_mech = NULL;
 
-               status = parse_spnego_mechanisms(in_security_buffer,
+               status = parse_spnego_mechanisms(talloc_tos(),
+                               in_security_buffer,
                                &secblob_in, &kerb_mech);
                if (!NT_STATUS_IS_OK(status)) {
                        TALLOC_FREE(session);
@@ -731,7 +748,7 @@ static NTSTATUS smbd_smb2_spnego_auth(struct smbd_smb2_session *session,
                                        out_session_id);
 
                        data_blob_free(&secblob_in);
-                       SAFE_FREE(kerb_mech);
+                       TALLOC_FREE(kerb_mech);
                        if (!NT_STATUS_IS_OK(status)) {
                                TALLOC_FREE(session);
                        }
@@ -749,16 +766,33 @@ static NTSTATUS smbd_smb2_spnego_auth(struct smbd_smb2_session *session,
                                "not enabled\n"));
                        TALLOC_FREE(session);
                        data_blob_free(&secblob_in);
-                       SAFE_FREE(kerb_mech);
+                       TALLOC_FREE(kerb_mech);
                        return NT_STATUS_LOGON_FAILURE;
                }
+
+               data_blob_free(&secblob_in);
+       }
+
+       if (session->auth_ntlmssp_state == NULL) {
+               status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
+               if (!NT_STATUS_IS_OK(status)) {
+                       data_blob_free(&auth);
+                       TALLOC_FREE(session);
+                       return status;
+               }
        }
 
        status = auth_ntlmssp_update(session->auth_ntlmssp_state,
                                     auth,
                                     &auth_out);
-       if (!NT_STATUS_IS_OK(status)) {
-               auth_ntlmssp_end(&session->auth_ntlmssp_state);
+       if (!NT_STATUS_IS_OK(status) &&
+                       !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+               status = setup_ntlmssp_server_info(session, status);
+       }
+
+       if (!NT_STATUS_IS_OK(status) &&
+                       !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+               TALLOC_FREE(session->auth_ntlmssp_state);
                data_blob_free(&auth);
                TALLOC_FREE(session);
                return status;
@@ -766,20 +800,22 @@ static NTSTATUS smbd_smb2_spnego_auth(struct smbd_smb2_session *session,
 
        data_blob_free(&auth);
 
-       secblob_out = spnego_gen_auth_response(&auth_out,
-                               status, NULL);
+       *out_security_buffer = spnego_gen_auth_response(smb2req,
+                               &auth_out, status, NULL);
 
-       *out_security_buffer = data_blob_talloc(smb2req,
-                                               secblob_out.data,
-                                               secblob_out.length);
-       if (secblob_out.data && out_security_buffer->data == NULL) {
-               auth_ntlmssp_end(&session->auth_ntlmssp_state);
+       if (out_security_buffer->data == NULL) {
+               TALLOC_FREE(session->auth_ntlmssp_state);
                TALLOC_FREE(session);
                return NT_STATUS_NO_MEMORY;
        }
 
        *out_session_id = session->vuid;
 
+       if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+               return NT_STATUS_MORE_PROCESSING_REQUIRED;
+       }
+
+       /* We're done - claim the session. */
        return smbd_smb2_common_ntlmssp_auth_return(session,
                                                smb2req,
                                                in_security_mode,
@@ -818,7 +854,7 @@ static NTSTATUS smbd_smb2_raw_ntlmssp_auth(struct smbd_smb2_session *session,
                                                secblob_out.data,
                                                secblob_out.length);
                if (secblob_out.data && out_security_buffer->data == NULL) {
-                       auth_ntlmssp_end(&session->auth_ntlmssp_state);
+                       TALLOC_FREE(session->auth_ntlmssp_state);
                        TALLOC_FREE(session);
                        return NT_STATUS_NO_MEMORY;
                }
@@ -828,8 +864,11 @@ static NTSTATUS smbd_smb2_raw_ntlmssp_auth(struct smbd_smb2_session *session,
                *out_session_id = session->vuid;
                return status;
        }
+
+       status = setup_ntlmssp_server_info(session, status);
+
        if (!NT_STATUS_IS_OK(status)) {
-               auth_ntlmssp_end(&session->auth_ntlmssp_state);
+               TALLOC_FREE(session->auth_ntlmssp_state);
                TALLOC_FREE(session);
                return status;
        }
@@ -928,7 +967,7 @@ static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *smb2req,
        /* Unknown packet type. */
        DEBUG(1,("Unknown packet type %u in smb2 sessionsetup\n",
                (unsigned int)in_security_buffer.data[0] ));
-       auth_ntlmssp_end(&session->auth_ntlmssp_state);
+       TALLOC_FREE(session->auth_ntlmssp_state);
        TALLOC_FREE(session);
        return NT_STATUS_LOGON_FAILURE;
 }