s3-auth remove auth_ntlmssp_start(), call auth_generic_start() directly
[mat/samba.git] / source3 / smbd / sesssetup.c
index 694c0874f2e897496ff4f4d2962a46c302aa72d5..04783a4fcd4482129efa7084c9a484de40b4bd3f 100644 (file)
@@ -27,7 +27,7 @@
 #include "smbd/smbd.h"
 #include "smbd/globals.h"
 #include "../libcli/auth/spnego.h"
-#include "../libcli/auth/ntlmssp.h"
+#include "../auth/ntlmssp/ntlmssp.h"
 #include "ntlmssp_wrap.h"
 #include "../librpc/gen_ndr/krb5pac.h"
 #include "libads/kerberos_proto.h"
@@ -35,6 +35,8 @@
 #include "auth.h"
 #include "messages.h"
 #include "smbprofile.h"
+#include "../libcli/security/security.h"
+#include "auth/gensec/gensec.h"
 
 /* For split krb5 SPNEGO blobs. */
 struct pending_auth_data {
@@ -45,68 +47,6 @@ struct pending_auth_data {
        DATA_BLOB partial_data;
 };
 
-/*
-  on a logon error possibly map the error to success if "map to guest"
-  is set approriately
-*/
-static NTSTATUS do_map_to_guest_server_info(NTSTATUS status,
-                                           struct auth_serversupplied_info **server_info,
-                                           const char *user, const char *domain)
-{
-       user = user ? user : "";
-       domain = domain ? domain : "";
-
-       if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
-               if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) ||
-                   (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
-                       DEBUG(3,("No such user %s [%s] - using guest account\n",
-                                user, domain));
-                       status = make_server_info_guest(NULL, server_info);
-               }
-       }
-
-       if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
-               if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
-                       DEBUG(3,("Registered username %s for guest access\n",
-                               user));
-                       status = make_server_info_guest(NULL, server_info);
-               }
-       }
-
-       return status;
-}
-
-/*
-  on a logon error possibly map the error to success if "map to guest"
-  is set approriately
-*/
-NTSTATUS do_map_to_guest(NTSTATUS status,
-                       struct auth3_session_info **session_info,
-                       const char *user, const char *domain)
-{
-       user = user ? user : "";
-       domain = domain ? domain : "";
-
-       if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
-               if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) ||
-                   (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
-                       DEBUG(3,("No such user %s [%s] - using guest account\n",
-                                user, domain));
-                       status = make_session_info_guest(NULL, session_info);
-               }
-       }
-
-       if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
-               if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
-                       DEBUG(3,("Registered username %s for guest access\n",
-                               user));
-                       status = make_session_info_guest(NULL, session_info);
-               }
-       }
-
-       return status;
-}
-
 /****************************************************************************
  Add the standard 'Samba' signature to the end of the session setup.
 ****************************************************************************/
