r23727: Explicitly pass down FLAGS2 to srvstr_get_path.
[ira/wip.git] / source3 / smbd / nttrans.c
index 90a208585943838e65708757e4e63ad7eaab1880..8865afad0d5cb7a45efa103653083aa26097ac76 100644 (file)
@@ -50,7 +50,7 @@ static const char *known_nt_pipes[] = {
 static char *nttrans_realloc(char **ptr, size_t size)
 {
        if (ptr==NULL) {
-               smb_panic("nttrans_realloc() called with NULL ptr\n");
+               smb_panic("nttrans_realloc() called with NULL ptr");
        }
                
        *ptr = (char *)SMB_REALLOC(*ptr, size);
@@ -68,9 +68,14 @@ static char *nttrans_realloc(char **ptr, size_t size)
  HACK ! Always assumes smb_setup field is zero.
 ****************************************************************************/
 
-static int send_nt_replies(char *outbuf, int bufsize, NTSTATUS nt_error,
-                          char *params, int paramsize, char *pdata,
-                          int datasize)
+int send_nt_replies(const char *inbuf,
+                       char *outbuf,
+                       int bufsize,
+                       NTSTATUS nt_error,
+                       char *params,
+                       int paramsize,
+                       char *pdata,
+                       int datasize)
 {
        int data_to_send = datasize;
        int params_to_send = paramsize;
@@ -86,7 +91,7 @@ static int send_nt_replies(char *outbuf, int bufsize, NTSTATUS nt_error,
         * transNT replies.
         */
 
-       set_message(outbuf,18,0,True);
+       set_message(inbuf,outbuf,18,0,True);
 
        if (NT_STATUS_V(nt_error)) {
                ERROR_NT(nt_error);
@@ -100,7 +105,7 @@ static int send_nt_replies(char *outbuf, int bufsize, NTSTATUS nt_error,
        if(params_to_send == 0 && data_to_send == 0) {
                show_msg(outbuf);
                if (!send_smb(smbd_server_fd(),outbuf)) {
-                       exit_server("send_nt_replies: send_smb failed.");
+                       exit_server_cleanly("send_nt_replies: send_smb failed.");
                }
                return 0;
        }
@@ -150,7 +155,7 @@ static int send_nt_replies(char *outbuf, int bufsize, NTSTATUS nt_error,
 
                total_sent_thistime = MIN(total_sent_thistime, useable_space);
 
-               set_message(outbuf, 18, total_sent_thistime, True);
+               set_message(inbuf,outbuf, 18, total_sent_thistime, True);
 
                /*
                 * Set total params and data to be sent.
@@ -235,7 +240,7 @@ static int send_nt_replies(char *outbuf, int bufsize, NTSTATUS nt_error,
                /* Send the packet */
                show_msg(outbuf);
                if (!send_smb(smbd_server_fd(),outbuf)) {
-                       exit_server("send_nt_replies: send_smb failed.");
+                       exit_server_cleanly("send_nt_replies: send_smb failed.");
                }
     
                pp += params_sent_thistime;
@@ -282,10 +287,10 @@ static BOOL saved_short_case_preserve;
  Save case semantics.
 ****************************************************************************/
 
-static void set_posix_case_semantics(connection_struct *conn, uint32 file_attributes)
+static uint32 set_posix_case_semantics(connection_struct *conn, uint32 file_attributes)
 {
        if(!(file_attributes & FILE_FLAG_POSIX_SEMANTICS)) {
-               return;
+               return file_attributes;
        }
 
        saved_case_sensitive = conn->case_sensitive;
@@ -296,6 +301,8 @@ static void set_posix_case_semantics(connection_struct *conn, uint32 file_attrib
        conn->case_sensitive = True;
        conn->case_preserve = True;
        conn->short_case_preserve = True;
+
+       return (file_attributes & ~FILE_FLAG_POSIX_SEMANTICS);
 }
 
 /****************************************************************************
@@ -373,8 +380,10 @@ static int do_ntcreate_pipe_open(connection_struct *conn,
        int ret;
        int pnum = -1;
        char *p = NULL;
+       uint32 flags = IVAL(inbuf,smb_ntcreate_Flags);
 
-       srvstr_pull_buf(inbuf, fname, smb_buf(inbuf), sizeof(fname), STR_TERMINATE);
+       srvstr_pull_buf(inbuf, SVAL(inbuf, smb_flg2), fname, smb_buf(inbuf),
+                       sizeof(fname), STR_TERMINATE);
 
        if ((ret = nt_open_pipe(fname, conn, inbuf, outbuf, &pnum)) != 0) {
                return ret;
@@ -384,7 +393,17 @@ static int do_ntcreate_pipe_open(connection_struct *conn,
         * Deal with pipe return.
         */  
 
-       set_message(outbuf,34,0,True);
+       if (flags & EXTENDED_RESPONSE_REQUIRED) {
+               /* This is very strange. We
+                * return 50 words, but only set
+                * the wcnt to 42 ? It's definately
+                * what happens on the wire....
+                */
+               set_message(inbuf,outbuf,50,0,True);
+               SCVAL(outbuf,smb_wct,42);
+       } else {
+               set_message(inbuf,outbuf,34,0,True);
+       }
 
        p = outbuf + smb_vwv2;
        p++;
@@ -399,6 +418,18 @@ static int do_ntcreate_pipe_open(connection_struct *conn,
        SSVAL(p,0,FILE_TYPE_MESSAGE_MODE_PIPE);
        /* Device state. */
        SSVAL(p,2, 0x5FF); /* ? */
+       p += 4;
+
+       if (flags & EXTENDED_RESPONSE_REQUIRED) {
+               p += 25;
+               SIVAL(p,0,FILE_GENERIC_ALL);
+               /* 
+                * For pipes W2K3 seems to return
+                * 0x12019B next.
+                * This is ((FILE_GENERIC_READ|FILE_GENERIC_WRITE) & ~FILE_APPEND_DATA)
+                */
+               SIVAL(p,4,(FILE_GENERIC_READ|FILE_GENERIC_WRITE)&~FILE_APPEND_DATA);
+       }
 
        DEBUG(5,("do_ntcreate_pipe_open: open pipe = %s\n", fname));
 
@@ -430,7 +461,7 @@ int reply_ntcreate_and_X_quota(connection_struct *conn,
                return ERROR_NT(status);
        }
 
-       set_message(outbuf,34,0,True);
+       set_message(inbuf,outbuf,34,0,True);
        
        p = outbuf + smb_vwv2;
        
@@ -456,6 +487,7 @@ int reply_ntcreate_and_X(connection_struct *conn,
        uint32 flags = IVAL(inbuf,smb_ntcreate_Flags);
        uint32 access_mask = IVAL(inbuf,smb_ntcreate_DesiredAccess);
        uint32 file_attributes = IVAL(inbuf,smb_ntcreate_FileAttributes);
+       uint32 new_file_attributes;
        uint32 share_access = IVAL(inbuf,smb_ntcreate_ShareAccess);
        uint32 create_disposition = IVAL(inbuf,smb_ntcreate_CreateDisposition);
        uint32 create_options = IVAL(inbuf,smb_ntcreate_CreateOptions);
@@ -467,14 +499,14 @@ int reply_ntcreate_and_X(connection_struct *conn,
        SMB_OFF_T file_len = 0;
        SMB_STRUCT_STAT sbuf;
        int info = 0;
-       BOOL bad_path = False;
-       files_struct *fsp=NULL;
+       files_struct *fsp = NULL;
        char *p = NULL;
        struct timespec c_timespec;
        struct timespec a_timespec;
        struct timespec m_timespec;
        BOOL extended_oplock_granted = False;
        NTSTATUS status;
+       struct smb_request req;
 
        START_PROFILE(SMBntcreateX);
 
@@ -490,7 +522,11 @@ int reply_ntcreate_and_X(connection_struct *conn,
                        (unsigned int)create_options,
                        (unsigned int)root_dir_fid ));
 
-       /* If it's an IPC, use the pipe handler. */
+       init_smb_request(&req, (uint8 *)inbuf);
+
+       /*
+        * If it's an IPC, use the pipe handler.
+        */
 
        if (IS_IPC(conn)) {
                if (lp_nt_pipe_support()) {
@@ -501,7 +537,7 @@ int reply_ntcreate_and_X(connection_struct *conn,
                        return(ERROR_DOS(ERRDOS,ERRnoaccess));
                }
        }
-                       
+
        if (create_options & FILE_OPEN_BY_FILE_ID) {
                END_PROFILE(SMBntcreateX);
                return ERROR_NT(NT_STATUS_NOT_SUPPORTED);
@@ -521,18 +557,20 @@ int reply_ntcreate_and_X(connection_struct *conn,
 
                if(!dir_fsp) {
                        END_PROFILE(SMBntcreateX);
-                       return(ERROR_DOS(ERRDOS,ERRbadfid));
+                       return ERROR_DOS(ERRDOS,ERRbadfid);
                }
 
                if(!dir_fsp->is_directory) {
 
-                       srvstr_get_path(inbuf, fname, smb_buf(inbuf), sizeof(fname), 0, STR_TERMINATE, &status);
+                       srvstr_get_path(inbuf, SVAL(inbuf,smb_flg2), fname,
+                                       smb_buf(inbuf), sizeof(fname), 0,
+                                       STR_TERMINATE, &status);
                        if (!NT_STATUS_IS_OK(status)) {
                                END_PROFILE(SMBntcreateX);
                                return ERROR_NT(status);
                        }
 
-                       /* 
+                       /*
                         * Check to see if this is a mac fork of some kind.
                         */
 
@@ -563,25 +601,29 @@ int reply_ntcreate_and_X(connection_struct *conn,
                 * Ensure it ends in a '\'.
                 */
 
-               if(fname[dir_name_len-1] != '\\' && fname[dir_name_len-1] != '/') {
+               if((fname[dir_name_len-1] != '\\') && (fname[dir_name_len-1] != '/')) {
                        pstrcat(fname, "/");
                        dir_name_len++;
                }
 
-               srvstr_get_path(inbuf, rel_fname, smb_buf(inbuf), sizeof(rel_fname), 0, STR_TERMINATE, &status);
+               srvstr_get_path(inbuf, SVAL(inbuf,smb_flg2), rel_fname,
+                               smb_buf(inbuf), sizeof(rel_fname), 0,
+                               STR_TERMINATE, &status);
                if (!NT_STATUS_IS_OK(status)) {
                        END_PROFILE(SMBntcreateX);
                        return ERROR_NT(status);
                }
                pstrcat(fname, rel_fname);
        } else {
-               srvstr_get_path(inbuf, fname, smb_buf(inbuf), sizeof(fname), 0, STR_TERMINATE, &status);
+               srvstr_get_path(inbuf, SVAL(inbuf,smb_flg2), fname,
+                               smb_buf(inbuf), sizeof(fname), 0,
+                               STR_TERMINATE, &status);
                if (!NT_STATUS_IS_OK(status)) {
                        END_PROFILE(SMBntcreateX);
                        return ERROR_NT(status);
                }
 
-               /* 
+               /*
                 * Check to see if this is a mac fork of some kind.
                 */
 
@@ -612,7 +654,14 @@ int reply_ntcreate_and_X(connection_struct *conn,
         * Now contruct the smb_open_mode value from the filename, 
         * desired access and the share access.
         */
-       RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+       status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBntcreateX);
+               if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+                       return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+               }
+               return ERROR_NT(status);
+       }
 
        oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
        if (oplock_request) {
@@ -627,71 +676,87 @@ int reply_ntcreate_and_X(connection_struct *conn,
         * Check if POSIX semantics are wanted.
         */
                
-       set_posix_case_semantics(conn, file_attributes);
+       new_file_attributes = set_posix_case_semantics(conn, file_attributes);
                
-       unix_convert(fname,conn,0,&bad_path,&sbuf);
-
-       if (bad_path) {
+       status = unix_convert(conn, fname, False, NULL, &sbuf);
+       if (!NT_STATUS_IS_OK(status)) {
                restore_case_semantics(conn, file_attributes);
                END_PROFILE(SMBntcreateX);
-               return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+               return ERROR_NT(status);
        }
        /* All file access must go through check_name() */
-       if (!check_name(fname,conn)) {
+       status = check_name(conn, fname);
+       if (!NT_STATUS_IS_OK(status)) {
                restore_case_semantics(conn, file_attributes);
                END_PROFILE(SMBntcreateX);
-               return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
+               return ERROR_NT(status);
        }
 
-#if 0
        /* This is the correct thing to do (check every time) but can_delete is
           expensive (it may have to read the parent directory permissions). So
           for now we're not doing it unless we have a strong hint the client
-          is really going to delete this file. */
-       if (desired_access & DELETE_ACCESS) {
-#else
+          is really going to delete this file. If the client is forcing FILE_CREATE
+          let the filesystem take care of the permissions. */
+
        /* Setting FILE_SHARE_DELETE is the hint. */
-       if (lp_acl_check_permissions(SNUM(conn)) && (share_access & FILE_SHARE_DELETE)
-                               && (access_mask & DELETE_ACCESS)) {
-#endif
-               status = can_delete(conn, fname, file_attributes, bad_path, True);
-               /* We're only going to fail here if it's access denied, as that's the
-                  only error we care about for "can we delete this ?" questions. */
-               if (!NT_STATUS_IS_OK(status) && (NT_STATUS_EQUAL(status,NT_STATUS_ACCESS_DENIED) ||
-                                                NT_STATUS_EQUAL(status,NT_STATUS_CANNOT_DELETE))) {
+
+       if (lp_acl_check_permissions(SNUM(conn))
+           && (create_disposition != FILE_CREATE)
+           && (share_access & FILE_SHARE_DELETE)
+           && (access_mask & DELETE_ACCESS)) {
+               if ((dos_mode(conn, fname, &sbuf) & FILE_ATTRIBUTE_READONLY) ||
+                               !can_delete_file_in_directory(conn, fname)) {
                        restore_case_semantics(conn, file_attributes);
                        END_PROFILE(SMBntcreateX);
                        return ERROR_NT(NT_STATUS_ACCESS_DENIED);
                }
        }
 
-       /* 
+#if 0
+       /* We need to support SeSecurityPrivilege for this. */
+       if ((access_mask & SEC_RIGHT_SYSTEM_SECURITY)) && 
+                       !user_has_privileges(current_user.nt_user_token,
+                               &se_security)) {
+               restore_case_semantics(conn, file_attributes);
+               END_PROFILE(SMBntcreateX);
+               return ERROR_NT(NT_STATUS_PRIVILEGE_NOT_HELD);
+       }
+#endif
+
+       /*
         * If it's a request for a directory open, deal with it separately.
         */
 
        if(create_options & FILE_DIRECTORY_FILE) {
-               oplock_request = 0;
-               
+
                /* Can't open a temp directory. IFS kit test. */
                if (file_attributes & FILE_ATTRIBUTE_TEMPORARY) {
                        END_PROFILE(SMBntcreateX);
                        return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
                }
 
-               status = open_directory(conn, fname, &sbuf,
+               oplock_request = 0;
+               status = open_directory(conn, &req, fname, &sbuf,
                                        access_mask,
                                        share_access,
                                        create_disposition,
                                        create_options,
+                                       new_file_attributes,
                                        &info, &fsp);
 
                restore_case_semantics(conn, file_attributes);
 
                if(!NT_STATUS_IS_OK(status)) {
+                       if (!use_nt_status() && NT_STATUS_EQUAL(
+                                   status, NT_STATUS_OBJECT_NAME_COLLISION)) {
+                               status = NT_STATUS_DOS(ERRDOS, ERRfilexists);
+                       }
                        END_PROFILE(SMBntcreateX);
                        return ERROR_NT(status);
                }
+
        } else {
+
                /*
                 * Ordinary file case.
                 */
@@ -709,14 +774,15 @@ int reply_ntcreate_and_X(connection_struct *conn,
                 * before issuing an oplock break request to
                 * our client. JRA.  */
 
-               status = open_file_ntcreate(conn,fname,&sbuf,
+               status = open_file_ntcreate(conn, &req, fname, &sbuf,
                                        access_mask,
                                        share_access,
                                        create_disposition,
                                        create_options,
-                                       file_attributes,
+                                       new_file_attributes,
                                        oplock_request,
                                        &info, &fsp);
+
                if (!NT_STATUS_IS_OK(status)) { 
                        /* We cheat here. There are two cases we
                         * care about. One is a directory rename,
@@ -751,20 +817,25 @@ int reply_ntcreate_and_X(connection_struct *conn,
                                }
        
                                oplock_request = 0;
-                               status = open_directory(conn, fname, &sbuf,
+                               status = open_directory(conn, &req, fname,
+                                                       &sbuf,
                                                        access_mask,
                                                        share_access,
                                                        create_disposition,
                                                        create_options,
+                                                       new_file_attributes,
                                                        &info, &fsp);
 
                                if(!NT_STATUS_IS_OK(status)) {
                                        restore_case_semantics(conn, file_attributes);
+                                       if (!use_nt_status() && NT_STATUS_EQUAL(
+                                                   status, NT_STATUS_OBJECT_NAME_COLLISION)) {
+                                               status = NT_STATUS_DOS(ERRDOS, ERRfilexists);
+                                       }
                                        END_PROFILE(SMBntcreateX);
                                        return ERROR_NT(status);
                                }
                        } else {
-
                                restore_case_semantics(conn, file_attributes);
                                END_PROFILE(SMBntcreateX);
                                if (open_was_deferred(SVAL(inbuf,smb_mid))) {
@@ -777,7 +848,7 @@ int reply_ntcreate_and_X(connection_struct *conn,
        }
                
        restore_case_semantics(conn, file_attributes);
-               
+
        file_len = sbuf.st_size;
        fattr = dos_mode(conn,fname,&sbuf);
        if(fattr == 0) {
@@ -818,22 +889,27 @@ int reply_ntcreate_and_X(connection_struct *conn,
         * and we granted one (by whatever means) - set the
         * correct bit for extended oplock reply.
         */
-       
+
        if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
                extended_oplock_granted = True;
        }
-       
+
        if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
                extended_oplock_granted = True;
        }
 
-#if 0
-       /* W2K sends back 42 words here ! If we do the same it breaks offline sync. Go figure... ? JRA. */
-       set_message(outbuf,42,0,True);
-#else
-       set_message(outbuf,34,0,True);
-#endif
-       
+       if (flags & EXTENDED_RESPONSE_REQUIRED) {
+               /* This is very strange. We
+                * return 50 words, but only set
+                * the wcnt to 42 ? It's definately
+                * what happens on the wire....
+                */
+               set_message(inbuf,outbuf,50,0,True);
+               SCVAL(outbuf,smb_wct,42);
+       } else {
+               set_message(inbuf,outbuf,34,0,True);
+       }
+
        p = outbuf + smb_vwv2;
        
        /*
@@ -862,8 +938,8 @@ int reply_ntcreate_and_X(connection_struct *conn,
                SIVAL(p,0,info);
        }
        p += 4;
-       
-       /* Create time. */  
+
+       /* Create time. */
        c_timespec = get_create_timespec(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
        a_timespec = get_atimespec(&sbuf);
        m_timespec = get_mtimespec(&sbuf);
@@ -874,7 +950,7 @@ int reply_ntcreate_and_X(connection_struct *conn,
                dos_filetime_timespec(&m_timespec);
        }
 
-       put_long_date_timespec(p, c_timespec);
+       put_long_date_timespec(p, c_timespec); /* create time. */
        p += 8;
        put_long_date_timespec(p, a_timespec); /* access time */
        p += 8;
@@ -894,6 +970,17 @@ int reply_ntcreate_and_X(connection_struct *conn,
        p += 4;
        SCVAL(p,0,fsp->is_directory ? 1 : 0);
 
+       if (flags & EXTENDED_RESPONSE_REQUIRED) {
+               uint32 perms = 0;
+               p += 25;
+               if (fsp->is_directory || can_write_to_file(conn, fname, &sbuf)) {
+                       perms = FILE_GENERIC_ALL;
+               } else {
+                       perms = FILE_GENERIC_READ|FILE_EXECUTE;
+               }
+               SIVAL(p,0,perms);
+       }
+
        DEBUG(5,("reply_ntcreate_and_X: fnum = %d, open name = %s\n", fsp->fnum, fsp->fsp_name));
 
        result = chain_reply(inbuf,outbuf,length,bufsize);
@@ -916,6 +1003,8 @@ static int do_nt_transact_create_pipe( connection_struct *conn, char *inbuf, cha
        int pnum = -1;
        char *p = NULL;
        NTSTATUS status;
+       size_t param_len;
+       uint32 flags;
 
        /*
         * Ensure minimum number of parameters sent.
@@ -926,7 +1015,11 @@ static int do_nt_transact_create_pipe( connection_struct *conn, char *inbuf, cha
                return ERROR_DOS(ERRDOS,ERRnoaccess);
        }
 
-       srvstr_get_path(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE, &status);
+       flags = IVAL(params,0);
+
+       srvstr_get_path(inbuf, SVAL(inbuf,smb_flg2), fname, params+53,
+                       sizeof(fname), parameter_count-53, STR_TERMINATE,
+                       &status);
        if (!NT_STATUS_IS_OK(status)) {
                return ERROR_NT(status);
        }
@@ -936,7 +1029,13 @@ static int do_nt_transact_create_pipe( connection_struct *conn, char *inbuf, cha
        }
        
        /* Realloc the size of parameters and data we will return */
-       params = nttrans_realloc(ppparams, 69);
+       if (flags & EXTENDED_RESPONSE_REQUIRED) {
+               /* Extended response is 32 more byyes. */
+               param_len = 101;
+       } else {
+               param_len = 69;
+       }
+       params = nttrans_realloc(ppparams, param_len);
        if(params == NULL) {
                return ERROR_DOS(ERRDOS,ERRnomem);
        }
@@ -957,11 +1056,23 @@ static int do_nt_transact_create_pipe( connection_struct *conn, char *inbuf, cha
        SSVAL(p,0,FILE_TYPE_MESSAGE_MODE_PIPE);
        /* Device state. */
        SSVAL(p,2, 0x5FF); /* ? */
+       p += 4;
        
+       if (flags & EXTENDED_RESPONSE_REQUIRED) {
+               p += 25;
+               SIVAL(p,0,FILE_GENERIC_ALL);
+               /* 
+                * For pipes W2K3 seems to return
+                * 0x12019B next.
+                * This is ((FILE_GENERIC_READ|FILE_GENERIC_WRITE) & ~FILE_APPEND_DATA)
+                */
+               SIVAL(p,4,(FILE_GENERIC_READ|FILE_GENERIC_WRITE)&~FILE_APPEND_DATA);
+       }
+
        DEBUG(5,("do_nt_transact_create_pipe: open name = %s\n", fname));
        
        /* Send the required number of replies */
-       send_nt_replies(outbuf, bufsize, NT_STATUS_OK, params, 69, *ppdata, 0);
+       send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, params, param_len, *ppdata, 0);
        
        return -1;
 }
@@ -975,7 +1086,7 @@ static NTSTATUS set_sd(files_struct *fsp, char *data, uint32 sd_len, uint32 secu
        prs_struct pd;
        SEC_DESC *psd = NULL;
        TALLOC_CTX *mem_ctx;
-       BOOL ret;
+       NTSTATUS status;
        
        if (sd_len == 0 || !lp_nt_acl_support(SNUM(fsp->conn))) {
                return NT_STATUS_OK;
@@ -1025,16 +1136,10 @@ static NTSTATUS set_sd(files_struct *fsp, char *data, uint32 sd_len, uint32 secu
                security_info_sent &= ~DACL_SECURITY_INFORMATION;
        }
        
-       ret = SMB_VFS_FSET_NT_ACL( fsp, fsp->fh->fd, security_info_sent, psd);
-       
-       if (!ret) {
-               talloc_destroy(mem_ctx);
-               return NT_STATUS_ACCESS_DENIED;
-       }
+       status = SMB_VFS_FSET_NT_ACL( fsp, fsp->fh->fd, security_info_sent, psd);
        
        talloc_destroy(mem_ctx);
-       
-       return NT_STATUS_OK;
+       return status;
 }
 
 /****************************************************************************
@@ -1086,13 +1191,13 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
        SMB_OFF_T file_len = 0;
        SMB_STRUCT_STAT sbuf;
        int info = 0;
-       BOOL bad_path = False;
        files_struct *fsp = NULL;
        char *p = NULL;
        BOOL extended_oplock_granted = False;
        uint32 flags;
        uint32 access_mask;
        uint32 file_attributes;
+       uint32 new_file_attributes;
        uint32 share_access;
        uint32 create_disposition;
        uint32 create_options;
@@ -1106,6 +1211,8 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
        TALLOC_CTX *ctx = NULL;
        char *pdata = NULL;
        NTSTATUS status;
+       size_t param_len;
+       struct smb_request req;
 
        DEBUG(5,("call_nt_transact_create\n"));
 
@@ -1134,6 +1241,8 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
                return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
        }
 
+       init_smb_request(&req, (uint8 *)inbuf);
+
        flags = IVAL(params,0);
        access_mask = IVAL(params,8);
        file_attributes = IVAL(params,20);
@@ -1187,7 +1296,10 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
                }
 
                if(!dir_fsp->is_directory) {
-                       srvstr_get_path(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE, &status);
+                       srvstr_get_path(inbuf, SVAL(inbuf,smb_flg2), fname,
+                                       params+53, sizeof(fname),
+                                       parameter_count-53, STR_TERMINATE,
+                                       &status);
                        if (!NT_STATUS_IS_OK(status)) {
                                return ERROR_NT(status);
                        }
@@ -1221,14 +1333,19 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
 
                {
                        pstring tmpname;
-                       srvstr_get_path(inbuf, tmpname, params+53, sizeof(tmpname), parameter_count-53, STR_TERMINATE, &status);
+                       srvstr_get_path(inbuf, SVAL(inbuf,smb_flg2), tmpname,
+                                       params+53, sizeof(tmpname),
+                                       parameter_count-53, STR_TERMINATE,
+                                       &status);
                        if (!NT_STATUS_IS_OK(status)) {
                                return ERROR_NT(status);
                        }
                        pstrcat(fname, tmpname);
                }
        } else {
-               srvstr_get_path(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE, &status);
+               srvstr_get_path(inbuf, SVAL(inbuf,smb_flg2), fname, params+53,
+                               sizeof(fname), parameter_count-53,
+                               STR_TERMINATE, &status);
                if (!NT_STATUS_IS_OK(status)) {
                        return ERROR_NT(status);
                }
@@ -1243,61 +1360,66 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
        }
 
        oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
-       oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
+       if (oplock_request) {
+               oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
+       }
 
+       /*
+        * Ordinary file or directory.
+        */
+               
        /*
         * Check if POSIX semantics are wanted.
         */
-
-       set_posix_case_semantics(conn, file_attributes);
+               
+       new_file_attributes = set_posix_case_semantics(conn, file_attributes);
     
-       RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+       status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
+       if (!NT_STATUS_IS_OK(status)) {
+               if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+                       return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+               }
+               return ERROR_NT(status);
+       }
 
-       unix_convert(fname,conn,0,&bad_path,&sbuf);
-       if (bad_path) {
+       status = unix_convert(conn, fname, False, NULL, &sbuf);
+       if (!NT_STATUS_IS_OK(status)) {
                restore_case_semantics(conn, file_attributes);
-               return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+               return ERROR_NT(status);
        }
        /* All file access must go through check_name() */
-       if (!check_name(fname,conn)) {
+       status = check_name(conn, fname);
+       if (!NT_STATUS_IS_OK(status)) {
                restore_case_semantics(conn, file_attributes);
-               return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
+               return ERROR_NT(status);
        }
-    
-#if 0
+
        /* This is the correct thing to do (check every time) but can_delete is
           expensive (it may have to read the parent directory permissions). So
           for now we're not doing it unless we have a strong hint the client
-          is really going to delete this file. */
-       if (desired_access & DELETE_ACCESS) {
-#else
+          is really going to delete this file. If the client is forcing FILE_CREATE
+          let the filesystem take care of the permissions. */
+
        /* Setting FILE_SHARE_DELETE is the hint. */
-       if (lp_acl_check_permissions(SNUM(conn)) && (share_access & FILE_SHARE_DELETE) && (access_mask & DELETE_ACCESS)) {
-#endif
-               status = can_delete(conn, fname, file_attributes, bad_path, True);
-               /* We're only going to fail here if it's access denied, as that's the
-                  only error we care about for "can we delete this ?" questions. */
-               if (!NT_STATUS_IS_OK(status) && (NT_STATUS_EQUAL(status,NT_STATUS_ACCESS_DENIED) ||
-                                                NT_STATUS_EQUAL(status,NT_STATUS_CANNOT_DELETE))) {
+
+       if (lp_acl_check_permissions(SNUM(conn))
+           && (create_disposition != FILE_CREATE)
+           && (share_access & FILE_SHARE_DELETE)
+           && (access_mask & DELETE_ACCESS)) {
+               if ((dos_mode(conn, fname, &sbuf) & FILE_ATTRIBUTE_READONLY) ||
+                               !can_delete_file_in_directory(conn, fname)) {
                        restore_case_semantics(conn, file_attributes);
-                       return ERROR_NT(status);
+                       return ERROR_NT(NT_STATUS_ACCESS_DENIED);
                }
        }
 
        if (ea_len) {
-               ctx = talloc_init("NTTRANS_CREATE_EA");
-               if (!ctx) {
-                       talloc_destroy(ctx);
-                       restore_case_semantics(conn, file_attributes);
-                       return ERROR_NT(NT_STATUS_NO_MEMORY);
-               }
-
                pdata = data + sd_len;
 
                /* We have already checked that ea_len <= data_count here. */
-               ea_list = read_nttrans_ea_list(ctx, pdata, ea_len);
+               ea_list = read_nttrans_ea_list(tmp_talloc_ctx(), pdata,
+                                              ea_len);
                if (!ea_list ) {
-                       talloc_destroy(ctx);
                        restore_case_semantics(conn, file_attributes);
                        return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
                }
@@ -1311,27 +1433,25 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
 
                /* Can't open a temp directory. IFS kit test. */
                if (file_attributes & FILE_ATTRIBUTE_TEMPORARY) {
-                       talloc_destroy(ctx);
                        restore_case_semantics(conn, file_attributes);
                        return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
                }
 
-               oplock_request = 0;
-
                /*
                 * We will get a create directory here if the Win32
                 * app specified a security descriptor in the 
                 * CreateDirectory() call.
                 */
 
-               status = open_directory(conn, fname, &sbuf,
+               oplock_request = 0;
+               status = open_directory(conn, &req, fname, &sbuf,
                                        access_mask,
                                        share_access,
                                        create_disposition,
                                        create_options,
+                                       new_file_attributes,
                                        &info, &fsp);
                if(!NT_STATUS_IS_OK(status)) {
-                       talloc_destroy(ctx);
                        restore_case_semantics(conn, file_attributes);
                        return ERROR_NT(status);
                }
@@ -1342,12 +1462,12 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
                 * Ordinary file case.
                 */
 
-               status = open_file_ntcreate(conn,fname,&sbuf,
+               status = open_file_ntcreate(conn,&req,fname,&sbuf,
                                        access_mask,
                                        share_access,
                                        create_disposition,
                                        create_options,
-                                       file_attributes,
+                                       new_file_attributes,
                                        oplock_request,
                                        &info, &fsp);
 
@@ -1365,19 +1485,19 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
                                }
        
                                oplock_request = 0;
-                               status = open_directory(conn, fname, &sbuf,
+                               status = open_directory(conn, &req, fname,
+                                                       &sbuf,
                                                        access_mask,
                                                        share_access,
                                                        create_disposition,
                                                        create_options,
+                                                       new_file_attributes,
                                                        &info, &fsp);
                                if(!NT_STATUS_IS_OK(status)) {
-                                       talloc_destroy(ctx);
                                        restore_case_semantics(conn, file_attributes);
                                        return ERROR_NT(status);
                                }
                        } else {
-                               talloc_destroy(ctx);
                                restore_case_semantics(conn, file_attributes);
                                if (open_was_deferred(SVAL(inbuf,smb_mid))) {
                                        /* We have re-scheduled this call. */
@@ -1418,7 +1538,6 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
        
        if (ea_len && (info == FILE_WAS_CREATED)) {
                status = set_ea(conn, fsp, fname, ea_list);
-               talloc_destroy(ctx);
                if (!NT_STATUS_IS_OK(status)) {
                        close_file(fsp,ERROR_CLOSE);
                        restore_case_semantics(conn, file_attributes);
@@ -1465,25 +1584,35 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
         * and we granted one (by whatever means) - set the
         * correct bit for extended oplock reply.
         */
-    
+
        if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
                extended_oplock_granted = True;
        }
-  
+
        if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
                extended_oplock_granted = True;
        }
 
        /* Realloc the size of parameters and data we will return */
-       params = nttrans_realloc(ppparams, 69);
+       if (flags & EXTENDED_RESPONSE_REQUIRED) {
+               /* Extended response is 32 more byyes. */
+               param_len = 101;
+       } else {
+               param_len = 69;
+       }
+       params = nttrans_realloc(ppparams, param_len);
        if(params == NULL) {
                return ERROR_DOS(ERRDOS,ERRnomem);
        }
 
        p = params;
        if (extended_oplock_granted) {
-               SCVAL(p,0, BATCH_OPLOCK_RETURN);
-       } else if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type)) {
+               if (flags & REQUEST_BATCH_OPLOCK) {
+                       SCVAL(p,0, BATCH_OPLOCK_RETURN);
+               } else {
+                       SCVAL(p,0, EXCLUSIVE_OPLOCK_RETURN);
+               }
+       } else if (fsp->oplock_type == LEVEL_II_OPLOCK) {
                SCVAL(p,0, LEVEL_II_OPLOCK_RETURN);
        } else {
                SCVAL(p,0,NO_OPLOCK_RETURN);
@@ -1530,10 +1659,21 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
        p += 4;
        SCVAL(p,0,fsp->is_directory ? 1 : 0);
 
+       if (flags & EXTENDED_RESPONSE_REQUIRED) {
+               uint32 perms = 0;
+               p += 25;
+               if (fsp->is_directory || can_write_to_file(conn, fname, &sbuf)) {
+                       perms = FILE_GENERIC_ALL;
+               } else {
+                       perms = FILE_GENERIC_READ|FILE_EXECUTE;
+               }
+               SIVAL(p,0,perms);
+       }
+
        DEBUG(5,("call_nt_transact_create: open name = %s\n", fname));
 
        /* Send the required number of replies */
-       send_nt_replies(outbuf, bufsize, NT_STATUS_OK, params, 69, *ppdata, 0);
+       send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, params, param_len, *ppdata, 0);
 
        return -1;
 }
@@ -1566,10 +1706,10 @@ int reply_ntcancel(connection_struct *conn,
  Copy a file.
 ****************************************************************************/
 
-static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *newname, uint32 attrs)
+static NTSTATUS copy_internals(connection_struct *conn,
+                              struct smb_request *req,
+                              char *oldname, char *newname, uint32 attrs)
 {
-       BOOL bad_path_oldname = False;
-       BOOL bad_path_newname = False;
        SMB_STRUCT_STAT sbuf1, sbuf2;
        pstring last_component_oldname;
        pstring last_component_newname;
@@ -1577,56 +1717,43 @@ static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *new
        uint32 fattr;
        int info;
        SMB_OFF_T ret=-1;
-       int close_ret;
        NTSTATUS status = NT_STATUS_OK;
 
        ZERO_STRUCT(sbuf1);
        ZERO_STRUCT(sbuf2);
 
-       /* No wildcards. */
-       if (ms_has_wild(newname) || ms_has_wild(oldname)) {
-               return NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
-       }
-
-       if (!CAN_WRITE(conn))
+       if (!CAN_WRITE(conn)) {
                return NT_STATUS_MEDIA_WRITE_PROTECTED;
+       }
 
-       unix_convert(oldname,conn,last_component_oldname,&bad_path_oldname,&sbuf1);
-       if (bad_path_oldname) {
-               return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+       status = unix_convert(conn, oldname, False, last_component_oldname, &sbuf1);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
        }
 
-       /* Quick check for "." and ".." */
-       if (last_component_oldname[0] == '.') {
-               if (!last_component_oldname[1] || (last_component_oldname[1] == '.' && !last_component_oldname[2])) {
-                       return NT_STATUS_OBJECT_NAME_INVALID;
-               }
+       status = check_name(conn, oldname);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
        }
 
         /* Source must already exist. */
        if (!VALID_STAT(sbuf1)) {
                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
        }
-       if (!check_name(oldname,conn)) {
-               return NT_STATUS_ACCESS_DENIED;
-       }
-
        /* Ensure attributes match. */
        fattr = dos_mode(conn,oldname,&sbuf1);
        if ((fattr & ~attrs) & (aHIDDEN | aSYSTEM)) {
                return NT_STATUS_NO_SUCH_FILE;
        }
 
-       unix_convert(newname,conn,last_component_newname,&bad_path_newname,&sbuf2);
-       if (bad_path_newname) {
-               return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+       status = unix_convert(conn, newname, False, last_component_newname, &sbuf2);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
        }
 
-       /* Quick check for "." and ".." */
-       if (last_component_newname[0] == '.') {
-               if (!last_component_newname[1] || (last_component_newname[1] == '.' && !last_component_newname[2])) {
-                       return NT_STATUS_OBJECT_NAME_INVALID;
-               }
+       status = check_name(conn, newname);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
        }
 
        /* Disallow if newname already exists. */
@@ -1634,23 +1761,20 @@ static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *new
                return NT_STATUS_OBJECT_NAME_COLLISION;
        }
 
-       if (!check_name(newname,conn)) {
-               return NT_STATUS_ACCESS_DENIED;
-       }
-
        /* No links from a directory. */
        if (S_ISDIR(sbuf1.st_mode)) {
                return NT_STATUS_FILE_IS_A_DIRECTORY;
        }
 
        /* Ensure this is within the share. */
-       if (!reduce_name(conn, oldname) != 0) {
-               return NT_STATUS_ACCESS_DENIED;
+       status = reduce_name(conn, oldname);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
        }
 
        DEBUG(10,("copy_internals: doing file copy %s to %s\n", oldname, newname));
 
-        status = open_file_ntcreate(conn,oldname,&sbuf1,
+        status = open_file_ntcreate(conn, req, oldname, &sbuf1,
                        FILE_READ_DATA, /* Read-only. */
                        FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
                        FILE_OPEN,
@@ -1663,7 +1787,7 @@ static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *new
                return status;
        }
 
-        status = open_file_ntcreate(conn,newname,&sbuf2,
+        status = open_file_ntcreate(conn, req, newname, &sbuf2,
                        FILE_WRITE_DATA, /* Read-only. */
                        FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
                        FILE_CREATE,
@@ -1690,21 +1814,21 @@ static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *new
        close_file(fsp1,NORMAL_CLOSE);
 
        /* Ensure the modtime is set correctly on the destination file. */
-       fsp_set_pending_modtime(fsp2, sbuf1.st_mtime);
+       fsp_set_pending_modtime(fsp2, get_mtimespec(&sbuf1));
 
-       close_ret = close_file(fsp2,NORMAL_CLOSE);
+       status = close_file(fsp2,NORMAL_CLOSE);
 
        /* Grrr. We have to do this as open_file_ntcreate adds aARCH when it
           creates the file. This isn't the correct thing to do in the copy
           case. JRA */
-       file_set_dosmode(conn, newname, fattr, &sbuf2, True);
+       file_set_dosmode(conn, newname, fattr, &sbuf2,
+                        parent_dirname(newname));
 
        if (ret < (SMB_OFF_T)sbuf1.st_size) {
                return NT_STATUS_DISK_FULL;
        }
 
-       if (close_ret != 0) {
-               status = map_nt_error_from_unix(close_ret);
+       if (!NT_STATUS_IS_OK(status)) {
                DEBUG(3,("copy_internals: Error %s copy file %s to %s\n",
                        nt_errstr(status), oldname, newname));
        }
@@ -1723,14 +1847,20 @@ int reply_ntrename(connection_struct *conn,
        pstring newname;
        char *p;
        NTSTATUS status;
-       BOOL path_contains_wcard = False;
+       BOOL src_has_wcard = False;
+       BOOL dest_has_wcard = False;
        uint32 attrs = SVAL(inbuf,smb_vwv0);
        uint16 rename_type = SVAL(inbuf,smb_vwv1);
+       struct smb_request req;
 
        START_PROFILE(SMBntrename);
 
+       init_smb_request(&req, (uint8 *)inbuf);
+
        p = smb_buf(inbuf) + 1;
-       p += srvstr_get_path_wcard(inbuf, oldname, p, sizeof(oldname), 0, STR_TERMINATE, &status, &path_contains_wcard);
+       p += srvstr_get_path_wcard(inbuf, SVAL(inbuf,smb_flg2), oldname, p,
+                                  sizeof(oldname), 0, STR_TERMINATE, &status,
+                                  &src_has_wcard);
        if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBntrename);
                return ERROR_NT(status);
@@ -1748,30 +1878,55 @@ int reply_ntrename(connection_struct *conn,
        }
 
        p++;
-       p += srvstr_get_path(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status);
+       p += srvstr_get_path_wcard(inbuf, SVAL(inbuf,smb_flg2), newname, p,
+                                  sizeof(newname), 0, STR_TERMINATE, &status,
+                                  &dest_has_wcard);
        if (!NT_STATUS_IS_OK(status)) {
                END_PROFILE(SMBntrename);
                return ERROR_NT(status);
        }
        
-       RESOLVE_DFSPATH(oldname, conn, inbuf, outbuf);
-       RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
-       
+       status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, oldname);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBntrename);
+               if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+                       return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+               }
+               return ERROR_NT(status);
+       }
+
+       status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, newname);
+       if (!NT_STATUS_IS_OK(status)) {
+               END_PROFILE(SMBntrename);
+               if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+                       return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+               }
+               return ERROR_NT(status);
+       }
+
        DEBUG(3,("reply_ntrename : %s -> %s\n",oldname,newname));
        
        switch(rename_type) {
                case RENAME_FLAG_RENAME:
-                       status = rename_internals(conn, oldname, newname, attrs, False, path_contains_wcard);
+                       status = rename_internals(conn, &req, oldname, newname,
+                                                 attrs, False, src_has_wcard,
+                                                 dest_has_wcard);
                        break;
                case RENAME_FLAG_HARD_LINK:
-                       status = hardlink_internals(conn, oldname, newname);
+                       if (src_has_wcard || dest_has_wcard) {
+                               /* No wildcards. */
+                               status = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
+                       } else {
+                               status = hardlink_internals(conn, oldname, newname);
+                       }
                        break;
                case RENAME_FLAG_COPY:
-                       if (path_contains_wcard) {
+                       if (src_has_wcard || dest_has_wcard) {
                                /* No wildcards. */
                                status = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
                        } else {
-                               status = copy_internals(conn, oldname, newname, attrs);
+                               status = copy_internals(conn, &req, oldname,
+                                                       newname, attrs);
                        }
                        break;
                case RENAME_FLAG_MOVE_CLUSTER_INFORMATION:
@@ -1791,12 +1946,7 @@ int reply_ntrename(connection_struct *conn,
                return ERROR_NT(status);
        }
 
-       /*
-        * Win2k needs a changenotify request response before it will
-        * update after a rename..
-        */     
-       process_pending_change_notify_queue((time_t)0);
-       outsize = set_message(outbuf,0,0,False);
+       outsize = set_message(inbuf,outbuf,0,0,False);
   
        END_PROFILE(SMBntrename);
        return(outsize);
@@ -1819,14 +1969,17 @@ static int call_nt_transact_notify_change(connection_struct *conn, char *inbuf,
 {
        uint16 *setup = *ppsetup;
        files_struct *fsp;
-       uint32 flags;
+       uint32 filter;
+       NTSTATUS status;
+       BOOL recursive;
 
        if(setup_count < 6) {
                return ERROR_DOS(ERRDOS,ERRbadfunc);
        }
 
        fsp = file_fsp((char *)setup,4);
-       flags = IVAL(setup, 0);
+       filter = IVAL(setup, 0);
+       recursive = (SVAL(setup, 6) != 0) ? True : False;
 
        DEBUG(3,("call_nt_transact_notify_change\n"));
 
@@ -1834,15 +1987,62 @@ static int call_nt_transact_notify_change(connection_struct *conn, char *inbuf,
                return ERROR_DOS(ERRDOS,ERRbadfid);
        }
 
-       DEBUG(3,("call_nt_transact_notify_change: notify change called on "
-                "directory name = %s\n", fsp->fsp_name ));
+       {
+               char *filter_string;
+
+               if (!(filter_string = notify_filter_string(NULL, filter))) {
+                       return ERROR_NT(NT_STATUS_NO_MEMORY);
+               }
+
+               DEBUG(3,("call_nt_transact_notify_change: notify change "
+                        "called on %s, filter = %s, recursive = %d\n",
+                        fsp->fsp_name, filter_string, recursive));
+
+               TALLOC_FREE(filter_string);
+       }
 
        if((!fsp->is_directory) || (conn != fsp->conn)) {
-               return ERROR_DOS(ERRDOS,ERRbadfid);
+               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+       }
+
+       if (fsp->notify == NULL) {
+
+               status = change_notify_create(fsp, filter, recursive);
+
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(10, ("change_notify_create returned %s\n",
+                                  nt_errstr(status)));
+                       return ERROR_NT(status);
+               }
+       }
+
+       if (fsp->notify->num_changes != 0) {
+
+               /*
+                * We've got changes pending, respond immediately
+                */
+
+               /*
+                * TODO: write a torture test to check the filtering behaviour
+                * here.
+                */
+
+               change_notify_reply(inbuf, fsp->notify);
+
+               /*
+                * change_notify_reply() above has independently sent its
+                * results
+                */
+               return -1;
        }
 
-       if (!change_notify_set(inbuf, fsp, conn, flags)) {
-               return(UNIXERROR(ERRDOS,ERRbadfid));
+       /*
+        * No changes pending, queue the request
+        */
+
+       status = change_notify_add_request(inbuf, filter, recursive, fsp);
+       if (!NT_STATUS_IS_OK(status)) {
+               return ERROR_NT(status);
        }
 
        return -1;
@@ -1861,41 +2061,45 @@ static int call_nt_transact_rename(connection_struct *conn, char *inbuf, char *o
        pstring new_name;
        files_struct *fsp = NULL;
        BOOL replace_if_exists = False;
-       BOOL path_contains_wcard = False;
+       BOOL dest_has_wcard = False;
        NTSTATUS status;
+       struct smb_request req;
 
-        if(parameter_count < 4) {
+       init_smb_request(&req, (uint8 *)inbuf);
+
+        if(parameter_count < 5) {
                return ERROR_DOS(ERRDOS,ERRbadfunc);
        }
 
        fsp = file_fsp(params, 0);
        replace_if_exists = (SVAL(params,2) & RENAME_REPLACE_IF_EXISTS) ? True : False;
        CHECK_FSP(fsp, conn);
-       srvstr_get_path_wcard(inbuf, new_name, params+4, sizeof(new_name), -1, STR_TERMINATE, &status, &path_contains_wcard);
+       srvstr_get_path_wcard(inbuf, SVAL(inbuf,smb_flg2), new_name, params+4,
+                             sizeof(new_name), parameter_count - 4,
+                             STR_TERMINATE, &status, &dest_has_wcard);
        if (!NT_STATUS_IS_OK(status)) {
                return ERROR_NT(status);
        }
 
-       status = rename_internals(conn, fsp->fsp_name,
-                                 new_name, 0, replace_if_exists, path_contains_wcard);
-       if (!NT_STATUS_IS_OK(status))
+       status = rename_internals(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(SVAL(inbuf,smb_mid))) {
+                       /* We have re-scheduled this call. */
+                       return -1;
+               }
                return ERROR_NT(status);
+       }
 
        /*
         * Rename was successful.
         */
-       send_nt_replies(outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0);
+       send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0);
        
        DEBUG(3,("nt transact rename from = %s, to = %s succeeded.\n", 
                 fsp->fsp_name, new_name));
        
-       /*
-        * Win2k needs a changenotify request response before it will
-        * update after a rename..
-        */
-       
-       process_pending_change_notify_queue((time_t)0);
-
        return -1;
 }
 
@@ -1979,7 +2183,7 @@ static int call_nt_transact_query_security_desc(connection_struct *conn, char *i
 
        if(max_data_count < sd_size) {
 
-               send_nt_replies(outbuf, bufsize, NT_STATUS_BUFFER_TOO_SMALL,
+               send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_BUFFER_TOO_SMALL,
                                params, 4, *ppdata, 0);
                talloc_destroy(mem_ctx);
                return -1;
@@ -2028,7 +2232,7 @@ security descriptor.\n"));
 
        talloc_destroy(mem_ctx);
 
-       send_nt_replies(outbuf, bufsize, NT_STATUS_OK, params, 4, data,
+       send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, params, 4, data,
                        (int)sd_size);
        return -1;
 }
@@ -2075,7 +2279,7 @@ static int call_nt_transact_set_security_desc(connection_struct *conn, char *inb
 
   done:
 
-       send_nt_replies(outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0);
+       send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0);
        return -1;
 }
    
@@ -2121,19 +2325,31 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou
                   so we can know if we need to pre-allocate or not */
 
                DEBUG(10,("FSCTL_SET_SPARSE: called on FID[0x%04X](but not implemented)\n", fidnum));
-               send_nt_replies(outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL,
+               send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL,
                                0);
                return -1;
        
-       case FSCTL_0x000900C0:
-               /* pretend this succeeded - don't know what this really is
-                  but works ok like this --metze
+       case FSCTL_CREATE_OR_GET_OBJECT_ID:
+       {
+               unsigned char objid[16];
+
+               /* This should return the object-id on this file.
+                * I think I'll make this be the inode+dev. JRA.
                 */
 
-               DEBUG(10,("FSCTL_0x000900C0: called on FID[0x%04X](but not implemented)\n",fidnum));
-               send_nt_replies(outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL,
-                               0);
+               DEBUG(10,("FSCTL_CREATE_OR_GET_OBJECT_ID: called on FID[0x%04X]\n",fidnum));
+
+               data_count = 64;
+               pdata = nttrans_realloc(ppdata, data_count);
+               if (pdata == NULL) {
+                       return ERROR_NT(NT_STATUS_NO_MEMORY);
+               }
+               push_file_id_16(pdata, &fsp->file_id);
+               memcpy(pdata+16,create_volume_objectid(conn,objid),16);
+               push_file_id_16(pdata+32, &fsp->file_id);
+               send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, pdata, data_count);
                return -1;
+       }
 
        case FSCTL_GET_REPARSE_POINT:
                /* pretend this fail - my winXP does it like this
@@ -2141,9 +2357,7 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou
                 */
 
                DEBUG(10,("FSCTL_GET_REPARSE_POINT: called on FID[0x%04X](but not implemented)\n",fidnum));
-               send_nt_replies(outbuf, bufsize, NT_STATUS_NOT_A_REPARSE_POINT,
-                               NULL, 0, NULL, 0);
-               return -1;
+               return ERROR_NT(NT_STATUS_NOT_A_REPARSE_POINT);
 
        case FSCTL_SET_REPARSE_POINT:
                /* pretend this fail - I'm assuming this because of the FSCTL_GET_REPARSE_POINT case.
@@ -2151,9 +2365,7 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou
                 */
 
                DEBUG(10,("FSCTL_SET_REPARSE_POINT: called on FID[0x%04X](but not implemented)\n",fidnum));
-               send_nt_replies(outbuf, bufsize, NT_STATUS_NOT_A_REPARSE_POINT,
-                               NULL, 0, NULL, 0);
-               return -1;
+               return ERROR_NT(NT_STATUS_NOT_A_REPARSE_POINT);
                        
        case FSCTL_GET_SHADOW_COPY_DATA: /* don't know if this name is right...*/
        {
@@ -2194,7 +2406,7 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou
 
                shadow_data = TALLOC_ZERO_P(shadow_mem_ctx,SHADOW_COPY_DATA);
                if (shadow_data == NULL) {
-                       DEBUG(0,("talloc_zero() failed!\n"));
+                       DEBUG(0,("TALLOC_ZERO() failed!\n"));
                        talloc_destroy(shadow_mem_ctx);
                        return ERROR_NT(NT_STATUS_NO_MEMORY);
                }
@@ -2265,7 +2477,7 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou
 
                talloc_destroy(shadow_data->mem_ctx);
 
-               send_nt_replies(outbuf, bufsize, NT_STATUS_OK, NULL, 0,
+               send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0,
                                pdata, data_count);
 
                return -1;
@@ -2318,7 +2530,7 @@ static int call_nt_transact_ioctl(connection_struct *conn, char *inbuf, char *ou
                 */
                
                /* this works for now... */
-               send_nt_replies(outbuf, bufsize, NT_STATUS_OK, NULL, 0,
+               send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0,
                                NULL, 0);
                return -1;      
        }       
@@ -2585,7 +2797,7 @@ static int call_nt_transact_get_user_quota(connection_struct *conn, char *inbuf,
                        break;
        }
 
-       send_nt_replies(outbuf, bufsize, nt_status, params, param_len,
+       send_nt_replies(inbuf, outbuf, bufsize, nt_status, params, param_len,
                        pdata, data_len);
 
        return -1;
@@ -2703,7 +2915,7 @@ static int call_nt_transact_set_user_quota(connection_struct *conn, char *inbuf,
                return ERROR_DOS(ERRSRV,ERRerror);      
        }
 
-       send_nt_replies(outbuf, bufsize, NT_STATUS_OK, params, param_len,
+       send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, params, param_len,
                        pdata, data_len);
 
        return -1;
@@ -2724,44 +2936,44 @@ static int handle_nttrans(connection_struct *conn,
        switch(state->call) {
                case NT_TRANSACT_CREATE:
                {
-                       START_PROFILE_NESTED(NT_transact_create);
+                       START_PROFILE(NT_transact_create);
                        outsize = call_nt_transact_create(conn, inbuf, outbuf,
                                                          size, bufsize, 
                                                        &state->setup, state->setup_count,
                                                        &state->param, state->total_param, 
                                                        &state->data, state->total_data,
                                                          state->max_data_return);
-                       END_PROFILE_NESTED(NT_transact_create);
+                       END_PROFILE(NT_transact_create);
                        break;
                }
 
                case NT_TRANSACT_IOCTL:
                {
-                       START_PROFILE_NESTED(NT_transact_ioctl);
+                       START_PROFILE(NT_transact_ioctl);
                        outsize = call_nt_transact_ioctl(conn, inbuf, outbuf,
                                                         size, bufsize, 
                                                         &state->setup, state->setup_count,
                                                         &state->param, state->total_param, 
                                                         &state->data, state->total_data, state->max_data_return);
-                       END_PROFILE_NESTED(NT_transact_ioctl);
+                       END_PROFILE(NT_transact_ioctl);
                        break;
                }
 
                case NT_TRANSACT_SET_SECURITY_DESC:
                {
-                       START_PROFILE_NESTED(NT_transact_set_security_desc);
+                       START_PROFILE(NT_transact_set_security_desc);
                        outsize = call_nt_transact_set_security_desc(conn, inbuf, outbuf, 
                                                         size, bufsize, 
                                                         &state->setup, state->setup_count,
                                                         &state->param, state->total_param, 
                                                         &state->data, state->total_data, state->max_data_return);
-                       END_PROFILE_NESTED(NT_transact_set_security_desc);
+                       END_PROFILE(NT_transact_set_security_desc);
                        break;
                }
 
                case NT_TRANSACT_NOTIFY_CHANGE:
                {
-                       START_PROFILE_NESTED(NT_transact_notify_change);
+                       START_PROFILE(NT_transact_notify_change);
                        outsize = call_nt_transact_notify_change(
                                conn, inbuf, outbuf, size, bufsize, 
                                &state->setup, state->setup_count,
@@ -2769,56 +2981,56 @@ static int handle_nttrans(connection_struct *conn,
                                &state->data, state->total_data,
                                state->max_data_return,
                                state->max_param_return);
-                       END_PROFILE_NESTED(NT_transact_notify_change);
+                       END_PROFILE(NT_transact_notify_change);
                        break;
                }
 
                case NT_TRANSACT_RENAME:
                {
-                       START_PROFILE_NESTED(NT_transact_rename);
+                       START_PROFILE(NT_transact_rename);
                        outsize = call_nt_transact_rename(conn, inbuf, outbuf,
                                                         size, bufsize, 
                                                         &state->setup, state->setup_count,
                                                         &state->param, state->total_param, 
                                                         &state->data, state->total_data, state->max_data_return);
-                       END_PROFILE_NESTED(NT_transact_rename);
+                       END_PROFILE(NT_transact_rename);
                        break;
                }
 
                case NT_TRANSACT_QUERY_SECURITY_DESC:
                {
-                       START_PROFILE_NESTED(NT_transact_query_security_desc);
+                       START_PROFILE(NT_transact_query_security_desc);
                        outsize = call_nt_transact_query_security_desc(conn, inbuf, outbuf, 
                                                         size, bufsize, 
                                                         &state->setup, state->setup_count,
                                                         &state->param, state->total_param, 
                                                         &state->data, state->total_data, state->max_data_return);
-                       END_PROFILE_NESTED(NT_transact_query_security_desc);
+                       END_PROFILE(NT_transact_query_security_desc);
                        break;
                }
 
 #ifdef HAVE_SYS_QUOTAS
                case NT_TRANSACT_GET_USER_QUOTA:
                {
-                       START_PROFILE_NESTED(NT_transact_get_user_quota);
+                       START_PROFILE(NT_transact_get_user_quota);
                        outsize = call_nt_transact_get_user_quota(conn, inbuf, outbuf, 
                                                         size, bufsize, 
                                                         &state->setup, state->setup_count,
                                                         &state->param, state->total_param, 
                                                         &state->data, state->total_data, state->max_data_return);
-                       END_PROFILE_NESTED(NT_transact_get_user_quota);
+                       END_PROFILE(NT_transact_get_user_quota);
                        break;
                }
 
                case NT_TRANSACT_SET_USER_QUOTA:
                {
-                       START_PROFILE_NESTED(NT_transact_set_user_quota);
+                       START_PROFILE(NT_transact_set_user_quota);
                        outsize = call_nt_transact_set_user_quota(conn, inbuf, outbuf, 
                                                         size, bufsize, 
                                                         &state->setup, state->setup_count,
                                                         &state->param, state->total_param, 
                                                         &state->data, state->total_data, state->max_data_return);
-                       END_PROFILE_NESTED(NT_transact_set_user_quota);
+                       END_PROFILE(NT_transact_set_user_quota);
                        break;                                  
                }
 #endif /* HAVE_SYS_QUOTAS */
@@ -2969,7 +3181,7 @@ int reply_nttrans(connection_struct *conn,
                }
 
                memcpy( state->setup, &inbuf[smb_nt_SetupStart], state->setup_count);
-               dump_data(10, (char *)state->setup, state->setup_count);
+               dump_data(10, (uint8 *)state->setup, state->setup_count);
        }
 
        if ((state->received_data == state->total_data) &&
@@ -2987,7 +3199,7 @@ int reply_nttrans(connection_struct *conn,
 
        /* We need to send an interim response then receive the rest
           of the parameter/data bytes */
-       outsize = set_message(outbuf,0,0,False);
+       outsize = set_message(inbuf,outbuf,0,0,False);
        show_msg(outbuf);
        END_PROFILE(SMBnttrans);
        return outsize;