s3:is_trusted_domain: shortcut if domain name is NULL or empty
[ira/wip.git] / source3 / smbd / smb2_sesssetup.c
index eb88a60420bc33658d633fc07ee703f61d848ecf..dc24124b54708692cb0ea9d0c14f341068bbad01 100644 (file)
@@ -20,7 +20,8 @@
 
 #include "includes.h"
 #include "smbd/globals.h"
-#include "../source4/libcli/smb2/smb2_constants.h"
+#include "../libcli/smb/smb_common.h"
+#include "../libcli/auth/spnego.h"
 
 static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *req,
                                        uint64_t in_session_id,
@@ -114,12 +115,13 @@ NTSTATUS smbd_smb2_request_process_sesssetup(struct smbd_smb2_request *req)
 
        outdyn = out_security_buffer;
 
-       return smbd_smb2_request_done_ex(req, status, outbody, &outdyn);
+       return smbd_smb2_request_done_ex(req, status, outbody, &outdyn,
+                                        __location__);
 }
 
 static int smbd_smb2_session_destructor(struct smbd_smb2_session *session)
 {
-       if (session->conn == NULL) {
+       if (session->sconn == NULL) {
                return 0;
        }
 
@@ -128,12 +130,13 @@ static int smbd_smb2_session_destructor(struct smbd_smb2_session *session)
                talloc_free(session->tcons.list);
        }
 
-       idr_remove(session->conn->smb2.sessions.idtree, session->vuid);
-       DLIST_REMOVE(session->conn->smb2.sessions.list, session);
+       idr_remove(session->sconn->smb2.sessions.idtree, session->vuid);
+       DLIST_REMOVE(session->sconn->smb2.sessions.list, session);
+       invalidate_vuid(session->sconn, session->vuid);
 
        session->vuid = 0;
        session->status = NT_STATUS_USER_SESSION_DELETED;
-       session->conn = NULL;
+       session->sconn = NULL;
 
        return 0;
 }
@@ -150,19 +153,20 @@ static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *req,
        NTSTATUS status;
 
        *out_session_flags = 0;
+       *out_session_id = 0;
 
        if (in_session_id == 0) {
                int id;
 
                /* create a new session */
-               session = talloc_zero(req->conn, struct smbd_smb2_session);
+               session = talloc_zero(req->sconn, struct smbd_smb2_session);
                if (session == NULL) {
                        return NT_STATUS_NO_MEMORY;
                }
                session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
-               id = idr_get_new_random(req->conn->smb2.sessions.idtree,
+               id = idr_get_new_random(req->sconn->smb2.sessions.idtree,
                                        session,
-                                       req->conn->smb2.sessions.limit);
+                                       req->sconn->smb2.sessions.limit);
                if (id == -1) {
                        return NT_STATUS_INSUFFICIENT_RESOURCES;
                }
@@ -172,18 +176,18 @@ static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *req,
                if (session->tcons.idtree == NULL) {
                        return NT_STATUS_NO_MEMORY;
                }
-               session->tcons.limit = 0x00FFFFFF;
+               session->tcons.limit = 0x0000FFFE;
                session->tcons.list = NULL;
 
-               DLIST_ADD_END(req->conn->smb2.sessions.list, session,
+               DLIST_ADD_END(req->sconn->smb2.sessions.list, session,
                              struct smbd_smb2_session *);
-               session->conn = req->conn;
+               session->sconn = req->sconn;
                talloc_set_destructor(session, smbd_smb2_session_destructor);
        } else {
                void *p;
 
                /* lookup an existing session */
-               p = idr_find(req->conn->smb2.sessions.idtree, in_session_id);
+               p = idr_find(req->sconn->smb2.sessions.idtree, in_session_id);
                if (p == NULL) {
                        return NT_STATUS_USER_SESSION_DELETED;
                }
@@ -202,15 +206,75 @@ static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *req,
                }
        }
 
-       status = auth_ntlmssp_update(session->auth_ntlmssp_state,
-                                    in_security_buffer,
-                                    out_security_buffer);
-       if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+       if (in_security_buffer.data[0] == ASN1_APPLICATION(0)) {
+               DATA_BLOB secblob_in;
+               DATA_BLOB chal_out;
+               char *kerb_mech = NULL;
+
+               status = parse_spnego_mechanisms(in_security_buffer,
+                               &secblob_in, &kerb_mech);
+               if (!NT_STATUS_IS_OK(status)) {
+                       TALLOC_FREE(session);
+                       return nt_status_squash(status);
+               }
+
+               /* For now, just SPNEGO NTLMSSP - krb5 goes here later.. */
+               status = auth_ntlmssp_update(session->auth_ntlmssp_state,
+                                            secblob_in,
+                                            &chal_out);
+
+               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);
+                       return nt_status_squash(status);
+               }
+
+               *out_security_buffer = spnego_gen_auth_response(&chal_out,
+                                status, OID_NTLMSSP);
+
                *out_session_id = session->vuid;
                return status;
-       } else if (!NT_STATUS_IS_OK(status)) {
-               TALLOC_FREE(session);
-               return status;
+       } else if (in_security_buffer.data[0] == ASN1_CONTEXT(1)) {
+               DATA_BLOB auth = data_blob_null;
+               DATA_BLOB auth_out = data_blob_null;
+
+               /* its an auth packet */
+               if (!spnego_parse_auth(in_security_buffer, &auth)) {
+                       TALLOC_FREE(session);
+                       return NT_STATUS_LOGON_FAILURE;
+               }
+               /* For now, just SPNEGO NTLMSSP - krb5 goes here later.. */
+               status = auth_ntlmssp_update(session->auth_ntlmssp_state,
+                                            auth,
+                                            &auth_out);
+               if (!NT_STATUS_IS_OK(status)) {
+                       auth_ntlmssp_end(&session->auth_ntlmssp_state);
+                       TALLOC_FREE(session);
+                       return nt_status_squash(status);
+               }
+
+               *out_security_buffer = spnego_gen_auth_response(&auth_out,
+                                status, NULL);
+
+               *out_session_id = session->vuid;
+       } else if (strncmp((char *)(in_security_buffer.data), "NTLMSSP", 7) == 0) {
+
+               /* RAW NTLMSSP */
+               status = auth_ntlmssp_update(session->auth_ntlmssp_state,
+                                            in_security_buffer,
+                                            out_security_buffer);
+
+               if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+                       *out_session_id = session->vuid;
+                       return status;
+               }
+               if (!NT_STATUS_IS_OK(status)) {
+                       auth_ntlmssp_end(&session->auth_ntlmssp_state);
+                       TALLOC_FREE(session);
+                       return nt_status_squash(status);
+               }
+               *out_session_id = session->vuid;
        }
 
        /* TODO: setup session key for signing */
@@ -253,7 +317,7 @@ static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *req,
        session->compat_vuser->server_info = session->server_info;
        session->compat_vuser->session_keystr = NULL;
        session->compat_vuser->vuid = session->vuid;
-       DLIST_ADD(session->conn->smb1.sessions.validated_users, session->compat_vuser);
+       DLIST_ADD(session->sconn->smb1.sessions.validated_users, session->compat_vuser);
 
        session->status = NT_STATUS_OK;
 
@@ -283,7 +347,7 @@ NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
        in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
 
        /* lookup an existing session */
-       p = idr_find(req->conn->smb2.sessions.idtree, in_session_id);
+       p = idr_find(req->sconn->smb2.sessions.idtree, in_session_id);
        if (p == NULL) {
                return NT_STATUS_USER_SESSION_DELETED;
        }