diff options
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>"); |