smbd: some write time fixes
[tprouty/samba.git] / source / smbd / nttrans.c
index ae64c06215687d9982d3e018941dee9456d32ae3..0b48fa2c4d522104de041149bb013ccec8ead3b7 100644 (file)
@@ -271,6 +271,9 @@ void send_nt_replies(connection_struct *conn,
 
 /****************************************************************************
  Is it an NTFS stream name ?
+ An NTFS file name is <path>.<extention>:<stream name>:<stream type>
+ $DATA can be used as both a stream name and a stream type. A missing stream
+ name or type implies $DATA.
 ****************************************************************************/
 
 bool is_ntfs_stream_name(const char *fname)
@@ -486,6 +489,12 @@ void reply_ntcreate_and_X(struct smb_request *req)
                        (unsigned int)root_dir_fid,
                        fname));
 
+       /*
+        * we need to remove ignored bits when they come directly from the client
+        * because we reuse some of them for internal stuff
+        */
+       create_options &= ~NTCREATEX_OPTIONS_MUST_IGNORE_MASK;
+
        /*
         * If it's an IPC, use the pipe handler.
         */
@@ -495,11 +504,10 @@ void reply_ntcreate_and_X(struct smb_request *req)
                        do_ntcreate_pipe_open(conn, req);
                        END_PROFILE(SMBntcreateX);
                        return;
-               } else {
-                       reply_doserror(req, ERRDOS, ERRnoaccess);
-                       END_PROFILE(SMBntcreateX);
-                       return;
                }
+               reply_doserror(req, ERRDOS, ERRnoaccess);
+               END_PROFILE(SMBntcreateX);
+               return;
        }
 
        oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
@@ -555,7 +563,7 @@ void reply_ntcreate_and_X(struct smb_request *req)
        }
 
        file_len = sbuf.st_size;
-       fattr = dos_mode(conn,fname,&sbuf);
+       fattr = dos_mode(conn,fsp->fsp_name,&sbuf);
        if (fattr == 0) {
                fattr = FILE_ATTRIBUTE_NORMAL;
        }
@@ -623,7 +631,7 @@ void reply_ntcreate_and_X(struct smb_request *req)
                uint32 perms = 0;
                p += 25;
                if (fsp->is_directory
-                   || can_write_to_file(conn, fname, &sbuf)) {
+                   || can_write_to_file(conn, fsp->fsp_name, &sbuf)) {
                        perms = FILE_GENERIC_ALL;
                } else {
                        perms = FILE_GENERIC_READ|FILE_EXECUTE;
@@ -868,10 +876,9 @@ static void call_nt_transact_create(connection_struct *conn,
                                ppparams, parameter_count,
                                ppdata, data_count);
                        return;
-               } else {
-                       reply_doserror(req, ERRDOS, ERRnoaccess);
-                       return;
                }
