s3-auth use auth_user_info not netr_SamInfo3 in auth3_session_info
[ira/wip.git] / source3 / smbd / smb2_server.c
index 24953edb5e9dd1de83f74900baecce33e39f7401..11b5ed8bf03d18378b75267fd655f88c6525fa04 100644 (file)
@@ -26,6 +26,9 @@
 #include "../lib/tsocket/tsocket.h"
 #include "../lib/util/tevent_ntstatus.h"
 #include "smbprofile.h"
+#include "../lib/util/bitmap.h"
+#include "../librpc/gen_ndr/krb5pac.h"
+#include "auth.h"
 
 #define OUTVEC_ALLOC_SIZE (SMB2_HDR_BODY + 9)
 
@@ -923,7 +926,7 @@ NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
 
        if (req->do_signing) {
                status = smb2_signing_sign_pdu(req->session->session_key,
-                                       state->vector, 3);
+                                       &state->vector[1], 2);
                if (!NT_STATUS_IS_OK(status)) {
                        return status;
                }
@@ -1071,6 +1074,134 @@ static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req)
        return NT_STATUS_OK;
 }
 
+/*************************************************************
+ Ensure an incoming tid is a valid one for us to access.
+ Change to the associated uid credentials and chdir to the
+ valid tid directory.
+*************************************************************/
+
+static NTSTATUS smbd_smb2_request_check_tcon(struct smbd_smb2_request *req)
+{
+       const uint8_t *inhdr;
+       const uint8_t *outhdr;
+       int i = req->current_idx;
+       uint32_t in_tid;
+       void *p;
+       struct smbd_smb2_tcon *tcon;
+       bool chained_fixup = false;
+
+       inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
+
+       in_tid = IVAL(inhdr, SMB2_HDR_TID);
+
+       if (in_tid == (0xFFFFFFFF)) {
+               if (req->async) {
+                       /*
+                        * async request - fill in tid from
+                        * already setup out.vector[].iov_base.
+                        */
+                       outhdr = (const uint8_t *)req->out.vector[i].iov_base;
+                       in_tid = IVAL(outhdr, SMB2_HDR_TID);
+               } else if (i > 2) {
+                       /*
+                        * Chained request - fill in tid from
+                        * the previous request out.vector[].iov_base.
+                        */
+                       outhdr = (const uint8_t *)req->out.vector[i-3].iov_base;
+                       in_tid = IVAL(outhdr, SMB2_HDR_TID);
+                       chained_fixup = true;
+               }
+       }
+
+       /* lookup an existing session */
+       p = idr_find(req->session->tcons.idtree, in_tid);
+       if (p == NULL) {
+               return NT_STATUS_NETWORK_NAME_DELETED;
+       }
+       tcon = talloc_get_type_abort(p, struct smbd_smb2_tcon);
+
+       if (!change_to_user(tcon->compat_conn,req->session->vuid)) {
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
+       /* should we pass FLAG_CASELESS_PATHNAMES here? */
+       if (!set_current_service(tcon->compat_conn, 0, true)) {
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
+       req->tcon = tcon;
+
+       if (chained_fixup) {
+               /* Fix up our own outhdr. */
+               outhdr = (const uint8_t *)req->out.vector[i].iov_base;
+               SIVAL(discard_const_p(uint8_t, outhdr), SMB2_HDR_TID, in_tid);
+       }
+
+       return NT_STATUS_OK;
+}
+
+/*************************************************************
+ Ensure an incoming session_id is a valid one for us to access.
+*************************************************************/
+
+static NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
+{
+       const uint8_t *inhdr;
+       const uint8_t *outhdr;
+       int i = req->current_idx;
+       uint64_t in_session_id;
+       void *p;
+       struct smbd_smb2_session *session;
+       bool chained_fixup = false;
+
+       inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
+
+       in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
+
+       if (in_session_id == (0xFFFFFFFFFFFFFFFFLL)) {
+               if (req->async) {
+                       /*
+                        * async request - fill in session_id from
+                        * already setup request out.vector[].iov_base.
+                        */
+                       outhdr = (const uint8_t *)req->out.vector[i].iov_base;
+                       in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
+               } else if (i > 2) {
+                       /*
+                        * Chained request - fill in session_id from
+                        * the previous request out.vector[].iov_base.
+                        */
+                       outhdr = (const uint8_t *)req->out.vector[i-3].iov_base;
+                       in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
+                       chained_fixup = true;
+               }
+       }
+
+       /* lookup an existing session */
+       p = idr_find(req->sconn->smb2.sessions.idtree, in_session_id);
+       if (p == NULL) {
+               return NT_STATUS_USER_SESSION_DELETED;
+       }
+       session = talloc_get_type_abort(p, struct smbd_smb2_session);
+
+       if (!NT_STATUS_IS_OK(session->status)) {
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
+       set_current_user_info(session->session_info->unix_info->sanitized_username,
+                             session->session_info->unix_info->unix_name,
+                             session->session_info->info->domain_name);
+
+       req->session = session;
+
+       if (chained_fixup) {
+               /* Fix up our own outhdr. */
+               outhdr = (const uint8_t *)req->out.vector[i].iov_base;
+               SBVAL(discard_const_p(uint8_t, outhdr), SMB2_HDR_SESSION_ID, in_session_id);
+       }
+       return NT_STATUS_OK;
+}
+
 NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
 {
        const uint8_t *inhdr;
@@ -1104,6 +1235,14 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
        }
 
+       /*
+        * Check if the client provided a valid session id,
+        * if so smbd_smb2_request_check_session() calls
+        * set_current_user_info().
+        *
+        * As some command don't require a valid session id
+        * we defer the check of the session_status
+        */
        session_status = smbd_smb2_request_check_session(req);
 
        req->do_signing = false;
@@ -1139,6 +1278,9 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
 
        switch (opcode) {
        case SMB2_OP_NEGPROT:
+               /* This call needs to be run as root */
+               change_to_root_user();
+
                {
                        START_PROFILE(smb2_negprot);
                        return_value = smbd_smb2_request_process_negprot(req);
@@ -1147,6 +1289,9 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                break;
 
        case SMB2_OP_SESSSETUP:
+               /* This call needs to be run as root */
+               change_to_root_user();
+
                {
                        START_PROFILE(smb2_sesssetup);
                        return_value = smbd_smb2_request_process_sesssetup(req);
@@ -1160,6 +1305,9 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                        break;
                }
 
+               /* This call needs to be run as root */
+               change_to_root_user();
+
                {
                        START_PROFILE(smb2_logoff);
                        return_value = smbd_smb2_request_process_logoff(req);
@@ -1172,11 +1320,15 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                        return_value = smbd_smb2_request_error(req, session_status);
                        break;
                }
-               status = smbd_smb2_request_check_session(req);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return_value = smbd_smb2_request_error(req, status);
-                       break;
-               }
+
+               /*
+                * This call needs to be run as root.
+                *
+                * smbd_smb2_request_process_tcon()
+                * calls make_connection_snum(), which will call
+                * change_to_user(), when needed.
+                */
+               change_to_root_user();
 
                {
                        START_PROFILE(smb2_tcon);
@@ -1190,11 +1342,20 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                        return_value = smbd_smb2_request_error(req, session_status);
                        break;
                }
+               /*
+                * This call needs to be run as user.
+                *
+                * smbd_smb2_request_check_tcon()
+                * calls change_to_user() on success.
+                */
                status = smbd_smb2_request_check_tcon(req);
                if (!NT_STATUS_IS_OK(status)) {
                        return_value = smbd_smb2_request_error(req, status);
                        break;
                }
+               /* This call needs to be run as root */
+               change_to_root_user();
+
 
                {
                        START_PROFILE(smb2_tdis);
@@ -1208,6 +1369,12 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                        return_value = smbd_smb2_request_error(req, session_status);
                        break;
                }
+               /*
+                * This call needs to be run as user.
+                *
+                * smbd_smb2_request_check_tcon()
+                * calls change_to_user() on success.
+                */
                status = smbd_smb2_request_check_tcon(req);
                if (!NT_STATUS_IS_OK(status)) {
                        return_value = smbd_smb2_request_error(req, status);
@@ -1226,6 +1393,12 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                        return_value = smbd_smb2_request_error(req, session_status);
                        break;
                }
+               /*
+                * This call needs to be run as user.
+                *
+                * smbd_smb2_request_check_tcon()
+                * calls change_to_user() on success.
+                */
                status = smbd_smb2_request_check_tcon(req);
                if (!NT_STATUS_IS_OK(status)) {
                        return_value = smbd_smb2_request_error(req, status);
@@ -1244,6 +1417,12 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                        return_value = smbd_smb2_request_error(req, session_status);
                        break;
                }
+               /*
+                * This call needs to be run as user.
+                *
+                * smbd_smb2_request_check_tcon()
+                * calls change_to_user() on success.
+                */
                status = smbd_smb2_request_check_tcon(req);
                if (!NT_STATUS_IS_OK(status)) {
                        return_value = smbd_smb2_request_error(req, status);
@@ -1262,6 +1441,12 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                        return_value = smbd_smb2_request_error(req, session_status);
                        break;
                }
+               /*
+                * This call needs to be run as user.
+                *
+                * smbd_smb2_request_check_tcon()
+                * calls change_to_user() on success.
+                */
                status = smbd_smb2_request_check_tcon(req);
                if (!NT_STATUS_IS_OK(status)) {
                        return_value = smbd_smb2_request_error(req, status);
@@ -1280,6 +1465,12 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                        return_value = smbd_smb2_request_error(req, session_status);
                        break;
                }
+               /*
+                * This call needs to be run as user.
+                *
+                * smbd_smb2_request_check_tcon()
+                * calls change_to_user() on success.
+                */
                status = smbd_smb2_request_check_tcon(req);
                if (!NT_STATUS_IS_OK(status)) {
                        return_value = smbd_smb2_request_error(req, status);
@@ -1302,6 +1493,12 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                        return_value = smbd_smb2_request_error(req, session_status);
                        break;
                }
+               /*
+                * This call needs to be run as user.
+                *
+                * smbd_smb2_request_check_tcon()
+                * calls change_to_user() on success.
+                */
                status = smbd_smb2_request_check_tcon(req);
                if (!NT_STATUS_IS_OK(status)) {
                        /* Too ugly to live ? JRA. */
@@ -1324,6 +1521,12 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                        return_value = smbd_smb2_request_error(req, session_status);
                        break;
                }
+               /*
+                * This call needs to be run as user.
+                *
+                * smbd_smb2_request_check_tcon()
+                * calls change_to_user() on success.
+                */
                status = smbd_smb2_request_check_tcon(req);
                if (!NT_STATUS_IS_OK(status)) {
                        return_value = smbd_smb2_request_error(req, status);
@@ -1338,6 +1541,13 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                break;
 
        case SMB2_OP_CANCEL:
+               /*
+                * This call needs to be run as root
+                *
+                * That is what we also do in the SMB1 case.
+                */
+               change_to_root_user();
+
                {
                        START_PROFILE(smb2_cancel);
                        return_value = smbd_smb2_request_process_cancel(req);
@@ -1346,9 +1556,14 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                break;
 
        case SMB2_OP_KEEPALIVE:
-               {START_PROFILE(smb2_keepalive);
-               return_value = smbd_smb2_request_process_keepalive(req);
-               END_PROFILE(smb2_keepalive);}
+               /* This call needs to be run as root */
+               change_to_root_user();
+
+               {
+                       START_PROFILE(smb2_keepalive);
+                       return_value = smbd_smb2_request_process_keepalive(req);
+                       END_PROFILE(smb2_keepalive);
+               }
                break;
 
        case SMB2_OP_FIND:
@@ -1356,6 +1571,12 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                        return_value = smbd_smb2_request_error(req, session_status);
                        break;
                }
+               /*
+                * This call needs to be run as user.
+                *
+                * smbd_smb2_request_check_tcon()
+                * calls change_to_user() on success.
+                */
                status = smbd_smb2_request_check_tcon(req);
                if (!NT_STATUS_IS_OK(status)) {
                        return_value = smbd_smb2_request_error(req, status);
@@ -1374,6 +1595,12 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                        return_value = smbd_smb2_request_error(req, session_status);
                        break;
                }
+               /*
+                * This call needs to be run as user.
+                *
+                * smbd_smb2_request_check_tcon()
+                * calls change_to_user() on success.
+                */
                status = smbd_smb2_request_check_tcon(req);
                if (!NT_STATUS_IS_OK(status)) {
                        return_value = smbd_smb2_request_error(req, status);
@@ -1392,6 +1619,12 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                        return_value = smbd_smb2_request_error(req, session_status);
                        break;
                }
+               /*
+                * This call needs to be run as user.
+                *
+                * smbd_smb2_request_check_tcon()
+                * calls change_to_user() on success.
+                */
                status = smbd_smb2_request_check_tcon(req);
                if (!NT_STATUS_IS_OK(status)) {
                        return_value = smbd_smb2_request_error(req, status);
@@ -1410,6 +1643,12 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                        return_value = smbd_smb2_request_error(req, session_status);
                        break;
                }
+               /*
+                * This call needs to be run as user.
+                *
+                * smbd_smb2_request_check_tcon()
+                * calls change_to_user() on success.
+                */
                status = smbd_smb2_request_check_tcon(req);
                if (!NT_STATUS_IS_OK(status)) {
                        return_value = smbd_smb2_request_error(req, status);
@@ -1428,6 +1667,12 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                        return_value = smbd_smb2_request_error(req, session_status);
                        break;
                }
+               /*
+                * This call needs to be run as user.
+                *
+                * smbd_smb2_request_check_tcon()
+                * calls change_to_user() on success.
+                */
                status = smbd_smb2_request_check_tcon(req);
                if (!NT_STATUS_IS_OK(status)) {
                        return_value = smbd_smb2_request_error(req, status);
@@ -2216,6 +2461,8 @@ void smbd_smb2_first_negprot(struct smbd_server_connection *sconn,
                return;
        }
        tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
+
+       sconn->num_requests++;
 }
 
 static void smbd_smb2_request_incoming(struct tevent_req *subreq)
@@ -2272,4 +2519,19 @@ next:
                return;
        }
        tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
+
+       sconn->num_requests++;
+
+       /* The timeout_processing function isn't run nearly
+          often enough to implement 'max log size' without
+          overrunning the size of the file by many megabytes.
+          This is especially true if we are running at debug
+          level 10.  Checking every 50 SMB2s is a nice
+          tradeoff of performance vs log file size overrun. */
+
+       if ((sconn->num_requests % 50) == 0 &&
+           need_to_check_log_size()) {
+               change_to_root_user();
+               check_log_size();
+       }
 }