Fix bug #226. Stop unmangle of name into a wildcard name from deleting more
[tprouty/samba.git] / source / smbd / reply.c
index 0ccb4d0e9d2c487fa533efa0bd82726d7b9733a0..71312295f4f51b5b02e72b93f51c56db7f982603 100644 (file)
@@ -39,7 +39,7 @@ unsigned int smb_echo_count = 0;
 extern BOOL global_encrypted_passwords_negotiated;
 
 /****************************************************************************
- Reply to an special message.
+ Reply to a special message.
 ****************************************************************************/
 
 int reply_special(char *inbuf,char *outbuf)
@@ -48,8 +48,6 @@ int reply_special(char *inbuf,char *outbuf)
        int msg_type = CVAL(inbuf,0);
        int msg_flags = CVAL(inbuf,1);
        pstring name1,name2;
-
-       int len;
        char name_type = 0;
        
        static BOOL already_got_session = False;
@@ -75,23 +73,16 @@ int reply_special(char *inbuf,char *outbuf)
                        return(0);
                }
                name_extract(inbuf,4,name1);
-               name_extract(inbuf,4 + name_len(inbuf + 4),name2);
+               name_type = name_extract(inbuf,4 + name_len(inbuf + 4),name2);
                DEBUG(2,("netbios connect: name1=%s name2=%s\n",
                         name1,name2));      
 
-               name1[15] = 0;
-
-               len = strlen(name2);
-               if (len == 16) {
-                       name_type = name2[15];
-                       name2[15] = 0;
-               }
-
                set_local_machine_name(name1, True);
                set_remote_machine_name(name2, True);
 