+               reply_doserror(req, ERRDOS, ERRnoaccess);
+               return;
        }
 
        /*
@@ -898,6 +905,12 @@ static void call_nt_transact_create(connection_struct *conn,
        allocation_size |= (((SMB_BIG_UINT)IVAL(params,16)) << 32);
 #endif
 
+       /*
+        * we need to remove ignored bits when they come directly from the client
+        * because we reuse some of them for internal stuff
+        */
+       create_options &= ~NTCREATEX_OPTIONS_MUST_IGNORE_MASK;
+
        /* Ensure the data_len is correct for the sd and ea values given. */
        if ((ea_len + sd_len > data_count)
            || (ea_len > data_count) || (sd_len > data_count)
@@ -1004,7 +1017,7 @@ static void call_nt_transact_create(connection_struct *conn,
        }
 
        file_len = sbuf.st_size;
-       fattr = dos_mode(conn,fname,&sbuf);
+       fattr = dos_mode(conn,fsp->fsp_name,&sbuf);
        if (fattr == 0) {
                fattr = FILE_ATTRIBUTE_NORMAL;
        }
@@ -1072,7 +1085,7 @@ static void call_nt_transact_create(connection_struct *conn,
                uint32 perms = 0;
                p += 25;
                if (fsp->is_directory
-                   || can_write_to_file(conn, fname, &sbuf)) {
+                   || can_write_to_file(conn, fsp->fsp_name, &sbuf)) {
                        perms = FILE_GENERIC_ALL;
                } else {
                        perms = FILE_GENERIC_READ|FILE_EXECUTE;
@@ -1080,7 +1093,7 @@ static void call_nt_transact_create(connection_struct *conn,
                SIVAL(p,0,perms);
        }
 
-       DEBUG(5,("call_nt_transact_create: open name = %s\n", fname));
+       DEBUG(5,("call_nt_transact_create: open name = %s\n", fsp->fsp_name));
 
        /* Send the required number of replies */
        send_nt_replies(conn, req, NT_STATUS_OK, params, param_len, *ppdata, 0);
@@ -1230,7 +1243,7 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx,
        close_file(fsp1,NORMAL_CLOSE);
 
        /* Ensure the modtime is set correctly on the destination file. */
-       fsp_set_pending_modtime(fsp2, get_mtimespec(&sbuf1));
+       set_close_write_time(fsp2, get_mtimespec(&sbuf1));
 
        status = close_file(fsp2,NORMAL_CLOSE);
 
@@ -1350,7 +1363,7 @@ void reply_ntrename(struct smb_request *req)
                case RENAME_FLAG_RENAME:
                        status = rename_internals(ctx, conn, req, oldname,
                                        newname, attrs, False, src_has_wcard,
-                                       dest_has_wcard);
+                                       dest_has_wcard, DELETE_ACCESS);
                        break;
                case RENAME_FLAG_HARD_LINK:
                        if (src_has_wcard || dest_has_wcard) {
@@ -1515,7 +1528,6 @@ static void call_nt_transact_rename(connection_struct *conn,
        char *params = *ppparams;
        char *new_name = NULL;
        files_struct *fsp = NULL;
-       bool replace_if_exists = False;
        bool dest_has_wcard = False;
        NTSTATUS status;
        TALLOC_CTX *ctx = talloc_tos();
@@ -1526,7 +1538,6 @@ static void call_nt_transact_rename(connection_struct *conn,
        }
 
        fsp = file_fsp(SVAL(params, 0));
-       replace_if_exists = (SVAL(params,2) & RENAME_REPLACE_IF_EXISTS) ? True : False;
        if (!check_fsp(conn, req, fsp, &current_user)) {
                return;
        }
@@ -1538,31 +1549,13 @@ static void call_nt_transact_rename(connection_struct *conn,
                return;
        }
 
-       status = rename_internals(ctx,
-                       conn,
-                       req,
-                       fsp->fsp_name,
-                       new_name,
-                       0,
-                       replace_if_exists,
-                       False,
-                       dest_has_wcard);
-
-       if (!NT_STATUS_IS_OK(status)) {
-               if (open_was_deferred(req->mid)) {
-                       /* We have re-scheduled this call. */
-                       return;
-               }
-               reply_nterror(req, status);
-               return;
-       }
-
        /*
-        * Rename was successful.
+        * W2K3 ignores this request as the RAW-RENAME test
+        * demonstrates, so we do.
         */
        send_nt_replies(conn, req, NT_STATUS_OK, NULL, 0, NULL, 0);
 
-       DEBUG(3,("nt transact rename from = %s, to = %s succeeded.\n",
+       DEBUG(3,("nt transact rename from = %s, to = %s ignored!\n",
                 fsp->fsp_name, new_name));
 
        return;
@@ -1604,7 +1597,6 @@ static void call_nt_transact_query_security_desc(connection_struct *conn,
        SEC_DESC *psd = NULL;
        size_t sd_size;
        uint32 security_info_wanted;
-       TALLOC_CTX *frame;
        files_struct *fsp = NULL;
        NTSTATUS status;
        DATA_BLOB blob;
@@ -1631,8 +1623,6 @@ static void call_nt_transact_query_security_desc(connection_struct *conn,
                return;
        }
 
-       frame = talloc_stackframe();
-
        /*
         * Get the permissions to return.
         */
@@ -1651,7 +1641,6 @@ static void call_nt_transact_query_security_desc(connection_struct *conn,
        }
 
        if (!NT_STATUS_IS_OK(status)) {
-               TALLOC_FREE(frame);
                reply_nterror(req, status);
                return;
        }
@@ -1665,7 +1654,6 @@ static void call_nt_transact_query_security_desc(connection_struct *conn,
        if (max_data_count < sd_size) {
                send_nt_replies(conn, req, NT_STATUS_BUFFER_TOO_SMALL,
                                params, 4, *ppdata, 0);
-               TALLOC_FREE(frame);
                return;
        }
 
@@ -1675,7 +1663,6 @@ static void call_nt_transact_query_security_desc(connection_struct *conn,
 
        data = nttrans_realloc(ppdata, sd_size);
        if(data == NULL) {
-               TALLOC_FREE(frame);
                reply_doserror(req, ERRDOS, ERRnomem);
                return;
        }
@@ -1684,7 +1671,6 @@ static void call_nt_transact_query_security_desc(connection_struct *conn,
                                   &blob.data, &blob.length);
 
        if (!NT_STATUS_IS_OK(status)) {
-               TALLOC_FREE(frame);
                reply_nterror(req, status);
                return;
        }
@@ -1694,7 +1680,6 @@ static void call_nt_transact_query_security_desc(connection_struct *conn,
 
        send_nt_replies(conn, req, NT_STATUS_OK, params, 4, data, (int)sd_size);
 
-       TALLOC_FREE(frame);
        return;
 }
 
@@ -2582,14 +2567,15 @@ static void handle_nttrans(connection_struct *conn,
 void reply_nttrans(struct smb_request *req)
 {
        connection_struct *conn = req->conn;
-       uint32 pscnt;
-       uint32 psoff;
-       uint32 dscnt;
-       uint32 dsoff;
+       uint32_t pscnt;
+       uint32_t psoff;
+       uint32_t dscnt;
+       uint32_t dsoff;
        uint16 function_code;
        NTSTATUS result;
        struct trans_state *state;
-       int size;
+       uint32_t size;
+       uint32_t av_size;
 
        START_PROFILE(SMBnttrans);
 
@@ -2600,6 +2586,7 @@ void reply_nttrans(struct smb_request *req)
        }
 
        size = smb_len(req->inbuf) + 4;
+       av_size = smb_len(req->inbuf);
        pscnt = IVAL(req->inbuf,smb_nt_ParameterCount);
        psoff = IVAL(req->inbuf,smb_nt_ParameterOffset);
        dscnt = IVAL(req->inbuf,smb_nt_DataCount);
@@ -2675,12 +2662,17 @@ void reply_nttrans(struct smb_request *req)
                        END_PROFILE(SMBnttrans);
                        return;
                }
-               if ((dsoff+dscnt < dsoff) || (dsoff+dscnt < dscnt))
+
+               if (dscnt > state->total_data ||
+                               dsoff+dscnt < dsoff) {
                        goto bad_param;
-               if ((smb_base(req->inbuf)+dsoff+dscnt
-                    > (char *)req->inbuf + size) ||
-                   (smb_base(req->inbuf)+dsoff+dscnt < smb_base(req->inbuf)))
+               }
+
+               if (dsoff > av_size ||
+                               dscnt > av_size ||
+                               dsoff+dscnt > av_size) {
                        goto bad_param;
+               }
 
                memcpy(state->data,smb_base(req->inbuf)+dsoff,dscnt);
        }
@@ -2697,12 +2689,17 @@ void reply_nttrans(struct smb_request *req)
                        END_PROFILE(SMBnttrans);
                        return;
                }
-               if ((psoff+pscnt < psoff) || (psoff+pscnt < pscnt))
+
+               if (pscnt > state->total_param ||
+                               psoff+pscnt < psoff) {
                        goto bad_param;
-               if ((smb_base(req->inbuf)+psoff+pscnt
-                    > (char *)req->inbuf + size) ||
-                   (smb_base(req->inbuf)+psoff+pscnt < smb_base(req->inbuf)))
+               }
+
+               if (psoff > av_size ||
+                               pscnt > av_size ||
+                               psoff+pscnt > av_size) {
                        goto bad_param;
+               }
 
                memcpy(state->param,smb_base(req->inbuf)+psoff,pscnt);
        }
@@ -2774,10 +2771,10 @@ void reply_nttrans(struct smb_request *req)
 void reply_nttranss(struct smb_request *req)
 {
        connection_struct *conn = req->conn;
-       unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp;
+       uint32_t pcnt,poff,dcnt,doff,pdisp,ddisp;
        struct trans_state *state;
-
-       int size;
+       uint32_t av_size;
+       uint32_t size;
 
        START_PROFILE(SMBnttranss);
 
@@ -2814,6 +2811,7 @@ void reply_nttranss(struct smb_request *req)
        }
 
        size = smb_len(req->inbuf) + 4;
+       av_size = smb_len(req->inbuf);
 
        pcnt = IVAL(req->inbuf,smb_nts_ParameterCount);
        poff = IVAL(req->inbuf, smb_nts_ParameterOffset);
@@ -2831,38 +2829,38 @@ void reply_nttranss(struct smb_request *req)
                goto bad_param;
 
        if (pcnt) {
-               if (pdisp+pcnt > state->total_param)
+               if (pdisp > state->total_param ||
+                               pcnt > state->total_param ||
+                               pdisp+pcnt > state->total_param ||
+                               pdisp+pcnt < pdisp) {
                        goto bad_param;
-               if ((pdisp+pcnt < pdisp) || (pdisp+pcnt < pcnt))
-                       goto bad_param;
-               if (pdisp > state->total_param)
-                       goto bad_param;
-               if ((smb_base(req->inbuf) + poff + pcnt
-                    > (char *)req->inbuf + size) ||
-                   (smb_base(req->inbuf) + poff + pcnt
-                    < smb_base(req->inbuf)))
-                       goto bad_param;
-               if (state->param + pdisp < state->param)
+               }
+
+               if (poff > av_size ||
+                               pcnt > av_size ||
+                               poff+pcnt > av_size ||
+                               poff+pcnt < poff) {
                        goto bad_param;
+               }
 
                memcpy(state->param+pdisp, smb_base(req->inbuf)+poff,
                       pcnt);
        }
 
        if (dcnt) {
-               if (ddisp+dcnt > state->total_data)
+               if (ddisp > state->total_data ||
+                               dcnt > state->total_data ||
+                               ddisp+dcnt > state->total_data ||
+                               ddisp+dcnt < ddisp) {
                        goto bad_param;
-               if ((ddisp+dcnt < ddisp) || (ddisp+dcnt < dcnt))
-                       goto bad_param;
-               if (ddisp > state->total_data)
-                       goto bad_param;
-               if ((smb_base(req->inbuf) + doff + dcnt
-                    > (char *)req->inbuf + size) ||
-                   (smb_base(req->inbuf) + doff + dcnt
-                    < smb_base(req->inbuf)))
-                       goto bad_param;
-               if (state->data + ddisp < state->data)
+               }
+
+               if (ddisp > av_size ||
+                               dcnt > av_size ||
+                               ddisp+dcnt > av_size ||
+                               ddisp+dcnt < ddisp) {
                        goto bad_param;
+               }
 
                memcpy(state->data+ddisp, smb_base(req->inbuf)+doff,
                       dcnt);