diff options
Diffstat (limited to 'source3/smbd/trans2.c')
-rw-r--r-- | source3/smbd/trans2.c | 257 |
1 files changed, 146 insertions, 111 deletions
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index d4daf1fd69..602656080e 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -3,6 +3,7 @@ SMB transaction2 handling Copyright (C) Jeremy Allison 1994-2003 Copyright (C) Stefan (metze) Metzmacher 2003 + Copyright (C) Volker Lendecke 2005 Extensively modified by Andrew Tridgell, 1995 @@ -119,8 +120,8 @@ static BOOL get_ea_value(TALLOC_CTX *mem_ctx, connection_struct *conn, files_str return False; } - if (fsp && fsp->fd != -1) { - sizeret = SMB_VFS_FGETXATTR(fsp, fsp->fd, ea_name, val, attr_size); + if (fsp && fsp->fh->fd != -1) { + sizeret = SMB_VFS_FGETXATTR(fsp, fsp->fh->fd, ea_name, val, attr_size); } else { sizeret = SMB_VFS_GETXATTR(conn, fname, ea_name, val, attr_size); } @@ -171,8 +172,8 @@ static struct ea_list *get_ea_list_from_file(TALLOC_CTX *mem_ctx, connection_str for (i = 0, ea_namelist = TALLOC(mem_ctx, ea_namelist_size); i < 6; ea_namelist = TALLOC_REALLOC_ARRAY(mem_ctx, ea_namelist, char, ea_namelist_size), i++) { - if (fsp && fsp->fd != -1) { - sizeret = SMB_VFS_FLISTXATTR(fsp, fsp->fd, ea_namelist, ea_namelist_size); + if (fsp && fsp->fh->fd != -1) { + sizeret = SMB_VFS_FLISTXATTR(fsp, fsp->fh->fd, ea_namelist, ea_namelist_size); } else { sizeret = SMB_VFS_LISTXATTR(conn, fname, ea_namelist, ea_namelist_size); } @@ -337,10 +338,10 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp, const char *fname, s if (ea_list->ea.value.length == 0) { /* Remove the attribute. */ - if (fsp && (fsp->fd != -1)) { + if (fsp && (fsp->fh->fd != -1)) { DEBUG(10,("set_ea: deleting ea name %s on file %s by file descriptor.\n", unix_ea_name, fsp->fsp_name)); - ret = SMB_VFS_FREMOVEXATTR(fsp, fsp->fd, unix_ea_name); + ret = SMB_VFS_FREMOVEXATTR(fsp, fsp->fh->fd, unix_ea_name); } else { DEBUG(10,("set_ea: deleting ea name %s on file %s.\n", unix_ea_name, fname)); @@ -355,10 +356,10 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp, const char *fname, s } #endif } else { - if (fsp && (fsp->fd != -1)) { + if (fsp && (fsp->fh->fd != -1)) { DEBUG(10,("set_ea: setting ea name %s on file %s by file descriptor.\n", unix_ea_name, fsp->fsp_name)); - ret = SMB_VFS_FSETXATTR(fsp, fsp->fd, unix_ea_name, + ret = SMB_VFS_FSETXATTR(fsp, fsp->fh->fd, unix_ea_name, ea_list->ea.value.data, ea_list->ea.value.length, 0); } else { DEBUG(10,("set_ea: setting ea name %s on file %s.\n", @@ -717,20 +718,20 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i { char *params = *pparams; char *pdata = *ppdata; - int16 open_mode; - int16 open_attr; + int deny_mode; + int32 open_attr; BOOL oplock_request; #if 0 BOOL return_additional_info; int16 open_sattr; time_t open_time; #endif - int16 open_ofun; + int open_ofun; int32 open_size; char *pname; pstring fname; SMB_OFF_T size=0; - int fmode=0,mtime=0,rmode; + int fattr=0,mtime=0; SMB_INO_T inode = 0; SMB_STRUCT_STAT sbuf; int smb_action = 0; @@ -740,6 +741,10 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i struct ea_list *ea_list = NULL; uint16 flags = 0; NTSTATUS status; + uint32 access_mask; + uint32 share_mode; + uint32 create_disposition; + uint32 create_options = 0; /* * Ensure we have enough parameters to perform the operation. @@ -750,7 +755,7 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i } flags = SVAL(params, 0); - open_mode = SVAL(params, 2); + deny_mode = SVAL(params, 2); open_attr = SVAL(params,6); oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0; if (oplock_request) { @@ -766,16 +771,18 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i open_size = IVAL(params,14); pname = ¶ms[28]; - if (IS_IPC(conn)) + if (IS_IPC(conn)) { return(ERROR_DOS(ERRSRV,ERRaccess)); + } srvstr_get_path(inbuf, fname, pname, sizeof(fname), -1, STR_TERMINATE, &status, False); if (!NT_STATUS_IS_OK(status)) { return ERROR_NT(status); } - DEBUG(3,("call_trans2open %s mode=%d attr=%d ofun=%d size=%d\n", - fname,open_mode, open_attr, open_ofun, open_size)); + DEBUG(3,("call_trans2open %s deny_mode=0x%x attr=%d ofun=0x%x size=%d\n", + fname, (unsigned int)deny_mode, (unsigned int)open_attr, + (unsigned int)open_ofun, open_size)); /* XXXX we need to handle passed times, sattr and flags */ @@ -788,11 +795,12 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess); } - /* Strange open mode mapping. */ - if (open_ofun == 0) { - if (GET_OPEN_MODE(open_mode) == DOS_OPEN_EXEC) { - open_ofun = FILE_EXISTS_FAIL | FILE_CREATE_IF_NOT_EXIST; - } + if (!map_open_params_to_ntcreate(fname, deny_mode, open_ofun, + &access_mask, + &share_mode, + &create_disposition, + &create_options)) { + return ERROR_DOS(ERRDOS, ERRbadaccess); } /* Any data in this call is an EA list. */ @@ -822,8 +830,14 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i } } - fsp = open_file_shared(conn,fname,&sbuf,open_mode,open_ofun,(uint32)open_attr, - oplock_request, &rmode,&smb_action); + fsp = open_file_ntcreate(conn,fname,&sbuf, + access_mask, + share_mode, + create_disposition, + create_options, + open_attr, + oplock_request, + &smb_action); if (!fsp) { talloc_destroy(ctx); @@ -835,10 +849,10 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i } size = get_file_size(sbuf); - fmode = dos_mode(conn,fname,&sbuf); + fattr = dos_mode(conn,fname,&sbuf); mtime = sbuf.st_mtime; inode = sbuf.st_ino; - if (fmode & aDIR) { + if (fattr & aDIR) { talloc_destroy(ctx); close_file(fsp,False); return(ERROR_DOS(ERRDOS,ERRnoaccess)); @@ -861,10 +875,10 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i *pparams = params; SSVAL(params,0,fsp->fnum); - SSVAL(params,2,fmode); + SSVAL(params,2,open_attr); put_dos_date2(params,4, mtime); SIVAL(params,8, (uint32)size); - SSVAL(params,12,rmode); + SSVAL(params,12,open_ofun); SSVAL(params,16,0); /* Padding. */ if (oplock_request && lp_fake_oplocks(SNUM(conn))) { @@ -2332,7 +2346,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned fsp.conn = conn; fsp.fnum = -1; - fsp.fd = -1; + fsp.fh->fd = -1; /* access check */ if (current_user.uid != 0) { @@ -2709,6 +2723,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char * char *pdata = *ppdata; uint16 info_level; int mode=0; + int nlink; SMB_OFF_T file_size=0; SMB_BIG_UINT allocation_size=0; unsigned int data_size = 0; @@ -2726,7 +2741,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char * files_struct *fsp = NULL; TALLOC_CTX *ea_ctx = NULL; struct ea_list *ea_list = NULL; - uint32 desired_access = 0x12019F; /* Default - GENERIC_EXECUTE mapping from Windows */ + uint32 access_mask = 0x12019F; /* Default - GENERIC_EXECUTE mapping from Windows */ if (!params) return ERROR_NT(NT_STATUS_INVALID_PARAMETER); @@ -2751,7 +2766,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char * pstrcpy(fname, fsp->fsp_name); /* We know this name is ok, it's already passed the checks. */ - } else if(fsp && (fsp->is_directory || fsp->fd == -1)) { + } else if(fsp && (fsp->is_directory || fsp->fh->fd == -1)) { /* * This is actually a QFILEINFO on a directory * handle (returned from an NT SMB). NT5.0 seems @@ -2771,7 +2786,9 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char * return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath); } - delete_pending = fsp->is_directory ? fsp->directory_delete_on_close : 0; + delete_pending = + get_delete_on_close_flag(sbuf.st_dev, + sbuf.st_ino); } else { /* * Original code - this is an open file. @@ -2779,13 +2796,15 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char * CHECK_FSP(fsp,conn); pstrcpy(fname, fsp->fsp_name); - if (SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0) { + if (SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf) != 0) { DEBUG(3,("fstat of fnum %d failed (%s)\n", fsp->fnum, strerror(errno))); return(UNIXERROR(ERRDOS,ERRbadfid)); } - pos = fsp->position_information; - delete_pending = fsp->delete_on_close; - desired_access = fsp->desired_access; + pos = fsp->fh->position_information; + delete_pending = + get_delete_on_close_flag(sbuf.st_dev, + sbuf.st_ino); + access_mask = fsp->access_mask; } } else { NTSTATUS status = NT_STATUS_OK; @@ -2825,6 +2844,23 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char * DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno))); return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath); } + + delete_pending = get_delete_on_close_flag(sbuf.st_dev, + sbuf.st_ino); + if (delete_pending) { + return ERROR_NT(NT_STATUS_DELETE_PENDING); + } + } + + nlink = sbuf.st_nlink; + + if ((nlink > 0) && S_ISDIR(sbuf.st_mode)) { + /* NTFS does not seem to count ".." */ + nlink -= 1; + } + + if ((nlink > 0) && delete_pending) { + nlink -= 1; } if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) @@ -3054,11 +3090,8 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd data_size = 24; SOFF_T(pdata,0,allocation_size); SOFF_T(pdata,8,file_size); - if (delete_pending & sbuf.st_nlink) - SIVAL(pdata,16,sbuf.st_nlink - 1); - else - SIVAL(pdata,16,sbuf.st_nlink); - SCVAL(pdata,20,0); + SIVAL(pdata,16,nlink); + SCVAL(pdata,20,delete_pending?1:0); SCVAL(pdata,21,(mode&aDIR)?1:0); SSVAL(pdata,22,0); /* Padding. */ break; @@ -3129,10 +3162,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd pdata += 40; SOFF_T(pdata,0,allocation_size); SOFF_T(pdata,8,file_size); - if (delete_pending && sbuf.st_nlink) - SIVAL(pdata,16,sbuf.st_nlink - 1); - else - SIVAL(pdata,16,sbuf.st_nlink); + SIVAL(pdata,16,nlink); SCVAL(pdata,20,delete_pending); SCVAL(pdata,21,(mode&aDIR)?1:0); SSVAL(pdata,22,0); @@ -3160,7 +3190,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd case SMB_FILE_ACCESS_INFORMATION: DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ACCESS_INFORMATION\n")); - SIVAL(pdata,0,desired_access); + SIVAL(pdata,0,access_mask); data_size = 4; break; @@ -3343,8 +3373,8 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd uint16 num_file_acls = 0; uint16 num_def_acls = 0; - if (fsp && !fsp->is_directory && (fsp->fd != -1)) { - file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fd); + if (fsp && !fsp->is_directory && (fsp->fh->fd != -1)) { + file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fh->fd); } else { file_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS); } @@ -3429,50 +3459,46 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd open_file_shared. JRA. ****************************************************************************/ -NTSTATUS set_delete_on_close_internal(files_struct *fsp, BOOL delete_on_close, uint32 dosmode) +NTSTATUS can_set_delete_on_close(files_struct *fsp, BOOL delete_on_close, + uint32 dosmode) { - if (delete_on_close) { - /* - * Only allow delete on close for writable files. - */ - - if (!lp_delete_readonly(SNUM(fsp->conn))) { - if (dosmode & aRONLY) { - DEBUG(10,("set_delete_on_close_internal: file %s delete on close flag set but file attribute is readonly.\n", - fsp->fsp_name )); - return NT_STATUS_CANNOT_DELETE; - } - } + if (!delete_on_close) { + return NT_STATUS_OK; + } - /* - * Only allow delete on close for writable shares. - */ + /* + * Only allow delete on close for writable files. + */ - if (!CAN_WRITE(fsp->conn)) { - DEBUG(10,("set_delete_on_close_internal: file %s delete on close flag set but write access denied on share.\n", - fsp->fsp_name )); - return NT_STATUS_ACCESS_DENIED; - } + if ((dosmode & aRONLY) && + !lp_delete_readonly(SNUM(fsp->conn))) { + DEBUG(10,("can_set_delete_on_close: file %s delete on close " + "flag set but file attribute is readonly.\n", + fsp->fsp_name )); + return NT_STATUS_CANNOT_DELETE; + } - /* - * Only allow delete on close for files/directories opened with delete intent. - */ + /* + * Only allow delete on close for writable shares. + */ - if (!(fsp->desired_access & DELETE_ACCESS)) { - DEBUG(10,("set_delete_on_close_internal: file %s delete on close flag set but delete access denied.\n", - fsp->fsp_name )); - return NT_STATUS_ACCESS_DENIED; - } + if (!CAN_WRITE(fsp->conn)) { + DEBUG(10,("can_set_delete_on_close: file %s delete on " + "close flag set but write access denied on share.\n", + fsp->fsp_name )); + return NT_STATUS_ACCESS_DENIED; } - if(fsp->is_directory) { - fsp->directory_delete_on_close = delete_on_close; - DEBUG(10, ("set_delete_on_close_internal: %s delete on close flag for fnum = %d, directory %s\n", - delete_on_close ? "Added" : "Removed", fsp->fnum, fsp->fsp_name )); - } else { - fsp->delete_on_close = delete_on_close; - DEBUG(10, ("set_delete_on_close_internal: %s delete on close flag for fnum = %d, file %s\n", - delete_on_close ? "Added" : "Removed", fsp->fnum, fsp->fsp_name )); + /* + * Only allow delete on close for files/directories opened with delete + * intent. + */ + + if (!(fsp->access_mask & DELETE_ACCESS)) { + DEBUG(10,("can_set_delete_on_close: file %s delete on " + "close flag set but delete access denied.\n", + fsp->fsp_name )); + return NT_STATUS_ACCESS_DENIED; } return NT_STATUS_OK; @@ -3487,10 +3513,12 @@ NTSTATUS set_delete_on_close_internal(files_struct *fsp, BOOL delete_on_close, u if flag is set. ****************************************************************************/ -NTSTATUS set_delete_on_close_over_all(files_struct *fsp, BOOL delete_on_close) +NTSTATUS set_delete_on_close(files_struct *fsp, BOOL delete_on_close) { - DEBUG(10,("set_delete_on_close_over_all: %s delete on close flag for fnum = %d, file %s\n", - delete_on_close ? "Adding" : "Removing", fsp->fnum, fsp->fsp_name )); + DEBUG(10,("set_delete_on_close: %s delete on close flag for " + "fnum = %d, file %s\n", + delete_on_close ? "Adding" : "Removing", fsp->fnum, + fsp->fsp_name )); if (fsp->is_directory || fsp->is_stat) return NT_STATUS_OK; @@ -3499,8 +3527,9 @@ NTSTATUS set_delete_on_close_over_all(files_struct *fsp, BOOL delete_on_close) return NT_STATUS_ACCESS_DENIED; if (!modify_delete_flag(fsp->dev, fsp->inode, delete_on_close)) { - DEBUG(0,("set_delete_on_close_over_all: failed to change delete on close flag for file %s\n", - fsp->fsp_name )); + DEBUG(0,("set_delete_on_close: failed to change delete " + "on close flag for file %s\n", + fsp->fsp_name )); unlock_share_entry_fsp(fsp); return NT_STATUS_ACCESS_DENIED; } @@ -3632,7 +3661,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char fsp = file_fsp(params,0); info_level = SVAL(params,2); - if(fsp && (fsp->is_directory || fsp->fd == -1)) { + if(fsp && (fsp->is_directory || fsp->fh->fd == -1)) { /* * This is actually a SETFILEINFO on a directory * handle (returned from an NT SMB). NT5.0 seems @@ -3648,7 +3677,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char * Doing a DELETE_ON_CLOSE should cancel a print job. */ if ((info_level == SMB_SET_FILE_DISPOSITION_INFO) && CVAL(pdata,0)) { - fsp->share_mode = FILE_DELETE_ON_CLOSE; + fsp->fh->private_options |= FILE_DELETE_ON_CLOSE; DEBUG(3,("call_trans2setfilepathinfo: Cancelling print job (%s)\n", fsp->fsp_name )); @@ -3664,7 +3693,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char CHECK_FSP(fsp,conn); pstrcpy(fname, fsp->fsp_name); - fd = fsp->fd; + fd = fsp->fh->fd; if (SMB_VFS_FSTAT(fsp,fd,&sbuf) != 0) { DEBUG(3,("call_trans2setfilepathinfo: fstat of fnum %d failed (%s)\n",fsp->fnum, strerror(errno))); @@ -3881,8 +3910,6 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char if (fd == -1) { files_struct *new_fsp = NULL; - int access_mode = 0; - int action = 0; if(global_oplock_break) { /* Queue this file modify as we are the process of an oplock break. */ @@ -3894,16 +3921,20 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char return -1; } - new_fsp = open_file_shared1(conn, fname, &sbuf,FILE_WRITE_DATA, - SET_OPEN_MODE(DOS_OPEN_RDWR), - (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), + new_fsp = open_file_ntcreate(conn, fname, &sbuf, + FILE_WRITE_DATA, + FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_OPEN, + 0, FILE_ATTRIBUTE_NORMAL, - INTERNAL_OPEN_ONLY, &access_mode, &action); + INTERNAL_OPEN_ONLY, + NULL); - if (new_fsp == NULL) + if (new_fsp == NULL) { return(UNIXERROR(ERRDOS,ERRbadpath)); + } ret = vfs_allocate_file_space(new_fsp, allocation_size); - if (SMB_VFS_FSTAT(new_fsp,new_fsp->fd,&new_sbuf) != 0) { + if (SMB_VFS_FSTAT(new_fsp,new_fsp->fh->fd,&new_sbuf) != 0) { DEBUG(3,("call_trans2setfilepathinfo: fstat of fnum %d failed (%s)\n", new_fsp->fnum, strerror(errno))); ret = -1; @@ -3963,14 +3994,15 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char if (fsp == NULL) return(UNIXERROR(ERRDOS,ERRbadfid)); - status = set_delete_on_close_internal(fsp, delete_on_close, dosmode); + status = can_set_delete_on_close(fsp, delete_on_close, + dosmode); if (!NT_STATUS_IS_OK(status)) { return ERROR_NT(status); } /* The set is across all open files on this dev/inode pair. */ - status =set_delete_on_close_over_all(fsp, delete_on_close); + status =set_delete_on_close(fsp, delete_on_close); if (!NT_STATUS_IS_OK(status)) { return ERROR_NT(status); } @@ -3998,7 +4030,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char DEBUG(10,("call_trans2setfilepathinfo: Set file position information for file %s to %.0f\n", fname, (double)position_information )); if (fsp) { - fsp->position_information = position_information; + fsp->fh->position_information = position_information; } /* We're done. We only get position info in this call. */ @@ -4422,8 +4454,6 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", if (fd == -1) { files_struct *new_fsp = NULL; - int access_mode = 0; - int action = 0; if(global_oplock_break) { /* Queue this file modify as we are the process of an oplock break. */ @@ -4435,22 +4465,27 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", return -1; } - new_fsp = open_file_shared(conn, fname, &sbuf, - SET_OPEN_MODE(DOS_OPEN_RDWR), - (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), + new_fsp = open_file_ntcreate(conn, fname, &sbuf, + FILE_WRITE_DATA, + FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_OPEN, + 0, FILE_ATTRIBUTE_NORMAL, - INTERNAL_OPEN_ONLY, &access_mode, &action); + INTERNAL_OPEN_ONLY, + NULL); - if (new_fsp == NULL) + if (new_fsp == NULL) { return(UNIXERROR(ERRDOS,ERRbadpath)); + } ret = vfs_set_filelen(new_fsp, size); close_file(new_fsp,True); } else { ret = vfs_set_filelen(fsp, size); } - if (ret == -1) + if (ret == -1) { return (UNIXERROR(ERRHRD,ERRdiskfull)); + } } /* |