Add check for invalid data size.
[kamenim/samba.git] / source3 / smbd / nttrans.c
index b79bb0b8f2b65a8b89530c82b0aba3aada64028b..9b3085c327d00108d5bbd389e4b3043fbc4f04a5 100644 (file)
@@ -20,6 +20,8 @@
 
 #include "includes.h"
 #include "smbd/globals.h"
+#include "fake_file.h"
+#include "../librpc/gen_ndr/ndr_security.h"
 
 extern const struct generic_mapping file_generic_mapping;
 
@@ -57,7 +59,7 @@ void send_nt_replies(connection_struct *conn,
        int params_sent_thistime, data_sent_thistime, total_sent_thistime;
        int alignment_offset = 3;
        int data_alignment_offset = 0;
-       struct smbd_server_connection *sconn = smbd_server_conn;
+       struct smbd_server_connection *sconn = req->sconn;
        int max_send = sconn->smb1.sessions.max_send;
 
        /*
@@ -73,7 +75,7 @@ void send_nt_replies(connection_struct *conn,
                                         __LINE__,__FILE__);
                }
                show_msg((char *)req->outbuf);
-               if (!srv_send_smb(smbd_server_fd(),
+               if (!srv_send_smb(sconn,
                                (char *)req->outbuf,
                                true, req->seqnum+1,
                                IS_CONN_ENCRYPTED(conn),
@@ -242,7 +244,7 @@ void send_nt_replies(connection_struct *conn,
 
                /* Send the packet */
                show_msg((char *)req->outbuf);
-               if (!srv_send_smb(smbd_server_fd(),
+               if (!srv_send_smb(sconn,
                                (char *)req->outbuf,
                                true, req->seqnum+1,
                                IS_CONN_ENCRYPTED(conn),
@@ -828,12 +830,16 @@ static void do_nt_transact_create_pipe(connection_struct *conn,
  Internal fn to set security descriptors.
 ****************************************************************************/
 
-static NTSTATUS set_sd(files_struct *fsp, uint8 *data, uint32 sd_len,
-                      uint32 security_info_sent)
+NTSTATUS set_sd(files_struct *fsp, uint8_t *data, uint32_t sd_len,
+                      uint32_t security_info_sent)
 {
-       SEC_DESC *psd = NULL;
+       struct security_descriptor *psd = NULL;
        NTSTATUS status;
 
+       if (!CAN_WRITE(fsp->conn)) {
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
        if (sd_len == 0 || !lp_nt_acl_support(SNUM(fsp->conn))) {
                return NT_STATUS_OK;
        }
@@ -845,10 +851,10 @@ static NTSTATUS set_sd(files_struct *fsp, uint8 *data, uint32 sd_len,
        }
 
        if (psd->owner_sid == NULL) {
-               security_info_sent &= ~OWNER_SECURITY_INFORMATION;
+               security_info_sent &= ~SECINFO_OWNER;
        }
        if (psd->group_sid == NULL) {
-               security_info_sent &= ~GROUP_SECURITY_INFORMATION;
+               security_info_sent &= ~SECINFO_GROUP;
        }
 
        /* Convert all the generic bits. */
@@ -1276,11 +1282,12 @@ void reply_ntcancel(struct smb_request *req)
         */
 
        START_PROFILE(SMBntcancel);
-       srv_cancel_sign_response(smbd_server_conn);
-       remove_pending_change_notify_requests_by_mid(req->mid);
-       remove_pending_lock_requests_by_mid(req->mid);
+       srv_cancel_sign_response(req->sconn);
+       remove_pending_change_notify_requests_by_mid(req->sconn, req->mid);
+       remove_pending_lock_requests_by_mid_smb1(req->sconn, req->mid);
 
-       DEBUG(3,("reply_ntcancel: cancel called on mid = %d.\n", req->mid));
+       DEBUG(3,("reply_ntcancel: cancel called on mid = %llu.\n",
+               (unsigned long long)req->mid));
 
        END_PROFILE(SMBntcancel);
        return;
@@ -1549,6 +1556,8 @@ void reply_ntrename(struct smb_request *req)
                                status = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
                        } else {
                                status = hardlink_internals(ctx, conn,
+                                                           req,
+                                                           false,
                                                            smb_fname_old,
                                                            smb_fname_new);
                        }
@@ -1675,7 +1684,7 @@ static void call_nt_transact_notify_change(connection_struct *conn,
                 * here.
                 */
 
-               change_notify_reply(fsp->conn, req,
+               change_notify_reply(req,
                                    NT_STATUS_OK,
                                    max_param_count,
                                    fsp->notify,
@@ -1754,7 +1763,7 @@ static void call_nt_transact_rename(connection_struct *conn,
  Fake up a completely empty SD.
 *******************************************************************************/
 
-static NTSTATUS get_null_nt_acl(TALLOC_CTX *mem_ctx, SEC_DESC **ppsd)
+static NTSTATUS get_null_nt_acl(TALLOC_CTX *mem_ctx, struct security_descriptor **ppsd)
 {
        size_t sd_size;
 
@@ -1769,6 +1778,75 @@ static NTSTATUS get_null_nt_acl(TALLOC_CTX *mem_ctx, SEC_DESC **ppsd)
 
 /****************************************************************************
  Reply to query a security descriptor.
+ Callable from SMB2 and SMB2.
+ If it returns NT_STATUS_BUFFER_TOO_SMALL, pdata_size is initialized with
+ the required size.
+****************************************************************************/
+
+NTSTATUS smbd_do_query_security_desc(connection_struct *conn,
+                                       TALLOC_CTX *mem_ctx,
+                                       files_struct *fsp,
+                                       uint32_t security_info_wanted,
+                                       uint32_t max_data_count,
+                                       uint8_t **ppmarshalled_sd,
+                                       size_t *psd_size)
+{
+       NTSTATUS status;
+       struct security_descriptor *psd = NULL;
+
+       /*
+        * Get the permissions to return.
+        */
+
+       if (!lp_nt_acl_support(SNUM(conn))) {
+               status = get_null_nt_acl(mem_ctx, &psd);
+       } else {
+               status = SMB_VFS_FGET_NT_ACL(
+                       fsp, security_info_wanted, &psd);
+       }
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       /* If the SACL/DACL is NULL, but was requested, we mark that it is
+        * present in the reply to match Windows behavior */
+       if (psd->sacl == NULL &&
+           security_info_wanted & SECINFO_SACL)
+               psd->type |= SEC_DESC_SACL_PRESENT;
+       if (psd->dacl == NULL &&
+           security_info_wanted & SECINFO_DACL)
+               psd->type |= SEC_DESC_DACL_PRESENT;
+
+       *psd_size = ndr_size_security_descriptor(psd, 0);
+
+       DEBUG(3,("smbd_do_query_security_desc: sd_size = %lu.\n",
+               (unsigned long)*psd_size));
+
+       if (DEBUGLEVEL >= 10) {
+               DEBUG(10,("smbd_do_query_security_desc for file %s\n",
+                         fsp_str_dbg(fsp)));
+               NDR_PRINT_DEBUG(security_descriptor, psd);
+       }
+
+       if (max_data_count < *psd_size) {
+               TALLOC_FREE(psd);
+               return NT_STATUS_BUFFER_TOO_SMALL;
+       }
+
+       status = marshall_sec_desc(mem_ctx, psd,
+                                  ppmarshalled_sd, psd_size);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(psd);
+               return status;
+       }
+
+       TALLOC_FREE(psd);
+       return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ SMB1 reply to query a security descriptor.
 ****************************************************************************/
 
 static void call_nt_transact_query_security_desc(connection_struct *conn,
@@ -1783,12 +1861,11 @@ static void call_nt_transact_query_security_desc(connection_struct *conn,
 {
        char *params = *ppparams;
        char *data = *ppdata;
-       SEC_DESC *psd = NULL;
-       size_t sd_size;
+       size_t sd_size = 0;
        uint32 security_info_wanted;
        files_struct *fsp = NULL;
        NTSTATUS status;
-       DATA_BLOB blob;
+       uint8_t *marshalled_sd = NULL;
 
         if(parameter_count < 8) {
                reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
@@ -1817,46 +1894,38 @@ static void call_nt_transact_query_security_desc(connection_struct *conn,
         * Get the permissions to return.
         */
 
-       if (!lp_nt_acl_support(SNUM(conn))) {
-               status = get_null_nt_acl(talloc_tos(), &psd);
-       } else {
-               status = SMB_VFS_FGET_NT_ACL(
-                       fsp, security_info_wanted, &psd);
-       }
+       status = smbd_do_query_security_desc(conn,
+                                       talloc_tos(),
+                                       fsp,
+                                       security_info_wanted,
+                                       max_data_count,
+                                       &marshalled_sd,
+                                       &sd_size);
+
+       if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
+               SIVAL(params,0,(uint32_t)sd_size);
+               send_nt_replies(conn, req, NT_STATUS_BUFFER_TOO_SMALL,
+                       params, 4, NULL, 0);
+               return;
+        }
+
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);
                return;
        }
 
-       /* If the SACL/DACL is NULL, but was requested, we mark that it is
-        * present in the reply to match Windows behavior */
-       if (psd->sacl == NULL &&
-           security_info_wanted & SACL_SECURITY_INFORMATION)
-               psd->type |= SEC_DESC_SACL_PRESENT;
-       if (psd->dacl == NULL &&
-           security_info_wanted & DACL_SECURITY_INFORMATION)
-               psd->type |= SEC_DESC_DACL_PRESENT;
-
-       sd_size = ndr_size_security_descriptor(psd, NULL, 0);
+       SMB_ASSERT(sd_size > 0);
 
-       DEBUG(3,("call_nt_transact_query_security_desc: sd_size = %lu.\n",(unsigned long)sd_size));
-
-       if (DEBUGLEVEL >= 10) {
-               DEBUG(10,("call_nt_transact_query_security_desc for file %s\n",
-                         fsp_str_dbg(fsp)));
-               NDR_PRINT_DEBUG(security_descriptor, psd);
-       }
-
-       SIVAL(params,0,(uint32)sd_size);
+       SIVAL(params,0,(uint32_t)sd_size);
 
        if (max_data_count < sd_size) {
                send_nt_replies(conn, req, NT_STATUS_BUFFER_TOO_SMALL,
-                               params, 4, *ppdata, 0);
+                               params, 4, NULL, 0);
                return;
        }
 
        /*
-        * Allocate the data we will point this at.
+        * Allocate the data we will return.
         */
 
        data = nttrans_realloc(ppdata, sd_size);
@@ -1865,16 +1934,7 @@ static void call_nt_transact_query_security_desc(connection_struct *conn,
                return;
        }
 
-       status = marshall_sec_desc(talloc_tos(), psd,
-                                  &blob.data, &blob.length);
-
-       if (!NT_STATUS_IS_OK(status)) {
-               reply_nterror(req, status);
-               return;
-       }
-
-       SMB_ASSERT(sd_size == blob.length);
-       memcpy(data, blob.data, sd_size);
+       memcpy(data, marshalled_sd, sd_size);
 
        send_nt_replies(conn, req, NT_STATUS_OK, params, 4, data, (int)sd_size);
 
@@ -1911,6 +1971,11 @@ static void call_nt_transact_set_security_desc(connection_struct *conn,
                return;
        }
 
+       if (!CAN_WRITE(fsp->conn)) {
+               reply_nterror(req, NT_STATUS_ACCESS_DENIED);
+               return;
+       }
+
        if(!lp_nt_acl_support(SNUM(conn))) {
                goto done;
        }
@@ -1996,7 +2061,7 @@ static void call_nt_transact_ioctl(connection_struct *conn,
 
                DEBUG(10,("FSCTL_CREATE_OR_GET_OBJECT_ID: called on FID[0x%04X]\n",fidnum));
 
-               if (!fsp_belongs_conn(conn, req, fsp)) {
+               if (!check_fsp_open(conn, req, fsp)) {
                        return;
                }
 
@@ -2053,7 +2118,7 @@ static void call_nt_transact_ioctl(connection_struct *conn,
                uint32 i;
                char *cur_pdata;
 
-               if (!fsp_belongs_conn(conn, req, fsp)) {
+               if (!check_fsp_open(conn, req, fsp)) {
                        return;
                }
 
@@ -2170,16 +2235,23 @@ static void call_nt_transact_ioctl(connection_struct *conn,
                 *
                 * but I have to check that --metze
                 */
-               DOM_SID sid;
+               struct dom_sid sid;
                uid_t uid;
-               size_t sid_len = MIN(data_count-4,SID_MAX_SIZE);
+               size_t sid_len;
 
                DEBUG(10,("FSCTL_FIND_FILES_BY_SID: called on FID[0x%04X]\n",fidnum));
 
-               if (!fsp_belongs_conn(conn, req, fsp)) {
+               if (!check_fsp_open(conn, req, fsp)) {
                        return;
                }
 
+               if (data_count < 8) {
+                       reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+                       return;
+               }
+
+               sid_len = MIN(data_count-4,SID_MAX_SIZE);
+
                /* unknown 4 bytes: this is not the length of the sid :-(  */
                /*unknown = IVAL(pdata,0);*/
 
@@ -2215,6 +2287,64 @@ static void call_nt_transact_ioctl(connection_struct *conn,
                send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0);
                return;
        }
+       case FSCTL_QUERY_ALLOCATED_RANGES:
+       {
+               /* FIXME: This is just a dummy reply, telling that all of the
+                * file is allocated. MKS cp needs that.
+                * Adding the real allocated ranges via FIEMAP on Linux
+                * and SEEK_DATA/SEEK_HOLE on Solaris is needed to make
+                * this FSCTL correct for sparse files.
+                */
+               NTSTATUS status;
+               uint64_t offset, length;
+
+               if (!check_fsp_open(conn, req, fsp)) {
+                       return;
+               }
+
+               if (data_count != 16) {
+                       DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: data_count(%u) != 16 is invalid!\n",
+                               data_count));
+                       reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+                       return;
+               }
+
+               if (max_data_count < 16) {
+                       DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: max_data_count(%u) < 16 is invalid!\n",
+                               max_data_count));
+                       reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+                       return;
+               }
+
+               offset = BVAL(pdata,0);
+               length = BVAL(pdata,8);
+
+               if (offset + length < offset) {
+                       /* No 64-bit integer wrap. */
+                       reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+                       return;
+               }
+
+               status = vfs_stat_fsp(fsp);
+               if (!NT_STATUS_IS_OK(status)) {
+                       reply_nterror(req, status);
+                       return;
+               }
+
+               if (offset > fsp->fsp_name->st.st_ex_size ||
+                               fsp->fsp_name->st.st_ex_size == 0 ||
+                               length == 0) {
+                       send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0);
+               } else {
+                       uint64_t end = offset + length;
+                       end = MIN(end, fsp->fsp_name->st.st_ex_size);
+                       SBVAL(pdata,0,0);
+                       SBVAL(pdata,8,end);
+                       send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0,
+                               pdata, 16);
+               }
+               return;
+       }
        default:
                if (!logged_ioctl_message) {
                        logged_ioctl_message = true; /* Only print this once... */
@@ -2252,7 +2382,7 @@ static void call_nt_transact_get_user_quota(connection_struct *conn,
        files_struct *fsp = NULL;
        uint16 level = 0;
        size_t sid_len;
-       DOM_SID sid;
+       struct dom_sid sid;
        bool start_enum = True;
        SMB_NTQUOTA_STRUCT qt;
        SMB_NTQUOTA_LIST *tmp_list;
@@ -2368,7 +2498,7 @@ static void call_nt_transact_get_user_quota(connection_struct *conn,
                                tmp_list=tmp_list->next,entry+=entry_len,qt_len+=entry_len) {
 
                                sid_len = ndr_size_dom_sid(
-                                       &tmp_list->quotas->sid, NULL, 0);
+                                       &tmp_list->quotas->sid, 0);
                                entry_len = 40 + sid_len;
 
                                /* nextoffset entry 4 bytes */
@@ -2522,7 +2652,7 @@ static void call_nt_transact_set_user_quota(connection_struct *conn,
        int data_len=0,param_len=0;
        SMB_NTQUOTA_STRUCT qt;
        size_t sid_len;
-       DOM_SID sid;
+       struct dom_sid sid;
        files_struct *fsp = NULL;
 
        ZERO_STRUCT(qt);