-               DEBUG(2,("netbios connect: local=%s remote=%s\n",
-                       get_local_machine_name(), get_remote_machine_name() ));
+               DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
+                        get_local_machine_name(), get_remote_machine_name(),
+                        name_type));
 
                if (name_type == 'R') {
                        /* We are being asked for a pathworks session --- 
@@ -283,14 +274,14 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
                set_message_end(outbuf,p);
        } else {
                /* NT sets the fstype of IPC$ to the null string */
-               const char *fsname = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
+               const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
                
                set_message(outbuf,3,0,True);
 
                p = smb_buf(outbuf);
                p += srvstr_push(outbuf, p, server_devicetype, -1, 
                                 STR_TERMINATE|STR_ASCII);
-               p += srvstr_push(outbuf, p, fsname, -1, 
+               p += srvstr_push(outbuf, p, fstype, -1, 
                                 STR_TERMINATE);
                
                set_message_end(outbuf,p);
@@ -399,7 +390,7 @@ int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
        mode = SVAL(inbuf,smb_vwv0);
 
        if (check_name(name,conn)) {
-               if (VALID_STAT(sbuf) || vfs_stat(conn,name,&sbuf) == 0)
+               if (VALID_STAT(sbuf) || SMB_VFS_STAT(conn,name,&sbuf) == 0)
                        if (!(ok = S_ISDIR(sbuf.st_mode)))
                                errno = ENOTDIR;
        }
@@ -458,7 +449,7 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
        } else {
                unix_convert(fname,conn,0,&bad_path,&sbuf);
                if (check_name(fname,conn)) {
-                       if (VALID_STAT(sbuf) || vfs_stat(conn,fname,&sbuf) == 0) {
+                       if (VALID_STAT(sbuf) || SMB_VFS_STAT(conn,fname,&sbuf) == 0) {
                                mode = dos_mode(conn,fname,&sbuf);
                                size = sbuf.st_size;
                                mtime = sbuf.st_mtime;
@@ -553,7 +544,7 @@ int reply_dskattr(connection_struct *conn, char *inbuf,char *outbuf, int dum_siz
        SMB_BIG_UINT dfree,dsize,bsize;
        START_PROFILE(SMBdskattr);
 
-       conn->vfs_ops.disk_free(conn,".",True,&bsize,&dfree,&dsize);
+       SMB_VFS_DISK_FREE(conn,".",True,&bsize,&dfree,&dsize);
   
        outsize = set_message(outbuf,5,0,True);
        
@@ -1128,7 +1119,7 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                return(UNIXERROR(ERRDOS,ERRnoaccess));
        }
 
-       vfs_stat(conn,fname,&sbuf);
+       SMB_VFS_STAT(conn,fname,&sbuf);
 
        /* Open file in dos compatibility share mode. */
        /* We should fail if file does not exist. */
@@ -1227,7 +1218,7 @@ static NTSTATUS can_delete(char *fname,connection_struct *conn, int dirtype)
        if (!CAN_WRITE(conn))
                return NT_STATUS_MEDIA_WRITE_PROTECTED;
 
-       if (conn->vfs_ops.lstat(conn,fname,&sbuf) != 0)
+       if (SMB_VFS_LSTAT(conn,fname,&sbuf) != 0)
                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
 
        fmode = dos_mode(conn,fname,&sbuf);
@@ -1281,6 +1272,16 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name)
        
        *directory = *mask = 0;
        
+       /* We must check for wildcards in the name given
+        * directly by the client - before any unmangling.
+        * This prevents an unmangling of a UNIX name containing
+        * a DOS wildcard like '*' or '?' from unmangling into
+        * a wildcard delete which was not intended.
+        * FIX for #226. JRA.
+        */
+
+       has_wild = ms_has_wild(name);
+
        rc = unix_convert(name,conn,0,&bad_path,&sbuf);
        
        p = strrchr_m(name,'/');
@@ -1305,15 +1306,14 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name)
        if (!rc && mangle_is_mangled(mask))
                mangle_check_cache( mask );
        
-       has_wild = ms_has_wild(mask);
-       
        if (!has_wild) {
                pstrcat(directory,"/");
                pstrcat(directory,mask);
                error = can_delete(directory,conn,dirtype);
-               if (!NT_STATUS_IS_OK(error)) return error;
+               if (!NT_STATUS_IS_OK(error))
+                       return error;
 
-               if (vfs_unlink(conn,directory) == 0) {
+               if (SMB_VFS_UNLINK(conn,directory) == 0) {
                        count++;
                }
        } else {
@@ -1338,12 +1338,15 @@ NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name)
                                pstring fname;
                                pstrcpy(fname,dname);
                                
-                               if(!mask_match(fname, mask, case_sensitive)) continue;
+                               if(!mask_match(fname, mask, case_sensitive))
+                                       continue;
                                
                                slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
                                error = can_delete(fname,conn,dirtype);
-                               if (!NT_STATUS_IS_OK(error)) continue;
-                               if (vfs_unlink(conn,fname) == 0) count++;
+                               if (!NT_STATUS_IS_OK(error))
+                                       continue;
+                               if (SMB_VFS_UNLINK(conn,fname) == 0)
+                                       count++;
                                DEBUG(3,("unlink_internals: succesful unlink [%s]\n",fname));
                        }
                        CloseDir(dirptr);
@@ -1379,7 +1382,8 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
        DEBUG(3,("reply_unlink : %s\n",name));
        
        status = unlink_internals(conn, dirtype, name);
-       if (!NT_STATUS_IS_OK(status)) return ERROR_NT(status);
+       if (!NT_STATUS_IS_OK(status))
+               return ERROR_NT(status);
 
        /*
         * Win2k needs a changenotify request response before it will
@@ -1429,7 +1433,7 @@ void send_file_readbraw(connection_struct *conn, files_struct *fsp, SMB_OFF_T st
                header.length = 4;
                header.free = NULL;
 
-               if ( conn->vfs_ops.sendfile( smbd_server_fd(), fsp, fsp->fd, &header, startpos, nread) == -1) {
+               if ( SMB_VFS_SENDFILE( smbd_server_fd(), fsp, fsp->fd, &header, startpos, nread) == -1) {
                        /*
                         * Special hack for broken Linux with no 64 bit clean sendfile. If we
                         * return ENOSYS then pretend we just got a normal read.
@@ -1472,6 +1476,10 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s
        files_struct *fsp;
        START_PROFILE(SMBreadbraw);
 
+       if (srv_is_signing_active()) {
+               exit_server("reply_readbraw: SMB signing is active - raw reads/writes are disallowed.");
+       }
+
        /*
         * Special check if an oplock break has been issued
         * and the readraw request croses on the wire, we must
@@ -1554,7 +1562,7 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s
   
                if (size < sizeneeded) {
                        SMB_STRUCT_STAT st;
-                       if (vfs_fstat(fsp,fsp->fd,&st) == 0)
+                       if (SMB_VFS_FSTAT(fsp,fsp->fd,&st) == 0)
                                size = st.st_size;
                        if (!fsp->can_write) 
                                fsp->size = size;
@@ -1723,7 +1731,7 @@ int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length
                SMB_STRUCT_STAT sbuf;
                DATA_BLOB header;
 
-               if(vfs_fstat(fsp,fsp->fd, &sbuf) == -1)
+               if(SMB_VFS_FSTAT(fsp,fsp->fd, &sbuf) == -1)
                        return(UNIXERROR(ERRDOS,ERRnoaccess));
 
                if (startpos > sbuf.st_size)
@@ -1750,7 +1758,7 @@ int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length
                header.length = data - outbuf;
                header.free = NULL;
 
-               if ( conn->vfs_ops.sendfile( smbd_server_fd(), fsp, fsp->fd, &header, startpos, smb_maxcnt) == -1) {
+               if ( SMB_VFS_SENDFILE( smbd_server_fd(), fsp, fsp->fd, &header, startpos, smb_maxcnt) == -1) {
                        /*
                         * Special hack for broken Linux with no 64 bit clean sendfile. If we
                         * return ENOSYS then pretend we just got a normal read.
@@ -1870,6 +1878,10 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size,
        int outsize = 0;
        START_PROFILE(SMBwritebraw);
 
+       if (srv_is_signing_active()) {
+               exit_server("reply_readbraw: SMB signing is active - raw reads/writes are disallowed.");
+       }
+
        CHECK_FSP(fsp,conn);
        CHECK_WRITE(fsp);
   
@@ -2262,7 +2274,7 @@ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int
                        break;
        }
 
-       if((res = conn->vfs_ops.lseek(fsp,fsp->fd,startpos,umode)) == -1) {
+       if((res = SMB_VFS_LSEEK(fsp,fsp->fd,startpos,umode)) == -1) {
                /*
                 * Check for the special case where a seek before the start
                 * of the file sets the offset to zero. Added in the CIFS spec,
@@ -2274,7 +2286,7 @@ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int
 
                        if(umode == SEEK_CUR) {
 
-                               if((current_pos = conn->vfs_ops.lseek(fsp,fsp->fd,0,SEEK_CUR)) == -1) {
+                               if((current_pos = SMB_VFS_LSEEK(fsp,fsp->fd,0,SEEK_CUR)) == -1) {
                                        END_PROFILE(SMBlseek);
                                        return(UNIXERROR(ERRDOS,ERRnoaccess));
                                }
@@ -2285,7 +2297,7 @@ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int
 
                                SMB_STRUCT_STAT sbuf;
 
-                               if(vfs_fstat(fsp,fsp->fd, &sbuf) == -1) {
+                               if(SMB_VFS_FSTAT(fsp,fsp->fd, &sbuf) == -1) {
                                        END_PROFILE(SMBlseek);
                                        return(UNIXERROR(ERRDOS,ERRnoaccess));
                                }
@@ -2294,7 +2306,7 @@ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int
                        }
  
                        if(current_pos < 0)
-                               res = conn->vfs_ops.lseek(fsp,fsp->fd,0,SEEK_SET);
+                               res = SMB_VFS_LSEEK(fsp,fsp->fd,0,SEEK_SET);
                }
 
                if(res == -1) {
@@ -2828,9 +2840,13 @@ NTSTATUS mkdir_internal(connection_struct *conn, pstring directory)
        int ret= -1;
        
        unix_convert(directory,conn,0,&bad_path,&sbuf);
-       
+
+       if (ms_has_wild(directory)) {
+               return NT_STATUS_OBJECT_NAME_INVALID;
+       }
+
        if (check_name(directory, conn))
-               ret = vfs_mkdir(conn,directory,unix_mode(conn,aDIR,directory));
+               ret = vfs_MkDir(conn,directory,unix_mode(conn,aDIR,directory));
        
        if (ret == -1) {
                NTSTATUS nterr = set_bad_path_error(errno, bad_path);
@@ -2901,7 +2917,7 @@ static BOOL recursive_rmdir(connection_struct *conn, char *directory)
                pstrcat(fullname, "/");
                pstrcat(fullname, dname);
 
-               if(conn->vfs_ops.lstat(conn,fullname, &st) != 0) {
+               if(SMB_VFS_LSTAT(conn,fullname, &st) != 0) {
                        ret = True;
                        break;
                }
@@ -2911,11 +2927,11 @@ static BOOL recursive_rmdir(connection_struct *conn, char *directory)
                                ret = True;
                                break;
                        }
-                       if(vfs_rmdir(conn,fullname) != 0) {
+                       if(SMB_VFS_RMDIR(conn,fullname) != 0) {
                                ret = True;
                                break;
                        }
-               } else if(vfs_unlink(conn,fullname) != 0) {
+               } else if(SMB_VFS_UNLINK(conn,fullname) != 0) {
                        ret = True;
                        break;
                }
@@ -2932,7 +2948,7 @@ BOOL rmdir_internals(connection_struct *conn, char *directory)
 {
        BOOL ok;
 
-       ok = (vfs_rmdir(conn,directory) == 0);
+       ok = (SMB_VFS_RMDIR(conn,directory) == 0);
        if(!ok && ((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn))) {
                /* 
                 * Check to see if the only thing in this directory are
@@ -2974,21 +2990,21 @@ BOOL rmdir_internals(connection_struct *conn, char *directory)
                                        pstrcat(fullname, "/");
                                        pstrcat(fullname, dname);
                      
-                                       if(conn->vfs_ops.lstat(conn,fullname, &st) != 0)
+                                       if(SMB_VFS_LSTAT(conn,fullname, &st) != 0)
                                                break;
                                        if(st.st_mode & S_IFDIR) {
                                                if(lp_recursive_veto_delete(SNUM(conn))) {
                                                        if(recursive_rmdir(conn, fullname) != 0)
                                                                break;
                                                }
-                                               if(vfs_rmdir(conn,fullname) != 0)
+                                               if(SMB_VFS_RMDIR(conn,fullname) != 0)
                                                        break;
-                                       } else if(vfs_unlink(conn,fullname) != 0)
+                                       } else if(SMB_VFS_UNLINK(conn,fullname) != 0)
                                                break;
                                }
                                CloseDir(dirptr);
                                /* Retry the rmdir */
-                               ok = (vfs_rmdir(conn,directory) == 0);
+                               ok = (SMB_VFS_RMDIR(conn,directory) == 0);
                        } else {
                                CloseDir(dirptr);
                        }
@@ -3104,11 +3120,10 @@ static BOOL resolve_wildcards(const char *name1, char *name2)
 
        available_space = sizeof(pstring) - PTR_DIFF(pname2, name2);
        
-       StrnCpy(pname2, root2, available_space-1);
-       available_space -= strlen(root2);
        if (ext2[0]) {
-               strncat(pname2, ".", available_space-1);
-               strncat(pname2, ext2, available_space-2);
+               snprintf(pname2, available_space - 1, "%s.%s", root2, ext2);
+       } else {
+               pstrcpy_base(pname2, root2, name2);
        }
 
        return(True);
@@ -3285,7 +3300,7 @@ directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n",
                        return NT_STATUS_OBJECT_NAME_COLLISION;
                }
 
-               if(conn->vfs_ops.rename(conn,directory, newname) == 0) {
+               if(SMB_VFS_RENAME(conn,directory, newname) == 0) {
                        DEBUG(3,("rename_internals: succeeded doing rename on %s -> %s\n",
                                directory,newname));
                        return NT_STATUS_OK;    
@@ -3352,7 +3367,7 @@ directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n",
                                        continue;
                                }
                                
-                               if (!conn->vfs_ops.rename(conn,fname,destname))
+                               if (!SMB_VFS_RENAME(conn,fname,destname))
                                        count++;
                                DEBUG(3,("rename_internals: doing rename on %s -> %s\n",fname,destname));
                        }
@@ -3446,7 +3461,7 @@ static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
        if (!target_is_directory && count)
                ofun = FILE_EXISTS_OPEN;
 
-       if (vfs_stat(conn,dest,&sbuf2) == -1)
+       if (SMB_VFS_STAT(conn,dest,&sbuf2) == -1)
                ZERO_STRUCTP(&sbuf2);
 
        fsp2 = open_file_shared(conn,dest,&sbuf2,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_WRONLY),
@@ -3458,7 +3473,7 @@ static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
        }
 
        if ((ofun&3) == 1) {
-               if(conn->vfs_ops.lseek(fsp2,fsp2->fd,0,SEEK_END) == -1) {
+               if(SMB_VFS_LSEEK(fsp2,fsp2->fd,0,SEEK_END) == -1) {
                        DEBUG(0,("copy_file: error - vfs lseek returned error %s\n", strerror(errno) ));
                        /*
                         * Stop the copy from occurring.
@@ -3942,7 +3957,7 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
 
        /* Setup the timeout in seconds. */
 
-       lock_timeout = ((lock_timeout == -1) ? -1 : (lock_timeout+999)/1000);
+       lock_timeout = ((lock_timeout == -1) ? -1 : (lock_timeout+499)/500);
        
        /* Now do any requested locks */
        data += ((large_file_format ? 20 : 10)*num_ulocks);
@@ -4386,8 +4401,9 @@ int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int size,
                SIVAL(outbuf,smb_vwv6,0);
                SIVAL(outbuf,smb_vwv8,0);
        } else {
+               uint32 allocation_size = get_allocation_size(fsp, &sbuf);
                SIVAL(outbuf,smb_vwv6,(uint32)sbuf.st_size);
-               SIVAL(outbuf,smb_vwv8,SMB_ROUNDUP(sbuf.st_size,1024));
+               SIVAL(outbuf,smb_vwv8,allocation_size);
        }
        SSVAL(outbuf,smb_vwv10, mode);