diff options
author | Jeremy Allison <jra@samba.org> | 2005-07-08 04:51:27 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 10:58:18 -0500 |
commit | c7fe18761e2c753afbffd3a78abff46472a9b8eb (patch) | |
tree | f60b3a473919fe3a6294822226bd950b8d832c70 | |
parent | 053e892e07936f6b71a6bb5e31be09c1d2a2c837 (diff) | |
download | samba-c7fe18761e2c753afbffd3a78abff46472a9b8eb.tar.gz |
r8219: Merge the new open code from HEAD to 3.0. Haven't yet run the torture
tests on this as it's very late NY time (just wanted to get this work
into the tree). I'll test this over the weekend....
Jerry - in looking at the difference between the two trees there
seem to be some printing/ntprinting.c and registry changes we might
want to examine to try keep in sync.
Jeremy.
35 files changed, 2566 insertions, 1964 deletions
diff --git a/source/include/doserr.h b/source/include/doserr.h index 77255ee4c11..647f11527b7 100644 --- a/source/include/doserr.h +++ b/source/include/doserr.h @@ -63,6 +63,9 @@ #define ERRinvalidname 123 /* Invalid name */ #define ERRunknownlevel 124 #define ERRnotlocked 158 /* This region is not locked by this locking context. */ +#define ERRinvalidpath 161 +#define ERRcancelviolation 173 +#define ERRnoatomiclocks 174 #define ERRrename 183 #define ERRbadpipe 230 /* Named pipe invalid */ #define ERRpipebusy 231 /* All instances of pipe are busy */ diff --git a/source/include/ntlmssp.h b/source/include/ntlmssp.h index 8ab6265673c..267779c434d 100644 --- a/source/include/ntlmssp.h +++ b/source/include/ntlmssp.h @@ -124,7 +124,6 @@ typedef struct ntlmssp_state * * @param ntlmssp_state This structure * @param challenge 8 bytes of data, agreed by the client and server to be the effective challenge for NTLM2 authentication - * @param challange 8 bytes of data, agreed by the client and server to be the effective challenge for NTLM2 authentication * */ NTSTATUS (*set_challenge)(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *challenge); diff --git a/source/include/smb.h b/source/include/smb.h index 50bd233da76..55baf845315 100644 --- a/source/include/smb.h +++ b/source/include/smb.h @@ -107,44 +107,32 @@ typedef int BOOL; #define DOS_OPEN_FCB 0xF /* define shifts and masks for share and open modes. */ -#define OPEN_MODE_MASK 0xF -#define SHARE_MODE_SHIFT 4 -#define SHARE_MODE_MASK 0x7 -#define GET_OPEN_MODE(x) ((x) & OPEN_MODE_MASK) -#define SET_OPEN_MODE(x) ((x) & OPEN_MODE_MASK) -#define GET_DENY_MODE(x) (((x)>>SHARE_MODE_SHIFT) & SHARE_MODE_MASK) -#define SET_DENY_MODE(x) (((x) & SHARE_MODE_MASK) <<SHARE_MODE_SHIFT) +#define OPENX_MODE_MASK 0xF +#define DENY_MODE_SHIFT 4 +#define DENY_MODE_MASK 0x7 +#define GET_OPENX_MODE(x) ((x) & OPENX_MODE_MASK) +#define SET_OPENX_MODE(x) ((x) & OPENX_MODE_MASK) +#define GET_DENY_MODE(x) (((x)>>DENY_MODE_SHIFT) & DENY_MODE_MASK) +#define SET_DENY_MODE(x) (((x) & DENY_MODE_MASK) <<DENY_MODE_SHIFT) /* Sync on open file (not sure if used anymore... ?) */ #define FILE_SYNC_OPENMODE (1<<14) #define GET_FILE_SYNC_OPENMODE(x) (((x) & FILE_SYNC_OPENMODE) ? True : False) -/* allow delete on open file mode (used by NT SMB's). */ -#define ALLOW_SHARE_DELETE (1<<15) -#define GET_ALLOW_SHARE_DELETE(x) (((x) & ALLOW_SHARE_DELETE) ? True : False) -#define SET_ALLOW_SHARE_DELETE(x) ((x) ? ALLOW_SHARE_DELETE : 0) - -/* delete on close flag (used by NT SMB's). */ -#define DELETE_ON_CLOSE_FLAG (1<<16) -#define GET_DELETE_ON_CLOSE_FLAG(x) (((x) & DELETE_ON_CLOSE_FLAG) ? True : False) -#define SET_DELETE_ON_CLOSE_FLAG(x) ((x) ? DELETE_ON_CLOSE_FLAG : 0) - /* open disposition values */ -#define FILE_EXISTS_FAIL 0 -#define FILE_EXISTS_OPEN 1 -#define FILE_EXISTS_TRUNCATE 2 +#define OPENX_FILE_EXISTS_FAIL 0 +#define OPENX_FILE_EXISTS_OPEN 1 +#define OPENX_FILE_EXISTS_TRUNCATE 2 /* mask for open disposition. */ -#define FILE_OPEN_MASK 0x3 +#define OPENX_FILE_OPEN_MASK 0x3 -#define GET_FILE_OPEN_DISPOSITION(x) ((x) & FILE_OPEN_MASK) -#define SET_FILE_OPEN_DISPOSITION(x) ((x) & FILE_OPEN_MASK) +#define GET_FILE_OPENX_DISPOSITION(x) ((x) & FILE_OPEN_MASK) +#define SET_FILE_OPENX_DISPOSITION(x) ((x) & FILE_OPEN_MASK) /* The above can be OR'ed with... */ -#define FILE_CREATE_IF_NOT_EXIST 0x10 -#define FILE_FAIL_IF_NOT_EXIST 0 - -#define GET_FILE_CREATE_DISPOSITION(x) ((x) & (FILE_CREATE_IF_NOT_EXIST|FILE_FAIL_IF_NOT_EXIST)) +#define OPENX_FILE_CREATE_IF_NOT_EXIST 0x10 +#define OPENX_FILE_FAIL_IF_NOT_EXIST 0 /* share types */ #define STYPE_DISKTREE 0 /* Disk drive */ @@ -407,27 +395,38 @@ typedef struct #include "fake_file.h" +struct fd_handle { + size_t ref_count; + int fd; + SMB_BIG_UINT position_information; + SMB_OFF_T pos; + uint32 private_options; /* NT Create options, but we only look at + * NTCREATEX_OPTIONS_PRIVATE_DENY_DOS and + * NTCREATEX_OPTIONS_PRIVATE_DENY_FCB (Except + * for print files *only*, where + * DELETE_ON_CLOSE is not stored in the share + * mode database. + */ +}; + typedef struct files_struct { struct files_struct *next, *prev; int fnum; struct connection_struct *conn; - int fd; + struct fd_handle *fh; unsigned int num_smb_operations; uint16 rap_print_jobid; SMB_DEV_T dev; SMB_INO_T inode; - BOOL delete_on_close; - SMB_OFF_T pos; SMB_BIG_UINT initial_allocation_size; /* Faked up initial allocation on disk. */ - SMB_BIG_UINT position_information; mode_t mode; uint16 file_pid; uint16 vuid; write_bmpx_struct *wbmpx_ptr; write_cache *wcp; struct timeval open_time; - int share_mode; - uint32 desired_access; + uint32 access_mask; /* NTCreateX access bits (FILE_READ_DATA etc.) */ + uint32 share_access; /* NTCreateX share constants (FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE). */ BOOL pending_modtime_owner; time_t pending_modtime; time_t last_write_time; @@ -441,7 +440,6 @@ typedef struct files_struct { BOOL modified; BOOL is_directory; BOOL is_stat; - BOOL directory_delete_on_close; BOOL aio_write_behind; char *fsp_name; FAKE_FILE_HANDLE *fake_file_handle; @@ -639,8 +637,12 @@ typedef struct { pid_t pid; uint16 op_port; uint16 op_type; - int share_mode; - uint32 desired_access; + uint32 access_mask; /* NTCreateX access bits (FILE_READ_DATA etc.) */ + uint32 share_access; /* NTCreateX share constants (FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE). */ + uint32 private_options; /* NT Create options, but we only look at + * NTCREATEX_OPTIONS_PRIVATE_DENY_DOS and + * NTCREATEX_OPTIONS_PRIVATE_DENY_FCB for + * smbstatus and swat */ struct timeval time; SMB_DEV_T dev; SMB_INO_T inode; @@ -1079,18 +1081,18 @@ struct bitmap { #define DESIRED_ACCESS_PIPE 0x2019f /* Generic access masks & rights. */ -#define DELETE_ACCESS (1L<<16) /* 0x00010000 */ -#define READ_CONTROL_ACCESS (1L<<17) /* 0x00020000 */ -#define WRITE_DAC_ACCESS (1L<<18) /* 0x00040000 */ -#define WRITE_OWNER_ACCESS (1L<<19) /* 0x00080000 */ -#define SYNCHRONIZE_ACCESS (1L<<20) /* 0x00100000 */ - -#define SYSTEM_SECURITY_ACCESS (1L<<24) /* 0x01000000 */ -#define MAXIMUM_ALLOWED_ACCESS (1L<<25) /* 0x02000000 */ -#define GENERIC_ALL_ACCESS (1<<28) /* 0x10000000 */ -#define GENERIC_EXECUTE_ACCESS (1<<29) /* 0x20000000 */ -#define GENERIC_WRITE_ACCESS (1<<30) /* 0x40000000 */ -#define GENERIC_READ_ACCESS (((unsigned)1)<<31) /* 0x80000000 */ +#define DELETE_ACCESS 0x00010000 /* (1L<<16) */ +#define READ_CONTROL_ACCESS 0x00020000 /* (1L<<17) */ +#define WRITE_DAC_ACCESS 0x00040000 /* (1L<<18) */ +#define WRITE_OWNER_ACCESS 0x00080000 /* (1L<<19) */ +#define SYNCHRONIZE_ACCESS 0x00100000 /* (1L<<20) */ + +#define SYSTEM_SECURITY_ACCESS 0x01000000 /* (1L<<24) */ +#define MAXIMUM_ALLOWED_ACCESS 0x02000000 /* (1L<<25) */ +#define GENERIC_ALL_ACCESS 0x10000000 /* (1<<28) */ +#define GENERIC_EXECUTE_ACCESS 0x20000000 /* (1<<29) */ +#define GENERIC_WRITE_ACCESS 0x40000000 /* (1<<30) */ +#define GENERIC_READ_ACCESS ((unsigned)0x80000000) /* (((unsigned)1)<<31) */ /* Mapping of generic access rights for files to specific rights. */ @@ -1172,12 +1174,12 @@ struct bitmap { #define FILE_FLAG_POSIX_SEMANTICS 0x01000000L /* CreateDisposition field. */ -#define FILE_SUPERSEDE 0 -#define FILE_OPEN 1 -#define FILE_CREATE 2 -#define FILE_OPEN_IF 3 -#define FILE_OVERWRITE 4 -#define FILE_OVERWRITE_IF 5 +#define FILE_SUPERSEDE 0 /* File exists overwrite/supersede. File not exist create. */ +#define FILE_OPEN 1 /* File exists open. File not exist fail. */ +#define FILE_CREATE 2 /* File exists fail. File not exist create. */ +#define FILE_OPEN_IF 3 /* File exists open. File not exist create. */ +#define FILE_OVERWRITE 4 /* File exists overwrite. File not exist fail. */ +#define FILE_OVERWRITE_IF 5 /* File exists overwrite. File not exist create. */ /* CreateOptions field. */ #define FILE_DIRECTORY_FILE 0x0001 @@ -1190,6 +1192,10 @@ struct bitmap { #define FILE_DELETE_ON_CLOSE 0x1000 #define FILE_OPEN_BY_FILE_ID 0x2000 +/* Private create options used by the ntcreatex processing code. From Samba4. */ +#define NTCREATEX_OPTIONS_PRIVATE_DENY_DOS 0x01000000 +#define NTCREATEX_OPTIONS_PRIVATE_DENY_FCB 0x02000000 + /* Responses when opening a file. */ #define FILE_WAS_SUPERSEDED 0 #define FILE_WAS_OPENED 1 @@ -1335,7 +1341,7 @@ char *strdup(char *s); #define FLAGS2_IS_LONG_NAME 0x0040 #define FLAGS2_EXTENDED_SECURITY 0x0800 #define FLAGS2_DFS_PATHNAMES 0x1000 -#define FLAGS2_READ_PERMIT_NO_EXECUTE 0x2000 +#define FLAGS2_READ_PERMIT_EXECUTE 0x2000 #define FLAGS2_32_BIT_ERROR_CODES 0x4000 #define FLAGS2_UNICODE_STRINGS 0x8000 @@ -1442,36 +1448,36 @@ extern int chain_size; #define LOCKING_ANDX_CANCEL_LOCK 0x8 #define LOCKING_ANDX_LARGE_FILES 0x10 -/* Oplock levels */ -#define OPLOCKLEVEL_NONE 0 -#define OPLOCKLEVEL_II 1 - /* * Bits we test with. */ - + #define NO_OPLOCK 0 #define EXCLUSIVE_OPLOCK 1 #define BATCH_OPLOCK 2 #define LEVEL_II_OPLOCK 4 #define INTERNAL_OPEN_ONLY 8 -#define EXCLUSIVE_OPLOCK_TYPE(lck) ((lck) & (EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) -#define BATCH_OPLOCK_TYPE(lck) ((lck) & BATCH_OPLOCK) -#define LEVEL_II_OPLOCK_TYPE(lck) ((lck) & LEVEL_II_OPLOCK) - -#define CORE_OPLOCK_GRANTED (1<<5) -#define EXTENDED_OPLOCK_GRANTED (1<<15) +#define EXCLUSIVE_OPLOCK_TYPE(lck) ((lck) & ((unsigned int)EXCLUSIVE_OPLOCK|(unsigned int)BATCH_OPLOCK)) +#define BATCH_OPLOCK_TYPE(lck) ((lck) & (unsigned int)BATCH_OPLOCK) +#define LEVEL_II_OPLOCK_TYPE(lck) ((lck) & (unsigned int)LEVEL_II_OPLOCK) /* - * Return values for oplock types. + * On the wire return values for oplock types. */ +#define CORE_OPLOCK_GRANTED (1<<5) +#define EXTENDED_OPLOCK_GRANTED (1<<15) + #define NO_OPLOCK_RETURN 0 #define EXCLUSIVE_OPLOCK_RETURN 1 #define BATCH_OPLOCK_RETURN 2 #define LEVEL_II_OPLOCK_RETURN 3 +/* Oplock levels */ +#define OPLOCKLEVEL_NONE 0 +#define OPLOCKLEVEL_II 1 + /* * Loopback command offsets. */ diff --git a/source/include/smb_macros.h b/source/include/smb_macros.h index b7e27d22667..7a0afdfc192 100644 --- a/source/include/smb_macros.h +++ b/source/include/smb_macros.h @@ -101,15 +101,16 @@ extern struct current_user current_user;\ if (!FNUM_OK(fsp,conn)) \ return(ERROR_DOS(ERRDOS,ERRbadfid)); \ - else if((fsp)->fd == -1) \ + else if((fsp)->fh->fd == -1) \ return(ERROR_DOS(ERRDOS,ERRbadaccess));\ (fsp)->num_smb_operations++;\ } while(0) -#define CHECK_READ(fsp) if (!(fsp)->can_read) \ - return(ERROR_DOS(ERRDOS,ERRbadaccess)) -#define CHECK_WRITE(fsp) if (!(fsp)->can_write) \ - return(ERROR_DOS(ERRDOS,ERRbadaccess)) +#define CHECK_READ(fsp,inbuf) (((fsp)->fh->fd != -1) && ((fsp)->can_read || \ + ((SVAL((inbuf),smb_flg2) & FLAGS2_READ_PERMIT_EXECUTE) && \ + (fsp->access_mask & FILE_EXECUTE)))) + +#define CHECK_WRITE(fsp) ((fsp)->can_write && ((fsp)->fh->fd != -1)) #define ERROR_WAS_LOCK_DENIED(status) (NT_STATUS_EQUAL((status), NT_STATUS_LOCK_NOT_GRANTED) || \ NT_STATUS_EQUAL((status), NT_STATUS_FILE_LOCK_CONFLICT) ) diff --git a/source/include/vfs.h b/source/include/vfs.h index 71b4f656279..7f6c94f6e99 100644 --- a/source/include/vfs.h +++ b/source/include/vfs.h @@ -58,7 +58,8 @@ /* Changed to version 11 to include seekdir/telldir/rewinddir calls. JRA */ /* Changed to version 12 to add mask and attributes to opendir(). JRA Also include aio calls. JRA. */ -#define SMB_VFS_INTERFACE_VERSION 12 +/* Changed to version 13 as the internal structure of files_struct has changed. JRA */ +#define SMB_VFS_INTERFACE_VERSION 13 /* to bug old modules which are trying to compile with the old functions */ diff --git a/source/lib/util.c b/source/lib/util.c index 42cbc7288f9..de366c604ff 100644 --- a/source/lib/util.c +++ b/source/lib/util.c @@ -2735,3 +2735,25 @@ int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6) return ret; } #endif + +uint32 map_share_mode_to_deny_mode(uint32 share_access, uint32 private_options) +{ + switch (share_access) { + case FILE_SHARE_NONE: + return DENY_ALL; + case FILE_SHARE_READ: + return DENY_WRITE; + case FILE_SHARE_WRITE: + return DENY_READ; + case FILE_SHARE_READ|FILE_SHARE_WRITE: + case FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE: + return DENY_NONE; + } + if (private_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS) { + return DENY_DOS; + } else if (private_options & NTCREATEX_OPTIONS_PRIVATE_DENY_FCB) { + return DENY_FCB; + } + + return (uint32)-1; +} diff --git a/source/libsmb/clifile.c b/source/libsmb/clifile.c index 2fb5b456cc4..87c6f2568b1 100644 --- a/source/libsmb/clifile.c +++ b/source/libsmb/clifile.c @@ -705,7 +705,7 @@ int cli_nt_create_full(struct cli_state *cli, const char *fname, int cli_nt_create(struct cli_state *cli, const char *fname, uint32 DesiredAccess) { return cli_nt_create_full(cli, fname, 0, DesiredAccess, 0, - FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_EXISTS_OPEN, 0x0, 0x0); + FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0x0, 0x0); } /**************************************************************************** diff --git a/source/libsmb/errormap.c b/source/libsmb/errormap.c index c79561bda87..8462fbee877 100644 --- a/source/libsmb/errormap.c +++ b/source/libsmb/errormap.c @@ -124,9 +124,9 @@ static const struct { {ERRHRD, ERRgeneral, NT_STATUS_HANDLE_NOT_WAITABLE}, {ERRDOS, ERRbadfid, NT_STATUS_PORT_DISCONNECTED}, {ERRHRD, ERRgeneral, NT_STATUS_DEVICE_ALREADY_ATTACHED}, - {ERRDOS, 161, NT_STATUS_OBJECT_PATH_INVALID}, + {ERRDOS, ERRinvalidpath, NT_STATUS_OBJECT_PATH_INVALID}, {ERRDOS, ERRbadpath, NT_STATUS_OBJECT_PATH_NOT_FOUND}, - {ERRDOS, 161, NT_STATUS_OBJECT_PATH_SYNTAX_BAD}, + {ERRDOS, ERRinvalidpath, NT_STATUS_OBJECT_PATH_SYNTAX_BAD}, {ERRHRD, ERRgeneral, NT_STATUS_DATA_OVERRUN}, {ERRHRD, ERRgeneral, NT_STATUS_DATA_LATE_ERROR}, {ERRDOS, 23, NT_STATUS_DATA_ERROR}, diff --git a/source/locking/locking.c b/source/locking/locking.c index 3c5ab63b4ab..5bcf7f2eda8 100644 --- a/source/locking/locking.c +++ b/source/locking/locking.c @@ -3,6 +3,7 @@ Locking functions Copyright (C) Andrew Tridgell 1992-2000 Copyright (C) Jeremy Allison 1992-2000 + Copyright (C) Volker Lendecke 2005 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -46,7 +47,10 @@ static TDB_CONTEXT *deferred_open_tdb; struct locking_data { union { - int num_share_mode_entries; + struct { + int num_share_mode_entries; + BOOL delete_on_close; + } s; share_mode_entry dummy; /* Needed for alignment. */ } u; /* the following two entries are implicit @@ -432,10 +436,14 @@ char *share_mode_str(int num, share_mode_entry *e) { static pstring share_str; - slprintf(share_str, sizeof(share_str)-1, "share_mode_entry[%d]: \ -pid = %lu, share_mode = 0x%x, desired_access = 0x%x, port = 0x%x, type= 0x%x, file_id = %lu, dev = 0x%x, inode = %.0f", - num, (unsigned long)e->pid, e->share_mode, (unsigned int)e->desired_access, e->op_port, e->op_type, e->share_file_id, - (unsigned int)e->dev, (double)e->inode ); + slprintf(share_str, sizeof(share_str)-1, "share_mode_entry[%d]: " + "pid = %lu, share_access = 0x%x, private_options = 0x%x, " + "access_mask = 0x%x, port = 0x%x, type= 0x%x, file_id = %lu, " + "dev = 0x%x, inode = %.0f", + num, (unsigned long)e->pid, + e->share_access, e->private_options, + e->access_mask, e->op_port, e->op_type, e->share_file_id, + (unsigned int)e->dev, (double)e->inode ); return share_str; } @@ -446,7 +454,7 @@ pid = %lu, share_mode = 0x%x, desired_access = 0x%x, port = 0x%x, type= 0x%x, fi static void print_share_mode_table(struct locking_data *data) { - int num_share_modes = data->u.num_share_mode_entries; + int num_share_modes = data->u.s.num_share_mode_entries; share_mode_entry *shares = (share_mode_entry *)(data + 1); int i; @@ -460,9 +468,9 @@ static void print_share_mode_table(struct locking_data *data) Get all share mode entries for a dev/inode pair. ********************************************************************/ -int get_share_modes(connection_struct *conn, - SMB_DEV_T dev, SMB_INO_T inode, - share_mode_entry **pp_shares) +int get_share_modes(SMB_DEV_T dev, SMB_INO_T inode, + share_mode_entry **pp_shares, + BOOL *delete_on_close) { TDB_DATA dbuf; struct locking_data *data; @@ -470,13 +478,18 @@ int get_share_modes(connection_struct *conn, share_mode_entry *shares = NULL; TDB_DATA key = locking_key(dev, inode); *pp_shares = NULL; + *delete_on_close = False; dbuf = tdb_fetch(tdb, key); if (!dbuf.dptr) return 0; data = (struct locking_data *)dbuf.dptr; - num_share_modes = data->u.num_share_mode_entries; + + *delete_on_close = data->u.s.delete_on_close; + DEBUG(10, ("get_share_modes: delete_on_close: %d\n", + *delete_on_close)); + num_share_modes = data->u.s.num_share_mode_entries; if(num_share_modes) { pstring fname; int i; @@ -515,7 +528,7 @@ int get_share_modes(connection_struct *conn, /* Did we delete any ? If so, re-store in tdb. */ if (del_count) { - data->u.num_share_mode_entries = num_share_modes; + data->u.s.num_share_mode_entries = num_share_modes; if (num_share_modes) { memcpy(dbuf.dptr + sizeof(*data), shares, @@ -527,7 +540,7 @@ int get_share_modes(connection_struct *conn, /* The record has shrunk a bit */ dbuf.dsize -= del_count * sizeof(share_mode_entry); - if (data->u.num_share_mode_entries == 0) { + if (data->u.s.num_share_mode_entries == 0) { if (tdb_delete(tdb, key) == -1) { SAFE_FREE(shares); SAFE_FREE(dbuf.dptr); @@ -548,6 +561,15 @@ int get_share_modes(connection_struct *conn, return num_share_modes; } +BOOL get_delete_on_close_flag(SMB_DEV_T dev, SMB_INO_T inode) +{ + share_mode_entry *shares; + BOOL result; + get_share_modes(dev, inode, &shares, &result); + SAFE_FREE(shares); + return result; +} + /******************************************************************* Fill a share mode entry. ********************************************************************/ @@ -559,8 +581,9 @@ static void fill_share_mode(char *p, files_struct *fsp, uint16 port, uint16 op_t memset(e, '\0', sizeof(share_mode_entry)); e->pid = sys_getpid(); - e->share_mode = fsp->share_mode; - e->desired_access = fsp->desired_access; + e->share_access = fsp->share_access; + e->private_options = fsp->fh->private_options; + e->access_mask = fsp->access_mask; e->op_port = port; e->op_type = op_type; memcpy(x, &fsp->open_time, sizeof(struct timeval)); @@ -581,16 +604,17 @@ BOOL share_modes_identical( share_mode_entry *e1, share_mode_entry *e2) e1->share_file_id == e2->share_file_id && e1->dev == e2->dev && e1->inode == e2->inode && - (e1->share_mode & ~DELETE_ON_CLOSE_FLAG) != (e2->share_mode & ~DELETE_ON_CLOSE_FLAG)) { - DEBUG(0,("PANIC: share_modes_identical: share_mode missmatch (e1 = %u, e2 = %u). Logic error.\n", - (unsigned int)(e1->share_mode & ~DELETE_ON_CLOSE_FLAG), - (unsigned int)(e2->share_mode & ~DELETE_ON_CLOSE_FLAG) )); + (e1->share_access) != (e2->share_access)) { + DEBUG(0,("PANIC: share_modes_identical: share_mode " + "mismatch (e1 = 0x%x, e2 = 0x%x). Logic error.\n", + (unsigned int)e1->share_access, + (unsigned int)e2->share_access )); smb_panic("PANIC: share_modes_identical logic error.\n"); } #endif return (e1->pid == e2->pid && - (e1->share_mode & ~DELETE_ON_CLOSE_FLAG) == (e2->share_mode & ~DELETE_ON_CLOSE_FLAG) && + (e1->share_access) == (e2->share_access) && e1->dev == e2->dev && e1->inode == e2->inode && e1->share_file_id == e2->share_file_id ); @@ -602,8 +626,9 @@ BOOL share_modes_identical( share_mode_entry *e1, share_mode_entry *e2) Ignore if no entry deleted. ********************************************************************/ -ssize_t del_share_entry( SMB_DEV_T dev, SMB_INO_T inode, - share_mode_entry *entry, share_mode_entry **ppse) +ssize_t del_share_entry(SMB_DEV_T dev, SMB_INO_T inode, + share_mode_entry *entry, share_mode_entry **ppse, + BOOL *delete_on_close) { TDB_DATA dbuf; struct locking_data *data; @@ -621,6 +646,7 @@ ssize_t del_share_entry( SMB_DEV_T dev, SMB_INO_T inode, return -1; data = (struct locking_data *)dbuf.dptr; + *delete_on_close = data->u.s.delete_on_close; shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data)); /* @@ -629,15 +655,15 @@ ssize_t del_share_entry( SMB_DEV_T dev, SMB_INO_T inode, * from the record. */ - DEBUG(10,("del_share_entry: num_share_modes = %d\n", data->u.num_share_mode_entries )); + DEBUG(10,("del_share_entry: num_share_modes = %d\n", data->u.s.num_share_mode_entries )); - for (i=0;i<data->u.num_share_mode_entries;) { + for (i=0;i<data->u.s.num_share_mode_entries;) { if (share_modes_identical(&shares[i], entry)) { DEBUG(10,("del_share_entry: deleted %s\n", share_mode_str(i, &shares[i]) )); if (ppse) *ppse = memdup(&shares[i], sizeof(*shares)); - data->u.num_share_mode_entries--; + data->u.s.num_share_mode_entries--; if ((dbuf.dsize - (sizeof(*data) + (i+1)*sizeof(*shares))) > 0) { memmove(&shares[i], &shares[i+1], dbuf.dsize - (sizeof(*data) + (i+1)*sizeof(*shares))); @@ -655,10 +681,10 @@ ssize_t del_share_entry( SMB_DEV_T dev, SMB_INO_T inode, /* the record may have shrunk a bit */ dbuf.dsize -= del_count * sizeof(*shares); - count = (ssize_t)data->u.num_share_mode_entries; + count = (ssize_t)data->u.s.num_share_mode_entries; /* store it back in the database */ - if (data->u.num_share_mode_entries == 0) { + if (data->u.s.num_share_mode_entries == 0) { if (tdb_delete(tdb, key) == -1) count = -1; } else { @@ -677,7 +703,8 @@ ssize_t del_share_entry( SMB_DEV_T dev, SMB_INO_T inode, of entries left, and a memdup'ed copy of the entry deleted. ********************************************************************/ -ssize_t del_share_mode(files_struct *fsp, share_mode_entry **ppse) +ssize_t del_share_mode(files_struct *fsp, share_mode_entry **ppse, + BOOL *delete_on_close) { share_mode_entry entry; @@ -686,7 +713,8 @@ ssize_t del_share_mode(files_struct *fsp, share_mode_entry **ppse) */ fill_share_mode((char *)&entry, fsp, 0, 0); - return del_share_entry(fsp->dev, fsp->inode, &entry, ppse); + return del_share_entry(fsp->dev, fsp->inode, &entry, ppse, + delete_on_close); } /******************************************************************* @@ -718,7 +746,8 @@ BOOL set_share_mode(files_struct *fsp, uint16 port, uint16 op_type) if (!p) return False; data = (struct locking_data *)p; - data->u.num_share_mode_entries = 1; + ZERO_STRUCT(data->u); /* Keep valgrind happy */ + data->u.s.num_share_mode_entries = 1; DEBUG(10,("set_share_mode: creating entry for file %s. num_share_modes = 1\n", fsp->fsp_name )); @@ -740,10 +769,10 @@ BOOL set_share_mode(files_struct *fsp, uint16 port, uint16 op_type) /* we're adding to an existing entry - this is a bit fiddly */ data = (struct locking_data *)dbuf.dptr; - data->u.num_share_mode_entries++; + data->u.s.num_share_mode_entries++; DEBUG(10,("set_share_mode: adding entry for file %s. new num_share_modes = %d\n", - fsp->fsp_name, data->u.num_share_mode_entries )); + fsp->fsp_name, data->u.s.num_share_mode_entries )); size = dbuf.dsize + sizeof(share_mode_entry); p = SMB_MALLOC(size); @@ -790,7 +819,7 @@ static BOOL mod_share_mode( SMB_DEV_T dev, SMB_INO_T inode, share_mode_entry *en shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data)); /* find any with our pid and call the supplied function */ - for (i=0;i<data->u.num_share_mode_entries;i++) { + for (i=0;i<data->u.s.num_share_mode_entries;i++) { if (share_modes_identical(entry, &shares[i])) { mod_fn(&shares[i], dev, inode, param); need_store=True; @@ -799,7 +828,7 @@ static BOOL mod_share_mode( SMB_DEV_T dev, SMB_INO_T inode, share_mode_entry *en /* if the mod fn was called then store it back */ if (need_store) { - if (data->u.num_share_mode_entries == 0) { + if (data->u.s.num_share_mode_entries == 0) { if (tdb_delete(tdb, key) == -1) ret = False; } else { @@ -877,8 +906,7 @@ BOOL modify_delete_flag( SMB_DEV_T dev, SMB_INO_T inode, BOOL delete_on_close) { TDB_DATA dbuf; struct locking_data *data; - int i; - share_mode_entry *shares; + BOOL res; TDB_DATA key = locking_key(dev, inode); /* read in the existing share modes */ @@ -887,25 +915,14 @@ BOOL modify_delete_flag( SMB_DEV_T dev, SMB_INO_T inode, BOOL delete_on_close) return False; data = (struct locking_data *)dbuf.dptr; - shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data)); /* Set/Unset the delete on close element. */ - for (i=0;i<data->u.num_share_mode_entries;i++,shares++) { - shares->share_mode = (delete_on_close ? - (shares->share_mode | DELETE_ON_CLOSE_FLAG) : - (shares->share_mode & ~DELETE_ON_CLOSE_FLAG) ); - } + data->u.s.delete_on_close = delete_on_close; - /* store it back */ - if (data->u.num_share_mode_entries) { - if (tdb_store(tdb, key, dbuf, TDB_REPLACE)==-1) { - SAFE_FREE(dbuf.dptr); - return False; - } - } + res = (tdb_store(tdb, key, dbuf, TDB_REPLACE)!=-1); SAFE_FREE(dbuf.dptr); - return True; + return res; } /******************************************************************* @@ -1200,6 +1217,7 @@ BOOL add_deferred_open(uint16 mid, struct timeval *ptv, SMB_DEV_T dev, SMB_INO_T if (!p) return False; data = (struct deferred_open_data *)p; + ZERO_STRUCT(data->u.dummy); /* Keep valgrind happy */ data->u.num_deferred_open_entries = 1; DEBUG(10,("add_deferred_open: creating entry for file %s. num_deferred_open_entries = 1\n", @@ -1268,9 +1286,9 @@ static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, data = (struct locking_data *)dbuf.dptr; shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data)); - name = dbuf.dptr + sizeof(*data) + data->u.num_share_mode_entries*sizeof(*shares); + name = dbuf.dptr + sizeof(*data) + data->u.s.num_share_mode_entries*sizeof(*shares); - for (i=0;i<data->u.num_share_mode_entries;i++) { + for (i=0;i<data->u.s.num_share_mode_entries;i++) { traverse_callback(&shares[i], name); } return 0; diff --git a/source/locking/posix.c b/source/locking/posix.c index 218c4410280..c63992adc59 100644 --- a/source/locking/posix.c +++ b/source/locking/posix.c @@ -114,7 +114,7 @@ static BOOL add_fd_to_close_entry(files_struct *fsp) } else dbuf.dptr = tp; - memcpy(dbuf.dptr + dbuf.dsize, &fsp->fd, sizeof(int)); + memcpy(dbuf.dptr + dbuf.dsize, &fsp->fh->fd, sizeof(int)); dbuf.dsize += sizeof(int); if (tdb_store(posix_pending_close_tdb, kbuf, dbuf, TDB_REPLACE) == -1) { @@ -209,8 +209,8 @@ int fd_close_posix(struct connection_struct *conn, files_struct *fsp) /* * No POSIX to worry about, just close. */ - ret = SMB_VFS_CLOSE(fsp,fsp->fd); - fsp->fd = -1; + ret = SMB_VFS_CLOSE(fsp,fsp->fh->fd); + fsp->fh->fd = -1; return ret; } @@ -227,7 +227,7 @@ int fd_close_posix(struct connection_struct *conn, files_struct *fsp) */ for (i = 0; i < count; i++) { - if (entries[i].fd != fsp->fd) { + if (entries[i].fd != fsp->fh->fd) { locks_on_other_fds = True; break; } @@ -237,7 +237,7 @@ int fd_close_posix(struct connection_struct *conn, files_struct *fsp) /* * There are outstanding locks on this dev/inode pair on other fds. - * Add our fd to the pending close tdb and set fsp->fd to -1. + * Add our fd to the pending close tdb and set fsp->fh->fd to -1. */ if (!add_fd_to_close_entry(fsp)) { @@ -246,7 +246,7 @@ int fd_close_posix(struct connection_struct *conn, files_struct *fsp) } SAFE_FREE(entries); - fsp->fd = -1; + fsp->fh->fd = -1; return 0; } @@ -282,14 +282,14 @@ int fd_close_posix(struct connection_struct *conn, files_struct *fsp) * Finally close the fd associated with this fsp. */ - ret = SMB_VFS_CLOSE(fsp,fsp->fd); + ret = SMB_VFS_CLOSE(fsp,fsp->fh->fd); if (saved_errno != 0) { errno = saved_errno; ret = -1; } - fsp->fd = -1; + fsp->fh->fd = -1; return ret; } @@ -371,7 +371,7 @@ static BOOL add_posix_lock_entry(files_struct *fsp, SMB_OFF_T start, SMB_OFF_T s * Add new record. */ - pl.fd = fsp->fd; + pl.fd = fsp->fh->fd; pl.start = start; pl.size = size; pl.lock_type = lock_type; @@ -455,7 +455,7 @@ static int delete_posix_lock_entry(files_struct *fsp, SMB_OFF_T start, SMB_OFF_T for (i=0; i<count; i++) { struct posix_lock *entry = &locks[i]; - if (entry->fd == fsp->fd && + if (entry->fd == fsp->fh->fd && entry->start == start && entry->size == size) { @@ -490,7 +490,7 @@ static int delete_posix_lock_entry(files_struct *fsp, SMB_OFF_T start, SMB_OFF_T for (i = 0; i < count; i++) { struct posix_lock *entry = &locks[i]; - if (fsp->fd == entry->fd && + if (fsp->fh->fd == entry->fd && does_lock_overlap( start, size, entry->start, entry->size)) num_overlapping_records++; } @@ -524,13 +524,17 @@ static int map_posix_lock_type( files_struct *fsp, enum brl_type lock_type) */ DEBUG(10,("map_posix_lock_type: Downgrading write lock to read due to read-only file.\n")); return F_RDLCK; - } else if((lock_type == READ_LOCK) && !fsp->can_read) { + } +#if 0 + /* We no longer open files write-only. */ + else if((lock_type == READ_LOCK) && !fsp->can_read) { /* * Ditto for read locks on write only files. */ DEBUG(10,("map_posix_lock_type: Changing read lock to write due to write-only file.\n")); return F_WRLCK; } +#endif /* * This return should be the most normal, as we attempt @@ -652,9 +656,9 @@ static BOOL posix_fcntl_lock(files_struct *fsp, int op, SMB_OFF_T offset, SMB_OF { int ret; - DEBUG(8,("posix_fcntl_lock %d %d %.0f %.0f %d\n",fsp->fd,op,(double)offset,(double)count,type)); + DEBUG(8,("posix_fcntl_lock %d %d %.0f %.0f %d\n",fsp->fh->fd,op,(double)offset,(double)count,type)); - ret = SMB_VFS_LOCK(fsp,fsp->fd,op,offset,count,type); + ret = SMB_VFS_LOCK(fsp,fsp->fh->fd,op,offset,count,type); if (!ret && ((errno == EFBIG) || (errno == ENOLCK) || (errno == EINVAL))) { @@ -678,7 +682,7 @@ static BOOL posix_fcntl_lock(files_struct *fsp, int op, SMB_OFF_T offset, SMB_OF DEBUG(0,("Count greater than 31 bits - retrying with 31 bit truncated length.\n")); errno = 0; count &= 0x7fffffff; - ret = SMB_VFS_LOCK(fsp,fsp->fd,op,offset,count,type); + ret = SMB_VFS_LOCK(fsp,fsp->fh->fd,op,offset,count,type); } } @@ -1247,7 +1251,7 @@ void posix_locking_close_file(files_struct *fsp) } for (i = 0; i < count; i++) { - if (entries[i].fd != fsp->fd ) + if (entries[i].fd != fsp->fh->fd ) break; dump_entry(&entries[i]); @@ -1269,7 +1273,7 @@ void posix_locking_close_file(files_struct *fsp) for (i = 0; i < count; i++) { struct posix_lock *pl = &entries[i]; - if (pl->fd == fsp->fd) + if (pl->fd == fsp->fh->fd) release_posix_lock(fsp, (SMB_BIG_UINT)pl->start, (SMB_BIG_UINT)pl->size ); } SAFE_FREE(entries); diff --git a/source/modules/vfs_afsacl.c b/source/modules/vfs_afsacl.c index 3b54428f14c..731ddfa5836 100644 --- a/source/modules/vfs_afsacl.c +++ b/source/modules/vfs_afsacl.c @@ -605,13 +605,13 @@ static size_t afs_to_nt_acl(struct afs_acl *afs_acl, struct afs_ace *afs_ace; - if (fsp->is_directory || fsp->fd == -1) { + if (fsp->is_directory || fsp->fh->fd == -1) { /* Get the stat struct for the owner info. */ if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0) { return 0; } } else { - if(SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0) { + if(SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf) != 0) { return 0; } } diff --git a/source/printing/nt_printing.c b/source/printing/nt_printing.c index b3a2ca5893b..25083002c31 100644 --- a/source/printing/nt_printing.c +++ b/source/printing/nt_printing.c @@ -922,7 +922,7 @@ static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32 } /* Skip OEM header (if any) and the DOS stub to start of Windows header */ - if (SMB_VFS_LSEEK(fsp, fsp->fd, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (SMB_OFF_T)-1) { + if (SMB_VFS_LSEEK(fsp, fsp->fh->fd, SVAL(buf,DOS_HEADER_LFANEW_OFFSET), SEEK_SET) == (SMB_OFF_T)-1) { DEBUG(3,("get_file_version: File [%s] too short, errno = %d\n", fname, errno)); /* Assume this isn't an error... the file just looks sort of like a PE/NE file */ @@ -988,7 +988,7 @@ static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32 } /* Seek to the start of the .rsrc section info */ - if (SMB_VFS_LSEEK(fsp, fsp->fd, section_pos, SEEK_SET) == (SMB_OFF_T)-1) { + if (SMB_VFS_LSEEK(fsp, fsp->fh->fd, section_pos, SEEK_SET) == (SMB_OFF_T)-1) { DEBUG(3,("get_file_version: PE file [%s] too short for section info, errno = %d\n", fname, errno)); goto error_exit; @@ -1084,7 +1084,7 @@ static int get_file_version(files_struct *fsp, char *fname,uint32 *major, uint32 * twice, as it is simpler to read the code. */ if (strcmp(&buf[i], VS_SIGNATURE) == 0) { /* Compute skip alignment to next long address */ - int skip = -(SMB_VFS_LSEEK(fsp, fsp->fd, 0, SEEK_CUR) - (byte_count - i) + + int skip = -(SMB_VFS_LSEEK(fsp, fsp->fh->fd, 0, SEEK_CUR) - (byte_count - i) + sizeof(VS_SIGNATURE)) & 3; if (IVAL(buf,i+sizeof(VS_SIGNATURE)+skip) != 0xfeef04bd) continue; @@ -1142,8 +1142,6 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr uint32 old_minor; time_t old_create_time; - int access_mode; - int action; files_struct *fsp = NULL; SMB_STRUCT_STAT st; SMB_STRUCT_STAT stat_buf; @@ -1159,10 +1157,15 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr driver_unix_convert(filepath,conn,NULL,&bad_path,&stat_buf); - fsp = open_file_shared(conn, filepath, &stat_buf, - SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY), - (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), - FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY, &access_mode, &action); + fsp = open_file_ntcreate(conn, filepath, &stat_buf, + FILE_GENERIC_READ, + FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_OPEN, + 0, + FILE_ATTRIBUTE_NORMAL, + INTERNAL_OPEN_ONLY, + NULL); + if (!fsp) { /* Old file not found, so by definition new file is in fact newer */ DEBUG(10,("file_version_is_newer: Can't open old file [%s], errno = %d\n", @@ -1171,13 +1174,15 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr } else { int ret = get_file_version(fsp, old_file, &old_major, &old_minor); - if (ret == -1) goto error_exit; + if (ret == -1) { + goto error_exit; + } if (!ret) { DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n", old_file)); use_version = False; - if (SMB_VFS_FSTAT(fsp, fsp->fd, &st) == -1) goto error_exit; + if (SMB_VFS_FSTAT(fsp, fsp->fh->fd, &st) == -1) goto error_exit; old_create_time = st.st_mtime; DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n", old_create_time)); } @@ -1188,10 +1193,15 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr pstrcpy(filepath, new_file); driver_unix_convert(filepath,conn,NULL,&bad_path,&stat_buf); - fsp = open_file_shared(conn, filepath, &stat_buf, - SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY), - (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), - FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY, &access_mode, &action); + fsp = open_file_ntcreate(conn, filepath, &stat_buf, + FILE_GENERIC_READ, + FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_OPEN, + 0, + FILE_ATTRIBUTE_NORMAL, + INTERNAL_OPEN_ONLY, + NULL); + if (!fsp) { /* New file not found, this shouldn't occur if the caller did its job */ DEBUG(3,("file_version_is_newer: Can't open new file [%s], errno = %d\n", @@ -1200,13 +1210,15 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr } else { int ret = get_file_version(fsp, new_file, &new_major, &new_minor); - if (ret == -1) goto error_exit; + if (ret == -1) { + goto error_exit; + } if (!ret) { DEBUG(6,("file_version_is_newer: Version info not found [%s], use mod time\n", new_file)); use_version = False; - if (SMB_VFS_FSTAT(fsp, fsp->fd, &st) == -1) goto error_exit; + if (SMB_VFS_FSTAT(fsp, fsp->fh->fd, &st) == -1) goto error_exit; new_create_time = st.st_mtime; DEBUGADD(6,("file_version_is_newer: mod time = %ld sec\n", new_create_time)); } @@ -1251,8 +1263,6 @@ static uint32 get_correct_cversion(const char *architecture, fstring driverpath_ struct current_user *user, WERROR *perr) { int cversion; - int access_mode; - int action; NTSTATUS nt_status; pstring driverpath; DATA_BLOB null_pw; @@ -1309,18 +1319,21 @@ static uint32 get_correct_cversion(const char *architecture, fstring driverpath_ goto error_exit; } - fsp = open_file_shared(conn, driverpath, &st, - SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY), - (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), - FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY, &access_mode, &action); + fsp = open_file_ntcreate(conn, driverpath, &st, + FILE_GENERIC_READ, + FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_OPEN, + 0, + FILE_ATTRIBUTE_NORMAL, + INTERNAL_OPEN_ONLY, + NULL); if (!fsp) { DEBUG(3,("get_correct_cversion: Can't open file [%s], errno = %d\n", driverpath, errno)); *perr = WERR_ACCESS_DENIED; goto error_exit; - } - else { + } else { uint32 major; uint32 minor; int ret = get_file_version(fsp, driverpath, &major, &minor); @@ -1660,7 +1673,8 @@ WERROR move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->driverpath); if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) { driver_unix_convert(new_name, conn, NULL, &bad_path, &st); - if ( !copy_file(new_name, old_name, conn, FILE_EXISTS_TRUNCATE|FILE_CREATE_IF_NOT_EXIST, 0, False, &err) ) { + if ( !copy_file(new_name, old_name, conn, OPENX_FILE_EXISTS_TRUNCATE| + OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False, &err) ) { DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n", new_name, old_name)); *perr = WERR_ACCESS_DENIED; @@ -1675,7 +1689,8 @@ WERROR move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->datafile); if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) { driver_unix_convert(new_name, conn, NULL, &bad_path, &st); - if ( !copy_file(new_name, old_name, conn, FILE_EXISTS_TRUNCATE|FILE_CREATE_IF_NOT_EXIST, 0, False, &err) ) { + if ( !copy_file(new_name, old_name, conn, OPENX_FILE_EXISTS_TRUNCATE| + OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False, &err) ) { DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n", new_name, old_name)); *perr = WERR_ACCESS_DENIED; @@ -1692,7 +1707,8 @@ WERROR move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->configfile); if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) { driver_unix_convert(new_name, conn, NULL, &bad_path, &st); - if ( !copy_file(new_name, old_name, conn, FILE_EXISTS_TRUNCATE|FILE_CREATE_IF_NOT_EXIST, 0, False, &err) ) { + if ( !copy_file(new_name, old_name, conn, OPENX_FILE_EXISTS_TRUNCATE| + OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False, &err) ) { DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n", new_name, old_name)); *perr = WERR_ACCESS_DENIED; @@ -1710,7 +1726,8 @@ WERROR move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->helpfile); if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) { driver_unix_convert(new_name, conn, NULL, &bad_path, &st); - if ( !copy_file(new_name, old_name, conn, FILE_EXISTS_TRUNCATE|FILE_CREATE_IF_NOT_EXIST, 0, False, &err) ) { + if ( !copy_file(new_name, old_name, conn, OPENX_FILE_EXISTS_TRUNCATE| + OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False, &err) ) { DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n", new_name, old_name)); *perr = WERR_ACCESS_DENIED; @@ -1737,7 +1754,9 @@ WERROR move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract slprintf(old_name, sizeof(old_name)-1, "%s/%s", new_dir, driver->dependentfiles[i]); if (ver != -1 && (ver=file_version_is_newer(conn, new_name, old_name)) > 0) { driver_unix_convert(new_name, conn, NULL, &bad_path, &st); - if ( !copy_file(new_name, old_name, conn, FILE_EXISTS_TRUNCATE|FILE_CREATE_IF_NOT_EXIST, 0, False, &err) ) { + if ( !copy_file(new_name, old_name, conn, + OPENX_FILE_EXISTS_TRUNCATE| + OPENX_FILE_CREATE_IF_NOT_EXIST, 0, False, &err) ) { DEBUG(0,("move_driver_to_download_area: Unable to rename [%s] to [%s]\n", new_name, old_name)); *perr = WERR_ACCESS_DENIED; diff --git a/source/printing/printfsp.c b/source/printing/printfsp.c index 863de9624e7..eb81dc4536f 100644 --- a/source/printing/printfsp.c +++ b/source/printing/printfsp.c @@ -28,7 +28,7 @@ open a print file and setup a fsp for it. This is a wrapper around print_job_start(). ***************************************************************************/ -files_struct *print_fsp_open(connection_struct *conn, char *fname) +files_struct *print_fsp_open(connection_struct *conn, const char *fname) { int jobid; SMB_STRUCT_STAT sbuf; @@ -40,10 +40,11 @@ files_struct *print_fsp_open(connection_struct *conn, char *fname) fstrcpy( name, "Remote Downlevel Document"); if (fname) { - char *p = strrchr(fname, '/'); + const char *p = strrchr(fname, '/'); fstrcat(name, " "); - if (!p) + if (!p) { p = fname; + } fstrcat(name, p); } @@ -63,24 +64,23 @@ files_struct *print_fsp_open(connection_struct *conn, char *fname) } /* setup a full fsp */ - fsp->fd = print_job_fd(lp_const_servicename(SNUM(conn)),jobid); + fsp->fh->fd = print_job_fd(lp_const_servicename(SNUM(conn)),jobid); GetTimeOfDay(&fsp->open_time); fsp->vuid = current_user.vuid; - fsp->pos = -1; + fsp->fh->pos = -1; fsp->can_lock = True; fsp->can_read = False; + fsp->access_mask = FILE_GENERIC_WRITE; fsp->can_write = True; - fsp->share_mode = 0; fsp->print_file = True; fsp->modified = False; fsp->oplock_type = NO_OPLOCK; fsp->sent_oplock_break = NO_BREAK_SENT; fsp->is_directory = False; - fsp->directory_delete_on_close = False; string_set(&fsp->fsp_name,print_job_fname(lp_const_servicename(SNUM(conn)),jobid)); fsp->wbmpx_ptr = NULL; fsp->wcp = NULL; - SMB_VFS_FSTAT(fsp,fsp->fd, &sbuf); + SMB_VFS_FSTAT(fsp,fsp->fh->fd, &sbuf); fsp->mode = sbuf.st_mode; fsp->inode = sbuf.st_ino; fsp->dev = sbuf.st_dev; @@ -91,19 +91,20 @@ files_struct *print_fsp_open(connection_struct *conn, char *fname) } /**************************************************************************** -print a file - called on closing the file + Print a file - called on closing the file. ****************************************************************************/ + void print_fsp_end(files_struct *fsp, BOOL normal_close) { uint32 jobid; fstring sharename; - if (fsp->share_mode == FILE_DELETE_ON_CLOSE) { + if (fsp->fh->private_options & FILE_DELETE_ON_CLOSE) { /* * Truncate the job. print_job_end will take * care of deleting it for us. JRA. */ - sys_ftruncate(fsp->fd, 0); + sys_ftruncate(fsp->fh->fd, 0); } if (fsp->fsp_name) { diff --git a/source/rpc_server/srv_srvsvc_nt.c b/source/rpc_server/srv_srvsvc_nt.c index f8124031ce0..c3fd53a3844 100644 --- a/source/rpc_server/srv_srvsvc_nt.c +++ b/source/rpc_server/srv_srvsvc_nt.c @@ -1976,8 +1976,6 @@ WERROR _srv_net_file_query_secdesc(pipes_struct *p, SRV_Q_NET_FILE_QUERY_SECDESC files_struct *fsp = NULL; SMB_STRUCT_STAT st; BOOL bad_path; - int access_mode; - int action; NTSTATUS nt_status; struct current_user user; connection_struct *conn = NULL; @@ -2025,15 +2023,16 @@ WERROR _srv_net_file_query_secdesc(pipes_struct *p, SRV_Q_NET_FILE_QUERY_SECDESC goto error_exit; } - fsp = open_file_shared(conn, filename, &st, SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY), - (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY, - &access_mode, &action); - + fsp = open_file_stat(conn, filename, &st); if (!fsp) { /* Perhaps it is a directory */ if (errno == EISDIR) - fsp = open_directory(conn, filename, &st,FILE_READ_ATTRIBUTES,0, - (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), &action); + fsp = open_directory(conn, filename, &st, + READ_CONTROL_ACCESS, + FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_OPEN, + 0, + NULL); if (!fsp) { DEBUG(3,("_srv_net_file_query_secdesc: Unable to open file %s\n", filename)); @@ -2092,8 +2091,6 @@ WERROR _srv_net_file_set_secdesc(pipes_struct *p, SRV_Q_NET_FILE_SET_SECDESC *q_ files_struct *fsp = NULL; SMB_STRUCT_STAT st; BOOL bad_path; - int access_mode; - int action; NTSTATUS nt_status; struct current_user user; connection_struct *conn = NULL; @@ -2142,15 +2139,17 @@ WERROR _srv_net_file_set_secdesc(pipes_struct *p, SRV_Q_NET_FILE_SET_SECDESC *q_ } - fsp = open_file_shared(conn, filename, &st, SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDWR), - (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY, - &access_mode, &action); + fsp = open_file_stat(conn, filename, &st); if (!fsp) { /* Perhaps it is a directory */ if (errno == EISDIR) - fsp = open_directory(conn, filename, &st,FILE_READ_ATTRIBUTES,0, - (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), &action); + fsp = open_directory(conn, filename, &st, + FILE_READ_ATTRIBUTES, + FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_OPEN, + 0, + NULL); if (!fsp) { DEBUG(3,("_srv_net_file_set_secdesc: Unable to open file %s\n", filename)); @@ -2178,11 +2177,13 @@ error_exit: close_file(fsp, True); } - if (became_user) + if (became_user) { unbecome_user(); + } - if (conn) + if (conn) { close_cnum(conn, user.vuid); + } return r_u->status; } diff --git a/source/smbd/close.c b/source/smbd/close.c index b7649bcce4f..3fc7fdb0599 100644 --- a/source/smbd/close.c +++ b/source/smbd/close.c @@ -3,6 +3,7 @@ file closing Copyright (C) Andrew Tridgell 1992-1998 Copyright (C) Jeremy Allison 1992-2004. + Copyright (C) Volker Lendecke 2005 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -92,7 +93,7 @@ static int close_filestruct(files_struct *fsp) connection_struct *conn = fsp->conn; int ret = 0; - if (fsp->fd != -1) { + if (fsp->fh->fd != -1) { if(flush_write_cache(fsp, CLOSE_FLUSH) == -1) ret = -1; @@ -148,7 +149,7 @@ static int close_normal_file(files_struct *fsp, BOOL normal_close) { share_mode_entry *share_entry = NULL; size_t share_entry_count = 0; - BOOL delete_on_close = False; + BOOL delete_file = False; connection_struct *conn = fsp->conn; int saved_errno = 0; int err = 0; @@ -194,34 +195,16 @@ static int close_normal_file(files_struct *fsp, BOOL normal_close) lock_share_entry_fsp(fsp); - if (fsp->delete_on_close) { - - /* - * Modify the share mode entry for all files open - * on this device and inode to tell other smbds we have - * changed the delete on close flag. The last closer will delete the file - * if flag is set. - */ - - NTSTATUS status =set_delete_on_close_over_all(fsp, fsp->delete_on_close); - if (NT_STATUS_V(status) != NT_STATUS_V(NT_STATUS_OK)) - DEBUG(0,("close_normal_file: failed to change delete on close flag for file %s\n", - fsp->fsp_name )); - } - - share_entry_count = del_share_mode(fsp, &share_entry); + share_entry_count = del_share_mode(fsp, &share_entry, + &delete_file); DEBUG(10,("close_normal_file: share_entry_count = %lu for file %s\n", (unsigned long)share_entry_count, fsp->fsp_name )); - /* - * We delete on close if it's the last open, and the - * delete on close flag was set in the entry we just deleted. - */ - - if ((share_entry_count == 0) && share_entry && - GET_DELETE_ON_CLOSE_FLAG(share_entry->share_mode) ) - delete_on_close = True; + if (share_entry_count != 0) { + /* We're not the last ones -- don't delete */ + delete_file = False; + } SAFE_FREE(share_entry); @@ -233,7 +216,7 @@ static int close_normal_file(files_struct *fsp, BOOL normal_close) * reference to a file. */ - if (normal_close && delete_on_close) { + if (normal_close && delete_file) { DEBUG(5,("close_file: file %s. Delete on close was set - deleting file.\n", fsp->fsp_name)); if(SMB_VFS_UNLINK(conn,fsp->fsp_name) != 0) { @@ -311,7 +294,8 @@ static int close_directory(files_struct *fsp, BOOL normal_close) * reference to a directory also. */ - if (normal_close && fsp->directory_delete_on_close) { + if (normal_close && + get_delete_on_close_flag(fsp->dev, fsp->inode)) { BOOL ok = rmdir_internals(fsp->conn, fsp->fsp_name); DEBUG(5,("close_directory: %s. Delete on close was set - deleting directory %s.\n", fsp->fsp_name, ok ? "succeeded" : "failed" )); @@ -321,8 +305,9 @@ static int close_directory(files_struct *fsp, BOOL normal_close) * now fail as the directory has been deleted. */ - if(ok) + if(ok) { remove_pending_change_notify_requests_by_filename(fsp); + } process_pending_change_notify_queue((time_t)0); } @@ -331,8 +316,9 @@ static int close_directory(files_struct *fsp, BOOL normal_close) */ close_filestruct(fsp); - if (fsp->fsp_name) + if (fsp->fsp_name) { string_free(&fsp->fsp_name); + } file_free(fsp); return 0; diff --git a/source/smbd/dir.c b/source/smbd/dir.c index fd0a3035044..949e31210f6 100644 --- a/source/smbd/dir.c +++ b/source/smbd/dir.c @@ -822,7 +822,6 @@ static BOOL user_can_read_file(connection_struct *conn, char *name, SMB_STRUCT_S SEC_DESC *psd = NULL; size_t sd_size; files_struct *fsp; - int smb_action; NTSTATUS status; uint32 access_granted; @@ -831,32 +830,41 @@ static BOOL user_can_read_file(connection_struct *conn, char *name, SMB_STRUCT_S * we never hide files from them. */ - if (conn->admin_user) + if (conn->admin_user) { return True; + } /* If we can't stat it does not show it */ - if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0)) + if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0)) { return False; + } /* Pseudo-open the file (note - no fd's created). */ - if(S_ISDIR(pst->st_mode)) - fsp = open_directory(conn, name, pst, 0, SET_DENY_MODE(DENY_NONE), (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), - &smb_action); - else + if(S_ISDIR(pst->st_mode)) { + fsp = open_directory(conn, name, pst, + READ_CONTROL_ACCESS, + FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_OPEN, + 0, /* no create options. */ + NULL); + } else { fsp = open_file_stat(conn, name, pst); + } - if (!fsp) + if (!fsp) { return False; + } /* Get NT ACL -allocated in main loop talloc context. No free needed here. */ - sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fd, + sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fh->fd, (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd); close_file(fsp, True); /* No access if SD get failed. */ - if (!sd_size) + if (!sd_size) { return False; + } return se_access_check(psd, current_user.nt_user_token, FILE_READ_DATA, &access_granted, &status); @@ -874,8 +882,7 @@ static BOOL user_can_write_file(connection_struct *conn, char *name, SMB_STRUCT_ SEC_DESC *psd = NULL; size_t sd_size; files_struct *fsp; - int smb_action; - int access_mode; + int info; NTSTATUS status; uint32 access_granted; @@ -884,27 +891,36 @@ static BOOL user_can_write_file(connection_struct *conn, char *name, SMB_STRUCT_ * we never hide files from them. */ - if (conn->admin_user) + if (conn->admin_user) { return True; + } /* If we can't stat it does not show it */ - if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0)) + if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0)) { return False; + } - /* Pseudo-open the file (note - no fd's created). */ + /* Pseudo-open the file */ - if(S_ISDIR(pst->st_mode)) + if(S_ISDIR(pst->st_mode)) { return True; - else - fsp = open_file_shared1(conn, name, pst, FILE_WRITE_ATTRIBUTES, SET_DENY_MODE(DENY_NONE), - (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY, - &access_mode, &smb_action); + } else { + fsp = open_file_ntcreate(conn, name, pst, + FILE_WRITE_ATTRIBUTES, + FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_OPEN, + 0, + FILE_ATTRIBUTE_NORMAL, + INTERNAL_OPEN_ONLY, + &info); + } - if (!fsp) + if (!fsp) { return False; + } /* Get NT ACL -allocated in main loop talloc context. No free needed here. */ - sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fd, + sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fh->fd, (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd); close_file(fsp, False); diff --git a/source/smbd/dosmode.c b/source/smbd/dosmode.c index 3602e3f9081..a2bc424b8e7 100644 --- a/source/smbd/dosmode.c +++ b/source/smbd/dosmode.c @@ -430,7 +430,7 @@ int file_set_dosmode(connection_struct *conn, const char *fname, uint32 dosmode, if (!fsp) return -1; become_root(); - ret = SMB_VFS_FCHMOD(fsp, fsp->fd, unixmode); + ret = SMB_VFS_FCHMOD(fsp, fsp->fh->fd, unixmode); unbecome_root(); close_file_fchmod(fsp); } diff --git a/source/smbd/fake_file.c b/source/smbd/fake_file.c index 59ddb60db5e..799725a7820 100644 --- a/source/smbd/fake_file.c +++ b/source/smbd/fake_file.c @@ -22,77 +22,6 @@ extern struct current_user current_user; -/**************************************************************************** - Open a file with a share mode. -****************************************************************************/ -files_struct *open_fake_file_shared1(enum FAKE_FILE_TYPE fake_file_type, connection_struct *conn,char *fname, - SMB_STRUCT_STAT *psbuf, - uint32 desired_access, - int share_mode,int ofun, uint32 new_dos_attr, int oplock_request, - int *Access,int *action) -{ - int flags=0; - files_struct *fsp = NULL; - - if (fake_file_type == 0) { - return open_file_shared1(conn,fname,psbuf,desired_access, - share_mode,ofun,new_dos_attr, - oplock_request,Access,action); - } - - /* access check */ - if (current_user.uid != 0) { - DEBUG(1,("access_denied to service[%s] file[%s] user[%s]\n", - lp_servicename(SNUM(conn)),fname,conn->user)); - errno = EACCES; - return NULL; - } - - fsp = file_new(conn); - if(!fsp) - return NULL; - - DEBUG(5,("open_fake_file_shared1: fname = %s, FID = %d, share_mode = %x, ofun = %x, oplock request = %d\n", - fname, fsp->fnum, share_mode, ofun, oplock_request )); - - if (!check_name(fname,conn)) { - file_free(fsp); - return NULL; - } - - fsp->fd = -1; - fsp->mode = psbuf->st_mode; - fsp->inode = psbuf->st_ino; - fsp->dev = psbuf->st_dev; - fsp->vuid = current_user.vuid; - fsp->pos = -1; - fsp->can_lock = True; - fsp->can_read = ((flags & O_WRONLY)==0); - fsp->can_write = ((flags & (O_WRONLY|O_RDWR))!=0); - fsp->share_mode = 0; - fsp->desired_access = desired_access; - fsp->print_file = False; - fsp->modified = False; - fsp->oplock_type = NO_OPLOCK; - fsp->sent_oplock_break = NO_BREAK_SENT; - fsp->is_directory = False; - fsp->is_stat = False; - fsp->directory_delete_on_close = False; - fsp->conn = conn; - string_set(&fsp->fsp_name,fname); - fsp->wcp = NULL; /* Write cache pointer. */ - - fsp->fake_file_handle = init_fake_file_handle(fake_file_type); - - if (fsp->fake_file_handle==NULL) { - file_free(fsp); - return NULL; - } - - conn->num_files_open++; - return fsp; -} - static FAKE_FILE fake_files[] = { #ifdef WITH_QUOTAS {FAKE_FILE_NAME_QUOTA_UNIX, FAKE_FILE_TYPE_QUOTA, init_quota_handle, destroy_quota_handle}, @@ -100,24 +29,11 @@ static FAKE_FILE fake_files[] = { {NULL, FAKE_FILE_TYPE_NONE, NULL, NULL } }; -int is_fake_file(char *fname) -{ - int i; - - if (!fname) - return 0; - - for (i=0;fake_files[i].name!=NULL;i++) { - if (strncmp(fname,fake_files[i].name,strlen(fake_files[i].name))==0) { - DEBUG(5,("is_fake_file: [%s] is a fake file\n",fname)); - return fake_files[i].type; - } - } - - return FAKE_FILE_TYPE_NONE; -} +/**************************************************************************** + Create a fake file handle +****************************************************************************/ -struct _FAKE_FILE_HANDLE *init_fake_file_handle(enum FAKE_FILE_TYPE type) +static struct _FAKE_FILE_HANDLE *init_fake_file_handle(enum FAKE_FILE_TYPE type) { TALLOC_CTX *mem_ctx = NULL; FAKE_FILE_HANDLE *fh = NULL; @@ -141,8 +57,9 @@ struct _FAKE_FILE_HANDLE *init_fake_file_handle(enum FAKE_FILE_TYPE type) fh->type = type; fh->mem_ctx = mem_ctx; - if (fake_files[i].init_pd) + if (fake_files[i].init_pd) { fh->pd = fake_files[i].init_pd(fh->mem_ctx); + } fh->free_pd = fake_files[i].free_pd; @@ -153,13 +70,88 @@ struct _FAKE_FILE_HANDLE *init_fake_file_handle(enum FAKE_FILE_TYPE type) return NULL; } +/**************************************************************************** + Does this name match a fake filename ? +****************************************************************************/ + +enum FAKE_FILE_TYPE is_fake_file(const char *fname) +{ +#ifdef HAVE_SYS_QUOTAS + int i; +#endif + + if (!fname) { + return FAKE_FILE_TYPE_NONE; + } + +#ifdef HAVE_SYS_QUOTAS + for (i=0;fake_files[i].name!=NULL;i++) { + if (strncmp(fname,fake_files[i].name,strlen(fake_files[i].name))==0) { + DEBUG(5,("is_fake_file: [%s] is a fake file\n",fname)); + return fake_files[i].type; + } + } +#endif + + return FAKE_FILE_TYPE_NONE; +} + + +/**************************************************************************** + Open a fake quota file with a share mode. +****************************************************************************/ + +files_struct *open_fake_file(connection_struct *conn, + enum FAKE_FILE_TYPE fake_file_type, + const char *fname, + uint32 access_mask) +{ + files_struct *fsp = NULL; + + /* access check */ + if (current_user.uid != 0) { + DEBUG(1,("open_fake_file_shared: access_denied to service[%s] file[%s] user[%s]\n", + lp_servicename(SNUM(conn)),fname,conn->user)); + errno = EACCES; + return NULL; + } + + fsp = file_new(conn); + if(!fsp) { + return NULL; + } + + DEBUG(5,("open_fake_file_shared: fname = %s, FID = %d, access_mask = 0x%x\n", + fname, fsp->fnum, (unsigned int)access_mask)); + + fsp->conn = conn; + fsp->fh->fd = -1; + fsp->vuid = current_user.vuid; + fsp->fh->pos = -1; + fsp->can_lock = True; /* Should this be true ? */ + fsp->access_mask = access_mask; + string_set(&fsp->fsp_name,fname); + + fsp->fake_file_handle = init_fake_file_handle(fake_file_type); + + if (fsp->fake_file_handle==NULL) { + file_free(fsp); + return NULL; + } + + conn->num_files_open++; + return fsp; +} + void destroy_fake_file_handle(FAKE_FILE_HANDLE **fh) { - if (!fh||!(*fh)) + if (!fh||!(*fh)) { return; + } - if ((*fh)->free_pd) + if ((*fh)->free_pd) { (*fh)->free_pd(&(*fh)->pd); + } talloc_destroy((*fh)->mem_ctx); (*fh) = NULL; diff --git a/source/smbd/fileio.c b/source/smbd/fileio.c index ba0766c2986..76189d114bb 100644 --- a/source/smbd/fileio.c +++ b/source/smbd/fileio.c @@ -65,20 +65,20 @@ ssize_t read_file(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n) */ if(read_from_write_cache(fsp, data, pos, n)) { - fsp->pos = pos + n; - fsp->position_information = fsp->pos; + fsp->fh->pos = pos + n; + fsp->fh->position_information = fsp->fh->pos; return n; } flush_write_cache(fsp, READ_FLUSH); - fsp->pos = pos; + fsp->fh->pos = pos; if (n > 0) { #ifdef DMF_FIX int numretries = 3; tryagain: - readret = SMB_VFS_PREAD(fsp,fsp->fd,data,n,pos); + readret = SMB_VFS_PREAD(fsp,fsp->fh->fd,data,n,pos); if (readret == -1) { if ((errno == EAGAIN) && numretries) { @@ -90,7 +90,7 @@ tryagain: return -1; } #else /* NO DMF fix. */ - readret = SMB_VFS_PREAD(fsp,fsp->fd,data,n,pos); + readret = SMB_VFS_PREAD(fsp,fsp->fh->fd,data,n,pos); if (readret == -1) { return -1; @@ -104,8 +104,8 @@ tryagain: DEBUG(10,("read_file (%s): pos = %.0f, size = %lu, returned %lu\n", fsp->fsp_name, (double)pos, (unsigned long)n, (long)ret )); - fsp->pos += ret; - fsp->position_information = fsp->pos; + fsp->fh->pos += ret; + fsp->fh->position_information = fsp->fh->pos; return(ret); } @@ -124,7 +124,7 @@ static ssize_t real_write_file(files_struct *fsp,const char *data, SMB_OFF_T pos if (pos == -1) { ret = vfs_write_data(fsp, data, n); } else { - fsp->pos = pos; + fsp->fh->pos = pos; if (pos && lp_strict_allocate(SNUM(fsp->conn))) { if (vfs_fill_sparse(fsp, pos) == -1) { return -1; @@ -137,7 +137,7 @@ static ssize_t real_write_file(files_struct *fsp,const char *data, SMB_OFF_T pos fsp->fsp_name, (double)pos, (unsigned long)n, (long)ret )); if (ret != -1) { - fsp->pos += ret; + fsp->fh->pos += ret; /* * It turns out that setting the last write time from a Windows @@ -180,7 +180,7 @@ static int wcp_file_size_change(files_struct *fsp) write_cache *wcp = fsp->wcp; wcp->file_size = wcp->offset + wcp->data_size; - ret = SMB_VFS_FTRUNCATE(fsp, fsp->fd, wcp->file_size); + ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, wcp->file_size); if (ret == -1) { DEBUG(0,("wcp_file_size_change (%s): ftruncate of size %.0f error %s\n", fsp->fsp_name, (double)wcp->file_size, strerror(errno) )); @@ -221,7 +221,7 @@ ssize_t write_file(files_struct *fsp, const char *data, SMB_OFF_T pos, size_t n) SMB_STRUCT_STAT st; fsp->modified = True; - if (SMB_VFS_FSTAT(fsp,fsp->fd,&st) == 0) { + if (SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st) == 0) { int dosmode = dos_mode(fsp->conn,fsp->fsp_name,&st); if ((lp_store_dos_attributes(SNUM(fsp->conn)) || MAP_ARCHIVE(fsp->conn)) && !IS_DOS_ARCHIVE(dosmode)) { file_set_dosmode(fsp->conn,fsp->fsp_name,dosmode | aARCH,&st, False); @@ -288,9 +288,9 @@ nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n", } DEBUG(9,("write_file (%s)(fd=%d pos=%.0f size=%u) wcp->offset=%.0f wcp->data_size=%u\n", - fsp->fsp_name, fsp->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size)); + fsp->fsp_name, fsp->fh->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size)); - fsp->pos = pos + n; + fsp->fh->pos = pos + n; /* * If we have active cache and it isn't contiguous then we flush. @@ -589,7 +589,7 @@ nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n", */ DEBUG(9,("write_file: non cacheable write : fd = %d, pos = %.0f, len = %u, current cache pos = %.0f \ -len = %u\n",fsp->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size )); +len = %u\n",fsp->fh->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size )); /* * If write would fit in the cache, and is larger than @@ -612,7 +612,7 @@ len = %u\n",fsp->fd, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigne if ((pos <= wcp->offset) && (pos + n >= wcp->offset + wcp->data_size) ) { DEBUG(9,("write_file: discarding overwritten write \ -cache: fd = %d, off=%.0f, size=%u\n", fsp->fd, (double)wcp->offset, (unsigned int)wcp->data_size )); +cache: fd = %d, off=%.0f, size=%u\n", fsp->fh->fd, (double)wcp->offset, (unsigned int)wcp->data_size )); wcp->data_size = 0; } @@ -635,7 +635,7 @@ cache: fd = %d, off=%.0f, size=%u\n", fsp->fd, (double)wcp->offset, (unsigned in if (cache_flush_needed) { DEBUG(3,("WRITE_FLUSH:%d: due to noncontinuous write: fd = %d, size = %.0f, pos = %.0f, \ n = %u, wcp->offset=%.0f, wcp->data_size=%u\n", - write_path, fsp->fd, (double)wcp->file_size, (double)pos, (unsigned int)n, + write_path, fsp->fh->fd, (double)wcp->file_size, (double)pos, (unsigned int)n, (double)wcp->offset, (unsigned int)wcp->data_size )); flush_write_cache(fsp, WRITE_FLUSH); @@ -809,7 +809,7 @@ ssize_t flush_write_cache(files_struct *fsp, enum flush_reason_enum reason) DO_PROFILE_DEC_INC(writecache_num_write_caches,writecache_flushed_writes[reason]); DEBUG(9,("flushing write cache: fd = %d, off=%.0f, size=%u\n", - fsp->fd, (double)wcp->offset, (unsigned int)data_size)); + fsp->fh->fd, (double)wcp->offset, (unsigned int)data_size)); #ifdef WITH_PROFILE if(data_size == wcp->alloc_size) { @@ -836,9 +836,9 @@ sync a file void sync_file(connection_struct *conn, files_struct *fsp) { - if(lp_strict_sync(SNUM(conn)) && fsp->fd != -1) { + if(lp_strict_sync(SNUM(conn)) && fsp->fh->fd != -1) { flush_write_cache(fsp, SYNC_FLUSH); - SMB_VFS_FSYNC(fsp,fsp->fd); + SMB_VFS_FSYNC(fsp,fsp->fh->fd); } } @@ -849,9 +849,9 @@ void sync_file(connection_struct *conn, files_struct *fsp) int fsp_stat(files_struct *fsp, SMB_STRUCT_STAT *pst) { - if (fsp->fd == -1) { + if (fsp->fh->fd == -1) { return SMB_VFS_STAT(fsp->conn, fsp->fsp_name, pst); } else { - return SMB_VFS_FSTAT(fsp,fsp->fd, pst); + return SMB_VFS_FSTAT(fsp,fsp->fh->fd, pst); } } diff --git a/source/smbd/files.c b/source/smbd/files.c index e893e9fefc1..80e5b0f710f 100644 --- a/source/smbd/files.c +++ b/source/smbd/files.c @@ -106,7 +106,19 @@ files_struct *file_new(connection_struct *conn) } ZERO_STRUCTP(fsp); - fsp->fd = -1; + + fsp->fh = SMB_MALLOC_P(struct fd_handle); + if (!fsp->fh) { + SAFE_FREE(fsp); + set_saved_error_triple(ERRDOS, ERRnomem, NT_STATUS_NO_MEMORY); + return NULL; + } + + ZERO_STRUCTP(fsp->fh); + + fsp->fh->ref_count = 1; + fsp->fh->fd = -1; + fsp->conn = conn; fsp->file_id = get_gen_count(); GetTimeOfDay(&fsp->open_time); @@ -233,7 +245,7 @@ void file_dump_open_table(void) for (fsp=Files;fsp;fsp=fsp->next,count++) { DEBUG(10,("Files[%d], fnum = %d, name %s, fd = %d, fileid = %lu, dev = %x, inode = %.0f\n", - count, fsp->fnum, fsp->fsp_name, fsp->fd, (unsigned long)fsp->file_id, + count, fsp->fnum, fsp->fsp_name, fsp->fh->fd, (unsigned long)fsp->file_id, (unsigned int)fsp->dev, (double)fsp->inode )); } } @@ -248,7 +260,7 @@ files_struct *file_find_fd(int fd) files_struct *fsp; for (fsp=Files;fsp;fsp=fsp->next,count++) { - if (fsp->fd == fd) { + if (fsp->fh->fd == fd) { if (count > 10) { DLIST_PROMOTE(Files, fsp); } @@ -269,7 +281,7 @@ files_struct *file_find_dif(SMB_DEV_T dev, SMB_INO_T inode, unsigned long file_i files_struct *fsp; for (fsp=Files;fsp;fsp=fsp->next,count++) { - /* We can have a fsp->fd == -1 here as it could be a stat open. */ + /* We can have a fsp->fh->fd == -1 here as it could be a stat open. */ if (fsp->dev == dev && fsp->inode == inode && fsp->file_id == file_id ) { @@ -277,7 +289,7 @@ files_struct *file_find_dif(SMB_DEV_T dev, SMB_INO_T inode, unsigned long file_i DLIST_PROMOTE(Files, fsp); } /* Paranoia check. */ - if (fsp->fd == -1 && fsp->oplock_type != NO_OPLOCK) { + if (fsp->fh->fd == -1 && fsp->oplock_type != NO_OPLOCK) { DEBUG(0,("file_find_dif: file %s dev = %x, inode = %.0f, file_id = %u \ oplock_type = %u is a stat open with oplock type !\n", fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode, (unsigned int)fsp->file_id, @@ -326,7 +338,7 @@ files_struct *file_find_di_first(SMB_DEV_T dev, SMB_INO_T inode) fsp_fi_cache.inode = inode; for (fsp=Files;fsp;fsp=fsp->next) { - if ( fsp->fd != -1 && + if ( fsp->fh->fd != -1 && fsp->dev == dev && fsp->inode == inode ) { /* Setup positive cache. */ @@ -349,7 +361,7 @@ files_struct *file_find_di_next(files_struct *start_fsp) files_struct *fsp; for (fsp = start_fsp->next;fsp;fsp=fsp->next) { - if ( fsp->fd != -1 && + if ( fsp->fh->fd != -1 && fsp->dev == start_fsp->dev && fsp->inode == start_fsp->inode ) return fsp; @@ -389,7 +401,7 @@ void fsp_set_pending_modtime(files_struct *tfsp, time_t pmod) } for (fsp = Files;fsp;fsp=fsp->next) { - if ( fsp->fd != -1 && + if ( fsp->fh->fd != -1 && fsp->dev == tfsp->dev && fsp->inode == tfsp->inode ) { fsp->pending_modtime = pmod; @@ -410,7 +422,7 @@ void file_sync_all(connection_struct *conn) for (fsp=Files;fsp;fsp=next) { next=fsp->next; - if ((conn == fsp->conn) && (fsp->fd != -1)) { + if ((conn == fsp->conn) && (fsp->fh->fd != -1)) { sync_file(conn,fsp); } } @@ -430,6 +442,12 @@ void file_free(files_struct *fsp) destroy_fake_file_handle(&fsp->fake_file_handle); } + if (fsp->fh->ref_count == 1) { + SAFE_FREE(fsp->fh); + } else { + fsp->fh->ref_count--; + } + bitmap_clear(file_bmap, fsp->fnum - FILE_HANDLE_OFFSET); files_used--; @@ -506,3 +524,49 @@ void file_chain_restore(void) { chain_fsp = oplock_save_chain_fsp; } + +files_struct *dup_file_fsp(files_struct *fsp, + uint32 access_mask, + uint32 share_access, + uint32 create_options) +{ + files_struct *dup_fsp = file_new(fsp->conn); + + if (!dup_fsp) { + return NULL; + } + + SAFE_FREE(dup_fsp->fh); + + dup_fsp->fh = fsp->fh; + dup_fsp->fh->ref_count++; + + dup_fsp->dev = fsp->dev; + dup_fsp->inode = fsp->inode; + dup_fsp->initial_allocation_size = fsp->initial_allocation_size; + dup_fsp->mode = fsp->mode; + dup_fsp->file_pid = fsp->file_pid; + dup_fsp->vuid = fsp->vuid; + dup_fsp->open_time = fsp->open_time; + dup_fsp->access_mask = access_mask; + dup_fsp->share_access = share_access; + dup_fsp->pending_modtime_owner = fsp->pending_modtime_owner; + dup_fsp->pending_modtime = fsp->pending_modtime; + dup_fsp->last_write_time = fsp->last_write_time; + dup_fsp->oplock_type = fsp->oplock_type; + dup_fsp->can_lock = fsp->can_lock; + dup_fsp->can_read = (access_mask & (FILE_READ_DATA)) ? True : False; + if (!CAN_WRITE(fsp->conn)) { + dup_fsp->can_write = False; + } else { + dup_fsp->can_write = (access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) ? True : False; + } + dup_fsp->print_file = fsp->print_file; + dup_fsp->modified = fsp->modified; + dup_fsp->is_directory = fsp->is_directory; + dup_fsp->is_stat = fsp->is_stat; + dup_fsp->aio_write_behind = fsp->aio_write_behind; + string_set(&dup_fsp->fsp_name,fsp->fsp_name); + + return dup_fsp; +} diff --git a/source/smbd/ntquotas.c b/source/smbd/ntquotas.c index 8fbf858008b..9bc444d2536 100644 --- a/source/smbd/ntquotas.c +++ b/source/smbd/ntquotas.c @@ -259,4 +259,3 @@ void destroy_quota_handle(void **pqt_handle) return; } - diff --git a/source/smbd/nttrans.c b/source/smbd/nttrans.c index cc37d531f24..f9b70de0ace 100644 --- a/source/smbd/nttrans.c +++ b/source/smbd/nttrans.c @@ -46,20 +46,12 @@ static const char *known_nt_pipes[] = { NULL }; -/* Map generic permissions to file object specific permissions */ - -struct generic_mapping file_generic_mapping = { - FILE_GENERIC_READ, - FILE_GENERIC_WRITE, - FILE_GENERIC_EXECUTE, - FILE_GENERIC_ALL -}; - static char *nttrans_realloc(char **ptr, size_t size) { char *tptr = NULL; - if (ptr==NULL) + if (ptr==NULL) { smb_panic("nttrans_realloc() called with NULL ptr\n"); + } tptr = SMB_REALLOC(*ptr, size); if(tptr == NULL) { @@ -99,8 +91,9 @@ static int send_nt_replies(char *inbuf, char *outbuf, int bufsize, NTSTATUS nt_e set_message(outbuf,18,0,True); - if (NT_STATUS_V(nt_error)) + if (NT_STATUS_V(nt_error)) { ERROR_NT(nt_error); + } /* * If there genuinely are no parameters or data to send just send @@ -108,8 +101,10 @@ static int send_nt_replies(char *inbuf, char *outbuf, int bufsize, NTSTATUS nt_e */ if(params_to_send == 0 && data_to_send == 0) { - if (!send_smb(smbd_server_fd(),outbuf)) + show_msg(outbuf); + if (!send_smb(smbd_server_fd(),outbuf)) { exit_server("send_nt_replies: send_smb failed."); + } return 0; } @@ -119,8 +114,9 @@ static int send_nt_replies(char *inbuf, char *outbuf, int bufsize, NTSTATUS nt_e * can cause NT redirector problems. */ - if (((params_to_send % 4) != 0) && (data_to_send != 0)) + if (((params_to_send % 4) != 0) && (data_to_send != 0)) { data_alignment_offset = 4 - (params_to_send % 4); + } /* * Space is bufsize minus Netbios over TCP header minus SMB header. @@ -221,16 +217,18 @@ static int send_nt_replies(char *inbuf, char *outbuf, int bufsize, NTSTATUS nt_e * Copy the param bytes into the packet. */ - if(params_sent_thistime) + if(params_sent_thistime) { memcpy((smb_buf(outbuf)+alignment_offset),pp,params_sent_thistime); + } /* * Copy in the data bytes */ - if(data_sent_thistime) + if(data_sent_thistime) { memcpy(smb_buf(outbuf)+alignment_offset+params_sent_thistime+ data_alignment_offset,pd,data_sent_thistime); + } DEBUG(9,("nt_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n", params_sent_thistime, data_sent_thistime, useable_space)); @@ -238,8 +236,10 @@ static int send_nt_replies(char *inbuf, char *outbuf, int bufsize, NTSTATUS nt_e params_to_send, data_to_send, paramsize, datasize)); /* Send the packet */ - if (!send_smb(smbd_server_fd(),outbuf)) + show_msg(outbuf); + if (!send_smb(smbd_server_fd(),outbuf)) { exit_server("send_nt_replies: send_smb failed."); + } pp += params_sent_thistime; pd += data_sent_thistime; @@ -287,8 +287,9 @@ static BOOL saved_short_case_preserve; static void set_posix_case_semantics(connection_struct *conn, uint32 file_attributes) { - if(!(file_attributes & FILE_FLAG_POSIX_SEMANTICS)) + if(!(file_attributes & FILE_FLAG_POSIX_SEMANTICS)) { return; + } saved_case_sensitive = conn->case_sensitive; saved_case_preserve = conn->case_preserve; @@ -306,8 +307,9 @@ static void set_posix_case_semantics(connection_struct *conn, uint32 file_attrib static void restore_case_semantics(connection_struct *conn, uint32 file_attributes) { - if(!(file_attributes & FILE_FLAG_POSIX_SEMANTICS)) + if(!(file_attributes & FILE_FLAG_POSIX_SEMANTICS)) { return; + } conn->case_sensitive = saved_case_sensitive; conn->case_preserve = saved_case_preserve; @@ -315,192 +317,6 @@ static void restore_case_semantics(connection_struct *conn, uint32 file_attribut } /**************************************************************************** - Utility function to map create disposition. -****************************************************************************/ - -static int map_create_disposition( uint32 create_disposition) -{ - int ret; - - switch( create_disposition ) { - case FILE_CREATE: - /* create if not exist, fail if exist */ - ret = (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_FAIL); - break; - case FILE_SUPERSEDE: - case FILE_OVERWRITE_IF: - /* create if not exist, trunc if exist */ - ret = (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_TRUNCATE); - break; - case FILE_OPEN: - /* fail if not exist, open if exists */ - ret = (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN); - break; - case FILE_OPEN_IF: - /* create if not exist, open if exists */ - ret = (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_OPEN); - break; - case FILE_OVERWRITE: - /* fail if not exist, truncate if exists */ - ret = (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_TRUNCATE); - break; - default: - DEBUG(0,("map_create_disposition: Incorrect value for create_disposition = %d\n", - create_disposition )); - return -1; - } - - DEBUG(10,("map_create_disposition: Mapped create_disposition 0x%lx to 0x%x\n", - (unsigned long)create_disposition, ret )); - - return ret; -} - -/**************************************************************************** - Utility function to map share modes. -****************************************************************************/ - -static int map_share_mode( char *fname, uint32 create_options, - uint32 *desired_access, uint32 share_access, uint32 file_attributes) -{ - int smb_open_mode = -1; - uint32 original_desired_access = *desired_access; - - /* This is a nasty hack - must fix... JRA. */ - if (*desired_access == MAXIMUM_ALLOWED_ACCESS) { - *desired_access = FILE_GENERIC_ALL; - } - - /* - * Convert GENERIC bits to specific bits. - */ - - se_map_generic(desired_access, &file_generic_mapping); - - switch( *desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA) ) { - case FILE_READ_DATA: - smb_open_mode = DOS_OPEN_RDONLY; - break; - case FILE_WRITE_DATA: - case FILE_APPEND_DATA: - case FILE_WRITE_DATA|FILE_APPEND_DATA: - smb_open_mode = DOS_OPEN_WRONLY; - break; - case FILE_READ_DATA|FILE_WRITE_DATA: - case FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA: - case FILE_READ_DATA|FILE_APPEND_DATA: - smb_open_mode = DOS_OPEN_RDWR; - break; - } - - /* - * NB. For DELETE_ACCESS we should really check the - * directory permissions, as that is what controls - * delete, and for WRITE_DAC_ACCESS we should really - * check the ownership, as that is what controls the - * chmod. Note that this is *NOT* a security hole (this - * note is for you, Andrew) as we are not *allowing* - * the access at this point, the actual unlink or - * chown or chmod call would do this. We are just helping - * clients out by telling them if they have a hope - * of any of this succeeding. POSIX acls may still - * deny the real call. JRA. - */ - - if (smb_open_mode == -1) { - - if(*desired_access & (DELETE_ACCESS|WRITE_DAC_ACCESS|WRITE_OWNER_ACCESS|SYNCHRONIZE_ACCESS| - FILE_EXECUTE|FILE_READ_ATTRIBUTES| - FILE_READ_EA|FILE_WRITE_EA|SYSTEM_SECURITY_ACCESS| - FILE_WRITE_ATTRIBUTES|READ_CONTROL_ACCESS)) { - smb_open_mode = DOS_OPEN_RDONLY; - } else if(*desired_access == 0) { - - /* - * JRA - NT seems to sometimes send desired_access as zero. play it safe - * and map to a stat open. - */ - - smb_open_mode = DOS_OPEN_RDONLY; - - } else { - DEBUG(0,("map_share_mode: Incorrect value 0x%lx for desired_access to file %s\n", - (unsigned long)*desired_access, fname)); - return -1; - } - } - - /* - * Set the special bit that means allow share delete. - * This is held outside the normal share mode bits at 1<<15. - * JRA. - */ - - if(share_access & FILE_SHARE_DELETE) { - smb_open_mode |= ALLOW_SHARE_DELETE; - DEBUG(10,("map_share_mode: FILE_SHARE_DELETE requested. open_mode = 0x%x\n", smb_open_mode)); - } - - if(*desired_access & DELETE_ACCESS) { - DEBUG(10,("map_share_mode: DELETE_ACCESS requested. open_mode = 0x%x\n", smb_open_mode)); - } - - /* - * We need to store the intent to open for Delete. This - * is what determines if a delete on close flag can be set. - * This is the wrong way (and place) to store this, but for 2.2 this - * is the only practical way. JRA. - */ - - if (create_options & FILE_DELETE_ON_CLOSE) { - /* - * W2K3 bug compatibility mode... To set delete on close - * the redirector must have *specifically* set DELETE_ACCESS - * in the desired_access field. Just asking for GENERIC_ALL won't do. JRA. - */ - - if (!(original_desired_access & DELETE_ACCESS)) { - DEBUG(5,("map_share_mode: FILE_DELETE_ON_CLOSE requested without \ -DELETE_ACCESS for file %s. (desired_access = 0x%lx)\n", - fname, (unsigned long)*desired_access)); - return -1; - } - /* Implicit delete access is *NOT* requested... */ - smb_open_mode |= DELETE_ON_CLOSE_FLAG; - DEBUG(10,("map_share_mode: FILE_DELETE_ON_CLOSE requested. open_mode = 0x%x\n", smb_open_mode)); - } - - /* Add in the requested share mode. */ - switch( share_access & (FILE_SHARE_READ|FILE_SHARE_WRITE)) { - case FILE_SHARE_READ: - smb_open_mode |= SET_DENY_MODE(DENY_WRITE); - break; - case FILE_SHARE_WRITE: - smb_open_mode |= SET_DENY_MODE(DENY_READ); - break; - case (FILE_SHARE_READ|FILE_SHARE_WRITE): - smb_open_mode |= SET_DENY_MODE(DENY_NONE); - break; - case FILE_SHARE_NONE: - smb_open_mode |= SET_DENY_MODE(DENY_ALL); - break; - } - - /* - * Handle an O_SYNC request. - */ - - if(file_attributes & FILE_FLAG_WRITE_THROUGH) - smb_open_mode |= FILE_SYNC_OPENMODE; - - DEBUG(10,("map_share_mode: Mapped desired access 0x%lx, share access 0x%lx, file attributes 0x%lx \ -to open_mode 0x%x\n", (unsigned long)*desired_access, (unsigned long)share_access, - (unsigned long)file_attributes, smb_open_mode )); - - return smb_open_mode; -} - -/**************************************************************************** Reply to an NT create and X call on a pipe. ****************************************************************************/ @@ -508,7 +324,6 @@ static int nt_open_pipe(char *fname, connection_struct *conn, char *inbuf, char *outbuf, int *ppnum) { smb_np_struct *p = NULL; - uint16 vuid = SVAL(inbuf, smb_uid); int i; @@ -516,15 +331,19 @@ static int nt_open_pipe(char *fname, connection_struct *conn, /* See if it is one we want to handle. */ - if (lp_disable_spoolss() && strequal(fname, "\\spoolss")) + if (lp_disable_spoolss() && strequal(fname, "\\spoolss")) { return(ERROR_BOTH(NT_STATUS_OBJECT_NAME_NOT_FOUND,ERRDOS,ERRbadpipe)); + } - for( i = 0; known_nt_pipes[i]; i++ ) - if( strequal(fname,known_nt_pipes[i])) + for( i = 0; known_nt_pipes[i]; i++ ) { + if( strequal(fname,known_nt_pipes[i])) { break; + } + } - if ( known_nt_pipes[i] == NULL ) + if ( known_nt_pipes[i] == NULL ) { return(ERROR_BOTH(NT_STATUS_OBJECT_NAME_NOT_FOUND,ERRDOS,ERRbadpipe)); + } /* Strip \\ off the name. */ fname++; @@ -532,11 +351,11 @@ static int nt_open_pipe(char *fname, connection_struct *conn, DEBUG(3,("nt_open_pipe: Known pipe %s opening.\n", fname)); p = open_rpc_pipe_p(fname, conn, vuid); - if (!p) + if (!p) { return(ERROR_DOS(ERRSRV,ERRnofids)); + } *ppnum = p->pnum; - return 0; } @@ -554,8 +373,9 @@ static int do_ntcreate_pipe_open(connection_struct *conn, srvstr_pull_buf(inbuf, fname, smb_buf(inbuf), sizeof(fname), STR_TERMINATE); - if ((ret = nt_open_pipe(fname, conn, inbuf, outbuf, &pnum)) != 0) + if ((ret = nt_open_pipe(fname, conn, inbuf, outbuf, &pnum)) != 0) { return ret; + } /* * Deal with pipe return. @@ -583,6 +403,66 @@ static int do_ntcreate_pipe_open(connection_struct *conn, } /**************************************************************************** + Reply to an NT create and X call for a quota file. +****************************************************************************/ + +int reply_ntcreate_and_X_quota(connection_struct *conn, + char *inbuf, + char *outbuf, + int length, + int bufsize, + enum FAKE_FILE_TYPE fake_file_type, + const char *fname) +{ + int result; + char *p; + uint32 desired_access = IVAL(inbuf,smb_ntcreate_DesiredAccess); + files_struct *fsp = open_fake_file(conn, fake_file_type, fname, desired_access); + + if (!fsp) { + return ERROR_NT(NT_STATUS_ACCESS_DENIED); + } + + set_message(outbuf,34,0,True); + + p = outbuf + smb_vwv2; + + /* SCVAL(p,0,NO_OPLOCK_RETURN); */ + p++; + SSVAL(p,0,fsp->fnum); +#if 0 + p += 2; + SIVAL(p,0,smb_action); + p += 4; + + /* Create time. */ + put_long_date(p,c_time); + p += 8; + put_long_date(p,sbuf.st_atime); /* access time */ + p += 8; + put_long_date(p,sbuf.st_mtime); /* write time */ + p += 8; + put_long_date(p,sbuf.st_mtime); /* change time */ + p += 8; + SIVAL(p,0,fattr); /* File Attributes. */ + p += 4; + SOFF_T(p, 0, get_allocation_size(conn,fsp,&sbuf)); + p += 8; + SOFF_T(p,0,file_len); + p += 8; + if (flags & EXTENDED_RESPONSE_REQUIRED) + SSVAL(p,2,0x7); + p += 4; + SCVAL(p,0,fsp->is_directory ? 1 : 0); +#endif + + DEBUG(5,("reply_ntcreate_and_X_quota: fnum = %d, open name = %s\n", fsp->fnum, fsp->fsp_name)); + + result = chain_reply(inbuf,outbuf,length,bufsize); + return result; +} + +/**************************************************************************** Reply to an NT create and X call. ****************************************************************************/ @@ -591,23 +471,20 @@ int reply_ntcreate_and_X(connection_struct *conn, { int result; pstring fname; - enum FAKE_FILE_TYPE fake_file_type = FAKE_FILE_TYPE_NONE; uint32 flags = IVAL(inbuf,smb_ntcreate_Flags); - uint32 desired_access = IVAL(inbuf,smb_ntcreate_DesiredAccess); + uint32 access_mask = IVAL(inbuf,smb_ntcreate_DesiredAccess); uint32 file_attributes = IVAL(inbuf,smb_ntcreate_FileAttributes); uint32 share_access = IVAL(inbuf,smb_ntcreate_ShareAccess); uint32 create_disposition = IVAL(inbuf,smb_ntcreate_CreateDisposition); uint32 create_options = IVAL(inbuf,smb_ntcreate_CreateOptions); uint16 root_dir_fid = (uint16)IVAL(inbuf,smb_ntcreate_RootDirectoryFid); - int smb_ofun; - int smb_open_mode; /* Breakout the oplock request bits so we can set the reply bits separately. */ int oplock_request = 0; - int fmode=0,rmode=0; + uint32 fattr=0; SMB_OFF_T file_len = 0; SMB_STRUCT_STAT sbuf; - int smb_action = 0; + int info = 0; BOOL bad_path = False; files_struct *fsp=NULL; char *p = NULL; @@ -617,11 +494,16 @@ int reply_ntcreate_and_X(connection_struct *conn, START_PROFILE(SMBntcreateX); - DEBUG(10,("reply_ntcreateX: flags = 0x%x, desired_access = 0x%x \ + DEBUG(10,("reply_ntcreateX: flags = 0x%x, access_mask = 0x%x \ file_attributes = 0x%x, share_access = 0x%x, create_disposition = 0x%x \ -create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attributes, - share_access, create_disposition, - create_options, root_dir_fid )); +create_options = 0x%x root_dir_fid = 0x%x\n", + (unsigned int)flags, + (unsigned int)access_mask, + (unsigned int)file_attributes, + (unsigned int)share_access, + (unsigned int)create_disposition, + (unsigned int)create_options, + (unsigned int)root_dir_fid )); /* If it's an IPC, use the pipe handler. */ @@ -640,16 +522,6 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib return ERROR_NT(NT_STATUS_NOT_SUPPORTED); } - /* - * We need to construct the open_and_X ofun value from the - * NT values, as that's what our code is structured to accept. - */ - - if((smb_ofun = map_create_disposition( create_disposition )) == -1) { - END_PROFILE(SMBntcreateX); - return ERROR_NT(NT_STATUS_INVALID_PARAMETER); - } - /* * Get the file name. */ @@ -729,25 +601,25 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib */ if( is_ntfs_stream_name(fname)) { - -#ifdef HAVE_SYS_QUOTAS - if ((fake_file_type=is_fake_file(fname))!=FAKE_FILE_TYPE_NONE) { + enum FAKE_FILE_TYPE fake_file_type = is_fake_file(fname); + if (fake_file_type!=FAKE_FILE_TYPE_NONE) { /* - * here we go! support for changing the disk quotas --metze + * Here we go! support for changing the disk quotas --metze * - * we need to fake up to open this MAGIC QUOTA file - * and return a valid FID + * We need to fake up to open this MAGIC QUOTA file + * and return a valid FID. * * w2k close this file directly after openening * xp also tries a QUERY_FILE_INFO on the file and then close it */ + result = reply_ntcreate_and_X_quota(conn, inbuf, outbuf, length, bufsize, + fake_file_type, fname); + END_PROFILE(SMBntcreateX); + return result; } else { -#endif END_PROFILE(SMBntcreateX); return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); -#ifdef HAVE_SYS_QUOTAS } -#endif } } @@ -757,13 +629,6 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib */ RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); - if((smb_open_mode = map_share_mode(fname, create_options, &desired_access, - share_access, - file_attributes)) == -1) { - END_PROFILE(SMBntcreateX); - return ERROR_NT(NT_STATUS_INVALID_PARAMETER); - } - oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0; if (oplock_request) { oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0; @@ -781,20 +646,16 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib unix_convert(fname,conn,0,&bad_path,&sbuf); - /* FAKE_FILE is a special case */ - if (fake_file_type == FAKE_FILE_TYPE_NONE) { - /* Normal file. */ - if (bad_path) { - restore_case_semantics(conn, file_attributes); - END_PROFILE(SMBntcreateX); - return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); - } - /* All file access must go through check_name() */ - if (!check_name(fname,conn)) { - restore_case_semantics(conn, file_attributes); - END_PROFILE(SMBntcreateX); - return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath); - } + if (bad_path) { + restore_case_semantics(conn, file_attributes); + END_PROFILE(SMBntcreateX); + return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); + } + /* All file access must go through check_name() */ + if (!check_name(fname,conn)) { + restore_case_semantics(conn, file_attributes); + END_PROFILE(SMBntcreateX); + return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath); } #if 0 @@ -805,7 +666,8 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib if (desired_access & DELETE_ACCESS) { #else /* Setting FILE_SHARE_DELETE is the hint. */ - if (lp_acl_check_permissions(SNUM(conn)) && (share_access & FILE_SHARE_DELETE) && (desired_access & DELETE_ACCESS)) { + 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 @@ -814,7 +676,7 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib NT_STATUS_EQUAL(status,NT_STATUS_CANNOT_DELETE))) { restore_case_semantics(conn, file_attributes); END_PROFILE(SMBntcreateX); - return ERROR_NT(status); + return ERROR_NT(NT_STATUS_ACCESS_DENIED); } } @@ -831,8 +693,13 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib return ERROR_NT(NT_STATUS_INVALID_PARAMETER); } - fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, &smb_action); - + fsp = open_directory(conn, fname, &sbuf, + access_mask, + share_access, + create_disposition, + create_options, + &info); + restore_case_semantics(conn, file_attributes); if(!fsp) { @@ -857,21 +724,14 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib * before issuing an oplock break request to * our client. JRA. */ - if (fake_file_type==FAKE_FILE_TYPE_NONE) { - fsp = open_file_shared1(conn,fname,&sbuf, - desired_access, - smb_open_mode, - smb_ofun,file_attributes,oplock_request, - &rmode,&smb_action); - } else { - /* to open a fake_file --metze */ - fsp = open_fake_file_shared1(fake_file_type,conn,fname,&sbuf, - desired_access, - smb_open_mode, - smb_ofun,file_attributes, oplock_request, - &rmode,&smb_action); - } - + fsp = open_file_ntcreate(conn,fname,&sbuf, + access_mask, + share_access, + create_disposition, + create_options, + file_attributes, + oplock_request, + &info); if (!fsp) { /* We cheat here. There are two cases we * care about. One is a directory rename, @@ -905,8 +765,13 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib } oplock_request = 0; - fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, &smb_action); - + fsp = open_directory(conn, fname, &sbuf, + access_mask, + share_access, + create_disposition, + create_options, + &info); + if(!fsp) { restore_case_semantics(conn, file_attributes); END_PROFILE(SMBntcreateX); @@ -928,18 +793,18 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib restore_case_semantics(conn, file_attributes); file_len = sbuf.st_size; - fmode = dos_mode(conn,fname,&sbuf); - if(fmode == 0) { - fmode = FILE_ATTRIBUTE_NORMAL; + fattr = dos_mode(conn,fname,&sbuf); + if(fattr == 0) { + fattr = FILE_ATTRIBUTE_NORMAL; } - if (!fsp->is_directory && (fmode & aDIR)) { + if (!fsp->is_directory && (fattr & aDIR)) { close_file(fsp,False); END_PROFILE(SMBntcreateX); return ERROR_DOS(ERRDOS,ERRnoaccess); } /* Save the requested allocation size. */ - if ((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) { + if ((info == FILE_WAS_CREATED) || (info == FILE_WAS_OVERWRITTEN)) { SMB_BIG_UINT allocation_size = (SMB_BIG_UINT)IVAL(inbuf,smb_ntcreate_AllocationSize); #ifdef LARGE_SMB_OFF_T allocation_size |= (((SMB_BIG_UINT)IVAL(inbuf,smb_ntcreate_AllocationSize + 4)) << 32); @@ -1005,10 +870,11 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib p++; SSVAL(p,0,fsp->fnum); p += 2; - if ((create_disposition == FILE_SUPERSEDE) && (smb_action == FILE_WAS_OVERWRITTEN)) + if ((create_disposition == FILE_SUPERSEDE) && (info == FILE_WAS_OVERWRITTEN)) { SIVAL(p,0,FILE_WAS_SUPERSEDED); - else - SIVAL(p,0,smb_action); + } else { + SIVAL(p,0,info); + } p += 4; /* Create time. */ @@ -1029,14 +895,15 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib p += 8; put_long_date(p,sbuf.st_mtime); /* change time */ p += 8; - SIVAL(p,0,fmode); /* File Attributes. */ + SIVAL(p,0,fattr); /* File Attributes. */ p += 4; SOFF_T(p, 0, get_allocation_size(conn,fsp,&sbuf)); p += 8; SOFF_T(p,0,file_len); p += 8; - if (flags & EXTENDED_RESPONSE_REQUIRED) + if (flags & EXTENDED_RESPONSE_REQUIRED) { SSVAL(p,2,0x7); + } p += 4; SCVAL(p,0,fsp->is_directory ? 1 : 0); @@ -1077,13 +944,15 @@ static int do_nt_transact_create_pipe( connection_struct *conn, char *inbuf, cha return ERROR_NT(status); } - if ((ret = nt_open_pipe(fname, conn, inbuf, outbuf, &pnum)) != 0) + if ((ret = nt_open_pipe(fname, conn, inbuf, outbuf, &pnum)) != 0) { return ret; + } /* Realloc the size of parameters and data we will return */ params = nttrans_realloc(ppparams, 69); - if(params == NULL) + if(params == NULL) { return ERROR_DOS(ERRDOS,ERRnomem); + } p = params; SCVAL(p,0,NO_OPLOCK_RETURN); @@ -1156,16 +1025,20 @@ static NTSTATUS set_sd(files_struct *fsp, char *data, uint32 sd_len, uint32 secu return NT_STATUS_NO_MEMORY; } - if (psd->off_owner_sid==0) + if (psd->off_owner_sid==0) { security_info_sent &= ~OWNER_SECURITY_INFORMATION; - if (psd->off_grp_sid==0) + } + if (psd->off_grp_sid==0) { security_info_sent &= ~GROUP_SECURITY_INFORMATION; - if (psd->off_sacl==0) + } + if (psd->off_sacl==0) { security_info_sent &= ~SACL_SECURITY_INFORMATION; - if (psd->off_dacl==0) + } + if (psd->off_dacl==0) { security_info_sent &= ~DACL_SECURITY_INFORMATION; + } - ret = SMB_VFS_FSET_NT_ACL( fsp, fsp->fd, security_info_sent, psd); + ret = SMB_VFS_FSET_NT_ACL( fsp, fsp->fh->fd, security_info_sent, psd); if (!ret) { talloc_destroy(mem_ctx); @@ -1219,16 +1092,16 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o char *data = *ppdata; /* Breakout the oplock request bits so we can set the reply bits separately. */ int oplock_request = 0; - int fmode=0,rmode=0; + uint32 fattr=0; SMB_OFF_T file_len = 0; SMB_STRUCT_STAT sbuf; - int smb_action = 0; + int info = 0; BOOL bad_path = False; files_struct *fsp = NULL; char *p = NULL; BOOL extended_oplock_granted = False; uint32 flags; - uint32 desired_access; + uint32 access_mask; uint32 file_attributes; uint32 share_access; uint32 create_disposition; @@ -1236,8 +1109,6 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o uint32 sd_len; uint32 ea_len; uint16 root_dir_fid; - int smb_ofun; - int smb_open_mode; time_t c_time; struct ea_list *ea_list = NULL; TALLOC_CTX *ctx = NULL; @@ -1251,14 +1122,15 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o */ if (IS_IPC(conn)) { - if (lp_nt_pipe_support()) + if (lp_nt_pipe_support()) { return do_nt_transact_create_pipe(conn, inbuf, outbuf, length, bufsize, ppsetup, setup_count, ppparams, parameter_count, ppdata, data_count); - else + } else { return ERROR_DOS(ERRDOS,ERRnoaccess); + } } /* @@ -1271,7 +1143,7 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o } flags = IVAL(params,0); - desired_access = IVAL(params,8); + access_mask = IVAL(params,8); file_attributes = IVAL(params,20); share_access = IVAL(params,24); create_disposition = IVAL(params,28); @@ -1307,15 +1179,6 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o return ERROR_NT(NT_STATUS_NOT_SUPPORTED); } - /* - * We need to construct the open_and_X ofun value from the - * NT values, as that's what our code is structured to accept. - */ - - if((smb_ofun = map_create_disposition( create_disposition )) == -1) { - return ERROR_NT(NT_STATUS_INVALID_PARAMETER); - } - /* * Get the file name. */ @@ -1327,8 +1190,9 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o files_struct *dir_fsp = file_fsp(params,4); size_t dir_name_len; - if(!dir_fsp) + if(!dir_fsp) { return ERROR_DOS(ERRDOS,ERRbadfid); + } if(!dir_fsp->is_directory) { srvstr_get_path(inbuf, fname, params+53, sizeof(fname), parameter_count-53, STR_TERMINATE, &status, False); @@ -1386,15 +1250,6 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o } } - /* - * Now contruct the smb_open_mode value from the desired access - * and the share access. - */ - - if((smb_open_mode = map_share_mode( fname, create_options, &desired_access, - share_access, file_attributes)) == -1) - return ERROR_NT(NT_STATUS_INVALID_PARAMETER); - oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0; oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0; @@ -1425,7 +1280,7 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o if (desired_access & DELETE_ACCESS) { #else /* Setting FILE_SHARE_DELETE is the hint. */ - if (lp_acl_check_permissions(SNUM(conn)) && (share_access & FILE_SHARE_DELETE) && (desired_access & DELETE_ACCESS)) { + 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 @@ -1478,8 +1333,12 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o * CreateDirectory() call. */ - fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, &smb_action); - + fsp = open_directory(conn, fname, &sbuf, + access_mask, + share_access, + create_disposition, + create_options, + &info); if(!fsp) { talloc_destroy(ctx); restore_case_semantics(conn, file_attributes); @@ -1492,9 +1351,14 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o * Ordinary file case. */ - fsp = open_file_shared1(conn,fname,&sbuf,desired_access, - smb_open_mode,smb_ofun,file_attributes, - oplock_request,&rmode,&smb_action); + fsp = open_file_ntcreate(conn,fname,&sbuf, + access_mask, + share_access, + create_disposition, + create_options, + file_attributes, + oplock_request, + &info); if (!fsp) { if(errno == EISDIR) { @@ -1509,8 +1373,12 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o } oplock_request = 0; - fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, &smb_action); - + fsp = open_directory(conn, fname, &sbuf, + access_mask, + share_access, + create_disposition, + create_options, + &info); if(!fsp) { talloc_destroy(ctx); restore_case_semantics(conn, file_attributes); @@ -1539,12 +1407,12 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o * Patch for bug #2242 from Tom Lackemann <cessnatomny@yahoo.com>. */ - if (lp_nt_acl_support(SNUM(conn)) && sd_len && smb_action == FILE_WAS_CREATED) { - uint32 saved_access = fsp->desired_access; + if (lp_nt_acl_support(SNUM(conn)) && sd_len && info == FILE_WAS_CREATED) { + uint32 saved_access_mask = fsp->access_mask; /* We have already checked that sd_len <= data_count here. */ - fsp->desired_access = FILE_GENERIC_ALL; + fsp->access_mask = FILE_GENERIC_ALL; status = set_sd( fsp, data, sd_len, ALL_SECURITY_INFORMATION); if (!NT_STATUS_IS_OK(status)) { @@ -1553,10 +1421,10 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o restore_case_semantics(conn, file_attributes); return ERROR_NT(status); } - fsp->desired_access = saved_access; + fsp->access_mask = saved_access_mask; } - if (ea_len && (smb_action == FILE_WAS_CREATED)) { + if (ea_len && (info == FILE_WAS_CREATED)) { status = set_ea(conn, fsp, fname, ea_list); talloc_destroy(ctx); if (!NT_STATUS_IS_OK(status)) { @@ -1569,17 +1437,17 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o restore_case_semantics(conn, file_attributes); file_len = sbuf.st_size; - fmode = dos_mode(conn,fname,&sbuf); - if(fmode == 0) { - fmode = FILE_ATTRIBUTE_NORMAL; + fattr = dos_mode(conn,fname,&sbuf); + if(fattr == 0) { + fattr = FILE_ATTRIBUTE_NORMAL; } - if (!fsp->is_directory && (fmode & aDIR)) { + if (!fsp->is_directory && (fattr & aDIR)) { close_file(fsp,False); return ERROR_DOS(ERRDOS,ERRnoaccess); } /* Save the requested allocation size. */ - if ((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) { + if ((info == FILE_WAS_CREATED) || (info == FILE_WAS_OVERWRITTEN)) { SMB_BIG_UINT allocation_size = (SMB_BIG_UINT)IVAL(params,12); #ifdef LARGE_SMB_OFF_T allocation_size |= (((SMB_BIG_UINT)IVAL(params,16)) << 32); @@ -1616,24 +1484,27 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o /* Realloc the size of parameters and data we will return */ params = nttrans_realloc(ppparams, 69); - if(params == NULL) + if(params == NULL) { return ERROR_DOS(ERRDOS,ERRnomem); + } p = params; - if (extended_oplock_granted) + if (extended_oplock_granted) { SCVAL(p,0, BATCH_OPLOCK_RETURN); - else if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type)) + } else if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type)) { SCVAL(p,0, LEVEL_II_OPLOCK_RETURN); - else + } else { SCVAL(p,0,NO_OPLOCK_RETURN); + } p += 2; SSVAL(p,0,fsp->fnum); p += 2; - if ((create_disposition == FILE_SUPERSEDE) && (smb_action == FILE_WAS_OVERWRITTEN)) + if ((create_disposition == FILE_SUPERSEDE) && (info == FILE_WAS_OVERWRITTEN)) { SIVAL(p,0,FILE_WAS_SUPERSEDED); - else - SIVAL(p,0,smb_action); + } else { + SIVAL(p,0,info); + } p += 8; /* Create time. */ @@ -1654,14 +1525,15 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o p += 8; put_long_date(p,sbuf.st_mtime); /* change time */ p += 8; - SIVAL(p,0,fmode); /* File Attributes. */ + SIVAL(p,0,fattr); /* File Attributes. */ p += 4; SOFF_T(p, 0, get_allocation_size(conn,fsp,&sbuf)); p += 8; SOFF_T(p,0,file_len); p += 8; - if (flags & EXTENDED_RESPONSE_REQUIRED) + if (flags & EXTENDED_RESPONSE_REQUIRED) { SSVAL(p,2,0x7); + } p += 4; SCVAL(p,0,fsp->is_directory ? 1 : 0); @@ -1700,7 +1572,7 @@ int reply_ntcancel(connection_struct *conn, Copy a file. ****************************************************************************/ -static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *newname, uint16 attrs) +static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *newname, uint32 attrs) { BOOL bad_path_oldname = False; BOOL bad_path_newname = False; @@ -1708,9 +1580,8 @@ static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *new pstring last_component_oldname; pstring last_component_newname; files_struct *fsp1,*fsp2; - uint16 fmode; - int access_mode; - int smb_action; + uint32 fattr; + int info; SMB_OFF_T ret=-1; int close_ret; NTSTATUS status = NT_STATUS_OK; @@ -1747,9 +1618,10 @@ static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *new } /* Ensure attributes match. */ - fmode = dos_mode(conn,oldname,&sbuf1); - if ((fmode & ~attrs) & (aHIDDEN | aSYSTEM)) + 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) { @@ -1784,9 +1656,14 @@ static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *new DEBUG(10,("copy_internals: doing file copy %s to %s\n", oldname, newname)); - fsp1 = open_file_shared1(conn,oldname,&sbuf1,FILE_READ_DATA,SET_DENY_MODE(DENY_ALL)|SET_OPEN_MODE(DOS_OPEN_RDONLY), - (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),FILE_ATTRIBUTE_NORMAL,0, - &access_mode,&smb_action); + fsp1 = open_file_ntcreate(conn,oldname,&sbuf1, + FILE_READ_DATA, /* Read-only. */ + 0, /* No sharing. */ + FILE_OPEN, + 0, /* No create options. */ + FILE_ATTRIBUTE_NORMAL, + INTERNAL_OPEN_ONLY, + &info); if (!fsp1) { get_saved_error_triple(NULL, NULL, &status); @@ -1797,9 +1674,14 @@ static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *new return status; } - fsp2 = open_file_shared1(conn,newname,&sbuf2,FILE_WRITE_DATA,SET_DENY_MODE(DENY_ALL)|SET_OPEN_MODE(DOS_OPEN_WRONLY), - (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_FAIL),fmode,INTERNAL_OPEN_ONLY, - &access_mode,&smb_action); + fsp2 = open_file_ntcreate(conn,newname,&sbuf2, + FILE_WRITE_DATA, /* Read-only. */ + 0, /* No sharing. */ + FILE_CREATE, + 0, /* No create options. */ + fattr, + INTERNAL_OPEN_ONLY, + &info); if (!fsp2) { get_saved_error_triple(NULL, NULL, &status); @@ -1811,8 +1693,9 @@ static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *new return status; } - if (sbuf1.st_size) + if (sbuf1.st_size) { ret = vfs_transfer_file(fsp1, fsp2, sbuf1.st_size); + } /* * As we are opening fsp1 read-only we only expect @@ -1829,7 +1712,7 @@ static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *new /* Grrr. We have to do this as open_file_shared1 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, fmode, &sbuf2, True); + file_set_dosmode(conn, newname, fattr, &sbuf2, True); if (ret < (SMB_OFF_T)sbuf1.st_size) { return NT_STATUS_DISK_FULL; @@ -1855,7 +1738,7 @@ int reply_ntrename(connection_struct *conn, pstring newname; char *p; NTSTATUS status; - uint16 attrs = SVAL(inbuf,smb_vwv0); + uint32 attrs = SVAL(inbuf,smb_vwv0); uint16 rename_type = SVAL(inbuf,smb_vwv1); START_PROFILE(SMBntrename); @@ -1955,22 +1838,26 @@ static int call_nt_transact_notify_change(connection_struct *conn, char *inbuf, files_struct *fsp; uint32 flags; - if(setup_count < 6) + if(setup_count < 6) { return ERROR_DOS(ERRDOS,ERRbadfunc); + } fsp = file_fsp(setup,4); flags = IVAL(setup, 0); DEBUG(3,("call_nt_transact_notify_change\n")); - if(!fsp) + if(!fsp) { return ERROR_DOS(ERRDOS,ERRbadfid); + } - if((!fsp->is_directory) || (conn != fsp->conn)) + if((!fsp->is_directory) || (conn != fsp->conn)) { return ERROR_DOS(ERRDOS,ERRbadfid); + } - if (!change_notify_set(inbuf, fsp, conn, flags)) + if (!change_notify_set(inbuf, fsp, conn, flags)) { return(UNIXERROR(ERRDOS,ERRbadfid)); + } DEBUG(3,("call_nt_transact_notify_change: notify change called on directory \ name = %s\n", fsp->fsp_name )); @@ -1993,8 +1880,9 @@ static int call_nt_transact_rename(connection_struct *conn, char *inbuf, char *o BOOL replace_if_exists = False; NTSTATUS status; - if(parameter_count < 4) + if(parameter_count < 4) { return ERROR_DOS(ERRDOS,ERRbadfunc); + } fsp = file_fsp(params, 0); replace_if_exists = (SVAL(params,2) & RENAME_REPLACE_IF_EXISTS) ? True : False; @@ -2062,12 +1950,14 @@ static int call_nt_transact_query_security_desc(connection_struct *conn, char *i TALLOC_CTX *mem_ctx; files_struct *fsp = NULL; - if(parameter_count < 8) + if(parameter_count < 8) { return ERROR_DOS(ERRDOS,ERRbadfunc); + } fsp = file_fsp(params,0); - if(!fsp) + if(!fsp) { return ERROR_DOS(ERRDOS,ERRbadfid); + } security_info_wanted = IVAL(params,4); @@ -2075,8 +1965,9 @@ static int call_nt_transact_query_security_desc(connection_struct *conn, char *i (unsigned int)security_info_wanted )); params = nttrans_realloc(ppparams, 4); - if(params == NULL) + if(params == NULL) { return ERROR_DOS(ERRDOS,ERRnomem); + } if ((mem_ctx = talloc_init("call_nt_transact_query_security_desc")) == NULL) { DEBUG(0,("call_nt_transact_query_security_desc: talloc_init failed.\n")); @@ -2087,10 +1978,11 @@ static int call_nt_transact_query_security_desc(connection_struct *conn, char *i * Get the permissions to return. */ - if (!lp_nt_acl_support(SNUM(conn))) + if (!lp_nt_acl_support(SNUM(conn))) { sd_size = get_null_nt_acl(mem_ctx, &psd); - else - sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fd, security_info_wanted, &psd); + } else { + sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fh->fd, security_info_wanted, &psd); + } if (sd_size == 0) { talloc_destroy(mem_ctx); @@ -2171,25 +2063,30 @@ static int call_nt_transact_set_security_desc(connection_struct *conn, char *inb uint32 security_info_sent = 0; NTSTATUS nt_status; - if(parameter_count < 8) + if(parameter_count < 8) { return ERROR_DOS(ERRDOS,ERRbadfunc); + } - if((fsp = file_fsp(params,0)) == NULL) + if((fsp = file_fsp(params,0)) == NULL) { return ERROR_DOS(ERRDOS,ERRbadfid); + } - if(!lp_nt_acl_support(SNUM(conn))) + if(!lp_nt_acl_support(SNUM(conn))) { goto done; + } security_info_sent = IVAL(params,4); DEBUG(3,("call_nt_transact_set_security_desc: file = %s, sent 0x%x\n", fsp->fsp_name, (unsigned int)security_info_sent )); - if (data_count == 0) + if (data_count == 0) { return ERROR_DOS(ERRDOS, ERRnoaccess); + } - if (!NT_STATUS_IS_OK(nt_status = set_sd( fsp, data, data_count, security_info_sent))) + if (!NT_STATUS_IS_OK(nt_status = set_sd( fsp, data, data_count, security_info_sent))) { return ERROR_NT(nt_status); + } done: @@ -2520,8 +2417,9 @@ static int call_nt_transact_get_user_quota(connection_struct *conn, char *inbuf, /* Realloc the size of parameters and data we will return */ param_len = 4; params = nttrans_realloc(ppparams, param_len); - if(params == NULL) + if(params == NULL) { return ERROR_DOS(ERRDOS,ERRnomem); + } data_len = 0; SIVAL(params,0,data_len); @@ -2544,19 +2442,20 @@ static int call_nt_transact_get_user_quota(connection_struct *conn, char *inbuf, /* Realloc the size of parameters and data we will return */ param_len = 4; params = nttrans_realloc(ppparams, param_len); - if(params == NULL) + if(params == NULL) { return ERROR_DOS(ERRDOS,ERRnomem); + } /* we should not trust the value in max_data_count*/ max_data_count = MIN(max_data_count,2048); pdata = nttrans_realloc(ppdata, max_data_count);/* should be max data count from client*/ - if(pdata == NULL) + if(pdata == NULL) { return ERROR_DOS(ERRDOS,ERRnomem); + } entry = pdata; - /* set params Size of returned Quota Data 4 bytes*/ /* but set it later when we know it */ @@ -2641,7 +2540,6 @@ static int call_nt_transact_get_user_quota(connection_struct *conn, char *inbuf, sid_parse(pdata+8,sid_len,&sid); - if (vfs_get_ntquota(fsp, SMB_USER_QUOTA_TYPE, &sid, &qt)!=0) { ZERO_STRUCT(qt); /* @@ -2654,12 +2552,14 @@ static int call_nt_transact_get_user_quota(connection_struct *conn, char *inbuf, /* Realloc the size of parameters and data we will return */ param_len = 4; params = nttrans_realloc(ppparams, param_len); - if(params == NULL) + if(params == NULL) { return ERROR_DOS(ERRDOS,ERRnomem); + } pdata = nttrans_realloc(ppdata, data_len); - if(pdata == NULL) + if(pdata == NULL) { return ERROR_DOS(ERRDOS,ERRnomem); + } entry = pdata; @@ -2884,12 +2784,15 @@ due to being in oplock break state.\n", (unsigned int)function_code )); /* Allocate the space for the setup, the maximum needed parameters and data */ - if(setup_count > 0) + if(setup_count > 0) { setup = (char *)SMB_MALLOC(setup_count); - if (total_parameter_count > 0) + } + if (total_parameter_count > 0) { params = (char *)SMB_MALLOC(total_parameter_count); - if (total_data_count > 0) + } + if (total_data_count > 0) { data = (char *)SMB_MALLOC(total_data_count); + } if ((total_parameter_count && !params) || (total_data_count && !data) || (setup_count && !setup)) { @@ -2911,10 +2814,12 @@ due to being in oplock break state.\n", (unsigned int)function_code )); if(setup) { DEBUG(10,("reply_nttrans: setup_count = %d\n", setup_count)); if ((smb_nt_SetupStart + setup_count < smb_nt_SetupStart) || - (smb_nt_SetupStart + setup_count < setup_count)) + (smb_nt_SetupStart + setup_count < setup_count)) { goto bad_param; - if (smb_nt_SetupStart + setup_count > length) + } + if (smb_nt_SetupStart + setup_count > length) { goto bad_param; + } memcpy( setup, &inbuf[smb_nt_SetupStart], setup_count); dump_data(10, setup, setup_count); @@ -2922,22 +2827,26 @@ due to being in oplock break state.\n", (unsigned int)function_code )); if(params) { DEBUG(10,("reply_nttrans: parameter_count = %d\n", parameter_count)); if ((parameter_offset + parameter_count < parameter_offset) || - (parameter_offset + parameter_count < parameter_count)) + (parameter_offset + parameter_count < parameter_count)) { goto bad_param; + } if ((smb_base(inbuf) + parameter_offset + parameter_count > inbuf + length)|| - (smb_base(inbuf) + parameter_offset + parameter_count < smb_base(inbuf))) + (smb_base(inbuf) + parameter_offset + parameter_count < smb_base(inbuf))) { goto bad_param; + } memcpy( params, smb_base(inbuf) + parameter_offset, parameter_count); dump_data(10, params, parameter_count); } if(data) { DEBUG(10,("reply_nttrans: data_count = %d\n",data_count)); - if ((data_offset + data_count < data_offset) || (data_offset + data_count < data_count)) + if ((data_offset + data_count < data_offset) || (data_offset + data_count < data_count)) { goto bad_param; + } if ((smb_base(inbuf) + data_offset + data_count > inbuf + length) || - (smb_base(inbuf) + data_offset + data_count < smb_base(inbuf))) + (smb_base(inbuf) + data_offset + data_count < smb_base(inbuf))) { goto bad_param; + } memcpy( data, smb_base(inbuf) + data_offset, data_count); dump_data(10, data, data_count); @@ -2950,8 +2859,10 @@ due to being in oplock break state.\n", (unsigned int)function_code )); of the parameter/data bytes */ outsize = set_message(outbuf,0,0,True); srv_signing_trans_stop(); - if (!send_smb(smbd_server_fd(),outbuf)) + show_msg(outbuf); + if (!send_smb(smbd_server_fd(),outbuf)) { exit_server("reply_nttrans: send_smb failed."); + } while( num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) { BOOL ret; @@ -2982,10 +2893,12 @@ due to being in oplock break state.\n", (unsigned int)function_code )); } /* Revise total_params and total_data in case they have changed downwards */ - if (IVAL(inbuf, smb_nts_TotalParameterCount) < total_parameter_count) + if (IVAL(inbuf, smb_nts_TotalParameterCount) < total_parameter_count) { total_parameter_count = IVAL(inbuf, smb_nts_TotalParameterCount); - if (IVAL(inbuf, smb_nts_TotalDataCount) < total_data_count) + } + if (IVAL(inbuf, smb_nts_TotalDataCount) < total_data_count) { total_data_count = IVAL(inbuf, smb_nts_TotalDataCount); + } parameter_count = IVAL(inbuf,smb_nts_ParameterCount); parameter_offset = IVAL(inbuf, smb_nts_ParameterOffset); @@ -3003,43 +2916,54 @@ due to being in oplock break state.\n", (unsigned int)function_code )); } if (parameter_count) { - if (parameter_displacement + parameter_count > total_parameter_count) + if (parameter_displacement + parameter_count > total_parameter_count) { goto bad_param; + } if ((parameter_displacement + parameter_count < parameter_displacement) || - (parameter_displacement + parameter_count < parameter_count)) + (parameter_displacement + parameter_count < parameter_count)) { goto bad_param; - if (parameter_displacement > total_parameter_count) + } + if (parameter_displacement > total_parameter_count) { goto bad_param; + } if ((smb_base(inbuf) + parameter_offset + parameter_count > inbuf + length) || - (smb_base(inbuf) + parameter_offset + parameter_count < smb_base(inbuf))) + (smb_base(inbuf) + parameter_offset + parameter_count < smb_base(inbuf))) { goto bad_param; - if (parameter_displacement + params < params) + } + if (parameter_displacement + params < params) { goto bad_param; + } memcpy( ¶ms[parameter_displacement], smb_base(inbuf) + parameter_offset, parameter_count); } if (data_count) { - if (data_displacement + data_count > total_data_count) + if (data_displacement + data_count > total_data_count) { goto bad_param; + } if ((data_displacement + data_count < data_displacement) || - (data_displacement + data_count < data_count)) + (data_displacement + data_count < data_count)) { goto bad_param; - if (data_displacement > total_data_count) + } + if (data_displacement > total_data_count) { goto bad_param; + } if ((smb_base(inbuf) + data_offset + data_count > inbuf + length) || - (smb_base(inbuf) + data_offset + data_count < smb_base(inbuf))) + (smb_base(inbuf) + data_offset + data_count < smb_base(inbuf))) { goto bad_param; - if (data_displacement + data < data) + } + if (data_displacement + data < data) { goto bad_param; + } memcpy( &data[data_displacement], smb_base(inbuf)+ data_offset, data_count); } } } - if (Protocol >= PROTOCOL_NT1) + if (Protocol >= PROTOCOL_NT1) { SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | FLAGS2_IS_LONG_NAME); + } /* Now we must call the relevant NT_TRANS function */ switch(function_code) { diff --git a/source/smbd/open.c b/source/smbd/open.c index 9da53a5057a..810913c025d 100644 --- a/source/smbd/open.c +++ b/source/smbd/open.c @@ -3,6 +3,7 @@ file opening and share modes Copyright (C) Andrew Tridgell 1992-1998 Copyright (C) Jeremy Allison 2001-2004 + Copyright (C) Volker Lendecke 2005 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -36,13 +37,16 @@ struct dev_inode_bundle { fd support routines - attempt to do a dos_open. ****************************************************************************/ -static int fd_open(struct connection_struct *conn, const char *fname, - int flags, mode_t mode) +static int fd_open(struct connection_struct *conn, + const char *fname, + int flags, + mode_t mode) { int fd; #ifdef O_NOFOLLOW - if (!lp_symlinks(SNUM(conn))) + if (!lp_symlinks(SNUM(conn))) { flags |= O_NOFOLLOW; + } #endif fd = SMB_VFS_OPEN(conn,fname,flags,mode); @@ -57,10 +61,15 @@ static int fd_open(struct connection_struct *conn, const char *fname, Close the file associated with a fsp. ****************************************************************************/ -int fd_close(struct connection_struct *conn, files_struct *fsp) +int fd_close(struct connection_struct *conn, + files_struct *fsp) { - if (fsp->fd == -1) - return 0; /* what we used to call a stat open. */ + if (fsp->fh->fd == -1) { + return 0; /* What we used to call a stat open. */ + } + if (fsp->fh->ref_count > 1) { + return 0; /* Shared handle. Only close last reference. */ + } return fd_close_posix(conn, fsp); } @@ -86,7 +95,10 @@ static void check_for_pipe(const char *fname) Do this by fd if possible. ****************************************************************************/ -void change_owner_to_parent(connection_struct *conn, files_struct *fsp, const char *fname, SMB_STRUCT_STAT *psbuf) +void change_owner_to_parent(connection_struct *conn, + files_struct *fsp, + const char *fname, + SMB_STRUCT_STAT *psbuf) { const char *parent_path = parent_dirname(fname); SMB_STRUCT_STAT parent_st; @@ -94,56 +106,67 @@ void change_owner_to_parent(connection_struct *conn, files_struct *fsp, const ch ret = SMB_VFS_STAT(conn, parent_path, &parent_st); if (ret == -1) { - DEBUG(0,("change_owner_to_parent: failed to stat parent directory %s. Error was %s\n", - parent_path, strerror(errno) )); + DEBUG(0,("change_owner_to_parent: failed to stat parent " + "directory %s. Error was %s\n", + parent_path, strerror(errno) )); return; } - if (fsp && fsp->fd != -1) { + if (fsp && fsp->fh->fd != -1) { become_root(); - ret = SMB_VFS_FCHOWN(fsp, fsp->fd, parent_st.st_uid, (gid_t)-1); + ret = SMB_VFS_FCHOWN(fsp, fsp->fh->fd, parent_st.st_uid, (gid_t)-1); unbecome_root(); if (ret == -1) { - DEBUG(0,("change_owner_to_parent: failed to fchown file %s to parent directory uid %u. \ -Error was %s\n", - fname, (unsigned int)parent_st.st_uid, strerror(errno) )); + DEBUG(0,("change_owner_to_parent: failed to fchown " + "file %s to parent directory uid %u. Error " + "was %s\n", fname, + (unsigned int)parent_st.st_uid, + strerror(errno) )); } - DEBUG(10,("change_owner_to_parent: changed new file %s to parent directory uid %u.\n", - fname, (unsigned int)parent_st.st_uid )); + DEBUG(10,("change_owner_to_parent: changed new file %s to " + "parent directory uid %u.\n", fname, + (unsigned int)parent_st.st_uid )); } else { - /* We've already done an lstat into psbuf, and we know it's a directory. If - we can cd into the directory and the dev/ino are the same then we can safely - chown without races as we're locking the directory in place by being in it. - This should work on any UNIX (thanks tridge :-). JRA. + /* We've already done an lstat into psbuf, and we know it's a + directory. If we can cd into the directory and the dev/ino + are the same then we can safely chown without races as + we're locking the directory in place by being in it. This + should work on any UNIX (thanks tridge :-). JRA. */ pstring saved_dir; SMB_STRUCT_STAT sbuf; if (!vfs_GetWd(conn,saved_dir)) { - DEBUG(0,("change_owner_to_parent: failed to get current working directory\n")); + DEBUG(0,("change_owner_to_parent: failed to get " + "current working directory\n")); return; } /* Chdir into the new path. */ if (vfs_ChDir(conn, fname) == -1) { - DEBUG(0,("change_owner_to_parent: failed to change current working directory to %s. \ -Error was %s\n", fname, strerror(errno) )); + DEBUG(0,("change_owner_to_parent: failed to change " + "current working directory to %s. Error " + "was %s\n", fname, strerror(errno) )); goto out; } if (SMB_VFS_STAT(conn,".",&sbuf) == -1) { - DEBUG(0,("change_owner_to_parent: failed to stat directory '.' (%s) \ -Error was %s\n", fname, strerror(errno))); + DEBUG(0,("change_owner_to_parent: failed to stat " + "directory '.' (%s) Error was %s\n", + fname, strerror(errno))); goto out; } /* Ensure we're pointing at the same place. */ - if (sbuf.st_dev != psbuf->st_dev || sbuf.st_ino != psbuf->st_ino || sbuf.st_mode != psbuf->st_mode ) { - DEBUG(0,("change_owner_to_parent: device/inode/mode on directory %s changed. Refusing to chown !\n", - fname )); + if (sbuf.st_dev != psbuf->st_dev || + sbuf.st_ino != psbuf->st_ino || + sbuf.st_mode != psbuf->st_mode ) { + DEBUG(0,("change_owner_to_parent: " + "device/inode/mode on directory %s changed. " + "Refusing to chown !\n", fname )); goto out; } @@ -151,14 +174,16 @@ Error was %s\n", fname, strerror(errno))); ret = SMB_VFS_CHOWN(conn, ".", parent_st.st_uid, (gid_t)-1); unbecome_root(); if (ret == -1) { - DEBUG(10,("change_owner_to_parent: failed to chown directory %s to parent directory uid %u. \ -Error was %s\n", - fname, (unsigned int)parent_st.st_uid, strerror(errno) )); + DEBUG(10,("change_owner_to_parent: failed to chown " + "directory %s to parent directory uid %u. " + "Error was %s\n", fname, + (unsigned int)parent_st.st_uid, strerror(errno) )); goto out; } - DEBUG(10,("change_owner_to_parent: changed ownership of new directory %s to parent directory uid %u.\n", - fname, (unsigned int)parent_st.st_uid )); + DEBUG(10,("change_owner_to_parent: changed ownership of new " + "directory %s to parent directory uid %u.\n", + fname, (unsigned int)parent_st.st_uid )); out: @@ -170,13 +195,19 @@ Error was %s\n", Open a file. ****************************************************************************/ -static BOOL open_file(files_struct *fsp,connection_struct *conn, - const char *fname,SMB_STRUCT_STAT *psbuf,int flags,mode_t mode, uint32 desired_access) +static BOOL open_file(files_struct *fsp, + connection_struct *conn, + const char *fname, + SMB_STRUCT_STAT *psbuf, + int flags, + mode_t unx_mode, + uint32 access_mask) { int accmode = (flags & O_ACCMODE); int local_flags = flags; + BOOL file_existed = VALID_STAT(*psbuf); - fsp->fd = -1; + fsp->fh->fd = -1; fsp->oplock_type = NO_OPLOCK; errno = EPERM; @@ -199,9 +230,9 @@ static BOOL open_file(files_struct *fsp,connection_struct *conn, check_for_pipe(fname); return False; } else if(flags & O_CREAT) { - /* We don't want to write - but we must make sure that O_CREAT - doesn't create the file if we have write access into the - directory. + /* We don't want to write - but we must make sure that + O_CREAT doesn't create the file if we have write + access into the directory. */ flags &= ~O_CREAT; local_flags &= ~O_CREAT; @@ -221,12 +252,14 @@ static BOOL open_file(files_struct *fsp,connection_struct *conn, */ if ((accmode == O_RDONLY) && ((flags & O_TRUNC) == O_TRUNC)) { - DEBUG(10,("open_file: truncate requested on read-only open for file %s\n",fname )); + DEBUG(10,("open_file: truncate requested on read-only open " + "for file %s\n",fname )); local_flags = (flags & ~O_ACCMODE)|O_RDWR; } - if ((desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) || - (local_flags & O_CREAT) || ((local_flags & O_TRUNC) == O_TRUNC) ) { + if ((access_mask & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) || + (local_flags & O_CREAT) || + ((local_flags & O_TRUNC) == O_TRUNC) ) { /* * We can't actually truncate here as the file may be locked. @@ -242,42 +275,50 @@ static BOOL open_file(files_struct *fsp,connection_struct *conn, * open flags. JRA. */ - if (VALID_STAT(*psbuf) && S_ISFIFO(psbuf->st_mode)) + if (file_existed && S_ISFIFO(psbuf->st_mode)) { local_flags |= O_NONBLOCK; + } #endif /* Don't create files with Microsoft wildcard characters. */ - if ((local_flags & O_CREAT) && !VALID_STAT(*psbuf) && ms_has_wild(fname)) { - set_saved_error_triple(ERRDOS, ERRinvalidname, NT_STATUS_OBJECT_NAME_INVALID); + if ((local_flags & O_CREAT) && !file_existed && + ms_has_wild(fname)) { + set_saved_error_triple(ERRDOS, ERRinvalidname, + NT_STATUS_OBJECT_NAME_INVALID); return False; } /* Actually do the open */ - fsp->fd = fd_open(conn, fname, local_flags, mode); - if (fsp->fd == -1) { - DEBUG(3,("Error opening file %s (%s) (local_flags=%d) (flags=%d)\n", + fsp->fh->fd = fd_open(conn, fname, local_flags, unx_mode); + if (fsp->fh->fd == -1) { + DEBUG(3,("Error opening file %s (%s) (local_flags=%d) " + "(flags=%d)\n", fname,strerror(errno),local_flags,flags)); check_for_pipe(fname); return False; } /* Inherit the ACL if the file was created. */ - if ((local_flags & O_CREAT) && !VALID_STAT(*psbuf)) - inherit_access_acl(conn, fname, mode); + if ((local_flags & O_CREAT) && !file_existed) { + inherit_access_acl(conn, fname, unx_mode); + } - } else - fsp->fd = -1; /* What we used to call a stat open. */ + } else { + fsp->fh->fd = -1; /* What we used to call a stat open. */ + } - if (!VALID_STAT(*psbuf)) { + if (!file_existed) { int ret; - if (fsp->fd == -1) + if (fsp->fh->fd == -1) { ret = SMB_VFS_STAT(conn, fname, psbuf); - else { - ret = SMB_VFS_FSTAT(fsp,fsp->fd,psbuf); + } else { + ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,psbuf); /* If we have an fd, this stat should succeed. */ - if (ret == -1) - DEBUG(0,("Error doing fstat on open file %s (%s)\n", fname,strerror(errno) )); + if (ret == -1) { + DEBUG(0,("Error doing fstat on open file %s " + "(%s)\n", fname,strerror(errno) )); + } } /* For a non-io open, this stat failing means file not found. JRA */ @@ -305,18 +346,20 @@ static BOOL open_file(files_struct *fsp,connection_struct *conn, fsp->vuid = current_user.vuid; fsp->file_pid = global_smbpid; fsp->can_lock = True; - fsp->can_read = ((flags & O_WRONLY)==0); - fsp->can_write = ((flags & (O_WRONLY|O_RDWR))!=0); - fsp->share_mode = 0; - fsp->desired_access = desired_access; + fsp->can_read = (access_mask & (FILE_READ_DATA)) ? True : False; + if (!CAN_WRITE(conn)) { + fsp->can_write = False; + } else { + fsp->can_write = (access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) ? True : False; + } fsp->print_file = False; fsp->modified = False; fsp->oplock_type = NO_OPLOCK; fsp->sent_oplock_break = NO_BREAK_SENT; fsp->is_directory = False; fsp->is_stat = False; - fsp->directory_delete_on_close = False; - if (conn->aio_write_behind_list && is_in_path(fname, conn->aio_write_behind_list, conn->case_sensitive)) { + if (conn->aio_write_behind_list && + is_in_path(fname, conn->aio_write_behind_list, conn->case_sensitive)) { fsp->aio_write_behind = True; } @@ -349,293 +392,119 @@ static BOOL is_executable(const char *fname) return False; } -enum {AFAIL,AREAD,AWRITE,AALL}; - -/******************************************************************* - Reproduce the share mode access table. - This is horrendoously complex, and really can't be justified on any - rational grounds except that this is _exactly_ what NT does. See - the DENY1 and DENY2 tests in smbtorture for a comprehensive set of - test routines. -********************************************************************/ - -static int access_table(int new_deny,int old_deny,int old_mode, - BOOL same_pid, BOOL isexe) -{ - if (new_deny == DENY_ALL || old_deny == DENY_ALL) return(AFAIL); - - if (same_pid) { - if (isexe && old_mode == DOS_OPEN_RDONLY && - old_deny == DENY_DOS && new_deny == DENY_READ) { - return AFAIL; - } - if (!isexe && old_mode == DOS_OPEN_RDONLY && - old_deny == DENY_DOS && new_deny == DENY_DOS) { - return AREAD; - } - if (new_deny == DENY_FCB && old_deny == DENY_DOS) { - if (isexe) return AFAIL; - if (old_mode == DOS_OPEN_RDONLY) return AFAIL; - return AALL; - } - if (old_mode == DOS_OPEN_RDONLY && old_deny == DENY_DOS) { - if (new_deny == DENY_FCB || new_deny == DENY_READ) { - if (isexe) return AREAD; - return AFAIL; - } - } - if (old_deny == DENY_FCB) { - if (new_deny == DENY_DOS || new_deny == DENY_FCB) return AALL; - return AFAIL; - } - } - - if (old_deny == DENY_DOS || new_deny == DENY_DOS || - old_deny == DENY_FCB || new_deny == DENY_FCB) { - if (isexe) { - if (old_deny == DENY_FCB || new_deny == DENY_FCB) { - return AFAIL; - } - if (old_deny == DENY_DOS) { - if (new_deny == DENY_READ && - (old_mode == DOS_OPEN_RDONLY || - old_mode == DOS_OPEN_RDWR)) { - return AFAIL; - } - if (new_deny == DENY_WRITE && - (old_mode == DOS_OPEN_WRONLY || - old_mode == DOS_OPEN_RDWR)) { - return AFAIL; - } - return AALL; - } - if (old_deny == DENY_NONE) return AALL; - if (old_deny == DENY_READ) return AWRITE; - if (old_deny == DENY_WRITE) return AREAD; - } - /* it isn't a exe, dll, sym or com file */ - if (old_deny == new_deny && same_pid) - return(AALL); - - if (old_deny == DENY_READ || new_deny == DENY_READ) return AFAIL; - if (old_mode == DOS_OPEN_RDONLY) return(AREAD); - - return(AFAIL); - } - - switch (new_deny) - { - case DENY_WRITE: - if (old_deny==DENY_WRITE && old_mode==DOS_OPEN_RDONLY) return(AREAD); - if (old_deny==DENY_READ && old_mode==DOS_OPEN_RDONLY) return(AWRITE); - if (old_deny==DENY_NONE && old_mode==DOS_OPEN_RDONLY) return(AALL); - return(AFAIL); - case DENY_READ: - if (old_deny==DENY_WRITE && old_mode==DOS_OPEN_WRONLY) return(AREAD); - if (old_deny==DENY_READ && old_mode==DOS_OPEN_WRONLY) return(AWRITE); - if (old_deny==DENY_NONE && old_mode==DOS_OPEN_WRONLY) return(AALL); - return(AFAIL); - case DENY_NONE: - if (old_deny==DENY_WRITE) return(AREAD); - if (old_deny==DENY_READ) return(AWRITE); - if (old_deny==DENY_NONE) return(AALL); - return(AFAIL); - } - return(AFAIL); -} - /**************************************************************************** Check if we can open a file with a share mode. + Returns True if conflict, False if not. ****************************************************************************/ -static BOOL check_share_mode(connection_struct *conn, share_mode_entry *share, int share_mode, uint32 desired_access, - const char *fname, BOOL fcbopen, int *flags) +static BOOL share_conflict(share_mode_entry *entry, + uint32 access_mask, + uint32 share_access) { - int deny_mode = GET_DENY_MODE(share_mode); - int old_open_mode = GET_OPEN_MODE(share->share_mode); - int old_deny_mode = GET_DENY_MODE(share->share_mode); - BOOL non_io_open_request; - BOOL non_io_open_existing; - - /* - * share modes = false means don't bother to check for - * DENY mode conflict. This is a *really* bad idea :-). JRA. - */ - - if(!lp_share_modes(SNUM(conn))) - return True; - - if (desired_access & ~(SYNCHRONIZE_ACCESS|READ_CONTROL_ACCESS|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES)) { - non_io_open_request = False; - } else { - non_io_open_request = True; - } - - if (share->desired_access & ~(SYNCHRONIZE_ACCESS|READ_CONTROL_ACCESS|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES)) { - non_io_open_existing = False; - } else { - non_io_open_existing = True; - } - - /* - * Don't allow any opens once the delete on close flag has been - * set. - */ - - if (GET_DELETE_ON_CLOSE_FLAG(share->share_mode)) { - DEBUG(5,("check_share_mode: Failing open on file %s as delete on close flag is set.\n", - fname )); - /* Use errno to map to correct error. */ - set_saved_error_triple(SMB_SUCCESS, 0, NT_STATUS_OK); + DEBUG(10,("share_conflict: entry->access_mask = 0x%x, " + "entry->share_access = 0x%x, " + "entry->private_options = 0x%x\n", + (unsigned int)entry->access_mask, + (unsigned int)entry->share_access, + (unsigned int)entry->private_options)); + + DEBUG(10,("share_conflict: access_mask = 0x%x, share_access = 0x%x\n", + (unsigned int)access_mask, (unsigned int)share_access)); + + if ((entry->access_mask & (FILE_WRITE_DATA| + FILE_APPEND_DATA| + FILE_READ_DATA| + FILE_EXECUTE| + DELETE_ACCESS)) == 0) { + DEBUG(10,("share_conflict: No conflict due to " + "entry->access_mask = 0x%x\n", + (unsigned int)entry->access_mask )); return False; } - /* this is a nasty hack, but necessary until we rewrite our open - handling to use a NTCreateX call as the basic call. - NT may open a file with neither read nor write access, and in - this case it expects the open not to conflict with any - existing deny modes. This happens (for example) during a - "xcopy /o" where the second file descriptor is used for - ACL sets - (tridge) - */ - - /* - * This is a bit wierd - the test for desired access not having the - * critical bits seems seems odd. Firstly, if both opens have no - * critical bits then always ignore. Then check the "allow delete" - * then check for either. This probably isn't quite right yet but - * gets us much closer. JRA. - */ - - /* - * If desired_access doesn't contain READ_DATA,WRITE_DATA,APPEND_DATA or EXECUTE - * and the existing desired_acces then share modes don't conflict. - */ - - if (non_io_open_request && non_io_open_existing) { - - /* - * Wrinkle discovered by smbtorture.... - * If both are non-io open and requester is asking for delete and current open has delete access - * but neither open has allowed file share delete then deny.... this is very strange and - * seems to be the only case in which non-io opens conflict. JRA. - */ - - if ((desired_access & DELETE_ACCESS) && (share->desired_access & DELETE_ACCESS) && - (!GET_ALLOW_SHARE_DELETE(share->share_mode) || !GET_ALLOW_SHARE_DELETE(share_mode))) { - DEBUG(5,("check_share_mode: Failing open on file %s as delete access requests conflict.\n", - fname )); - set_saved_error_triple(ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION); - return False; - } - - DEBUG(5,("check_share_mode: Allowing open on file %s as both desired access (0x%x) \ -and existing desired access (0x%x) are non-data opens\n", - fname, (unsigned int)desired_access, (unsigned int)share->desired_access )); - return True; - } else if (non_io_open_request || non_io_open_existing) { - /* - * If either are non-io opens then share modes don't conflict. - */ - DEBUG(5,("check_share_mode: One non-io open. Allowing open on file %s as desired access (0x%x) doesn't conflict with\ -existing desired access (0x%x).\n", fname, (unsigned int)desired_access, (unsigned int)share->desired_access )); - return True; - } - - /* - * If delete access was requested and the existing share mode doesn't have - * ALLOW_SHARE_DELETE then deny. - */ - - if ((desired_access & DELETE_ACCESS) && !GET_ALLOW_SHARE_DELETE(share->share_mode)) { - DEBUG(5,("check_share_mode: Failing open on file %s as delete access requested and allow share delete not set.\n", - fname )); - set_saved_error_triple(ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION); + if ((access_mask & (FILE_WRITE_DATA| + FILE_APPEND_DATA| + FILE_READ_DATA| + FILE_EXECUTE| + DELETE_ACCESS)) == 0) { + DEBUG(10,("share_conflict: No conflict due to " + "access_mask = 0x%x\n", + (unsigned int)access_mask )); return False; } - /* - * The inverse of the above. - * If delete access was granted and the new share mode doesn't have - * ALLOW_SHARE_DELETE then deny. - */ - - if ((share->desired_access & DELETE_ACCESS) && !GET_ALLOW_SHARE_DELETE(share_mode)) { - DEBUG(5,("check_share_mode: Failing open on file %s as delete access granted and allow share delete not requested.\n", - fname )); - set_saved_error_triple(ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION); - return False; - } - -#if 0 - /* Bluarc test may need this ... needs further investigation. */ - if (deny_mode == DENY_ALL || old_deny_mode == DENY_ALL) { - set_saved_error_triple(ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION); - return False; +#if 1 /* JRA TEST - Superdebug. */ +#define CHECK_MASK(num, am, right, sa, share) \ + DEBUG(10,("share_conflict: [%d] am (0x%x) & right (0x%x) = 0x%x\n", \ + (unsigned int)(num), (unsigned int)(am), \ + (unsigned int)(right), (unsigned int)(am)&(right) )); \ + DEBUG(10,("share_conflict: [%d] sa (0x%x) & share (0x%x) = 0x%x\n", \ + (unsigned int)(num), (unsigned int)(sa), \ + (unsigned int)(share), (unsigned int)(sa)&(share) )); \ + if (((am) & (right)) && !((sa) & (share))) { \ + DEBUG(10,("share_conflict: check %d conflict am = 0x%x, right = 0x%x, \ +sa = 0x%x, share = 0x%x\n", (num), (unsigned int)(am), (unsigned int)(right), (unsigned int)(sa), \ + (unsigned int)(share) )); \ + set_saved_error_triple(ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION); \ + return True; \ + } +#else +#define CHECK_MASK(num, am, right, sa, share) \ + if (((am) & (right)) && !((sa) & (share))) { \ + DEBUG(10,("share_conflict: check %d conflict am = 0x%x, right = 0x%x, \ +sa = 0x%x, share = 0x%x\n", (num), (unsigned int)(am), (unsigned int)(right), (unsigned int)(sa), \ + (unsigned int)(share) )); \ + set_saved_error_triple(ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION); \ + return True; \ } #endif - /* - * If desired_access doesn't contain READ_DATA,WRITE_DATA,APPEND_DATA or EXECUTE - * then share modes don't conflict. Likewise with existing desired access. - */ - - if ( !(desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) || - !(share->desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) ) { - DEBUG(5,("check_share_mode: Allowing open on file %s as desired access (0x%x) doesn't conflict with \ -existing desired access (0x%x).\n", fname, (unsigned int)desired_access, (unsigned int)share->desired_access )); - return True; - } - - { - int access_allowed = access_table(deny_mode,old_deny_mode,old_open_mode, - (share->pid == sys_getpid()),is_executable(fname)); - - if ((access_allowed == AFAIL) || - (!fcbopen && (access_allowed == AREAD && *flags == O_RDWR)) || - (access_allowed == AREAD && *flags != O_RDONLY) || - (access_allowed == AWRITE && *flags != O_WRONLY)) { - - DEBUG(2,("Share violation on file (%d,%d,%d,%d,%s,fcbopen = %d, flags = %d) = %d\n", - deny_mode,old_deny_mode,old_open_mode, - (int)share->pid,fname, fcbopen, *flags, access_allowed)); - - set_saved_error_triple(ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION); - return False; - } - - if (access_allowed == AREAD) - *flags = O_RDONLY; - - if (access_allowed == AWRITE) - *flags = O_WRONLY; + CHECK_MASK(1, entry->access_mask, FILE_WRITE_DATA | FILE_APPEND_DATA, + share_access, FILE_SHARE_WRITE); + CHECK_MASK(2, access_mask, FILE_WRITE_DATA | FILE_APPEND_DATA, + entry->share_access, FILE_SHARE_WRITE); + + CHECK_MASK(3, entry->access_mask, FILE_READ_DATA | FILE_EXECUTE, + share_access, FILE_SHARE_READ); + CHECK_MASK(4, access_mask, FILE_READ_DATA | FILE_EXECUTE, + entry->share_access, FILE_SHARE_READ); - } + CHECK_MASK(5, entry->access_mask, DELETE_ACCESS, + share_access, FILE_SHARE_DELETE); + CHECK_MASK(6, access_mask, DELETE_ACCESS, + entry->share_access, FILE_SHARE_DELETE); - return True; + DEBUG(10,("share_conflict: No conflict.\n")); + return False; } - #if defined(DEVELOPER) -static void validate_my_share_entries(int num, share_mode_entry *share_entry) +static void validate_my_share_entries(int num, + share_mode_entry *share_entry) { files_struct *fsp; - if (share_entry->pid != sys_getpid()) + if (share_entry->pid != sys_getpid()) { return; + } - fsp = file_find_dif(share_entry->dev, share_entry->inode, share_entry->share_file_id); + fsp = file_find_dif(share_entry->dev, share_entry->inode, + share_entry->share_file_id); if (!fsp) { - DEBUG(0,("validate_my_share_entries: PANIC : %s\n", share_mode_str(num, share_entry) )); - smb_panic("validate_my_share_entries: Cannot match a share entry with an open file\n"); + DEBUG(0,("validate_my_share_entries: PANIC : %s\n", + share_mode_str(num, share_entry) )); + smb_panic("validate_my_share_entries: Cannot match a " + "share entry with an open file\n"); } if (((uint16)fsp->oplock_type) != share_entry->op_type) { pstring str; - DEBUG(0,("validate_my_share_entries: PANIC : %s\n", share_mode_str(num, share_entry) )); - slprintf(str, sizeof(str)-1, "validate_my_share_entries: file %s, oplock_type = 0x%x, op_type = 0x%x\n", - fsp->fsp_name, (unsigned int)fsp->oplock_type, (unsigned int)share_entry->op_type ); + DEBUG(0,("validate_my_share_entries: PANIC : %s\n", + share_mode_str(num, share_entry) )); + slprintf(str, sizeof(str)-1, "validate_my_share_entries: " + "file %s, oplock_type = 0x%x, op_type = 0x%x\n", + fsp->fsp_name, (unsigned int)fsp->oplock_type, + (unsigned int)share_entry->op_type ); smb_panic(str); } } @@ -655,42 +524,75 @@ static void free_broken_entry_list(struct share_mode_entry_list *broken_entry_li } } +static BOOL cause_oplock_break(int request, int existing, uint32 access_mask) +{ + if ((access_mask == DELETE_ACCESS) && + (request == NO_OPLOCK)) { + /* This is a delete request */ + return (BATCH_OPLOCK_TYPE(existing) != 0); + } + + if (EXCLUSIVE_OPLOCK_TYPE(existing) && (request != NO_OPLOCK)) { + return True; + } + + if ((existing != NO_OPLOCK) && (request == NO_OPLOCK)) { + return True; + } + + return False; +} + /**************************************************************************** Deal with open deny mode and oplock break processing. Invarient: Share mode must be locked on entry and exit. Returns -1 on error, or number of share modes on success (may be zero). ****************************************************************************/ -static int open_mode_check(connection_struct *conn, const char *fname, SMB_DEV_T dev, +static int open_mode_check(connection_struct *conn, + const char *fname, + SMB_DEV_T dev, SMB_INO_T inode, - uint32 desired_access, - int share_mode, int *p_flags, int *p_oplock_request, + uint32 access_mask, + uint32 share_access, + uint32 create_options, + int *p_flags, + int *p_oplock_request, BOOL *p_all_current_opens_are_level_II) { int i; int num_share_modes; int oplock_contention_count = 0; share_mode_entry *old_shares = NULL; - BOOL fcbopen = False; BOOL broke_oplock; + BOOL delete_on_close; - if(GET_OPEN_MODE(share_mode) == DOS_OPEN_FCB) - fcbopen = True; - - num_share_modes = get_share_modes(conn, dev, inode, &old_shares); + num_share_modes = get_share_modes(dev, inode, &old_shares, &delete_on_close); if(num_share_modes == 0) { SAFE_FREE(old_shares); return 0; } - if (desired_access && ((desired_access & ~(SYNCHRONIZE_ACCESS|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES))==0) && - ((desired_access & (SYNCHRONIZE_ACCESS|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES)) != 0)) { - /* Stat open that doesn't trigger oplock breaks or share mode checks... ! JRA. */ + if (access_mask && + ((access_mask & ~(SYNCHRONIZE_ACCESS| FILE_READ_ATTRIBUTES| + FILE_WRITE_ATTRIBUTES))==0) && + ((access_mask & (SYNCHRONIZE_ACCESS|FILE_READ_ATTRIBUTES| + FILE_WRITE_ATTRIBUTES)) != 0)) { + /* Stat open that doesn't trigger oplock breaks or share mode + * checks... ! JRA. */ SAFE_FREE(old_shares); return num_share_modes; } + /* A delete on close prohibits everything */ + + if (delete_on_close) { + SAFE_FREE(old_shares); + errno = EACCES; + return -1; + } + /* * Check if the share modes will give us access. */ @@ -703,132 +605,152 @@ static int open_mode_check(connection_struct *conn, const char *fname, SMB_DEV_T *p_all_current_opens_are_level_II = True; for(i = 0; i < num_share_modes; i++) { - BOOL cause_oplock_break = False; share_mode_entry *share_entry = &old_shares[i]; + BOOL opb_ret; #if defined(DEVELOPER) validate_my_share_entries(i, share_entry); #endif /* - * By observation of NetBench, oplocks are broken *before* share - * modes are checked. This allows a file to be closed by the client - * if the share mode would deny access and the client has an oplock. - * Check if someone has an oplock on this file. If so we must break - * it before continuing. + * By observation of NetBench, oplocks are broken + * *before* share modes are checked. This allows a + * file to be closed by the client if the share mode + * would deny access and the client has an oplock. + * Check if someone has an oplock on this file. If so + * we must break it before continuing. */ - - /* Was this a delete this file request ? */ - if (!*p_oplock_request && desired_access == DELETE_ACCESS && - !BATCH_OPLOCK_TYPE(share_entry->op_type)) { - /* Don't break the oplock in this case. */ - cause_oplock_break = False; - } else if((*p_oplock_request && EXCLUSIVE_OPLOCK_TYPE(share_entry->op_type)) || - (!*p_oplock_request && (share_entry->op_type != NO_OPLOCK))) { - cause_oplock_break = True; + + if (!cause_oplock_break(*p_oplock_request, + share_entry->op_type, + access_mask)) { + if (!LEVEL_II_OPLOCK_TYPE(share_entry->op_type)) { + *p_all_current_opens_are_level_II = False; + } + continue; } - if(cause_oplock_break) { - BOOL opb_ret; + /* This is an oplock break */ - DEBUG(5,("open_mode_check: oplock_request = %d, breaking oplock (%x) on file %s, \ -dev = %x, inode = %.0f\n", *p_oplock_request, share_entry->op_type, fname, (unsigned int)dev, (double)inode)); + DEBUG(5,("open_mode_check: oplock_request = %d, " + "breaking oplock (%x) on file %s, " + "dev = %x, inode = %.0f\n", + *p_oplock_request, share_entry->op_type, + fname, (unsigned int)dev, (double)inode)); - /* Ensure the reply for the open uses the correct sequence number. */ - /* This isn't a real deferred packet as it's response will also increment - * the sequence. - */ - srv_defer_sign_response(get_current_mid()); + /* Ensure the reply for the open uses the correct + * sequence number. */ + /* This isn't a real deferred packet as it's response + * will also increment the sequence. + */ + srv_defer_sign_response(get_current_mid()); - /* Oplock break - unlock to request it. */ - unlock_share_entry(conn, dev, inode); - - opb_ret = request_oplock_break(share_entry); + /* Oplock break - unlock to request it. */ + unlock_share_entry(conn, dev, inode); - /* Now relock. */ - lock_share_entry(conn, dev, inode); + opb_ret = request_oplock_break(share_entry); - if(opb_ret == False) { - DEBUG(0,("open_mode_check: FAILED when breaking oplock (%x) on file %s, \ -dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (double)inode)); - SAFE_FREE(old_shares); - set_saved_error_triple(ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION); - return -1; - } + /* Now relock. */ + lock_share_entry(conn, dev, inode); - broken_entry = SMB_MALLOC_P(struct share_mode_entry_list); - if (!broken_entry) { - smb_panic("open_mode_check: malloc fail.\n"); - } - broken_entry->entry = *share_entry; - DLIST_ADD(broken_entry_list, broken_entry); - broke_oplock = True; + if (!opb_ret) { + DEBUG(0,("open_mode_check: FAILED when breaking " + "oplock (%x) on file %s, dev = %x, " + "inode = %.0f\n", + old_shares[i].op_type, fname, + (unsigned int)dev, (double)inode)); + SAFE_FREE(old_shares); + set_saved_error_triple(ERRDOS, ERRbadshare, + NT_STATUS_SHARING_VIOLATION); + return -1; + } - } else if (!LEVEL_II_OPLOCK_TYPE(share_entry->op_type)) { - *p_all_current_opens_are_level_II = False; + broken_entry = SMB_MALLOC_P(struct share_mode_entry_list); + if (!broken_entry) { + smb_panic("open_mode_check: malloc fail.\n"); } + broken_entry->entry = *share_entry; + DLIST_ADD(broken_entry_list, broken_entry); + broke_oplock = True; + } /* end for */ if (broke_oplock) { /* Update the current open table. */ SAFE_FREE(old_shares); - num_share_modes = get_share_modes(conn, dev, inode, &old_shares); + num_share_modes = get_share_modes(dev, inode, + &old_shares, + &delete_on_close); } - /* Now we check the share modes, after any oplock breaks. */ - for(i = 0; i < num_share_modes; i++) { - share_mode_entry *share_entry = &old_shares[i]; + if (lp_share_modes(SNUM(conn))) { + /* Now we check the share modes, after any oplock breaks. */ + for(i = 0; i < num_share_modes; i++) { + share_mode_entry *share_entry = &old_shares[i]; - /* someone else has a share lock on it, check to see if we can too */ - if (!check_share_mode(conn, share_entry, share_mode, desired_access, - fname, fcbopen, p_flags)) { - SAFE_FREE(old_shares); - free_broken_entry_list(broken_entry_list); - errno = EACCES; - return -1; - } + /* someone else has a share lock on it, check to see + * if we can too */ + if (share_conflict(share_entry, access_mask, + share_access)) { + SAFE_FREE(old_shares); + free_broken_entry_list(broken_entry_list); + errno = EACCES; + return -1; + } + } } - for(broken_entry = broken_entry_list; broken_entry; broken_entry = broken_entry->next) { + for(broken_entry = broken_entry_list; broken_entry; + broken_entry = broken_entry->next) { oplock_contention_count++; /* Paranoia check that this is no longer an exlusive entry. */ for(i = 0; i < num_share_modes; i++) { share_mode_entry *share_entry = &old_shares[i]; - if (share_modes_identical(&broken_entry->entry, share_entry) && - EXCLUSIVE_OPLOCK_TYPE(share_entry->op_type) ) { + if (!(share_modes_identical(&broken_entry->entry, + share_entry) && + EXCLUSIVE_OPLOCK_TYPE(share_entry->op_type))) { + continue; + } - /* - * This should not happen. The target left this oplock - * as exlusive.... The process *must* be dead.... - */ + /* + * This should not happen. The target left this oplock + * as exlusive.... The process *must* be dead.... + */ - DEBUG(0,("open_mode_check: exlusive oplock left by process %d \ -after break ! For file %s, dev = %x, inode = %.0f. Deleting it to continue...\n", - (int)broken_entry->entry.pid, fname, (unsigned int)dev, (double)inode)); + DEBUG(0,("open_mode_check: exlusive oplock left by " + "process %d after break ! For file %s, " + "dev = %x, inode = %.0f. Deleting it to " + "continue...\n", + (int)broken_entry->entry.pid, fname, + (unsigned int)dev, (double)inode)); - if (process_exists(broken_entry->entry.pid)) { - DEBUG(0,("open_mode_check: Existent process %lu left active oplock.\n", - (unsigned long)broken_entry->entry.pid )); - } + if (process_exists(broken_entry->entry.pid)) { + DEBUG(0,("open_mode_check: Existent process " + "%lu left active oplock.\n", + (unsigned long)broken_entry->entry.pid )); + } - if (del_share_entry(dev, inode, &broken_entry->entry, NULL) == -1) { - free_broken_entry_list(broken_entry_list); - errno = EACCES; - set_saved_error_triple(ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION); - return -1; - } + if (del_share_entry(dev, inode, &broken_entry->entry, + NULL, &delete_on_close) == -1) { + free_broken_entry_list(broken_entry_list); + errno = EACCES; + set_saved_error_triple(ERRDOS, ERRbadshare, + NT_STATUS_SHARING_VIOLATION); + return -1; + } - /* - * We must reload the share modes after deleting the - * other process's entry. - */ + /* + * We must reload the share modes after deleting the + * other process's entry. + */ - SAFE_FREE(old_shares); - num_share_modes = get_share_modes(conn, dev, inode, &old_shares); - break; - } + SAFE_FREE(old_shares); + num_share_modes = get_share_modes(dev, inode, + &old_shares, + &delete_on_close); + break; } /* end for paranoia... */ } /* end for broken_entry */ free_broken_entry_list(broken_entry_list); @@ -853,7 +775,9 @@ after break ! For file %s, dev = %x, inode = %.0f. Deleting it to continue...\n" Delete the record for a handled deferred open entry. ****************************************************************************/ -static void delete_defered_open_entry_record(connection_struct *conn, SMB_DEV_T dev, SMB_INO_T inode) +static void delete_defered_open_entry_record(connection_struct *conn, + SMB_DEV_T dev, + SMB_INO_T inode) { uint16 mid = get_current_mid(); pid_t mypid = sys_getpid(); @@ -868,7 +792,7 @@ static void delete_defered_open_entry_record(connection_struct *conn, SMB_DEV_T for (i = 0; i < num_de_entries; i++) { deferred_open_entry *entry = &de_array[i]; if (entry->pid == mypid && entry->mid == mid && entry->dev == dev && - entry->inode == inode) { + entry->inode == inode) { /* Remove the deferred open entry from the array. */ delete_deferred_open_entry(entry); @@ -883,8 +807,11 @@ static void delete_defered_open_entry_record(connection_struct *conn, SMB_DEV_T Handle the 1 second delay in returning a SHARING_VIOLATION error. ****************************************************************************/ -void defer_open_sharing_error(connection_struct *conn, struct timeval *ptv, - char *fname, SMB_DEV_T dev, SMB_INO_T inode) +static void defer_open_sharing_error(connection_struct *conn, + struct timeval *ptv, + const char *fname, + SMB_DEV_T dev, + SMB_INO_T inode) { uint16 mid = get_current_mid(); pid_t mypid = sys_getpid(); @@ -906,10 +833,12 @@ void defer_open_sharing_error(connection_struct *conn, struct timeval *ptv, /* * Check if a 1 second timeout has expired. */ - if (usec_time_diff(ptv, &entry->time) > SHARING_VIOLATION_USEC_WAIT) { - DEBUG(10,("defer_open_sharing_error: Deleting deferred open entry for mid %u, \ -file %s\n", - (unsigned int)mid, fname )); + if (usec_time_diff(ptv, &entry->time) > + SHARING_VIOLATION_USEC_WAIT) { + DEBUG(10,("defer_open_sharing_error: Deleting " + "deferred open entry for mid %u, " + "file %s\n", + (unsigned int)mid, fname )); /* Expired, return a real error. */ /* Remove the deferred open entry from the array. */ @@ -919,24 +848,30 @@ file %s\n", return; } /* - * If the timeout hasn't expired yet and we still have a sharing violation, - * just leave the entry in the deferred open array alone. We do need to - * reschedule this open call though (with the original created time). + * If the timeout hasn't expired yet and we still have + * a sharing violation, just leave the entry in the + * deferred open array alone. We do need to reschedule + * this open call though (with the original created + * time). */ - DEBUG(10,("defer_open_sharing_error: time [%u.%06u] updating \ -deferred open entry for mid %u, file %s\n", - (unsigned int)entry->time.tv_sec, - (unsigned int)entry->time.tv_usec, - (unsigned int)mid, fname )); - - push_sharing_violation_open_smb_message(&entry->time, (char *)&dib, sizeof(dib)); + DEBUG(10,("defer_open_sharing_error: time [%u.%06u] " + "updating deferred open entry for mid %u, file %s\n", + (unsigned int)entry->time.tv_sec, + (unsigned int)entry->time.tv_usec, + (unsigned int)mid, fname )); + + push_sharing_violation_open_smb_message(&entry->time, + (char *)&dib, + sizeof(dib)); SAFE_FREE(de_array); return; } } - DEBUG(10,("defer_open_sharing_error: time [%u.%06u] adding deferred open entry for mid %u, file %s\n", - (unsigned int)ptv->tv_sec, (unsigned int)ptv->tv_usec, (unsigned int)mid, fname )); + DEBUG(10,("defer_open_sharing_error: time [%u.%06u] adding deferred " + "open entry for mid %u, file %s\n", + (unsigned int)ptv->tv_sec, (unsigned int)ptv->tv_usec, + (unsigned int)mid, fname )); if (!push_sharing_violation_open_smb_message(ptv, (char *)&dib, sizeof(dib))) { SAFE_FREE(de_array); @@ -963,80 +898,302 @@ deferred open entry for mid %u, file %s\n", This requires a patch to Linux. ****************************************************************************/ -static void kernel_flock(files_struct *fsp, int deny_mode) +static void kernel_flock(files_struct *fsp, uint32 share_mode) { #if HAVE_KERNEL_SHARE_MODES int kernel_mode = 0; - if (deny_mode == DENY_READ) kernel_mode = LOCK_MAND|LOCK_WRITE; - else if (deny_mode == DENY_WRITE) kernel_mode = LOCK_MAND|LOCK_READ; - else if (deny_mode == DENY_ALL) kernel_mode = LOCK_MAND; - if (kernel_mode) flock(fsp->fd, kernel_mode); + if (share_mode == FILE_SHARE_WRITE) { + kernel_mode = LOCK_MAND|LOCK_WRITE; + } else if (share_mode == FILE_SHARE_READ) { + kernel_mode = LOCK_MAND|LOCK_READ; + } else if (share_mode == FILE_SHARE_NONE) { + kernel_mode = LOCK_MAND; + } + if (kernel_mode) { + flock(fsp->fh->fd, kernel_mode); + } #endif - ;; + ; } +/**************************************************************************** + On overwrite open ensure that the attributes match. +****************************************************************************/ -static BOOL open_match_attributes(connection_struct *conn, const char *path, uint32 old_dos_mode, uint32 new_dos_mode, - mode_t existing_mode, mode_t new_mode, mode_t *returned_mode) +static BOOL open_match_attributes(connection_struct *conn, + const char *path, + uint32 old_dos_attr, + uint32 new_dos_attr, + mode_t existing_unx_mode, + mode_t new_unx_mode, + mode_t *returned_unx_mode) { - uint32 noarch_old_dos_mode, noarch_new_dos_mode; + uint32 noarch_old_dos_attr, noarch_new_dos_attr; - noarch_old_dos_mode = (old_dos_mode & ~FILE_ATTRIBUTE_ARCHIVE); - noarch_new_dos_mode = (new_dos_mode & ~FILE_ATTRIBUTE_ARCHIVE); + noarch_old_dos_attr = (old_dos_attr & ~FILE_ATTRIBUTE_ARCHIVE); + noarch_new_dos_attr = (new_dos_attr & ~FILE_ATTRIBUTE_ARCHIVE); - if((noarch_old_dos_mode == 0 && noarch_new_dos_mode != 0) || - (noarch_old_dos_mode != 0 && ((noarch_old_dos_mode & noarch_new_dos_mode) == noarch_old_dos_mode))) - *returned_mode = new_mode; - else - *returned_mode = (mode_t)0; + if((noarch_old_dos_attr == 0 && noarch_new_dos_attr != 0) || + (noarch_old_dos_attr != 0 && ((noarch_old_dos_attr & noarch_new_dos_attr) == noarch_old_dos_attr))) { + *returned_unx_mode = new_unx_mode; + } else { + *returned_unx_mode = (mode_t)0; + } - DEBUG(10,("open_match_attributes: file %s old_dos_mode = 0x%x, existing_mode = 0%o, new_dos_mode = 0x%x returned_mode = 0%o\n", - path, - old_dos_mode, (unsigned int)existing_mode, new_dos_mode, (unsigned int)*returned_mode )); + DEBUG(10,("open_match_attributes: file %s old_dos_attr = 0x%x, " + "existing_unx_mode = 0%o, new_dos_attr = 0x%x " + "returned_unx_mode = 0%o\n", + path, + (unsigned int)old_dos_attr, + (unsigned int)existing_unx_mode, + (unsigned int)new_dos_attr, + (unsigned int)*returned_unx_mode )); /* If we're mapping SYSTEM and HIDDEN ensure they match. */ if (lp_map_system(SNUM(conn)) || lp_store_dos_attributes(SNUM(conn))) { - if ((old_dos_mode & FILE_ATTRIBUTE_SYSTEM) && !(new_dos_mode & FILE_ATTRIBUTE_SYSTEM)) + if ((old_dos_attr & FILE_ATTRIBUTE_SYSTEM) && + !(new_dos_attr & FILE_ATTRIBUTE_SYSTEM)) { return False; + } } if (lp_map_hidden(SNUM(conn)) || lp_store_dos_attributes(SNUM(conn))) { - if ((old_dos_mode & FILE_ATTRIBUTE_HIDDEN) && !(new_dos_mode & FILE_ATTRIBUTE_HIDDEN)) + if ((old_dos_attr & FILE_ATTRIBUTE_HIDDEN) && + !(new_dos_attr & FILE_ATTRIBUTE_HIDDEN)) { return False; + } } return True; } /**************************************************************************** - Open a file with a share mode. + Special FCB or DOS processing in the case of a sharing violation. + Try and find a duplicated file handle. ****************************************************************************/ -files_struct *open_file_shared(connection_struct *conn,char *fname, SMB_STRUCT_STAT *psbuf, - int share_mode,int ofun, uint32 new_dos_mode, int oplock_request, - int *Access,int *action) +static files_struct *fcb_or_dos_open(connection_struct *conn, + const char *fname, SMB_DEV_T dev, + SMB_INO_T inode, + uint32 access_mask, + uint32 share_access, + uint32 create_options) { - return open_file_shared1(conn, fname, psbuf, 0, share_mode, ofun, new_dos_mode, - oplock_request, Access, action); + files_struct *fsp; + files_struct *dup_fsp; + + DEBUG(5,("fcb_or_dos_open: attempting old open semantics for " + "file %s.\n", fname )); + + for(fsp = file_find_di_first(dev, inode); fsp; + fsp = file_find_di_next(fsp)) { + + DEBUG(10,("fcb_or_dos_open: checking file %s, fd = %d, " + "vuid = %u, file_pid = %u, private_options = 0x%x " + "access_mask = 0x%x\n", fsp->fsp_name, + fsp->fh->fd, (unsigned int)fsp->vuid, + (unsigned int)fsp->file_pid, + (unsigned int)fsp->fh->private_options, + (unsigned int)fsp->access_mask )); + + if (fsp->fh->fd != -1 && + fsp->vuid == current_user.vuid && + fsp->file_pid == global_smbpid && + (fsp->fh->private_options & (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | + NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) && + (fsp->access_mask & FILE_WRITE_DATA) && + strequal(fsp->fsp_name, fname)) { + DEBUG(10,("fcb_or_dos_open: file match\n")); + break; + } + } + + if (!fsp) { + return NULL; + } + + /* quite an insane set of semantics ... */ + if (is_executable(fname) && + (fsp->fh->private_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) { + DEBUG(10,("fcb_or_dos_open: file fail due to is_executable.\n")); + return NULL; + } + + /* We need to duplicate this fsp. */ + dup_fsp = dup_file_fsp(fsp, access_mask, share_access, create_options); + if (!dup_fsp) { + return NULL; + } + + return dup_fsp; +} + +/**************************************************************************** + Open a file with a share mode - old openX method - map into NTCreate. +****************************************************************************/ + +BOOL map_open_params_to_ntcreate(const char *fname, int deny_mode, int open_func, + uint32 *paccess_mask, + uint32 *pshare_mode, + uint32 *pcreate_disposition, + uint32 *pcreate_options) +{ + uint32 access_mask; + uint32 share_mode; + uint32 create_disposition; + uint32 create_options = 0; + + DEBUG(10,("map_open_params_to_ntcreate: fname = %s, deny_mode = 0x%x, " + "open_func = 0x%x\n", + fname, (unsigned int)deny_mode, (unsigned int)open_func )); + + /* Create the NT compatible access_mask. */ + switch (GET_OPENX_MODE(deny_mode)) { + case DOS_OPEN_RDONLY: + access_mask = FILE_GENERIC_READ; + break; + case DOS_OPEN_WRONLY: + access_mask = FILE_GENERIC_WRITE; + break; + case DOS_OPEN_EXEC: /* This used to be FILE_READ_DATA... */ + case DOS_OPEN_RDWR: + case DOS_OPEN_FCB: + access_mask = FILE_GENERIC_READ|FILE_GENERIC_WRITE; + break; + default: + DEBUG(10,("map_open_params_to_ntcreate: bad open mode = 0x%x\n", + (unsigned int)GET_OPENX_MODE(deny_mode))); + return False; + } + + /* Create the NT compatible create_disposition. */ + switch (open_func) { + case OPENX_FILE_EXISTS_FAIL|OPENX_FILE_CREATE_IF_NOT_EXIST: + create_disposition = FILE_CREATE; + break; + + case OPENX_FILE_EXISTS_OPEN: + create_disposition = FILE_OPEN; + break; + + case OPENX_FILE_EXISTS_OPEN|OPENX_FILE_CREATE_IF_NOT_EXIST: + create_disposition = FILE_OPEN_IF; + break; + + case OPENX_FILE_EXISTS_TRUNCATE: + create_disposition = FILE_OVERWRITE; + break; + + case OPENX_FILE_EXISTS_TRUNCATE|OPENX_FILE_CREATE_IF_NOT_EXIST: + create_disposition = FILE_OVERWRITE_IF; + break; + + default: + /* From samba4 - to be confirmed. */ + if (GET_OPENX_MODE(deny_mode) == DOS_OPEN_EXEC) { + create_disposition = FILE_CREATE; + break; + } + DEBUG(10,("map_open_params_to_ntcreate: bad " + "open_func 0x%x\n", (unsigned int)open_func)); + return False; + } + + /* Create the NT compatible share modes. */ + switch (GET_DENY_MODE(deny_mode)) { + case DENY_ALL: + share_mode = FILE_SHARE_NONE; + break; + + case DENY_WRITE: + share_mode = FILE_SHARE_READ; + break; + + case DENY_READ: + share_mode = FILE_SHARE_WRITE; + break; + + case DENY_NONE: + share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE; + break; + + case DENY_DOS: + create_options |= NTCREATEX_OPTIONS_PRIVATE_DENY_DOS; + if (is_executable(fname)) { + share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE; + } else { + if (GET_OPENX_MODE(deny_mode) == DOS_OPEN_RDONLY) { + share_mode = FILE_SHARE_READ; + } else { + share_mode = FILE_SHARE_NONE; + } + } + break; + + case DENY_FCB: + create_options |= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB; + share_mode = FILE_SHARE_NONE; + break; + + default: + DEBUG(10,("map_open_params_to_ntcreate: bad deny_mode 0x%x\n", + (unsigned int)GET_DENY_MODE(deny_mode) )); + return False; + } + + DEBUG(10,("map_open_params_to_ntcreate: file %s, access_mask = 0x%x, " + "share_mode = 0x%x, create_disposition = 0x%x, " + "create_options = 0x%x\n", + fname, + (unsigned int)access_mask, + (unsigned int)share_mode, + (unsigned int)create_disposition, + (unsigned int)create_options )); + + if (paccess_mask) { + *paccess_mask = access_mask; + } + if (pshare_mode) { + *pshare_mode = share_mode; + } + if (pcreate_disposition) { + *pcreate_disposition = create_disposition; + } + if (pcreate_options) { + *pcreate_options = create_options; + } + + return True; + } +/* Map generic permissions to file object specific permissions */ + +struct generic_mapping file_generic_mapping = { + FILE_GENERIC_READ, + FILE_GENERIC_WRITE, + FILE_GENERIC_EXECUTE, + FILE_GENERIC_ALL +}; + /**************************************************************************** Open a file with a share mode. ****************************************************************************/ -files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_STAT *psbuf, - uint32 desired_access, - int share_mode,int ofun, uint32 new_dos_mode, - int oplock_request, - int *Access,int *paction) +files_struct *open_file_ntcreate(connection_struct *conn, + const char *fname, + SMB_STRUCT_STAT *psbuf, + uint32 access_mask, /* access bits (FILE_READ_DATA etc.) */ + uint32 share_access, /* share constants (FILE_SHARE_READ etc). */ + uint32 create_disposition, /* FILE_OPEN_IF etc. */ + uint32 create_options, /* options such as delete on close. */ + uint32 new_dos_attributes, /* attributes used for new file. */ + int oplock_request, /* internal Samba oplock codes. */ + /* Information (FILE_EXISTS etc.) */ + int *pinfo) { int flags=0; int flags2=0; - int deny_mode = GET_DENY_MODE(share_mode); - BOOL allow_share_delete = GET_ALLOW_SHARE_DELETE(share_mode); - BOOL delete_on_close = GET_DELETE_ON_CLOSE_FLAG(share_mode); BOOL file_existed = VALID_STAT(*psbuf); - BOOL fcbopen = False; BOOL def_acl = False; - BOOL add_share_mode = True; BOOL internal_only_open = False; SMB_DEV_T dev = 0; SMB_INO_T inode = 0; @@ -1044,15 +1201,40 @@ files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_ BOOL all_current_opens_are_level_II = False; BOOL fsp_open = False; files_struct *fsp = NULL; - int open_mode=0; - uint16 port = 0; - mode_t new_mode = (mode_t)0; - int action; - uint32 existing_dos_mode = 0; + mode_t new_unx_mode = (mode_t)0; + mode_t unx_mode = (mode_t)0; + int info; + uint32 existing_dos_attributes = 0; struct pending_message_list *pml = NULL; + uint16 port = 0; uint16 mid = get_current_mid(); - /* We add aARCH to this as this mode is only used if the file is created new. */ - mode_t mode = unix_mode(conn,new_dos_mode | aARCH,fname, True); + + if (conn->printer) { + /* + * Printers are handled completely differently. + * Most of the passed parameters are ignored. + */ + + if (pinfo) { + *pinfo = FILE_WAS_CREATED; + } + + DEBUG(10, ("open_file_ntcreate: printer open fname=%s\n", fname)); + + return print_fsp_open(conn, fname); + } + + /* We add aARCH to this as this mode is only used if the file is + * created new. */ + unx_mode = unix_mode(conn, new_dos_attributes | aARCH,fname, True); + + DEBUG(10, ("open_file_ntcreate: fname=%s, dos_attrs=0x%x " + "access_mask=0x%x share_access=0x%x " + "create_disposition = 0x%x create_options=0x%x " + "unix mode=0%o oplock_request=%d\n", + fname, new_dos_attributes, access_mask, share_access, + create_disposition, create_options, unx_mode, + oplock_request)); if (oplock_request == INTERNAL_OPEN_ONLY) { internal_only_open = True; @@ -1065,52 +1247,42 @@ files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_ memcpy(&dib, pml->private_data.data, sizeof(dib)); /* There could be a race condition where the dev/inode pair - has changed since we deferred the message. If so, just - remove the deferred open entry and return sharing violation. */ - - /* If the timeout value is non-zero, we need to just - return sharing violation. Don't retry the open - as we were not notified of a close and we don't want to - trigger another spurious oplock break. */ - - if (!file_existed || dib.dev != psbuf->st_dev || dib.inode != psbuf->st_ino || - pml->msg_time.tv_sec || pml->msg_time.tv_usec) { + has changed since we deferred the message. If so, just + remove the deferred open entry and return sharing + violation. */ + + /* If the timeout value is non-zero, we need to just return + sharing violation. Don't retry the open as we were not + notified of a close and we don't want to trigger another + spurious oplock break. */ + + if (!file_existed || dib.dev != psbuf->st_dev || + dib.inode != psbuf->st_ino || pml->msg_time.tv_sec || + pml->msg_time.tv_usec) { /* Ensure we don't reprocess this message. */ remove_sharing_violation_open_smb_message(mid); /* Now remove the deferred open entry under lock. */ lock_share_entry(conn, dib.dev, dib.inode); - delete_defered_open_entry_record(conn, dib.dev, dib.inode); + delete_defered_open_entry_record(conn, dib.dev, + dib.inode); unlock_share_entry(conn, dib.dev, dib.inode); - set_saved_error_triple(ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION); + set_saved_error_triple(ERRDOS, ERRbadshare, + NT_STATUS_SHARING_VIOLATION); return NULL; } /* Ensure we don't reprocess this message. */ remove_sharing_violation_open_smb_message(mid); - - } - - if (conn->printer) { - /* printers are handled completely differently. Most of the passed parameters are - ignored */ - if (Access) - *Access = DOS_OPEN_WRONLY; - if (paction) - *paction = FILE_WAS_CREATED; - return print_fsp_open(conn, fname); } - DEBUG(10,("open_file_shared: fname = %s, dos_attrs = %x, share_mode = %x, ofun = %x, mode = %o, oplock request = %d\n", - fname, new_dos_mode, share_mode, ofun, (int)mode, oplock_request )); - if (!check_name(fname,conn)) { return NULL; } - new_dos_mode &= SAMBA_ATTRIBUTES_MASK; + new_dos_attributes &= SAMBA_ATTRIBUTES_MASK; if (file_existed) { - existing_dos_mode = dos_mode(conn, fname, psbuf); + existing_dos_attributes = dos_mode(conn, fname, psbuf); } /* ignore any oplock requests if oplocks are disabled */ @@ -1119,114 +1291,173 @@ files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_ } /* this is for OS/2 long file names - say we don't support them */ - if (strstr(fname,".+,;=[].")) { - /* OS/2 Workplace shell fix may be main code stream in a later release. */ - set_saved_error_triple(ERRDOS, ERRcannotopen, NT_STATUS_OBJECT_NAME_NOT_FOUND); - DEBUG(5,("open_file_shared: OS/2 long filenames are not supported.\n")); + if (!lp_posix_pathnames() && strstr(fname,".+,;=[].")) { + /* OS/2 Workplace shell fix may be main code stream in a later + * release. */ + set_saved_error_triple(ERRDOS, ERRcannotopen, + NT_STATUS_OBJECT_NAME_NOT_FOUND); + DEBUG(5,("open_file_ntcreate: OS/2 long filenames are not " + "supported.\n")); return NULL; } - if ((GET_FILE_OPEN_DISPOSITION(ofun) == FILE_EXISTS_FAIL) && file_existed) { - DEBUG(5,("open_file_shared: create new requested for file %s and file already exists.\n", - fname )); - if (S_ISDIR(psbuf->st_mode)) { - errno = EISDIR; - } else { - errno = EEXIST; - } - return NULL; - } - - if (CAN_WRITE(conn) && (GET_FILE_CREATE_DISPOSITION(ofun) == FILE_CREATE_IF_NOT_EXIST)) - flags2 |= O_CREAT; + switch( create_disposition ) { + /* + * Currently we're using FILE_SUPERSEDE as the same as + * FILE_OVERWRITE_IF but they really are + * different. FILE_SUPERSEDE deletes an existing file + * (requiring delete access) then recreates it. + */ + case FILE_SUPERSEDE: + /* If file exists replace/overwrite. If file doesn't + * exist create. */ + flags2 |= (O_CREAT | O_TRUNC); + break; - if (CAN_WRITE(conn) && (GET_FILE_OPEN_DISPOSITION(ofun) == FILE_EXISTS_TRUNCATE)) - flags2 |= O_TRUNC; + case FILE_OVERWRITE_IF: + /* If file exists replace/overwrite. If file doesn't + * exist create. */ + flags2 |= (O_CREAT | O_TRUNC); + break; - /* We only care about matching attributes on file exists and truncate. */ - if (file_existed && (GET_FILE_OPEN_DISPOSITION(ofun) == FILE_EXISTS_TRUNCATE)) { - if (!open_match_attributes(conn, fname, existing_dos_mode, new_dos_mode, - psbuf->st_mode, mode, &new_mode)) { - DEBUG(5,("open_file_shared: attributes missmatch for file %s (%x %x) (0%o, 0%o)\n", - fname, existing_dos_mode, new_dos_mode, - (int)psbuf->st_mode, (int)mode )); + case FILE_OPEN: + /* If file exists open. If file doesn't exist error. */ + if (!file_existed) { + DEBUG(5,("open_file_ntcreate: FILE_OPEN " + "requested for file %s and file " + "doesn't exist.\n", fname )); + set_saved_error_triple(ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_NOT_FOUND); + errno = ENOENT; + return NULL; + } + break; + + case FILE_OVERWRITE: + /* If file exists overwrite. If file doesn't exist + * error. */ + if (!file_existed) { + DEBUG(5,("open_file_ntcreate: FILE_OVERWRITE " + "requested for file %s and file " + "doesn't exist.\n", fname )); + set_saved_error_triple(ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_NOT_FOUND); + errno = ENOENT; + return NULL; + } + flags2 |= O_TRUNC; + break; + + case FILE_CREATE: + /* If file exists error. If file doesn't exist + * create. */ + if (file_existed) { + DEBUG(5,("open_file_ntcreate: FILE_CREATE " + "requested for file %s and file " + "already exists.\n", fname )); + if (S_ISDIR(psbuf->st_mode)) { + errno = EISDIR; + } else { + errno = EEXIST; + } + return NULL; + } + flags2 |= (O_CREAT|O_EXCL); + break; + + case FILE_OPEN_IF: + /* If file exists open. If file doesn't exist + * create. */ + flags2 |= O_CREAT; + break; + + default: + set_saved_error_triple(ERRDOS, ERRinvalidparam, + NT_STATUS_INVALID_PARAMETER); + return NULL; + } + + /* We only care about matching attributes on file exists and + * overwrite. */ + + if (file_existed && ((create_disposition == FILE_OVERWRITE) || + (create_disposition == FILE_OVERWRITE_IF))) { + if (!open_match_attributes(conn, fname, + existing_dos_attributes, + new_dos_attributes, psbuf->st_mode, + unx_mode, &new_unx_mode)) { + DEBUG(5,("open_file_ntcreate: attributes missmatch " + "for file %s (%x %x) (0%o, 0%o)\n", + fname, existing_dos_attributes, + new_dos_attributes, + (unsigned int)psbuf->st_mode, + (unsigned int)unx_mode )); errno = EACCES; return NULL; } } - if (GET_FILE_OPEN_DISPOSITION(ofun) == FILE_EXISTS_FAIL) - flags2 |= O_EXCL; + /* This is a nasty hack - must fix... JRA. */ + if (access_mask == MAXIMUM_ALLOWED_ACCESS) { + access_mask = FILE_GENERIC_ALL; + } - /* note that we ignore the append flag as - append does not mean the same thing under dos and unix */ + /* + * Convert GENERIC bits to specific bits. + */ - switch (GET_OPEN_MODE(share_mode)) { - case DOS_OPEN_EXEC: - case DOS_OPEN_RDONLY: - flags = O_RDONLY; - if (desired_access == 0) - desired_access = FILE_READ_DATA; - break; - case DOS_OPEN_WRONLY: - flags = O_WRONLY; - if (desired_access == 0) - desired_access = FILE_WRITE_DATA; - break; - case DOS_OPEN_FCB: - fcbopen = True; - flags = O_RDWR; - if (desired_access == 0) - desired_access = FILE_READ_DATA|FILE_WRITE_DATA; - break; - case DOS_OPEN_RDWR: - flags = O_RDWR; - if (desired_access == 0) - desired_access = FILE_READ_DATA|FILE_WRITE_DATA; - break; - default: - /* Force DOS error. */ - set_saved_error_triple(ERRDOS, ERRinvalidparam, NT_STATUS_INVALID); - return NULL; + se_map_generic(&access_mask, &file_generic_mapping); + + DEBUG(10, ("open_file_ntcreate: fname=%s, after mapping " + "access_mask=0x%x\n", fname, access_mask )); + + /* + * Note that we ignore the append flag as append does not + * mean the same thing under DOS and Unix. + */ + + if (access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) { + flags = O_RDWR; + } else { + flags = O_RDONLY; } + /* + * Currently we only look at FILE_WRITE_THROUGH for create options. + */ + #if defined(O_SYNC) - if (GET_FILE_SYNC_OPENMODE(share_mode)) { + if (create_options & FILE_WRITE_THROUGH) { flags2 |= O_SYNC; } #endif /* O_SYNC */ - if (flags != O_RDONLY && file_existed && - (!CAN_WRITE(conn) || IS_DOS_READONLY(existing_dos_mode))) { - if (!fcbopen) { - DEBUG(5,("open_file_shared: read/write access requested for file %s on read only %s\n", - fname, !CAN_WRITE(conn) ? "share" : "file" )); - errno = EACCES; - return NULL; - } - flags = O_RDONLY; + if (!CAN_WRITE(conn)) { + /* + * We should really return a permission denied error if either + * O_CREAT or O_TRUNC are set, but for compatibility with + * older versions of Samba we just AND them out. + */ + flags2 &= ~(O_CREAT|O_TRUNC); } - if (deny_mode > DENY_NONE && deny_mode!=DENY_FCB) { - DEBUG(2,("Invalid deny mode %d on file %s\n",deny_mode,fname)); - errno = EINVAL; - return NULL; - } + /* + * Ensure we can't write on a read-only share or file. + */ - if (desired_access && ((desired_access & ~(SYNCHRONIZE_ACCESS|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES))==0) && - ((desired_access & (SYNCHRONIZE_ACCESS|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES)) != 0)) { - /* Stat open that doesn't trigger oplock breaks or share mode checks... ! JRA. */ - deny_mode = DENY_NONE; - if (file_existed) { - oplock_request = 0; - add_share_mode = False; - flags2 &= ~O_CREAT; - } + if (flags != O_RDONLY && file_existed && + (!CAN_WRITE(conn) || IS_DOS_READONLY(existing_dos_attributes))) { + DEBUG(5,("open_file_ntcreate: write access requested for " + "file %s on read only %s\n", + fname, !CAN_WRITE(conn) ? "share" : "file" )); + set_saved_error_triple(ERRDOS, ERRnoaccess, + NT_STATUS_ACCESS_DENIED); + errno = EACCES; + return NULL; } fsp = file_new(conn); - if(!fsp) + if(!fsp) { return NULL; + } if (file_existed) { @@ -1235,47 +1466,86 @@ files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_ lock_share_entry(conn, dev, inode); - num_share_modes = open_mode_check(conn, fname, dev, inode, - desired_access, - share_mode, - &flags, &oplock_request, &all_current_opens_are_level_II); + num_share_modes = open_mode_check(conn, fname, dev, inode, + access_mask, share_access, + create_options, + &flags, &oplock_request, + &all_current_opens_are_level_II); if(num_share_modes == -1) { + if (!internal_only_open) { + NTSTATUS status; + get_saved_error_triple(NULL, NULL, &status); + if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION)) { + /* Check if this can be done with the + * deny_dos and fcb calls. */ + if (create_options & + (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS| + NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) { + files_struct *fsp_dup; + fsp_dup = fcb_or_dos_open(conn, fname, dev, + inode, access_mask, + share_access, + create_options); + + if (fsp_dup) { + unlock_share_entry(conn, dev, inode); + file_free(fsp); + if (pinfo) { + *pinfo = FILE_WAS_OPENED; + } + conn->num_files_open++; + return fsp_dup; + } + } + } + } + /* - * This next line is a subtlety we need for MS-Access. If a file open will - * fail due to share permissions and also for security (access) - * reasons, we need to return the access failed error, not the - * share error. This means we must attempt to open the file anyway - * in order to get the UNIX access error - even if we're going to - * fail the open for share reasons. This is bad, as we're burning - * another fd if there are existing locks but there's nothing else - * we can do. We also ensure we're not going to create or tuncate - * the file as we only want an access decision at this stage. JRA. + * This next line is a subtlety we need for + * MS-Access. If a file open will fail due to share + * permissions and also for security (access) reasons, + * we need to return the access failed error, not the + * share error. This means we must attempt to open the + * file anyway in order to get the UNIX access error - + * even if we're going to fail the open for share + * reasons. This is bad, as we're burning another fd + * if there are existing locks but there's nothing + * else we can do. We also ensure we're not going to + * create or tuncate the file as we only want an + * access decision at this stage. JRA. */ errno = 0; fsp_open = open_file(fsp,conn,fname,psbuf, - flags|(flags2&~(O_TRUNC|O_CREAT)),mode,desired_access); + flags|(flags2&~(O_TRUNC|O_CREAT)), + unx_mode,access_mask); - DEBUG(4,("open_file_shared : share_mode deny - calling open_file with \ -flags=0x%X flags2=0x%X mode=0%o returned %d\n", - flags,(flags2&~(O_TRUNC|O_CREAT)),(int)mode,(int)fsp_open )); + DEBUG(4,("open_file_ntcreate : share_mode deny - " + "calling open_file with flags=0x%X " + "flags2=0x%X mode=0%o returned %d\n", + flags, (flags2&~(O_TRUNC|O_CREAT)), + (unsigned int)unx_mode, (int)fsp_open )); if (!fsp_open && errno) { /* Default error. */ - set_saved_error_triple(ERRDOS, ERRnoaccess, NT_STATUS_ACCESS_DENIED); + set_saved_error_triple(ERRDOS, ERRnoaccess, + NT_STATUS_ACCESS_DENIED); } /* - * If we're returning a share violation, ensure we cope with - * the braindead 1 second delay. + * If we're returning a share violation, ensure we + * cope with the braindead 1 second delay. */ if (!internal_only_open) { NTSTATUS status; get_saved_error_triple(NULL, NULL, &status); if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION)) { - /* The fsp->open_time here represents the current time of day. */ - defer_open_sharing_error(conn, &fsp->open_time, fname, dev, inode); + /* The fsp->open_time here represents + * the current time of day. */ + defer_open_sharing_error(conn, + &fsp->open_time, + fname, dev, inode); } } @@ -1286,7 +1556,8 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n", * We have detected a sharing violation here * so return the correct error code */ - set_saved_error_triple(ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION); + set_saved_error_triple(ERRDOS, ERRbadshare, + NT_STATUS_SHARING_VIOLATION); } file_free(fsp); return NULL; @@ -1302,35 +1573,39 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n", */ if ((flags2 & O_CREAT) && lp_inherit_acls(SNUM(conn)) && - (def_acl = directory_has_default_acl(conn, parent_dirname(fname)))) - mode = 0777; + (def_acl = directory_has_default_acl(conn, parent_dirname(fname)))) { + unx_mode = 0777; + } DEBUG(4,("calling open_file with flags=0x%X flags2=0x%X mode=0%o\n", - flags,flags2,(int)mode)); + (unsigned int)flags,(unsigned int)flags2,(unsigned int)unx_mode)); /* * open_file strips any O_TRUNC flags itself. */ - fsp_open = open_file(fsp,conn,fname,psbuf,flags|flags2,mode,desired_access); + fsp_open = open_file(fsp,conn,fname,psbuf,flags|flags2,unx_mode,access_mask); - if (!fsp_open && (flags == O_RDWR) && (errno != ENOENT) && fcbopen) { - if((fsp_open = open_file(fsp,conn,fname,psbuf,O_RDONLY,mode,desired_access)) == True) + if (!fsp_open && (flags == O_RDWR) && (errno != ENOENT)) { + if((fsp_open = open_file(fsp,conn,fname,psbuf, + O_RDONLY,unx_mode,access_mask)) == True) { flags = O_RDONLY; + } } if (!fsp_open) { - if(file_existed) + if(file_existed) { unlock_share_entry(conn, dev, inode); + } file_free(fsp); return NULL; } /* - * Deal with the race condition where two smbd's detect the file doesn't - * exist and do the create at the same time. One of them will win and - * set a share mode, the other (ie. this one) should check if the - * requested share mode for this create is allowed. + * Deal with the race condition where two smbd's detect the file + * doesn't exist and do the create at the same time. One of them will + * win and set a share mode, the other (ie. this one) should check if + * the requested share mode for this create is allowed. */ if (!file_existed) { @@ -1347,22 +1622,47 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n", lock_share_entry_fsp(fsp); - num_share_modes = open_mode_check(conn, fname, dev, inode, - desired_access, - share_mode, - &flags, &oplock_request, &all_current_opens_are_level_II); + num_share_modes = open_mode_check(conn, fname, dev, inode, + access_mask, share_access, + create_options, + &flags, &oplock_request, + &all_current_opens_are_level_II); if(num_share_modes == -1) { - /* - * If we're returning a share violation, ensure we cope with - * the braindead 1 second delay. - */ - NTSTATUS status; get_saved_error_triple(NULL, NULL, &status); if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION)) { - /* The fsp->open_time here represents the current time of day. */ - defer_open_sharing_error(conn, &fsp->open_time, fname, dev, inode); + /* Check if this can be done with the deny_dos + * and fcb calls. */ + if (create_options & + (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS| + NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) { + files_struct *fsp_dup; + fsp_dup = fcb_or_dos_open(conn, fname, dev, inode, + access_mask, share_access, + create_options); + if (fsp_dup) { + unlock_share_entry(conn, dev, inode); + fd_close(conn, fsp); + file_free(fsp); + if (pinfo) { + *pinfo = FILE_WAS_OPENED; + } + conn->num_files_open++; + return fsp_dup; + } + } + + /* + * If we're returning a share violation, + * ensure we cope with the braindead 1 second + * delay. + */ + + /* The fsp->open_time here represents the + * current time of day. */ + defer_open_sharing_error(conn, &fsp->open_time, + fname, dev, inode); } unlock_share_entry_fsp(fsp); @@ -1372,7 +1672,8 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n", * We have detected a sharing violation here, so * return the correct code. */ - set_saved_error_triple(ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION); + set_saved_error_triple(ERRDOS, ERRbadshare, + NT_STATUS_SHARING_VIOLATION); return NULL; } @@ -1381,8 +1682,9 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n", * exist. Ensure we return the correct value for action. */ - if (num_share_modes > 0) + if (num_share_modes > 0) { file_existed = True; + } /* * We exit this block with the share entry *locked*..... @@ -1395,7 +1697,8 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n", mode and we have already checked our more authoritative locking database for permission to set this deny mode. If the kernel refuses the operations then the kernel is wrong */ - kernel_flock(fsp, deny_mode); + + kernel_flock(fsp, share_access); /* * At this point onwards, we can guarentee that the share entry @@ -1409,9 +1712,11 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n", if (flags2&O_TRUNC) { /* - * We are modifing the file after open - update the stat struct.. + * We are modifing the file after open - update the stat + * struct.. */ - if ((SMB_VFS_FTRUNCATE(fsp,fsp->fd,0) == -1) || (SMB_VFS_FSTAT(fsp,fsp->fd,psbuf)==-1)) { + if ((SMB_VFS_FTRUNCATE(fsp,fsp->fh->fd,0) == -1) || + (SMB_VFS_FSTAT(fsp,fsp->fh->fd,psbuf)==-1)) { unlock_share_entry_fsp(fsp); fd_close(conn,fsp); file_free(fsp); @@ -1419,44 +1724,28 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n", } } - switch (flags) { - case O_RDONLY: - open_mode = DOS_OPEN_RDONLY; - break; - case O_RDWR: - open_mode = DOS_OPEN_RDWR; - break; - case O_WRONLY: - open_mode = DOS_OPEN_WRONLY; - break; - } + /* Record the options we were opened with. */ + fsp->share_access = share_access; + fsp->fh->private_options = create_options; + fsp->access_mask = access_mask; - fsp->share_mode = SET_DENY_MODE(deny_mode) | - SET_OPEN_MODE(open_mode) | - SET_ALLOW_SHARE_DELETE(allow_share_delete); - - DEBUG(10,("open_file_shared : share_mode = %x\n", fsp->share_mode )); - - if (Access) { - (*Access) = (SET_DENY_MODE(deny_mode) | SET_OPEN_MODE(open_mode)); - } - - action = 0; - - if (file_existed && !(flags2 & O_TRUNC)) - action = FILE_WAS_OPENED; - if (file_existed && (flags2 & O_TRUNC)) - action = FILE_WAS_OVERWRITTEN; - if (!file_existed) { - action = FILE_WAS_CREATED; + if (file_existed) { + if (!(flags2 & O_TRUNC)) { + info = FILE_WAS_OPENED; + } else { + info = FILE_WAS_OVERWRITTEN; + } + } else { + info = FILE_WAS_CREATED; /* Change the owner if required. */ if (lp_inherit_owner(SNUM(conn))) { - change_owner_to_parent(conn, fsp, fsp->fsp_name, psbuf); + change_owner_to_parent(conn, fsp, fsp->fsp_name, + psbuf); } } - if (paction) { - *paction = action; + if (pinfo) { + *pinfo = info; } /* @@ -1465,7 +1754,8 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n", */ if(oplock_request && (num_share_modes == 0) && - !IS_VETO_OPLOCK_PATH(conn,fname) && set_file_oplock(fsp, oplock_request) ) { + !IS_VETO_OPLOCK_PATH(conn,fname) && + set_file_oplock(fsp, oplock_request) ) { port = global_oplock_port; } else if (oplock_request && all_current_opens_are_level_II) { port = global_oplock_port; @@ -1476,26 +1766,25 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n", oplock_request = 0; } - if (add_share_mode) { - set_share_mode(fsp, port, oplock_request); - } + set_share_mode(fsp, port, oplock_request); - if (delete_on_close) { - uint32 dosmode = existing_dos_mode; + if (create_options & FILE_DELETE_ON_CLOSE) { + uint32 dosattr= existing_dos_attributes; NTSTATUS result; - if (action == FILE_WAS_OVERWRITTEN || action == FILE_WAS_CREATED) { - dosmode = new_dos_mode; + if (info == FILE_WAS_OVERWRITTEN || info == FILE_WAS_CREATED || + info == FILE_WAS_SUPERSEDED) { + dosattr = new_dos_attributes; } - result = set_delete_on_close_internal(fsp, delete_on_close, dosmode); - if (NT_STATUS_V(result) != NT_STATUS_V(NT_STATUS_OK)) { + result = can_set_delete_on_close(fsp, True, dosattr); + + if (!NT_STATUS_IS_OK(result)) { uint8 u_e_c; uint32 u_e_code; + BOOL dummy_del_on_close; /* Remember to delete the mode we just added. */ - if (add_share_mode) { - del_share_mode(fsp, NULL); - } + del_share_mode(fsp, NULL, &dummy_del_on_close); unlock_share_entry_fsp(fsp); fd_close(conn,fsp); file_free(fsp); @@ -1503,12 +1792,17 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n", set_saved_error_triple(u_e_c, u_e_code, result); return NULL; } + set_delete_on_close(fsp, True); } - if (action == FILE_WAS_OVERWRITTEN || action == FILE_WAS_CREATED) { + if (info == FILE_WAS_OVERWRITTEN || info == FILE_WAS_CREATED || + info == FILE_WAS_SUPERSEDED) { /* Files should be initially set as archive */ - if (lp_map_archive(SNUM(conn)) || lp_store_dos_attributes(SNUM(conn))) { - file_set_dosmode(conn, fname, new_dos_mode | aARCH, NULL, True); + if (lp_map_archive(SNUM(conn)) || + lp_store_dos_attributes(SNUM(conn))) { + file_set_dosmode(conn, fname, + new_dos_attributes | aARCH, NULL, + True); } } @@ -1519,36 +1813,45 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n", if (!file_existed && !def_acl) { - int saved_errno = errno; /* We might get ENOSYS in the next call.. */ + int saved_errno = errno; /* We might get ENOSYS in the next + * call.. */ - if (SMB_VFS_FCHMOD_ACL(fsp, fsp->fd, mode) == -1 && errno == ENOSYS) + if (SMB_VFS_FCHMOD_ACL(fsp, fsp->fh->fd, unx_mode) == -1 + && errno == ENOSYS) { errno = saved_errno; /* Ignore ENOSYS */ + } - } else if (new_mode) { + } else if (new_unx_mode) { int ret = -1; /* Attributes need changing. File already existed. */ { - int saved_errno = errno; /* We might get ENOSYS in the next call.. */ - ret = SMB_VFS_FCHMOD_ACL(fsp, fsp->fd, new_mode); + int saved_errno = errno; /* We might get ENOSYS in the + * next call.. */ + ret = SMB_VFS_FCHMOD_ACL(fsp, fsp->fh->fd, + new_unx_mode); if (ret == -1 && errno == ENOSYS) { errno = saved_errno; /* Ignore ENOSYS */ } else { - DEBUG(5, ("open_file_shared: failed to reset attributes of file %s to 0%o\n", - fname, (int)new_mode)); + DEBUG(5, ("open_file_shared: failed to reset " + "attributes of file %s to 0%o\n", + fname, (unsigned int)new_unx_mode)); ret = 0; /* Don't do the fchmod below. */ } } - if ((ret == -1) && (SMB_VFS_FCHMOD(fsp, fsp->fd, new_mode) == -1)) - DEBUG(5, ("open_file_shared: failed to reset attributes of file %s to 0%o\n", - fname, (int)new_mode)); + if ((ret == -1) && + (SMB_VFS_FCHMOD(fsp, fsp->fh->fd, new_unx_mode) == -1)) + DEBUG(5, ("open_file_shared: failed to reset " + "attributes of file %s to 0%o\n", + fname, (unsigned int)new_unx_mode)); } - /* If this is a successful open, we must remove any deferred open records. */ + /* If this is a successful open, we must remove any deferred open + * records. */ delete_defered_open_entry_record(conn, fsp->dev, fsp->inode); unlock_share_entry_fsp(fsp); @@ -1561,17 +1864,20 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n", Open a file for for write to ensure that we can fchmod it. ****************************************************************************/ -files_struct *open_file_fchmod(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf) +files_struct *open_file_fchmod(connection_struct *conn, const char *fname, + SMB_STRUCT_STAT *psbuf) { files_struct *fsp = NULL; BOOL fsp_open; - if (!VALID_STAT(*psbuf)) + if (!VALID_STAT(*psbuf)) { return NULL; + } fsp = file_new(conn); - if(!fsp) + if(!fsp) { return NULL; + } /* note! we must use a non-zero desired access or we don't get a real file descriptor. Oh what a twisted web we weave. */ @@ -1606,96 +1912,135 @@ int close_file_fchmod(files_struct *fsp) Open a directory from an NT SMB call. ****************************************************************************/ -files_struct *open_directory(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf, - uint32 desired_access, int share_mode, int smb_ofun, int *action) +files_struct *open_directory(connection_struct *conn, + const char *fname, + SMB_STRUCT_STAT *psbuf, + uint32 access_mask, + uint32 share_access, + uint32 create_disposition, + uint32 create_options, + int *pinfo) { - BOOL got_stat = False; - files_struct *fsp = file_new(conn); - BOOL delete_on_close = GET_DELETE_ON_CLOSE_FLAG(share_mode); - - if(!fsp) + files_struct *fsp = NULL; + BOOL dir_existed = VALID_STAT(*psbuf) ? True : False; + BOOL create_dir = False; + int info = 0; + + DEBUG(5,("open_directory: opening directory %s, access_mask = 0x%x, " + "share_access = 0x%x create_options = 0x%x, " + "create_disposition = 0x%x\n", + fname, + (unsigned int)access_mask, + (unsigned int)share_access, + (unsigned int)create_options, + (unsigned int)create_disposition)); + + if (is_ntfs_stream_name(fname)) { + DEBUG(0,("open_directory: %s is a stream name!\n", fname )); + /* NB. Is the DOS error ERRbadpath or ERRbaddirectory ? */ + set_saved_error_triple(ERRDOS, ERRbadpath, + NT_STATUS_NOT_A_DIRECTORY); return NULL; + } - if (VALID_STAT(*psbuf)) - got_stat = True; - - if (got_stat && (GET_FILE_OPEN_DISPOSITION(smb_ofun) == FILE_EXISTS_FAIL)) { - file_free(fsp); - errno = EEXIST; /* Setup so correct error is returned to client. */ + if (dir_existed && !S_ISDIR(psbuf->st_mode)) { + DEBUG(0,("open_directory: %s is not a directory !\n", fname )); + /* NB. Is the DOS error ERRbadpath or ERRbaddirectory ? */ + set_saved_error_triple(ERRDOS, ERRbadpath, + NT_STATUS_NOT_A_DIRECTORY); return NULL; } - if (GET_FILE_CREATE_DISPOSITION(smb_ofun) == FILE_CREATE_IF_NOT_EXIST) { - - if (got_stat) { - - if(!S_ISDIR(psbuf->st_mode)) { - DEBUG(0,("open_directory: %s is not a directory !\n", fname )); - file_free(fsp); - errno = EACCES; + switch( create_disposition ) { + case FILE_OPEN: + /* If directory exists open. If directory doesn't + * exist error. */ + if (!dir_existed) { + DEBUG(5,("open_directory: FILE_OPEN requested " + "for directory %s and it doesn't " + "exist.\n", fname )); + set_saved_error_triple(ERRDOS, ERRbadfile, + NT_STATUS_OBJECT_NAME_NOT_FOUND); return NULL; } - *action = FILE_WAS_OPENED; - - } else { - - /* - * Try and create the directory. - */ - - /* We know bad_path is false as it's caught earlier. */ - - NTSTATUS status = mkdir_internal(conn, fname, False); + info = FILE_WAS_OPENED; + break; - if (!NT_STATUS_IS_OK(status)) { - DEBUG(2,("open_directory: unable to create %s. Error was %s\n", - fname, strerror(errno) )); - file_free(fsp); - /* Ensure we return the correct NT status to the client. */ - set_saved_error_triple(0, 0, status); + case FILE_CREATE: + /* If directory exists error. If directory doesn't + * exist create. */ + if (dir_existed) { + DEBUG(5,("open_directory: FILE_CREATE " + "requested for directory %s and it " + "already exists.\n", fname )); + set_saved_error_triple(ERRDOS, ERRfilexists, + NT_STATUS_OBJECT_NAME_COLLISION); return NULL; } + create_dir = True; + info = FILE_WAS_CREATED; + break; - /* Ensure we're checking for a symlink here.... */ - /* We don't want to get caught by a symlink racer. */ - - if(SMB_VFS_LSTAT(conn,fname, psbuf) != 0) { - file_free(fsp); - return NULL; + case FILE_OPEN_IF: + /* If directory exists open. If directory doesn't + * exist create. */ + if (!dir_existed) { + create_dir = True; + info = FILE_WAS_CREATED; + } else { + info = FILE_WAS_OPENED; } + break; - if(!S_ISDIR(psbuf->st_mode)) { - DEBUG(0,("open_directory: %s is not a directory !\n", fname )); - file_free(fsp); - return NULL; - } + case FILE_SUPERSEDE: + case FILE_OVERWRITE: + case FILE_OVERWRITE_IF: + default: + DEBUG(5,("open_directory: invalid create_disposition " + "0x%x for directory %s\n", + (unsigned int)create_disposition, fname)); + file_free(fsp); + set_saved_error_triple(ERRDOS, ERRinvalidparam, + NT_STATUS_INVALID_PARAMETER); + return NULL; + } + + if (create_dir) { + /* + * Try and create the directory. + */ - *action = FILE_WAS_CREATED; + /* We know bad_path is false as it's caught earlier. */ + NTSTATUS status = mkdir_internal(conn, fname, False); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(2,("open_directory: unable to create %s. " + "Error was %s\n", fname, strerror(errno) )); + /* Ensure we return the correct NT status to the + * client. */ + set_saved_error_triple(0, 0, status); + return NULL; } - } else { - /* - * Don't create - just check that it *was* a directory. - */ + /* Ensure we're checking for a symlink here.... */ + /* We don't want to get caught by a symlink racer. */ - if(!got_stat) { - DEBUG(3,("open_directory: unable to stat name = %s. Error was %s\n", - fname, strerror(errno) )); - file_free(fsp); + if(SMB_VFS_LSTAT(conn,fname, psbuf) != 0) { return NULL; } if(!S_ISDIR(psbuf->st_mode)) { - DEBUG(0,("open_directory: %s is not a directory !\n", fname )); - file_free(fsp); + DEBUG(0,("open_directory: %s is not a directory !\n", + fname )); return NULL; } + } - *action = FILE_WAS_OPENED; + fsp = file_new(conn); + if(!fsp) { + return NULL; } - - DEBUG(5,("open_directory: opening directory %s\n", fname)); /* * Setup the files_struct for it. @@ -1709,20 +2054,21 @@ files_struct *open_directory(connection_struct *conn, const char *fname, SMB_STR fsp->can_lock = True; fsp->can_read = False; fsp->can_write = False; - fsp->share_mode = share_mode; - fsp->desired_access = desired_access; + + fsp->share_access = share_access; + fsp->fh->private_options = create_options; + fsp->access_mask = access_mask; + fsp->print_file = False; fsp->modified = False; fsp->oplock_type = NO_OPLOCK; fsp->sent_oplock_break = NO_BREAK_SENT; fsp->is_directory = True; fsp->is_stat = False; - fsp->directory_delete_on_close = False; string_set(&fsp->fsp_name,fname); - if (delete_on_close) { - NTSTATUS status = set_delete_on_close_internal(fsp, delete_on_close, 0); - + if (create_options & FILE_DELETE_ON_CLOSE) { + NTSTATUS status = can_set_delete_on_close(fsp, True, 0); if (!NT_STATUS_IS_OK(status)) { file_free(fsp); return NULL; @@ -1730,10 +2076,14 @@ files_struct *open_directory(connection_struct *conn, const char *fname, SMB_STR } /* Change the owner if required. */ - if ((*action == FILE_WAS_CREATED) && lp_inherit_owner(SNUM(conn))) { + if ((info == FILE_WAS_CREATED) && lp_inherit_owner(SNUM(conn))) { change_owner_to_parent(conn, fsp, fsp->fsp_name, psbuf); } + if (pinfo) { + *pinfo = info; + } + conn->num_files_open++; return fsp; @@ -1743,7 +2093,8 @@ files_struct *open_directory(connection_struct *conn, const char *fname, SMB_STR Open a pseudo-file (no locking checks - a 'stat' open). ****************************************************************************/ -files_struct *open_file_stat(connection_struct *conn, char *fname, SMB_STRUCT_STAT *psbuf) +files_struct *open_file_stat(connection_struct *conn, char *fname, + SMB_STRUCT_STAT *psbuf) { files_struct *fsp = NULL; @@ -1772,15 +2123,12 @@ files_struct *open_file_stat(connection_struct *conn, char *fname, SMB_STRUCT_ST fsp->can_lock = False; fsp->can_read = False; fsp->can_write = False; - fsp->share_mode = 0; - fsp->desired_access = 0; fsp->print_file = False; fsp->modified = False; fsp->oplock_type = NO_OPLOCK; fsp->sent_oplock_break = NO_BREAK_SENT; fsp->is_directory = False; fsp->is_stat = True; - fsp->directory_delete_on_close = False; string_set(&fsp->fsp_name,fname); conn->num_files_open++; diff --git a/source/smbd/oplock.c b/source/smbd/oplock.c index 8208fbebe34..3cfce5c7a1f 100644 --- a/source/smbd/oplock.c +++ b/source/smbd/oplock.c @@ -343,6 +343,7 @@ BOOL process_local_message(char *buffer, int buf_size) SMB_INO_T inode; unsigned long file_id; uint16 break_cmd_type; + struct sockaddr_in toaddr; msg_len = IVAL(buffer,OPBRK_CMD_LEN_OFFSET); from_port = SVAL(buffer,OPBRK_CMD_PORT_OFFSET); @@ -366,6 +367,7 @@ BOOL process_local_message(char *buffer, int buf_size) } if (!koplocks->parse_message(msg_start, msg_len, &inode, &dev, &file_id)) { DEBUG(0,("kernel oplock break parse failure!\n")); + return False; } break; @@ -449,49 +451,54 @@ pid %d, port %d, dev = %x, inode = %.0f, file_id = %lu\n", * Now actually process the break request. */ - if((exclusive_oplocks_open + level_II_oplocks_open) != 0) { - if (oplock_break(dev, inode, file_id, False) == False) { - DEBUG(0,("process_local_message: oplock break failed.\n")); - return False; - } - } else { + if ((exclusive_oplocks_open == 0) && + (level_II_oplocks_open == 0)) { /* * If we have no record of any currently open oplocks, * it's not an error, as a close command may have * just been issued on the file that was oplocked. * Just log a message and return success in this case. */ - DEBUG(3,("process_local_message: oplock break requested with no outstanding \ -oplocks. Returning success.\n")); + DEBUG(3,("process_local_message: oplock break requested with " + "no outstanding oplocks. Returning success.\n")); + return True; + } + + if (!oplock_break(dev, inode, file_id, False)) { + DEBUG(0,("process_local_message: oplock break failed.\n")); + return False; } /* - * Do the appropriate reply - none in the kernel or async level II case. + * Do the appropriate reply - none in the kernel or async level II + * case. */ - if(break_cmd_type == OPLOCK_BREAK_CMD || break_cmd_type == LEVEL_II_OPLOCK_BREAK_CMD) { - struct sockaddr_in toaddr; + if (!((break_cmd_type == OPLOCK_BREAK_CMD) || + (break_cmd_type == LEVEL_II_OPLOCK_BREAK_CMD))) { + return True; + } - /* Send the message back after OR'ing in the 'REPLY' bit. */ - SSVAL(msg_start,OPBRK_MESSAGE_CMD_OFFSET,break_cmd_type | CMD_REPLY); + /* Send the message back after OR'ing in the 'REPLY' bit. */ + SSVAL(msg_start,OPBRK_MESSAGE_CMD_OFFSET,break_cmd_type | CMD_REPLY); - memset((char *)&toaddr,'\0',sizeof(toaddr)); - toaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - toaddr.sin_port = htons(from_port); - toaddr.sin_family = AF_INET; + memset((char *)&toaddr,'\0',sizeof(toaddr)); + toaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + toaddr.sin_port = htons(from_port); + toaddr.sin_family = AF_INET; - if(sys_sendto( oplock_sock, msg_start, OPLOCK_BREAK_MSG_LEN, 0, - (struct sockaddr *)&toaddr, sizeof(toaddr)) < 0) { - DEBUG(0,("process_local_message: sendto process %d failed. Errno was %s\n", - (int)remotepid, strerror(errno))); - return False; - } - - DEBUG(5,("process_local_message: oplock break reply sent to \ -pid %d, port %d, for file dev = %x, inode = %.0f, file_id = %lu\n", - (int)remotepid, from_port, (unsigned int)dev, (double)inode, file_id)); + if(sys_sendto( oplock_sock, msg_start, OPLOCK_BREAK_MSG_LEN, 0, + (struct sockaddr *)&toaddr, sizeof(toaddr)) < 0) { + DEBUG(0,("process_local_message: sendto process %d failed. " + "Errno was %s\n", (int)remotepid, strerror(errno))); + return False; } + DEBUG(5,("process_local_message: oplock break reply sent to pid %d, " + "port %d, for file dev = %x, inode = %.0f, file_id = %lu\n", + (int)remotepid, from_port, (unsigned int)dev, + (double)inode, file_id)); + return True; } @@ -1150,7 +1157,7 @@ BOOL attempt_close_oplocked_file(files_struct *fsp) { DEBUG(5,("attempt_close_oplocked_file: checking file %s.\n", fsp->fsp_name)); - if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && !fsp->sent_oplock_break && (fsp->fd != -1)) { + if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && !fsp->sent_oplock_break && (fsp->fh->fd != -1)) { /* Try and break the oplock. */ if (oplock_break(fsp->dev, fsp->inode, fsp->file_id, True)) { if(file_find_fsp(fsp) == NULL) /* Did the oplock break close the file ? */ @@ -1223,6 +1230,7 @@ void release_level_2_oplocks_on_change(files_struct *fsp) pid_t pid = sys_getpid(); int num_share_modes = 0; int i; + BOOL dummy; /* * If this file is level II oplocked then we need @@ -1239,7 +1247,8 @@ void release_level_2_oplocks_on_change(files_struct *fsp) DEBUG(0,("release_level_2_oplocks_on_change: failed to lock share mode entry for file %s.\n", fsp->fsp_name )); } - num_share_modes = get_share_modes(fsp->conn, fsp->dev, fsp->inode, &share_list); + num_share_modes = get_share_modes(fsp->dev, fsp->inode, &share_list, + &dummy); DEBUG(10,("release_level_2_oplocks_on_change: num_share_modes = %d\n", num_share_modes )); diff --git a/source/smbd/oplock_linux.c b/source/smbd/oplock_linux.c index 78dc260939e..477832c6e8e 100644 --- a/source/smbd/oplock_linux.c +++ b/source/smbd/oplock_linux.c @@ -179,10 +179,10 @@ dev = %x, inode = %.0f fd = %d, fileid = %lu \n", (unsigned int)fsp->dev, (doubl static BOOL linux_set_kernel_oplock(files_struct *fsp, int oplock_type) { - if (linux_setlease(fsp->fd, F_WRLCK) == -1) { + if (linux_setlease(fsp->fh->fd, F_WRLCK) == -1) { DEBUG(3,("linux_set_kernel_oplock: Refused oplock on file %s, fd = %d, dev = %x, \ inode = %.0f. (%s)\n", - fsp->fsp_name, fsp->fd, + fsp->fsp_name, fsp->fh->fd, (unsigned int)fsp->dev, (double)fsp->inode, strerror(errno))); return False; } @@ -204,7 +204,7 @@ static void linux_release_kernel_oplock(files_struct *fsp) * Check and print out the current kernel * oplock state of this file. */ - int state = fcntl(fsp->fd, F_GETLEASE, 0); + int state = fcntl(fsp->fh->fd, F_GETLEASE, 0); dbgtext("linux_release_kernel_oplock: file %s, dev = %x, inode = %.0f file_id = %lu has kernel \ oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id, state ); @@ -213,7 +213,7 @@ oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev, /* * Remove the kernel oplock on this file. */ - if (linux_setlease(fsp->fd, F_UNLCK) == -1) { + if (linux_setlease(fsp->fh->fd, F_UNLCK) == -1) { if (DEBUGLVL(0)) { dbgtext("linux_release_kernel_oplock: Error when removing kernel oplock on file " ); dbgtext("%s, dev = %x, inode = %.0f, file_id = %lu. Error was %s\n", diff --git a/source/smbd/pipes.c b/source/smbd/pipes.c index 6c7faa4c056..951c192e396 100644 --- a/source/smbd/pipes.c +++ b/source/smbd/pipes.c @@ -4,6 +4,7 @@ Copyright (C) Andrew Tridgell 1992-1998 Copyright (C) Luke Kenneth Casson Leighton 1996-1998 Copyright (C) Paul Ashton 1997-1998. + Copyright (C) Jeremy Allison 2005. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -33,11 +34,11 @@ extern struct pipe_id_info pipe_names[]; /**************************************************************************** - reply to an open and X on a named pipe - - This code is basically stolen from reply_open_and_X with some - wrinkles to handle pipes. + Reply to an open and X on a named pipe. + This code is basically stolen from reply_open_and_X with some + wrinkles to handle pipes. ****************************************************************************/ + int reply_open_pipe_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize) { @@ -45,7 +46,6 @@ int reply_open_pipe_and_X(connection_struct *conn, pstring pipe_name; uint16 vuid = SVAL(inbuf, smb_uid); smb_np_struct *p; - int smb_ofun = SVAL(inbuf,smb_vwv8); int size=0,fmode=0,mtime=0,rmode=0; int i; @@ -55,23 +55,26 @@ int reply_open_pipe_and_X(connection_struct *conn, /* If the name doesn't start \PIPE\ then this is directed */ /* at a mailslot or something we really, really don't understand, */ /* not just something we really don't understand. */ - if ( strncmp(pipe_name,PIPE,PIPELEN) != 0 ) + if ( strncmp(pipe_name,PIPE,PIPELEN) != 0 ) { return(ERROR_DOS(ERRSRV,ERRaccess)); + } DEBUG(4,("Opening pipe %s.\n", pipe_name)); /* See if it is one we want to handle. */ - for( i = 0; pipe_names[i].client_pipe ; i++ ) - if( strequal(pipe_name,pipe_names[i].client_pipe) ) + for( i = 0; pipe_names[i].client_pipe ; i++ ) { + if( strequal(pipe_name,pipe_names[i].client_pipe)) { break; + } + } - if (pipe_names[i].client_pipe == NULL) + if (pipe_names[i].client_pipe == NULL) { return(ERROR_BOTH(NT_STATUS_OBJECT_NAME_NOT_FOUND,ERRDOS,ERRbadpipe)); + } /* Strip \PIPE\ off the name. */ pstrcpy(fname, pipe_name + PIPELEN); - #if 0 /* * Hack for NT printers... JRA. @@ -83,10 +86,11 @@ int reply_open_pipe_and_X(connection_struct *conn, /* Known pipes arrive with DIR attribs. Remove it so a regular file */ /* can be opened and add it in after the open. */ DEBUG(3,("Known pipe %s opening.\n",fname)); - smb_ofun |= FILE_CREATE_IF_NOT_EXIST; p = open_rpc_pipe_p(fname, conn, vuid); - if (!p) return(ERROR_DOS(ERRSRV,ERRnofids)); + if (!p) { + return(ERROR_DOS(ERRSRV,ERRnofids)); + } /* Prepare the reply */ set_message(outbuf,15,0,True); @@ -111,8 +115,9 @@ int reply_open_pipe_and_X(connection_struct *conn, } /**************************************************************************** - reply to a write on a pipe + Reply to a write on a pipe. ****************************************************************************/ + int reply_pipe_write(char *inbuf,char *outbuf,int length,int dum_bufsize) { smb_np_struct *p = get_rpc_pipe_p(inbuf,smb_vwv0); @@ -121,25 +126,27 @@ int reply_pipe_write(char *inbuf,char *outbuf,int length,int dum_bufsize) int outsize; char *data; - if (!p) + if (!p) { return(ERROR_DOS(ERRDOS,ERRbadfid)); + } data = smb_buf(inbuf) + 3; - if (numtowrite == 0) + if (numtowrite == 0) { nwritten = 0; - else + } else { nwritten = write_to_pipe(p, data, numtowrite); + } - if ((nwritten == 0 && numtowrite != 0) || (nwritten < 0)) + if ((nwritten == 0 && numtowrite != 0) || (nwritten < 0)) { return (UNIXERROR(ERRDOS,ERRnoaccess)); + } outsize = set_message(outbuf,1,0,True); SSVAL(outbuf,smb_vwv0,nwritten); - DEBUG(3,("write-IPC pnum=%04x nwritten=%d\n", - p->pnum, nwritten)); + DEBUG(3,("write-IPC pnum=%04x nwritten=%d\n", p->pnum, nwritten)); return(outsize); } @@ -158,24 +165,25 @@ int reply_pipe_write_and_X(char *inbuf,char *outbuf,int length,int bufsize) int nwritten = -1; int smb_doff = SVAL(inbuf, smb_vwv11); BOOL pipe_start_message_raw = ((SVAL(inbuf, smb_vwv7) & (PIPE_START_MESSAGE|PIPE_RAW_MODE)) == - (PIPE_START_MESSAGE|PIPE_RAW_MODE)); + (PIPE_START_MESSAGE|PIPE_RAW_MODE)); char *data; - if (!p) + if (!p) { return(ERROR_DOS(ERRDOS,ERRbadfid)); + } data = smb_base(inbuf) + smb_doff; - if (numtowrite == 0) + if (numtowrite == 0) { nwritten = 0; - else { + } else { if(pipe_start_message_raw) { /* * For the start of a message in named pipe byte mode, * the first two bytes are a length-of-pdu field. Ignore - * them (we don't trust the client. JRA. + * them (we don't trust the client). JRA. */ - if(numtowrite < 2) { + if(numtowrite < 2) { DEBUG(0,("reply_pipe_write_and_X: start of message set and not enough data sent.(%u)\n", (unsigned int)numtowrite )); return (UNIXERROR(ERRDOS,ERRnoaccess)); @@ -183,30 +191,30 @@ int reply_pipe_write_and_X(char *inbuf,char *outbuf,int length,int bufsize) data += 2; numtowrite -= 2; - } + } nwritten = write_to_pipe(p, data, numtowrite); } - if ((nwritten == 0 && numtowrite != 0) || (nwritten < 0)) + if ((nwritten == 0 && numtowrite != 0) || (nwritten < 0)) { return (UNIXERROR(ERRDOS,ERRnoaccess)); + } set_message(outbuf,6,0,True); nwritten = (pipe_start_message_raw ? nwritten + 2 : nwritten); SSVAL(outbuf,smb_vwv2,nwritten); - DEBUG(3,("writeX-IPC pnum=%04x nwritten=%d\n", - p->pnum, nwritten)); + DEBUG(3,("writeX-IPC pnum=%04x nwritten=%d\n", p->pnum, nwritten)); return chain_reply(inbuf,outbuf,length,bufsize); } /**************************************************************************** - reply to a read and X - - This code is basically stolen from reply_read_and_X with some - wrinkles to handle pipes. + Reply to a read and X. + This code is basically stolen from reply_read_and_X with some + wrinkles to handle pipes. ****************************************************************************/ + int reply_pipe_read_and_X(char *inbuf,char *outbuf,int length,int bufsize) { smb_np_struct *p = get_rpc_pipe_p(inbuf,smb_vwv2); @@ -223,16 +231,18 @@ int reply_pipe_read_and_X(char *inbuf,char *outbuf,int length,int bufsize) uint32 smb_offs = IVAL(inbuf,smb_vwv3); #endif - if (!p) + if (!p) { return(ERROR_DOS(ERRDOS,ERRbadfid)); + } set_message(outbuf,12,0,True); data = smb_buf(outbuf); nread = read_from_pipe(p, data, smb_maxcnt, &unused); - if (nread < 0) + if (nread < 0) { return(UNIXERROR(ERRDOS,ERRnoaccess)); + } SSVAL(outbuf,smb_vwv5,nread); SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf)); @@ -247,20 +257,23 @@ int reply_pipe_read_and_X(char *inbuf,char *outbuf,int length,int bufsize) } /**************************************************************************** - reply to a close + Reply to a close. ****************************************************************************/ + int reply_pipe_close(connection_struct *conn, char *inbuf,char *outbuf) { smb_np_struct *p = get_rpc_pipe_p(inbuf,smb_vwv0); int outsize = set_message(outbuf,0,0,True); - if (!p) + if (!p) { return(ERROR_DOS(ERRDOS,ERRbadfid)); + } DEBUG(5,("reply_pipe_close: pnum:%x\n", p->pnum)); - if (!close_rpc_pipe_hnd(p)) + if (!close_rpc_pipe_hnd(p)) { return ERROR_DOS(ERRDOS,ERRbadfid); + } return(outsize); } diff --git a/source/smbd/posix_acls.c b/source/smbd/posix_acls.c index ffcfbc4fb18..ab14638a24c 100644 --- a/source/smbd/posix_acls.c +++ b/source/smbd/posix_acls.c @@ -229,8 +229,8 @@ static void store_inheritance_attributes(files_struct *fsp, canon_ace *file_ace_ if (!pai_protected && num_inherited_entries(file_ace_list) == 0 && num_inherited_entries(dir_ace_list) == 0) { /* Instead just remove the attribute if it exists. */ - if (fsp->fd != -1) - SMB_VFS_FREMOVEXATTR(fsp, fsp->fd, SAMBA_POSIX_INHERITANCE_EA_NAME); + if (fsp->fh->fd != -1) + SMB_VFS_FREMOVEXATTR(fsp, fsp->fh->fd, SAMBA_POSIX_INHERITANCE_EA_NAME); else SMB_VFS_REMOVEXATTR(fsp->conn, fsp->fsp_name, SAMBA_POSIX_INHERITANCE_EA_NAME); return; @@ -238,8 +238,8 @@ static void store_inheritance_attributes(files_struct *fsp, canon_ace *file_ace_ pai_buf = create_pai_buf(file_ace_list, dir_ace_list, pai_protected, &store_size); - if (fsp->fd != -1) - ret = SMB_VFS_FSETXATTR(fsp, fsp->fd, SAMBA_POSIX_INHERITANCE_EA_NAME, + if (fsp->fh->fd != -1) + ret = SMB_VFS_FSETXATTR(fsp, fsp->fh->fd, SAMBA_POSIX_INHERITANCE_EA_NAME, pai_buf, store_size, 0); else ret = SMB_VFS_SETXATTR(fsp->conn,fsp->fsp_name, SAMBA_POSIX_INHERITANCE_EA_NAME, @@ -445,8 +445,8 @@ static struct pai_val *load_inherited_info(files_struct *fsp) return NULL; do { - if (fsp->fd != -1) - ret = SMB_VFS_FGETXATTR(fsp, fsp->fd, SAMBA_POSIX_INHERITANCE_EA_NAME, + if (fsp->fh->fd != -1) + ret = SMB_VFS_FGETXATTR(fsp, fsp->fh->fd, SAMBA_POSIX_INHERITANCE_EA_NAME, pai_buf, pai_buf_size); else ret = SMB_VFS_GETXATTR(fsp->conn,fsp->fsp_name,SAMBA_POSIX_INHERITANCE_EA_NAME, @@ -2422,7 +2422,7 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau * Finally apply it to the file or directory. */ - if(default_ace || fsp->is_directory || fsp->fd == -1) { + if(default_ace || fsp->is_directory || fsp->fh->fd == -1) { if (SMB_VFS_SYS_ACL_SET_FILE(conn, fsp->fsp_name, the_acl_type, the_acl) == -1) { /* * Some systems allow all the above calls and only fail with no ACL support @@ -2438,7 +2438,7 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau goto done; } } else { - if (SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fd, the_acl) == -1) { + if (SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fh->fd, the_acl) == -1) { /* * Some systems allow all the above calls and only fail with no ACL support * when attempting to apply the acl. HPUX with HFS is an example of this. JRA. @@ -2668,7 +2668,7 @@ size_t get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc) DEBUG(10,("get_nt_acl: called for file %s\n", fsp->fsp_name )); - if(fsp->is_directory || fsp->fd == -1) { + if(fsp->is_directory || fsp->fh->fd == -1) { /* Get the stat struct for the owner info. */ if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0) { @@ -2692,13 +2692,13 @@ size_t get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc) } else { /* Get the stat struct for the owner info. */ - if(SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0) { + if(SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf) != 0) { return 0; } /* * Get the ACL from the fd. */ - posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fd); + posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fh->fd); } DEBUG(5,("get_nt_acl : file ACL %s, directory ACL %s\n", @@ -2981,7 +2981,7 @@ static int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_ become_root(); /* Keep the current file gid the same. */ - ret = SMB_VFS_FCHOWN(fsp, fsp->fd, uid, (gid_t)-1); + ret = SMB_VFS_FCHOWN(fsp, fsp->fh->fd, uid, (gid_t)-1); unbecome_root(); close_file_fchmod(fsp); @@ -3022,11 +3022,11 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) * Get the current state of the file. */ - if(fsp->is_directory || fsp->fd == -1) { + if(fsp->is_directory || fsp->fh->fd == -1) { if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0) return False; } else { - if(SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0) + if(SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf) != 0) return False; } @@ -3081,10 +3081,10 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) int ret; - if(fsp->fd == -1) + if(fsp->fh->fd == -1) ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf); else - ret = SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf); + ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf); if(ret != 0) return False; @@ -3683,8 +3683,8 @@ static BOOL remove_posix_acl(connection_struct *conn, files_struct *fsp, const c } /* Get the current file ACL. */ - if (fsp && fsp->fd != -1) { - file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fd); + if (fsp && 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); } @@ -3767,9 +3767,9 @@ BOOL set_unix_posix_acl(connection_struct *conn, files_struct *fsp, const char * return False; } - if (fsp && fsp->fd != -1) { + if (fsp && fsp->fh->fd != -1) { /* The preferred way - use an open fd. */ - if (SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fd, file_acl) == -1) { + if (SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fh->fd, file_acl) == -1) { DEBUG(5,("set_unix_posix_acl: acl_set_file failed on %s (%s)\n", fname, strerror(errno) )); SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl); diff --git a/source/smbd/reply.c b/source/smbd/reply.c index 312a3ace23c..bb583fb94b8 100644 --- a/source/smbd/reply.c +++ b/source/smbd/reply.c @@ -1275,20 +1275,24 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, { pstring fname; int outsize = 0; - int fmode=0; - int share_mode; + uint32 fattr=0; SMB_OFF_T size = 0; time_t mtime=0; - int rmode=0; + int info; SMB_STRUCT_STAT sbuf; BOOL bad_path = False; files_struct *fsp; int oplock_request = CORE_OPLOCK_REQUEST(inbuf); - uint16 dos_attr = SVAL(inbuf,smb_vwv1); + int deny_mode; + uint32 dos_attr = SVAL(inbuf,smb_vwv1); + uint32 access_mask; + uint32 share_mode; + uint32 create_disposition; + uint32 create_options = 0; NTSTATUS status; START_PROFILE(SMBopen); - share_mode = SVAL(inbuf,smb_vwv0); + deny_mode = SVAL(inbuf,smb_vwv0); srvstr_get_path(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), 0, STR_TERMINATE, &status, False); if (!NT_STATUS_IS_OK(status)) { @@ -1304,8 +1308,20 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); } - fsp = open_file_shared(conn,fname,&sbuf,share_mode,(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), - (uint32)dos_attr, oplock_request,&rmode,NULL); + if (!map_open_params_to_ntcreate(fname, deny_mode, OPENX_FILE_EXISTS_OPEN, + &access_mask, &share_mode, &create_disposition, &create_options)) { + END_PROFILE(SMBopen); + return ERROR_DOS(ERRDOS, ERRbadaccess); + } + + fsp = open_file_ntcreate(conn,fname,&sbuf, + access_mask, + share_mode, + create_disposition, + create_options, + dos_attr, + oplock_request, + &info); if (!fsp) { END_PROFILE(SMBopen); @@ -1317,10 +1333,10 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, } size = sbuf.st_size; - fmode = dos_mode(conn,fname,&sbuf); + fattr = dos_mode(conn,fname,&sbuf); mtime = sbuf.st_mtime; - if (fmode & aDIR) { + if (fattr & aDIR) { DEBUG(3,("attempt to open a directory %s\n",fname)); close_file(fsp,False); END_PROFILE(SMBopen); @@ -1329,19 +1345,22 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, outsize = set_message(outbuf,7,0,True); SSVAL(outbuf,smb_vwv0,fsp->fnum); - SSVAL(outbuf,smb_vwv1,fmode); - if(lp_dos_filetime_resolution(SNUM(conn)) ) + SSVAL(outbuf,smb_vwv1,fattr); + if(lp_dos_filetime_resolution(SNUM(conn)) ) { put_dos_date3(outbuf,smb_vwv2,mtime & ~1); - else + } else { put_dos_date3(outbuf,smb_vwv2,mtime); + } SIVAL(outbuf,smb_vwv4,(uint32)size); - SSVAL(outbuf,smb_vwv6,rmode); + SSVAL(outbuf,smb_vwv6,FILE_WAS_OPENED); - if (oplock_request && lp_fake_oplocks(SNUM(conn))) + if (oplock_request && lp_fake_oplocks(SNUM(conn))) { SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED); + } - if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) + if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) { SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED); + } END_PROFILE(SMBopen); return(outsize); } @@ -1353,21 +1372,22 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize) { pstring fname; - int smb_mode = SVAL(inbuf,smb_vwv3); - int smb_attr = SVAL(inbuf,smb_vwv5); + uint16 open_flags = SVAL(inbuf,smb_vwv2); + int deny_mode = SVAL(inbuf,smb_vwv3); + uint32 smb_attr = SVAL(inbuf,smb_vwv5); /* Breakout the oplock request bits so we can set the reply bits separately. */ BOOL ex_oplock_request = EXTENDED_OPLOCK_REQUEST(inbuf); BOOL core_oplock_request = CORE_OPLOCK_REQUEST(inbuf); BOOL oplock_request = ex_oplock_request | core_oplock_request; #if 0 - int open_flags = SVAL(inbuf,smb_vwv2); int smb_sattr = SVAL(inbuf,smb_vwv4); uint32 smb_time = make_unix_date3(inbuf+smb_vwv6); #endif int smb_ofun = SVAL(inbuf,smb_vwv8); SMB_OFF_T size=0; - int fmode=0,mtime=0,rmode=0; + uint32 fattr=0; + int mtime=0; SMB_STRUCT_STAT sbuf; int smb_action = 0; BOOL bad_path = False; @@ -1375,6 +1395,10 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt NTSTATUS status; SMB_BIG_UINT allocation_size = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv9); ssize_t retval = -1; + uint32 access_mask; + uint32 share_mode; + uint32 create_disposition; + uint32 create_options = 0; START_PROFILE(SMBopenX); @@ -1404,18 +1428,23 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); } - /* Strange open mode mapping. */ - if (smb_ofun == 0) { - if (GET_OPEN_MODE(smb_mode) == DOS_OPEN_EXEC) { - smb_ofun = FILE_EXISTS_FAIL | FILE_CREATE_IF_NOT_EXIST; - } else { - END_PROFILE(SMBopenX); - return ERROR_FORCE_DOS(ERRDOS, ERRbadaccess); - } + if (!map_open_params_to_ntcreate(fname, deny_mode, smb_ofun, + &access_mask, + &share_mode, + &create_disposition, + &create_options)) { + END_PROFILE(SMBopenX); + return ERROR_DOS(ERRDOS, ERRbadaccess); } - fsp = open_file_shared(conn,fname,&sbuf,smb_mode,smb_ofun,(uint32)smb_attr, - oplock_request, &rmode,&smb_action); + fsp = open_file_ntcreate(conn,fname,&sbuf, + access_mask, + share_mode, + create_disposition, + create_options, + smb_attr, + oplock_request, + &smb_action); if (!fsp) { END_PROFILE(SMBopenX); @@ -1446,9 +1475,9 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt size = get_allocation_size(conn,fsp,&sbuf); } - fmode = dos_mode(conn,fname,&sbuf); + fattr = dos_mode(conn,fname,&sbuf); mtime = sbuf.st_mtime; - if (fmode & aDIR) { + if (fattr & aDIR) { close_file(fsp,False); END_PROFILE(SMBopenX); return ERROR_DOS(ERRDOS,ERRnoaccess); @@ -1459,34 +1488,47 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt correct bit for extended oplock reply. */ - if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) + if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) { smb_action |= EXTENDED_OPLOCK_GRANTED; + } - if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) + if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) { smb_action |= EXTENDED_OPLOCK_GRANTED; + } /* If the caller set the core oplock request bit and we granted one (by whatever means) - set the correct bit for core oplock reply. */ - if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) + if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) { SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED); + } - if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) + if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) { SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED); + } - set_message(outbuf,15,0,True); + if (open_flags & EXTENDED_RESPONSE_REQUIRED) { + set_message(outbuf,19,0,True); + } else { + set_message(outbuf,15,0,True); + } SSVAL(outbuf,smb_vwv2,fsp->fnum); - SSVAL(outbuf,smb_vwv3,fmode); - if(lp_dos_filetime_resolution(SNUM(conn)) ) + SSVAL(outbuf,smb_vwv3,fattr); + if(lp_dos_filetime_resolution(SNUM(conn)) ) { put_dos_date3(outbuf,smb_vwv4,mtime & ~1); - else + } else { put_dos_date3(outbuf,smb_vwv4,mtime); + } SIVAL(outbuf,smb_vwv6,(uint32)size); - SSVAL(outbuf,smb_vwv8,rmode); + SSVAL(outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode)); SSVAL(outbuf,smb_vwv11,smb_action); + if (open_flags & EXTENDED_RESPONSE_REQUIRED) { + SIVAL(outbuf, smb_vwv15, STD_RIGHT_ALL_ACCESS); + } + END_PROFILE(SMBopenX); return chain_reply(inbuf,outbuf,length,bufsize); } @@ -1528,18 +1570,21 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, pstring fname; int com; int outsize = 0; - int createmode; - int ofun = 0; + uint32 fattr = SVAL(inbuf,smb_vwv0); BOOL bad_path = False; files_struct *fsp; int oplock_request = CORE_OPLOCK_REQUEST(inbuf); SMB_STRUCT_STAT sbuf; NTSTATUS status; + uint32 access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE; + uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE; + uint32 create_disposition; + uint32 create_options = 0; + START_PROFILE(SMBcreate); com = SVAL(inbuf,smb_com); - createmode = SVAL(inbuf,smb_vwv0); srvstr_get_path(inbuf, fname, smb_buf(inbuf) + 1, sizeof(fname), 0, STR_TERMINATE, &status, False); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBcreate); @@ -1554,20 +1599,27 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND); } - if (createmode & aVOLID) + if (fattr & aVOLID) { DEBUG(0,("Attempt to create file (%s) with volid set - please report this\n",fname)); - + } + if(com == SMBmknew) { /* We should fail if file exists. */ - ofun = FILE_CREATE_IF_NOT_EXIST; + create_disposition = FILE_CREATE; } else { - /* SMBcreate - Create if file doesn't exist, truncate if it does. */ - ofun = FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_TRUNCATE; - } - - /* Open file in dos compatibility share mode. */ - fsp = open_file_shared(conn,fname,&sbuf,SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB), - ofun, (uint32)createmode, oplock_request, NULL, NULL); + /* Create if file doesn't exist, truncate if it does. */ + create_disposition = FILE_OPEN_IF; + } + + /* Open file using ntcreate. */ + fsp = open_file_ntcreate(conn,fname,&sbuf, + access_mask, + share_mode, + create_disposition, + create_options, + fattr, + oplock_request, + NULL); if (!fsp) { END_PROFILE(SMBcreate); @@ -1581,14 +1633,16 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, outsize = set_message(outbuf,1,0,True); SSVAL(outbuf,smb_vwv0,fsp->fnum); - if (oplock_request && lp_fake_oplocks(SNUM(conn))) + if (oplock_request && lp_fake_oplocks(SNUM(conn))) { SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED); + } - if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) + if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) { SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED); + } - DEBUG( 2, ( "new file %s\n", fname ) ); - DEBUG( 3, ( "mknew %s fd=%d dmode=%d\n", fname, fsp->fd, createmode ) ); + DEBUG( 2, ( "reply_mknew: file %s\n", fname ) ); + DEBUG( 3, ( "reply_mknew %s fd=%d dmode=0x%x\n", fname, fsp->fh->fd, (unsigned int)fattr ) ); END_PROFILE(SMBcreate); return(outsize); @@ -1602,7 +1656,7 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, { pstring fname; int outsize = 0; - int createattr; + uint32 fattr = SVAL(inbuf,smb_vwv0); BOOL bad_path = False; files_struct *fsp; int oplock_request = CORE_OPLOCK_REQUEST(inbuf); @@ -1614,7 +1668,6 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, START_PROFILE(SMBctemp); - createattr = SVAL(inbuf,smb_vwv0); srvstr_get_path(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), 0, STR_TERMINATE, &status, False); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBctemp); @@ -1642,12 +1695,15 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, SMB_VFS_STAT(conn,fname,&sbuf); - /* Open file in dos compatibility share mode. */ /* We should fail if file does not exist. */ - fsp = open_file_shared(conn,fname,&sbuf, - SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB), - FILE_EXISTS_OPEN|FILE_FAIL_IF_NOT_EXIST, - (uint32)createattr, oplock_request, NULL, NULL); + fsp = open_file_ntcreate(conn,fname,&sbuf, + FILE_GENERIC_READ | FILE_GENERIC_WRITE, + FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_OPEN, + 0, + fattr, + oplock_request, + NULL); /* close fd from smb_mkstemp() */ close(tmpfd); @@ -1666,10 +1722,11 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, /* the returned filename is relative to the directory */ s = strrchr_m(fname, '/'); - if (!s) + if (!s) { s = fname; - else + } else { s++; + } p = smb_buf(outbuf); #if 0 @@ -1681,15 +1738,17 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, p += namelen; outsize = set_message_end(outbuf, p); - if (oplock_request && lp_fake_oplocks(SNUM(conn))) + if (oplock_request && lp_fake_oplocks(SNUM(conn))) { SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED); + } - if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) + if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) { SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED); + } - DEBUG( 2, ( "created temp file %s\n", fname ) ); - DEBUG( 3, ( "ctemp %s fd=%d umode=%o\n", - fname, fsp->fd, sbuf.st_mode ) ); + DEBUG( 2, ( "reply_ctemp: created temp file %s\n", fname ) ); + DEBUG( 3, ( "reply_ctemp %s fd=%d umode=0%o\n", fname, fsp->fh->fd, + (unsigned int)sbuf.st_mode ) ); END_PROFILE(SMBctemp); return(outsize); @@ -1701,26 +1760,33 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, static NTSTATUS can_rename(connection_struct *conn, char *fname, uint16 dirtype, SMB_STRUCT_STAT *pst) { - int smb_action; - int access_mode; files_struct *fsp; - uint16 fmode; + uint32 fmode; - if (!CAN_WRITE(conn)) + if (!CAN_WRITE(conn)) { return NT_STATUS_MEDIA_WRITE_PROTECTED; + } fmode = dos_mode(conn,fname,pst); - if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM)) + if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM)) { return NT_STATUS_NO_SUCH_FILE; + } - if (S_ISDIR(pst->st_mode)) + if (S_ISDIR(pst->st_mode)) { return NT_STATUS_OK; + } /* We need a better way to return NT status codes from open... */ set_saved_error_triple(0, 0, NT_STATUS_OK); - fsp = open_file_shared1(conn, fname, pst, DELETE_ACCESS, SET_DENY_MODE(DENY_ALL), - (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &smb_action); + fsp = open_file_ntcreate(conn, fname, pst, + DELETE_ACCESS, + FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_OPEN, + 0, + FILE_ATTRIBUTE_NORMAL, + 0, + NULL); if (!fsp) { NTSTATUS ret; @@ -1742,43 +1808,46 @@ static NTSTATUS can_rename(connection_struct *conn, char *fname, uint16 dirtype, NTSTATUS can_delete(connection_struct *conn, char *fname, uint32 dirtype, BOOL bad_path, BOOL check_is_at_open) { SMB_STRUCT_STAT sbuf; - uint32 fmode; - int smb_action; - int access_mode; + uint32 fattr; files_struct *fsp; - DEBUG(10,("can_delete: %s, dirtype = %d\n", - fname, dirtype )); + DEBUG(10,("can_delete: %s, dirtype = %d\n", fname, dirtype )); - if (!CAN_WRITE(conn)) + if (!CAN_WRITE(conn)) { return NT_STATUS_MEDIA_WRITE_PROTECTED; + } if (SMB_VFS_LSTAT(conn,fname,&sbuf) != 0) { if(errno == ENOENT) { - if (bad_path) + if (bad_path) { return NT_STATUS_OBJECT_PATH_NOT_FOUND; - else + } else { return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } } return map_nt_error_from_unix(errno); } - fmode = dos_mode(conn,fname,&sbuf); + fattr = dos_mode(conn,fname,&sbuf); /* Can't delete a directory. */ - if (fmode & aDIR) + if (fattr & aDIR) { return NT_STATUS_FILE_IS_A_DIRECTORY; + } + #if 0 /* JRATEST */ else if (dirtype & aDIR) /* Asked for a directory and it isn't. */ return NT_STATUS_OBJECT_NAME_INVALID; #endif /* JRATEST */ if (!lp_delete_readonly(SNUM(conn))) { - if (fmode & aRONLY) + if (fattr & aRONLY) { return NT_STATUS_CANNOT_DELETE; + } } - if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM)) + if ((fattr & ~dirtype) & (aHIDDEN | aSYSTEM)) { return NT_STATUS_NO_SUCH_FILE; + } if (check_is_at_open) { if (!can_delete_file_in_directory(conn, fname)) { @@ -1791,8 +1860,14 @@ NTSTATUS can_delete(connection_struct *conn, char *fname, uint32 dirtype, BOOL b /* We need a better way to return NT status codes from open... */ set_saved_error_triple(0, 0, NT_STATUS_OK); - fsp = open_file_shared1(conn, fname, &sbuf, DELETE_ACCESS, SET_DENY_MODE(DENY_ALL), - (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, 0, &access_mode, &smb_action); + fsp = open_file_ntcreate(conn, fname, &sbuf, + DELETE_ACCESS, + FILE_SHARE_NONE, + FILE_OPEN, + 0, + FILE_ATTRIBUTE_NORMAL, + 0, + NULL); if (!fsp) { NTSTATUS ret; @@ -2058,7 +2133,7 @@ void send_file_readbraw(connection_struct *conn, files_struct *fsp, SMB_OFF_T st header.length = 4; header.free = NULL; - if ( SMB_VFS_SENDFILE( smbd_server_fd(), fsp, fsp->fd, &header, startpos, nread) == -1) { + if ( SMB_VFS_SENDFILE( smbd_server_fd(), fsp, fsp->fh->fd, &header, startpos, nread) == -1) { /* Returning ENOSYS means no data at all was sent. Do this as a normal read. */ if (errno == ENOSYS) { goto normal_readbraw; @@ -2205,7 +2280,7 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s SMB_STRUCT_STAT st; SMB_OFF_T size = 0; - if (SMB_VFS_FSTAT(fsp,fsp->fd,&st) == 0) { + if (SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st) == 0) { size = st.st_size; } @@ -2251,7 +2326,9 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length START_PROFILE(SMBlockread); CHECK_FSP(fsp,conn); - CHECK_READ(fsp); + if (!CHECK_READ(fsp,inbuf)) { + return(ERROR_DOS(ERRDOS,ERRbadaccess)); + } release_level_2_oplocks_on_change(fsp); @@ -2345,7 +2422,9 @@ int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int size, int START_PROFILE(SMBread); CHECK_FSP(fsp,conn); - CHECK_READ(fsp); + if (!CHECK_READ(fsp,inbuf)) { + return(ERROR_DOS(ERRDOS,ERRbadaccess)); + } numtoread = SVAL(inbuf,smb_vwv1); startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2); @@ -2413,7 +2492,7 @@ int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length SMB_STRUCT_STAT sbuf; DATA_BLOB header; - if(SMB_VFS_FSTAT(fsp,fsp->fd, &sbuf) == -1) + if(SMB_VFS_FSTAT(fsp,fsp->fh->fd, &sbuf) == -1) return(UNIXERROR(ERRDOS,ERRnoaccess)); if (startpos > sbuf.st_size) @@ -2442,7 +2521,7 @@ int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length header.length = data - outbuf; header.free = NULL; - if ((nread = SMB_VFS_SENDFILE( smbd_server_fd(), fsp, fsp->fd, &header, startpos, smb_maxcnt)) == -1) { + if ((nread = SMB_VFS_SENDFILE( smbd_server_fd(), fsp, fsp->fh->fd, &header, startpos, smb_maxcnt)) == -1) { /* Returning ENOSYS means no data at all was sent. Do this as a normal read. */ if (errno == ENOSYS) { goto normal_read; @@ -2530,7 +2609,9 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt } CHECK_FSP(fsp,conn); - CHECK_READ(fsp); + if (!CHECK_READ(fsp,inbuf)) { + return(ERROR_DOS(ERRDOS,ERRbadaccess)); + } set_message(outbuf,12,0,True); @@ -2610,7 +2691,9 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size, } CHECK_FSP(fsp,conn); - CHECK_WRITE(fsp); + if (!CHECK_WRITE(fsp)) { + return(ERROR_DOS(ERRDOS,ERRbadaccess)); + } tcount = IVAL(inbuf,smb_vwv1); startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3); @@ -2744,7 +2827,9 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, START_PROFILE(SMBwriteunlock); CHECK_FSP(fsp,conn); - CHECK_WRITE(fsp); + if (!CHECK_WRITE(fsp)) { + return(ERROR_DOS(ERRDOS,ERRbadaccess)); + } numtowrite = SVAL(inbuf,smb_vwv1); startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2); @@ -2758,10 +2843,11 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, /* The special X/Open SMB protocol handling of zero length writes is *NOT* done for this call */ - if(numtowrite == 0) + if(numtowrite == 0) { nwritten = 0; - else + } else { nwritten = write_file(fsp,data,startpos,numtowrite); + } if (lp_syncalways(SNUM(conn))) sync_file(conn,fsp); @@ -2815,7 +2901,9 @@ int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int size,int d } CHECK_FSP(fsp,conn); - CHECK_WRITE(fsp); + if (!CHECK_WRITE(fsp)) { + return(ERROR_DOS(ERRDOS,ERRbadaccess)); + } numtowrite = SVAL(inbuf,smb_vwv1); startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2); @@ -2896,7 +2984,9 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng } CHECK_FSP(fsp,conn); - CHECK_WRITE(fsp); + if (!CHECK_WRITE(fsp)) { + return(ERROR_DOS(ERRDOS,ERRbadaccess)); + } set_message(outbuf,6,0,True); @@ -3010,7 +3100,7 @@ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int break; case 1: umode = SEEK_CUR; - res = fsp->pos + startpos; + res = fsp->fh->pos + startpos; break; case 2: umode = SEEK_END; @@ -3022,19 +3112,19 @@ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int } if (umode == SEEK_END) { - if((res = SMB_VFS_LSEEK(fsp,fsp->fd,startpos,umode)) == -1) { + if((res = SMB_VFS_LSEEK(fsp,fsp->fh->fd,startpos,umode)) == -1) { if(errno == EINVAL) { SMB_OFF_T current_pos = startpos; SMB_STRUCT_STAT sbuf; - if(SMB_VFS_FSTAT(fsp,fsp->fd, &sbuf) == -1) { + if(SMB_VFS_FSTAT(fsp,fsp->fh->fd, &sbuf) == -1) { END_PROFILE(SMBlseek); return(UNIXERROR(ERRDOS,ERRnoaccess)); } current_pos += sbuf.st_size; if(current_pos < 0) - res = SMB_VFS_LSEEK(fsp,fsp->fd,0,SEEK_SET); + res = SMB_VFS_LSEEK(fsp,fsp->fh->fd,0,SEEK_SET); } } @@ -3044,7 +3134,7 @@ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int } } - fsp->pos = res; + fsp->fh->pos = res; outsize = set_message(outbuf,2,0,True); SIVAL(outbuf,smb_vwv0,res); @@ -3150,7 +3240,7 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size, pstrcpy( file_name, fsp->fsp_name); DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n", - fsp->fd, fsp->fnum, + fsp->fh->fd, fsp->fnum, conn->num_files_open)); /* @@ -3201,7 +3291,9 @@ int reply_writeclose(connection_struct *conn, START_PROFILE(SMBwriteclose); CHECK_FSP(fsp,conn); - CHECK_WRITE(fsp); + if (!CHECK_WRITE(fsp)) { + return(ERROR_DOS(ERRDOS,ERRbadaccess)); + } numtowrite = SVAL(inbuf,smb_vwv1); startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2); @@ -3276,7 +3368,7 @@ int reply_lock(connection_struct *conn, offset = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv3); DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n", - fsp->fd, fsp->fnum, (double)offset, (double)count)); + fsp->fh->fd, fsp->fnum, (double)offset, (double)count)); status = do_lock_spin(fsp, conn, SVAL(inbuf,smb_pid), count, offset, WRITE_LOCK, &my_lock_ctx); if (NT_STATUS_V(status)) { @@ -3327,7 +3419,7 @@ int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size, } DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n", - fsp->fd, fsp->fnum, (double)offset, (double)count ) ); + fsp->fh->fd, fsp->fnum, (double)offset, (double)count ) ); END_PROFILE(SMBunlock); return(outsize); @@ -3437,7 +3529,7 @@ int reply_printopen(connection_struct *conn, SSVAL(outbuf,smb_vwv0,fsp->fnum); DEBUG(3,("openprint fd=%d fnum=%d\n", - fsp->fd, fsp->fnum)); + fsp->fh->fd, fsp->fnum)); END_PROFILE(SMBsplopen); return(outsize); @@ -3463,7 +3555,7 @@ int reply_printclose(connection_struct *conn, } DEBUG(3,("printclose fd=%d fnum=%d\n", - fsp->fd,fsp->fnum)); + fsp->fh->fd,fsp->fnum)); close_err = close_file(fsp,True); @@ -3567,7 +3659,9 @@ int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_ } CHECK_FSP(fsp,conn); - CHECK_WRITE(fsp); + if (!CHECK_WRITE(fsp)) { + return(ERROR_DOS(ERRDOS,ERRbadaccess)); + } numtowrite = SVAL(smb_buf(inbuf),1); data = smb_buf(inbuf) + 3; @@ -4484,45 +4578,66 @@ int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun, int count,BOOL target_is_directory, int *err_ret) { - int Access,action; SMB_STRUCT_STAT src_sbuf, sbuf2; SMB_OFF_T ret=-1; files_struct *fsp1,*fsp2; pstring dest; uint32 dosattrs; + uint32 new_create_disposition; *err_ret = 0; pstrcpy(dest,dest1); if (target_is_directory) { char *p = strrchr_m(src,'/'); - if (p) + if (p) { p++; - else + } else { p = src; + } pstrcat(dest,"/"); pstrcat(dest,p); } - if (!vfs_file_exist(conn,src,&src_sbuf)) + if (!vfs_file_exist(conn,src,&src_sbuf)) { return(False); + } + + if (!target_is_directory && count) { + new_create_disposition = FILE_OPEN; + } else { + if (!map_open_params_to_ntcreate(dest1,0,ofun, + NULL, NULL, &new_create_disposition, NULL)) { + return(False); + } + } - fsp1 = open_file_shared(conn,src,&src_sbuf,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY), - (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),FILE_ATTRIBUTE_NORMAL,INTERNAL_OPEN_ONLY, - &Access,&action); + fsp1 = open_file_ntcreate(conn,src,&src_sbuf, + FILE_GENERIC_READ, + FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_OPEN, + 0, + FILE_ATTRIBUTE_NORMAL, + INTERNAL_OPEN_ONLY, + NULL); - if (!fsp1) + if (!fsp1) { return(False); - - if (!target_is_directory && count) - ofun = FILE_EXISTS_OPEN; + } dosattrs = dos_mode(conn, src, &src_sbuf); - if (SMB_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), - ofun,dosattrs,INTERNAL_OPEN_ONLY,&Access,&action); + fsp2 = open_file_ntcreate(conn,dest,&sbuf2, + FILE_GENERIC_WRITE, + FILE_SHARE_READ|FILE_SHARE_WRITE, + new_create_disposition, + 0, + dosattrs, + INTERNAL_OPEN_ONLY, + NULL); if (!fsp2) { close_file(fsp1,False); @@ -4530,7 +4645,7 @@ BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun, } if ((ofun&3) == 1) { - if(SMB_VFS_LSEEK(fsp2,fsp2->fd,0,SEEK_END) == -1) { + if(SMB_VFS_LSEEK(fsp2,fsp2->fh->fd,0,SEEK_END) == -1) { DEBUG(0,("copy_file: error - vfs lseek returned error %s\n", strerror(errno) )); /* * Stop the copy from occurring. @@ -4540,8 +4655,9 @@ BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun, } } - if (src_sbuf.st_size) + if (src_sbuf.st_size) { ret = vfs_transfer_file(fsp1, fsp2, src_sbuf.st_size); + } close_file(fsp1,False); @@ -4955,7 +5071,7 @@ int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length, /* we don't support these - and CANCEL_LOCK makes w2k and XP reboot so I don't really want to be compatible! (tridge) */ - return ERROR_NT(NT_STATUS_UNSUCCESSFUL); + return ERROR_DOS(ERRDOS, ERRnoatomiclocks); } if (locktype & LOCKING_ANDX_CANCEL_LOCK) { @@ -5158,7 +5274,9 @@ int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length, outsize = set_message(outbuf,8,0,True); CHECK_FSP(fsp,conn); - CHECK_READ(fsp); + if (!CHECK_READ(fsp,inbuf)) { + return(ERROR_DOS(ERRDOS,ERRbadaccess)); + } startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv1); maxcount = SVAL(inbuf,smb_vwv3); @@ -5286,7 +5404,9 @@ int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size, START_PROFILE(SMBwriteBmpx); CHECK_FSP(fsp,conn); - CHECK_WRITE(fsp); + if (!CHECK_WRITE(fsp)) { + return(ERROR_DOS(ERRDOS,ERRbadaccess)); + } if (HAS_CACHED_ERROR(fsp)) { return(CACHED_ERROR(fsp)); } @@ -5390,7 +5510,9 @@ int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_siz START_PROFILE(SMBwriteBs); CHECK_FSP(fsp,conn); - CHECK_WRITE(fsp); + if (!CHECK_WRITE(fsp)) { + return(ERROR_DOS(ERRDOS,ERRbadaccess)); + } tcount = SVAL(inbuf,smb_vwv1); startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2); diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c index d4daf1fd690..602656080ed 100644 --- a/source/smbd/trans2.c +++ b/source/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)); + } } /* diff --git a/source/smbd/vfs-wrap.c b/source/smbd/vfs-wrap.c index 1d205e59779..39ac402f346 100644 --- a/source/smbd/vfs-wrap.c +++ b/source/smbd/vfs-wrap.c @@ -226,7 +226,7 @@ ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, int fd, void if (result == -1 && errno == ESPIPE) { /* Maintain the fiction that pipes can be seeked (sought?) on. */ result = SMB_VFS_READ(fsp, fd, data, n); - fsp->pos = 0; + fsp->fh->pos = 0; } #else /* HAVE_PREAD */ @@ -237,7 +237,7 @@ ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, int fd, void if (curr == -1 && errno == ESPIPE) { /* Maintain the fiction that pipes can be seeked (sought?) on. */ result = SMB_VFS_READ(fsp, fd, data, n); - fsp->pos = 0; + fsp->fh->pos = 0; return result; } @@ -660,7 +660,7 @@ static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fs SMB_OFF_T retlen; SMB_OFF_T current_len_to_write = MIN(sizeof(zero_space),space_to_write); - retlen = SMB_VFS_WRITE(fsp,fsp->fd,(char *)zero_space,current_len_to_write); + retlen = SMB_VFS_WRITE(fsp,fsp->fh->fd,(char *)zero_space,current_len_to_write); if (retlen <= 0) return -1; diff --git a/source/smbd/vfs.c b/source/smbd/vfs.c index 11adfed6946..67970f203ac 100644 --- a/source/smbd/vfs.c +++ b/source/smbd/vfs.c @@ -430,7 +430,7 @@ ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count) while (total < byte_count) { - ssize_t ret = SMB_VFS_READ(fsp, fsp->fd, buf + total, + ssize_t ret = SMB_VFS_READ(fsp, fsp->fh->fd, buf + total, byte_count - total); if (ret == 0) return total; @@ -452,7 +452,7 @@ ssize_t vfs_pread_data(files_struct *fsp, char *buf, while (total < byte_count) { - ssize_t ret = SMB_VFS_PREAD(fsp, fsp->fd, buf + total, + ssize_t ret = SMB_VFS_PREAD(fsp, fsp->fh->fd, buf + total, byte_count - total, offset + total); if (ret == 0) return total; @@ -477,7 +477,7 @@ ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N) ssize_t ret; while (total < N) { - ret = SMB_VFS_WRITE(fsp,fsp->fd,buffer + total,N - total); + ret = SMB_VFS_WRITE(fsp,fsp->fh->fd,buffer + total,N - total); if (ret == -1) return -1; @@ -496,7 +496,7 @@ ssize_t vfs_pwrite_data(files_struct *fsp,const char *buffer, ssize_t ret; while (total < N) { - ret = SMB_VFS_PWRITE(fsp, fsp->fd, buffer + total, + ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, buffer + total, N - total, offset + total); if (ret == -1) @@ -535,7 +535,7 @@ int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len) return -1; } - ret = SMB_VFS_FSTAT(fsp,fsp->fd,&st); + ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st); if (ret == -1) return ret; @@ -549,7 +549,7 @@ int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len) fsp->fsp_name, (double)st.st_size )); flush_write_cache(fsp, SIZECHANGE_FLUSH); - if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fd, (SMB_OFF_T)len)) != -1) { + if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, (SMB_OFF_T)len)) != -1) { set_filelen_write_cache(fsp, len); } return ret; @@ -591,7 +591,7 @@ int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len) release_level_2_oplocks_on_change(fsp); DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len)); flush_write_cache(fsp, SIZECHANGE_FLUSH); - if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fd, len)) != -1) + if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, len)) != -1) set_filelen_write_cache(fsp, len); return ret; @@ -617,7 +617,7 @@ int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len) ssize_t pwrite_ret; release_level_2_oplocks_on_change(fsp); - ret = SMB_VFS_FSTAT(fsp,fsp->fd,&st); + ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st); if (ret == -1) { return ret; } @@ -646,7 +646,7 @@ int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len) while (total < num_to_write) { size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (num_to_write - total)); - pwrite_ret = SMB_VFS_PWRITE(fsp, fsp->fd, sparse_buf, curr_write_size, offset + total); + pwrite_ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, sparse_buf, curr_write_size, offset + total); if (pwrite_ret == -1) { DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file %s failed with error %s\n", fsp->fsp_name, strerror(errno) )); @@ -685,7 +685,7 @@ SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n) in_fsp = in; out_fsp = out; - return transfer_file_internal(in_fsp->fd, out_fsp->fd, n, read_fn, write_fn); + return transfer_file_internal(in_fsp->fh->fd, out_fsp->fh->fd, n, read_fn, write_fn); } /******************************************************************* diff --git a/source/torture/cmd_vfs.c b/source/torture/cmd_vfs.c index 2c977485449..974d3b8feed 100644 --- a/source/torture/cmd_vfs.c +++ b/source/torture/cmd_vfs.c @@ -286,7 +286,7 @@ static NTSTATUS cmd_open(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, c vfs->files[fd] = SMB_MALLOC_P(struct files_struct); vfs->files[fd]->fsp_name = SMB_STRDUP(argv[1]); - vfs->files[fd]->fd = fd; + vfs->files[fd]->fh->fd = fd; vfs->files[fd]->conn = vfs->conn; printf("open: fd=%d\n", fd); return NT_STATUS_OK; diff --git a/source/utils/status.c b/source/utils/status.c index 75e7cb3de71..f3c88616662 100644 --- a/source/utils/status.c +++ b/source/utils/status.c @@ -111,37 +111,47 @@ static void print_share_mode(share_mode_entry *e, char *fname) count++; if (Ucrit_checkPid(e->pid)) { - d_printf("%-5d ",(int)e->pid); - switch (GET_DENY_MODE(e->share_mode)) { - case DENY_NONE: d_printf("DENY_NONE "); break; - case DENY_ALL: d_printf("DENY_ALL "); break; - case DENY_DOS: d_printf("DENY_DOS "); break; - case DENY_READ: d_printf("DENY_READ "); break; - case DENY_WRITE:printf("DENY_WRITE "); break; - case DENY_FCB: d_printf("DENY_FCB "); break; - } - d_printf("0x%-8x ",(unsigned int)e->desired_access); - switch (e->share_mode&0xF) { - case 0: d_printf("RDONLY "); break; - case 1: d_printf("WRONLY "); break; - case 2: d_printf("RDWR "); break; - } - - if((e->op_type & - (EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) == - (EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) - d_printf("EXCLUSIVE+BATCH "); - else if (e->op_type & EXCLUSIVE_OPLOCK) - d_printf("EXCLUSIVE "); - else if (e->op_type & BATCH_OPLOCK) - d_printf("BATCH "); - else if (e->op_type & LEVEL_II_OPLOCK) - d_printf("LEVEL_II "); - else - d_printf("NONE "); - - d_printf(" %s %s",fname, - asctime(LocalTime((time_t *)&e->time.tv_sec))); + d_printf("%-5d ",(int)e->pid); + switch (map_share_mode_to_deny_mode(e->share_access, + e->private_options)) { + case DENY_NONE: d_printf("DENY_NONE "); break; + case DENY_ALL: d_printf("DENY_ALL "); break; + case DENY_DOS: d_printf("DENY_DOS "); break; + case DENY_READ: d_printf("DENY_READ "); break; + case DENY_WRITE:printf("DENY_WRITE "); break; + case DENY_FCB: d_printf("DENY_FCB "); break; + default: { + d_printf("unknown-please report ! " + "e->share_access = 0x%x, " + "e->private_options = 0x%x\n", + (unsigned int)e->share_access, + (unsigned int)e->private_options ); + break; + } + } + d_printf("0x%-8x ",(unsigned int)e->access_mask); + if (e->access_mask & (FILE_READ_DATA|FILE_WRITE_DATA)) { + d_printf("RDWR "); + } else if (e->access_mask & FILE_WRITE_DATA) { + d_printf("WRONLY "); + } else { + d_printf("RDONLY "); + } + + if((e->op_type & (EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) == + (EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) { + d_printf("EXCLUSIVE+BATCH "); + } else if (e->op_type & EXCLUSIVE_OPLOCK) { + d_printf("EXCLUSIVE "); + } else if (e->op_type & BATCH_OPLOCK) { + d_printf("BATCH "); + } else if (e->op_type & LEVEL_II_OPLOCK) { + d_printf("LEVEL_II "); + } else { + d_printf("NONE "); + } + + d_printf(" %s %s",fname, asctime(LocalTime((time_t *)&e->time.tv_sec))); } } diff --git a/source/web/cgi.c b/source/web/cgi.c index 5d52ad62793..6c9cfce13cd 100644 --- a/source/web/cgi.c +++ b/source/web/cgi.c @@ -457,6 +457,10 @@ static void cgi_download(char *file) printf("Content-Type: image/gif\r\n"); } else if (strcmp(p,".jpg")==0) { printf("Content-Type: image/jpeg\r\n"); + } else if (strcmp(p,".png")==0) { + printf("Content-Type: image/png\r\n"); + } else if (strcmp(p,".css")==0) { + printf("Content-Type: text/css\r\n"); } else if (strcmp(p,".txt")==0) { printf("Content-Type: text/plain\r\n"); } else { diff --git a/source/web/statuspage.c b/source/web/statuspage.c index 57b5d0f7b73..871e07b5d06 100644 --- a/source/web/statuspage.c +++ b/source/web/statuspage.c @@ -108,23 +108,28 @@ static char *tstring(time_t t) static void print_share_mode(share_mode_entry *e, char *fname) { char *utf8_fname; + int deny_mode = map_share_mode_to_deny_mode(e->share_access, + e->private_options); printf("<tr><td>%s</td>",_(mapPid2Machine(e->pid))); printf("<td>"); - switch ((e->share_mode>>4)&0xF) { + switch ((deny_mode>>4)&0xF) { case DENY_NONE: printf("DENY_NONE"); break; case DENY_ALL: printf("DENY_ALL "); break; case DENY_DOS: printf("DENY_DOS "); break; + case DENY_FCB: printf("DENY_FCB "); break; case DENY_READ: printf("DENY_READ "); break; case DENY_WRITE:printf("DENY_WRITE "); break; } printf("</td>"); printf("<td>"); - switch (e->share_mode&0xF) { - case 0: printf("%s", _("RDONLY ")); break; - case 1: printf("%s", _("WRONLY ")); break; - case 2: printf("%s", _("RDWR ")); break; + if (e->access_mask & (FILE_READ_DATA|FILE_WRITE_DATA)) { + printf("%s", _("RDWR ")); + } else if (e->access_mask & FILE_WRITE_DATA) { + printf("%s", _("WRONLY ")); + } else { + printf("%s", _("RDONLY ")); } printf("</td>"); |