@@ -282,7 +222,7 @@ static void reply_spnego_kerberos(struct smb_request *req,
        int sess_vuid = req->vuid;
        NTSTATUS ret = NT_STATUS_OK;
        DATA_BLOB ap_rep, ap_rep_wrapped, response;
-       struct auth3_session_info *session_info = NULL;
+       struct auth_session_info *session_info = NULL;
        DATA_BLOB session_key = data_blob_null;
        uint8 tok_id[2];
        DATA_BLOB nullblob = data_blob_null;
@@ -401,7 +341,7 @@ static void reply_spnego_kerberos(struct smb_request *req,
        sub_set_smb_name(real_username);
 
        /* reload services so that the new %U is taken into account */
-       reload_services(sconn->msg_ctx, sconn->sock, True);
+       reload_services(sconn, conn_snum_used, true);
 
        ret = make_session_info_krb5(mem_ctx,
                                     user, domain, real_username, pw,
@@ -428,7 +368,7 @@ static void reply_spnego_kerberos(struct smb_request *req,
         * it.... */
 
        sess_vuid = register_existing_vuid(sconn, sess_vuid,
-                                          session_info, nullblob, user);
+                                          session_info, nullblob);
 
        reply_outbuf(req, 4, 0);
        SSVAL(req->outbuf,smb_uid,sess_vuid);
@@ -437,11 +377,11 @@ static void reply_spnego_kerberos(struct smb_request *req,
                ret = NT_STATUS_LOGON_FAILURE;
        } else {
                /* current_user_info is changed on new vuid */
-               reload_services(sconn->msg_ctx, sconn->sock, True);
+               reload_services(sconn, conn_snum_used, true);
 
                SSVAL(req->outbuf, smb_vwv3, 0);
 
-               if (session_info->guest) {
+               if (security_session_user_level(session_info, NULL) < SECURITY_USER) {
                        SSVAL(req->outbuf,smb_vwv2,1);
                }
 
@@ -480,28 +420,20 @@ static void reply_spnego_kerberos(struct smb_request *req,
 
 static void reply_spnego_ntlmssp(struct smb_request *req,
                                 uint16 vuid,
-                                struct auth_ntlmssp_state **auth_ntlmssp_state,
+                                struct auth_generic_state **auth_ntlmssp_state,
                                 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
                                 const char *OID,
                                 bool wrap)
 {
        bool do_invalidate = true;
        DATA_BLOB response;
-       struct auth3_session_info *session_info = NULL;
+       struct auth_session_info *session_info = NULL;
        struct smbd_server_connection *sconn = req->sconn;
 
        if (NT_STATUS_IS_OK(nt_status)) {
-               nt_status = auth_ntlmssp_steal_session_info(talloc_tos(),
-                                       (*auth_ntlmssp_state), &session_info);
-       } else {
-               /* Note that this session_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 */
-               nt_status = do_map_to_guest(nt_status,
-                                           &session_info,
-                                           auth_ntlmssp_get_username(*auth_ntlmssp_state),
-                                           auth_ntlmssp_get_domain(*auth_ntlmssp_state));
+               nt_status = gensec_session_info((*auth_ntlmssp_state)->gensec_security,
+                                               talloc_tos(),
+                                               &session_info);
        }
 
        reply_outbuf(req, 4, 0);
@@ -518,8 +450,7 @@ static void reply_spnego_ntlmssp(struct smb_request *req,
 
                /* register_existing_vuid keeps the server info */
                if (register_existing_vuid(sconn, vuid,
-                                          session_info, nullblob,
-                                          auth_ntlmssp_get_username(*auth_ntlmssp_state)) !=
+                                          session_info, nullblob) !=
                                           vuid) {
                        /* The problem is, *auth_ntlmssp_state points
                         * into the vuser this will have
@@ -531,11 +462,11 @@ static void reply_spnego_ntlmssp(struct smb_request *req,
                }
 
                /* current_user_info is changed on new vuid */
-               reload_services(sconn->msg_ctx, sconn->sock, True);
+               reload_services(sconn, conn_snum_used, true);
 
                SSVAL(req->outbuf, smb_vwv3, 0);
 
-               if (session_info->guest) {
+               if (security_session_user_level(session_info, NULL) < SECURITY_USER) {
                        SSVAL(req->outbuf,smb_vwv2,1);
                }
        }
@@ -647,7 +578,7 @@ static void reply_spnego_downgrade_to_ntlmssp(struct smb_request *req,
 static void reply_spnego_negotiate(struct smb_request *req,
                                   uint16 vuid,
                                   DATA_BLOB blob1,
-                                  struct auth_ntlmssp_state **auth_ntlmssp_state)
+                                  struct auth_generic_state **auth_ntlmssp_state)
 {
        DATA_BLOB secblob;
        DATA_BLOB chal;
@@ -694,8 +625,18 @@ static void reply_spnego_negotiate(struct smb_request *req,
                return;
        }
 
-       status = auth_ntlmssp_start(sconn->remote_address,
-                                   auth_ntlmssp_state);
+       status = auth_generic_prepare(sconn->remote_address,
+                                     auth_ntlmssp_state);
+       if (!NT_STATUS_IS_OK(status)) {
+               /* Kill the intermediate vuid */
+               invalidate_vuid(sconn, vuid);
+               reply_nterror(req, nt_status_squash(status));
+               return;
+       }
+
+       gensec_want_feature((*auth_ntlmssp_state)->gensec_security, GENSEC_FEATURE_SESSION_KEY);
+
+       status = auth_generic_start(*auth_ntlmssp_state, GENSEC_OID_NTLMSSP);
        if (!NT_STATUS_IS_OK(status)) {
                /* Kill the intermediate vuid */
                invalidate_vuid(sconn, vuid);
@@ -703,8 +644,8 @@ static void reply_spnego_negotiate(struct smb_request *req,
                return;
        }
 
-       status = auth_ntlmssp_update(*auth_ntlmssp_state,
-                                       secblob, &chal);
+       status = gensec_update((*auth_ntlmssp_state)->gensec_security, talloc_tos(),
+                              NULL, secblob, &chal);
 
        data_blob_free(&secblob);
 
@@ -724,7 +665,7 @@ static void reply_spnego_negotiate(struct smb_request *req,
 static void reply_spnego_auth(struct smb_request *req,
                              uint16 vuid,
                              DATA_BLOB blob1,
-                             struct auth_ntlmssp_state **auth_ntlmssp_state)
+                             struct auth_generic_state **auth_ntlmssp_state)
 {
        DATA_BLOB auth = data_blob_null;
        DATA_BLOB auth_reply = data_blob_null;
@@ -796,8 +737,18 @@ static void reply_spnego_auth(struct smb_request *req,
        data_blob_free(&secblob);
 
        if (!*auth_ntlmssp_state) {
-               status = auth_ntlmssp_start(sconn->remote_address,
-                                           auth_ntlmssp_state);
+               status = auth_generic_prepare(sconn->remote_address,
+                                             auth_ntlmssp_state);
+               if (!NT_STATUS_IS_OK(status)) {
+                       /* Kill the intermediate vuid */
+                       invalidate_vuid(sconn, vuid);
+                       reply_nterror(req, nt_status_squash(status));
+                       return;
+               }
+
+               gensec_want_feature((*auth_ntlmssp_state)->gensec_security, GENSEC_FEATURE_SESSION_KEY);
+
+               status = auth_generic_start(*auth_ntlmssp_state, GENSEC_OID_NTLMSSP);
                if (!NT_STATUS_IS_OK(status)) {
                        /* Kill the intermediate vuid */
                        invalidate_vuid(sconn, vuid);
@@ -806,8 +757,8 @@ static void reply_spnego_auth(struct smb_request *req,
                }
        }
 
-       status = auth_ntlmssp_update(*auth_ntlmssp_state,
-                                       auth, &auth_reply);
+       status = gensec_update((*auth_ntlmssp_state)->gensec_security, talloc_tos(),
+                              NULL, auth, &auth_reply);
 
        data_blob_free(&auth);
 
@@ -1185,32 +1136,32 @@ static void reply_sesssetup_and_X_spnego(struct smb_request *req)
                return;
        }
 
-       if (blob1.data[0] == ASN1_APPLICATION(0)) {
-
-               /* its a negTokenTarg packet */
-
-               reply_spnego_negotiate(req, vuid, blob1,
-                                      &vuser->auth_ntlmssp_state);
-               data_blob_free(&blob1);
-               return;
-       }
-
-       if (blob1.data[0] == ASN1_CONTEXT(1)) {
-
-               /* its a auth packet */
-
-               reply_spnego_auth(req, vuid, blob1,
-                                 &vuser->auth_ntlmssp_state);
-               data_blob_free(&blob1);
-               return;
-       }
-
-       if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
+       /* Handle either raw NTLMSSP or hand off the whole blob to
+        * GENSEC.  The processing at this layer is essentially
+        * identical regardless.  In particular, both rely only on the
+        * status code (not the contents of the packet) and do not
+        * wrap the result */
+       if (sconn->use_gensec_hook || ntlmssp_blob_matches_magic(&blob1)) {
                DATA_BLOB chal;
 
                if (!vuser->auth_ntlmssp_state) {
-                       status = auth_ntlmssp_start(sconn->remote_address,
-                                                   &vuser->auth_ntlmssp_state);
+                       status = auth_generic_prepare(sconn->remote_address,
+                                                     &vuser->auth_ntlmssp_state);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               /* Kill the intermediate vuid */
+                               invalidate_vuid(sconn, vuid);
+                               data_blob_free(&blob1);
+                               reply_nterror(req, nt_status_squash(status));
+                               return;
+                       }
+
+                       gensec_want_feature(vuser->auth_ntlmssp_state->gensec_security, GENSEC_FEATURE_SESSION_KEY);
+
+                       if (sconn->use_gensec_hook) {
+                               status = auth_generic_start(vuser->auth_ntlmssp_state, GENSEC_OID_SPNEGO);
+                       } else {
+                               status = auth_generic_start(vuser->auth_ntlmssp_state, GENSEC_OID_NTLMSSP);
+                       }
                        if (!NT_STATUS_IS_OK(status)) {
                                /* Kill the intermediate vuid */
                                invalidate_vuid(sconn, vuid);
@@ -1220,18 +1171,39 @@ static void reply_sesssetup_and_X_spnego(struct smb_request *req)
                        }
                }
 
-               status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
-                                               blob1, &chal);
+               status = gensec_update(vuser->auth_ntlmssp_state->gensec_security,
+                                      talloc_tos(), NULL,
+                                      blob1, &chal);
 
                data_blob_free(&blob1);
 
                reply_spnego_ntlmssp(req, vuid,
                                     &vuser->auth_ntlmssp_state,
-                                    &chal, status, OID_NTLMSSP, false);
+                                    &chal, status, NULL, false);
                data_blob_free(&chal);
                return;
        }
 
+       if (blob1.data[0] == ASN1_APPLICATION(0)) {
+
+               /* its a negTokenTarg packet */
+
+               reply_spnego_negotiate(req, vuid, blob1,
+                                      &vuser->auth_ntlmssp_state);
+               data_blob_free(&blob1);
+               return;
+       }
+
+       if (blob1.data[0] == ASN1_CONTEXT(1)) {
+
+               /* its a auth packet */
+
+               reply_spnego_auth(req, vuid, blob1,
+                                 &vuser->auth_ntlmssp_state);
+               data_blob_free(&blob1);
+               return;
+       }
+
        /* what sort of packet is this? */
        DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
 
@@ -1328,13 +1300,15 @@ void reply_sesssetup_and_X(struct smb_request *req)
        const char *primary_domain;
        struct auth_usersupplied_info *user_info = NULL;
        struct auth_serversupplied_info *server_info = NULL;
-       struct auth3_session_info *session_info = NULL;
+       struct auth_session_info *session_info = NULL;
        uint16 smb_flag2 = req->flags2;
 
        NTSTATUS nt_status;
        struct smbd_server_connection *sconn = req->sconn;
 
        bool doencrypt = sconn->smb1.negprot.encrypted_passwords;
+       bool signing_allowed = false;
+       bool signing_mandatory = false;
 
        START_PROFILE(SMBsesssetupX);
 
@@ -1344,6 +1318,22 @@ void reply_sesssetup_and_X(struct smb_request *req)
 
        DEBUG(3,("wct=%d flg2=0x%x\n", req->wct, req->flags2));
 
+       if (req->flags2 & FLAGS2_SMB_SECURITY_SIGNATURES) {
+               signing_allowed = true;
+       }
+       if (req->flags2 & FLAGS2_SMB_SECURITY_SIGNATURES_REQUIRED) {
+               signing_mandatory = true;
+       }
+
+       /*
+        * We can call srv_set_signing_negotiated() each time.
+        * It finds out when it needs to turn into a noop
+        * itself.
+        */
+       srv_set_signing_negotiated(req->sconn,
+                                  signing_allowed,
+                                  signing_mandatory);
+
        /* a SPNEGO session setup has 12 command words, whereas a normal
           NT1 session setup has 13. See the cifs spec. */
        if (req->wct == 12 &&
@@ -1579,12 +1569,12 @@ void reply_sesssetup_and_X(struct smb_request *req)
                }
                fstrcpy(sub_user, user);
        } else {
-               fstrcpy(sub_user, lp_guestaccount());
+               fstrcpy(sub_user, "");
        }
 
        sub_set_smb_name(sub_user);
 
-       reload_services(sconn->msg_ctx, sconn->sock, True);
+       reload_services(sconn, conn_snum_used, true);
 
        if (lp_security() == SEC_SHARE) {
                char *sub_user_mapped = NULL;
@@ -1679,7 +1669,7 @@ void reply_sesssetup_and_X(struct smb_request *req)
                return;
        }
 
-       nt_status = create_local_token(req, server_info, NULL, &session_info);
+       nt_status = create_local_token(req, server_info, NULL, sub_user, &session_info);
        TALLOC_FREE(server_info);
 
        if (!NT_STATUS_IS_OK(nt_status)) {
@@ -1702,7 +1692,7 @@ void reply_sesssetup_and_X(struct smb_request *req)
                /* perhaps grab OS version here?? */
        }
 
-       if (session_info->guest) {
+       if (security_session_user_level(session_info, NULL) < SECURITY_USER) {
                SSVAL(req->outbuf,smb_vwv2,1);
        }
 
@@ -1726,8 +1716,7 @@ void reply_sesssetup_and_X(struct smb_request *req)
                /* register_existing_vuid keeps the session_info */
                sess_vuid = register_existing_vuid(sconn, sess_vuid,
                                        session_info,
-                                       nt_resp.data ? nt_resp : lm_resp,
-                                       sub_user);
+                                       nt_resp.data ? nt_resp : lm_resp);
                if (sess_vuid == UID_FIELD_INVALID) {
                        data_blob_free(&nt_resp);
                        data_blob_free(&lm_resp);
@@ -1738,7 +1727,7 @@ void reply_sesssetup_and_X(struct smb_request *req)
                }
 
                /* current_user_info is changed on new vuid */
-               reload_services(sconn->msg_ctx, sconn->sock, True);
+               reload_services(sconn, conn_snum_used, true);
        }
 
        data_blob_free(&nt_resp);