diff options
Diffstat (limited to 'source3/smbd')
-rw-r--r-- | source3/smbd/dosmode.c | 93 | ||||
-rw-r--r-- | source3/smbd/fileio.c | 20 | ||||
-rw-r--r-- | source3/smbd/nttrans.c | 14 | ||||
-rw-r--r-- | source3/smbd/open.c | 68 | ||||
-rw-r--r-- | source3/smbd/reply.c | 2 | ||||
-rw-r--r-- | source3/smbd/trans2.c | 17 |
6 files changed, 115 insertions, 99 deletions
diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c index 03ac0897ef..2006b75d52 100644 --- a/source3/smbd/dosmode.c +++ b/source3/smbd/dosmode.c @@ -429,15 +429,14 @@ static bool get_stat_dos_flags(connection_struct *conn, ****************************************************************************/ static bool set_stat_dos_flags(connection_struct *conn, - const char *fname, - SMB_STRUCT_STAT *sbuf, - uint32_t dosmode, - bool *attributes_changed) + const struct smb_filename *smb_fname, + uint32_t dosmode, + bool *attributes_changed) { uint32_t new_flags = 0; int error = 0; - SMB_ASSERT(sbuf && VALID_STAT(*sbuf)); + SMB_ASSERT(VALID_STAT(smb_fname->st)); SMB_ASSERT(attributes_changed); *attributes_changed = false; @@ -446,23 +445,25 @@ static bool set_stat_dos_flags(connection_struct *conn, return false; } - DEBUG(5, ("Setting stat dos attributes for %s.\n", fname)); + DEBUG(5, ("Setting stat dos attributes for %s.\n", + smb_fname_str_dbg(smb_fname))); - new_flags = (sbuf->st_ex_flags & ~UF_DOS_FLAGS) | + new_flags = (smb_fname->st.st_ex_flags & ~UF_DOS_FLAGS) | dos_attributes_to_stat_dos_flags(dosmode); /* Return early if no flags changed. */ - if (new_flags == sbuf->st_ex_flags) + if (new_flags == smb_fname->st.st_ex_flags) return true; DEBUG(5, ("Setting stat dos attributes=0x%x, prev=0x%x\n", new_flags, - sbuf->st_ex_flags)); + smb_fname->st.st_ex_flags)); /* Set new flags with chflags. */ - error = SMB_VFS_CHFLAGS(conn, fname, new_flags); + error = SMB_VFS_CHFLAGS(conn, smb_fname->base_name, new_flags); if (error) { DEBUG(0, ("Failed setting new stat dos attributes (0x%x) on " - "file %s! errno=%d\n", new_flags, fname, errno)); + "file %s! errno=%d\n", new_flags, + smb_fname_str_dbg(smb_fname), errno)); return false; } @@ -545,52 +546,56 @@ uint32 dos_mode(connection_struct *conn, const char *path, const SMB_STRUCT_STAT chmod a file - but preserve some bits. ********************************************************************/ -int file_set_dosmode(connection_struct *conn, const char *fname, - uint32 dosmode, SMB_STRUCT_STAT *st, - const char *parent_dir, - bool newfile) +int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname, + uint32 dosmode, const char *parent_dir, bool newfile) { - SMB_STRUCT_STAT st1; int mask=0; mode_t tmp; mode_t unixmode; int ret = -1, lret = -1; uint32_t old_mode; + char *fname = NULL; + NTSTATUS status; /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */ dosmode &= (SAMBA_ATTRIBUTES_MASK | FILE_ATTRIBUTE_OFFLINE); - DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n", dosmode, fname)); + DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n", + dosmode, smb_fname_str_dbg(smb_fname))); - if (st == NULL) { - SET_STAT_INVALID(st1); - st = &st1; - } - - if (!VALID_STAT(*st)) { - if (vfs_stat_smb_fname(conn,fname,st)) + if (!VALID_STAT(smb_fname->st)) { + if (SMB_VFS_STAT(conn, smb_fname)) return(-1); } - unixmode = st->st_ex_mode; + unixmode = smb_fname->st.st_ex_mode; - get_acl_group_bits(conn, fname, &st->st_ex_mode); + get_acl_group_bits(conn, smb_fname->base_name, + &smb_fname->st.st_ex_mode); - if (S_ISDIR(st->st_ex_mode)) + if (S_ISDIR(smb_fname->st.st_ex_mode)) dosmode |= aDIR; else dosmode &= ~aDIR; - old_mode = dos_mode(conn,fname,st); + status = get_full_smb_filename(talloc_tos(), smb_fname, &fname); + if (!NT_STATUS_IS_OK(status)) { + errno = map_errno_from_nt_status(status); + return -1; + } + + old_mode = dos_mode(conn, fname, &smb_fname->st); if (dosmode & FILE_ATTRIBUTE_OFFLINE) { if (!(old_mode & FILE_ATTRIBUTE_OFFLINE)) { lret = SMB_VFS_SET_OFFLINE(conn, fname); if (lret == -1) { - DEBUG(0, ("set_dos_mode: client has asked to set " - "FILE_ATTRIBUTE_OFFLINE to %s/%s but there was " - "an error while setting it or it is not supported.\n", - parent_dir, fname)); + DEBUG(0, ("set_dos_mode: client has asked to " + "set FILE_ATTRIBUTE_OFFLINE to " + "%s/%s but there was an error while " + "setting it or it is not " + "supported.\n", parent_dir, + smb_fname_str_dbg(smb_fname))); } } } @@ -599,7 +604,7 @@ int file_set_dosmode(connection_struct *conn, const char *fname, old_mode &= ~FILE_ATTRIBUTE_OFFLINE; if (old_mode == dosmode) { - st->st_ex_mode = unixmode; + smb_fname->st.st_ex_mode = unixmode; return(0); } @@ -607,26 +612,26 @@ int file_set_dosmode(connection_struct *conn, const char *fname, { bool attributes_changed; - if (set_stat_dos_flags(conn, fname, st, dosmode, + if (set_stat_dos_flags(conn, smb_fname, dosmode, &attributes_changed)) { if (!newfile && attributes_changed) { notify_fname(conn, NOTIFY_ACTION_MODIFIED, FILE_NOTIFY_CHANGE_ATTRIBUTES, fname); } - st->st_ex_mode = unixmode; + smb_fname->st.st_ex_mode = unixmode; return 0; } } #endif /* Store the DOS attributes in an EA by preference. */ - if (set_ea_dos_attribute(conn, fname, st, dosmode)) { + if (set_ea_dos_attribute(conn, fname, &smb_fname->st, dosmode)) { if (!newfile) { notify_fname(conn, NOTIFY_ACTION_MODIFIED, FILE_NOTIFY_CHANGE_ATTRIBUTES, fname); } - st->st_ex_mode = unixmode; + smb_fname->st.st_ex_mode = unixmode; return 0; } @@ -648,10 +653,10 @@ int file_set_dosmode(connection_struct *conn, const char *fname, if (!MAP_HIDDEN(conn)) mask |= S_IXOTH; - unixmode |= (st->st_ex_mode & mask); + unixmode |= (smb_fname->st.st_ex_mode & mask); /* if we previously had any r bits set then leave them alone */ - if ((tmp = st->st_ex_mode & (S_IRUSR|S_IRGRP|S_IROTH))) { + if ((tmp = smb_fname->st.st_ex_mode & (S_IRUSR|S_IRGRP|S_IROTH))) { unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH); unixmode |= tmp; } @@ -659,7 +664,7 @@ int file_set_dosmode(connection_struct *conn, const char *fname, /* if we previously had any w bits set then leave them alone whilst adding in the new w bits, if the new mode is not rdonly */ if (!IS_DOS_READONLY(dosmode)) { - unixmode |= (st->st_ex_mode & (S_IWUSR|S_IWGRP|S_IWOTH)); + unixmode |= (smb_fname->st.st_ex_mode & (S_IWUSR|S_IWGRP|S_IWOTH)); } ret = SMB_VFS_CHMOD(conn, fname, unixmode); @@ -668,7 +673,7 @@ int file_set_dosmode(connection_struct *conn, const char *fname, notify_fname(conn, NOTIFY_ACTION_MODIFIED, FILE_NOTIFY_CHANGE_ATTRIBUTES, fname); } - st->st_ex_mode = unixmode; + smb_fname->st.st_ex_mode = unixmode; return 0; } @@ -693,8 +698,8 @@ int file_set_dosmode(connection_struct *conn, const char *fname, * break batch oplocks open by others. JRA. */ files_struct *fsp; - if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, fname, st, - &fsp))) + if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, fname, + &smb_fname->st, &fsp))) return -1; become_root(); ret = SMB_VFS_FCHMOD(fsp, unixmode); @@ -705,7 +710,7 @@ int file_set_dosmode(connection_struct *conn, const char *fname, FILE_NOTIFY_CHANGE_ATTRIBUTES, fname); } if (ret == 0) { - st->st_ex_mode = unixmode; + smb_fname->st.st_ex_mode = unixmode; } } diff --git a/source3/smbd/fileio.c b/source3/smbd/fileio.c index 5cc3d4b88b..caaebf6217 100644 --- a/source3/smbd/fileio.c +++ b/source3/smbd/fileio.c @@ -294,10 +294,22 @@ ssize_t write_file(struct smb_request *req, 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, - NULL, - false); + struct smb_filename *smb_fname = NULL; + NTSTATUS status; + + status = create_synthetic_smb_fname_split( + talloc_tos(), fsp->fsp_name, &st, + &smb_fname); + if (!NT_STATUS_IS_OK(status)) { + errno = + map_errno_from_nt_status(status); + return -1; + } + + file_set_dosmode(fsp->conn, smb_fname, + dosmode | aARCH, NULL, false); + st = smb_fname->st; + TALLOC_FREE(smb_fname); } /* diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index add0b40f2e..b970ffc05e 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -1219,7 +1219,6 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx, uint32 attrs) { char *oldname = NULL; - char *newname = NULL; files_struct *fsp1,*fsp2; uint32 fattr; int info; @@ -1328,20 +1327,15 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx, status = close_file(NULL, fsp2, NORMAL_CLOSE); - status = get_full_smb_filename(ctx, smb_fname_dst, &newname); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - /* Grrr. We have to do this as open_file_ntcreate adds aARCH when it creates the file. This isn't the correct thing to do in the copy case. JRA */ - if (!parent_dirname(talloc_tos(), newname, &parent, NULL)) { + if (!parent_dirname(talloc_tos(), smb_fname_dst->base_name, &parent, + NULL)) { status = NT_STATUS_NO_MEMORY; goto out; } - file_set_dosmode(conn, newname, fattr, &smb_fname_dst->st, parent, - false); + file_set_dosmode(conn, smb_fname_dst, fattr, parent, false); TALLOC_FREE(parent); if (ret < (SMB_OFF_T)smb_fname_src->st.st_ex_size) { @@ -1356,8 +1350,6 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx, } TALLOC_FREE(oldname); - TALLOC_FREE(newname); - return status; } diff --git a/source3/smbd/open.c b/source3/smbd/open.c index df31365675..926c0ecaa7 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -2195,14 +2195,10 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, if (lp_map_archive(SNUM(conn)) || lp_store_dos_attributes(SNUM(conn))) { if (!posix_open) { - SMB_STRUCT_STAT tmp_sbuf; - SET_STAT_INVALID(tmp_sbuf); - if (file_set_dosmode( - conn, fname, + if (file_set_dosmode(conn, smb_fname, new_dos_attributes | aARCH, - &tmp_sbuf, parent_dir, - true) == 0) { - unx_mode = tmp_sbuf.st_ex_mode; + parent_dir, true) == 0) { + unx_mode = smb_fname->st.st_ex_mode; } } } @@ -2338,9 +2334,8 @@ NTSTATUS close_file_fchmod(struct smb_request *req, files_struct *fsp) } static NTSTATUS mkdir_internal(connection_struct *conn, - const char *name, - uint32 file_attributes, - SMB_STRUCT_STAT *psbuf) + struct smb_filename *smb_dname, + uint32 file_attributes) { mode_t mode; char *parent_dir; @@ -2353,12 +2348,13 @@ static NTSTATUS mkdir_internal(connection_struct *conn, return NT_STATUS_ACCESS_DENIED; } - status = check_name(conn, name); + status = check_name(conn, smb_dname->base_name); if (!NT_STATUS_IS_OK(status)) { return status; } - if (!parent_dirname(talloc_tos(), name, &parent_dir, NULL)) { + if (!parent_dirname(talloc_tos(), smb_dname->base_name, &parent_dir, + NULL)) { return NT_STATUS_NO_MEMORY; } @@ -2366,39 +2362,39 @@ static NTSTATUS mkdir_internal(connection_struct *conn, posix_open = true; mode = (mode_t)(file_attributes & ~FILE_FLAG_POSIX_SEMANTICS); } else { - mode = unix_mode(conn, aDIR, name, parent_dir); + mode = unix_mode(conn, aDIR, smb_dname->base_name, parent_dir); } - if (SMB_VFS_MKDIR(conn, name, mode) != 0) { + if (SMB_VFS_MKDIR(conn, smb_dname->base_name, mode) != 0) { return map_nt_error_from_unix(errno); } /* Ensure we're checking for a symlink here.... */ /* We don't want to get caught by a symlink racer. */ - if (vfs_lstat_smb_fname(conn, name, psbuf) == -1) { + if (SMB_VFS_LSTAT(conn, smb_dname) == -1) { DEBUG(2, ("Could not stat directory '%s' just created: %s\n", - name, strerror(errno))); + smb_fname_str_dbg(smb_dname), strerror(errno))); return map_nt_error_from_unix(errno); } - if (!S_ISDIR(psbuf->st_ex_mode)) { + if (!S_ISDIR(smb_dname->st.st_ex_mode)) { DEBUG(0, ("Directory just '%s' created is not a directory\n", - name)); + smb_fname_str_dbg(smb_dname))); return NT_STATUS_ACCESS_DENIED; } if (lp_store_dos_attributes(SNUM(conn))) { if (!posix_open) { - file_set_dosmode(conn, name, - file_attributes | aDIR, NULL, - parent_dir, - true); + file_set_dosmode(conn, smb_dname, + file_attributes | aDIR, + parent_dir, true); } } if (lp_inherit_perms(SNUM(conn))) { - inherit_access_posix_acl(conn, parent_dir, name, mode); + inherit_access_posix_acl(conn, parent_dir, + smb_dname->base_name, mode); } if (!(file_attributes & FILE_FLAG_POSIX_SEMANTICS)) { @@ -2408,19 +2404,23 @@ static NTSTATUS mkdir_internal(connection_struct *conn, * Consider bits automagically set by UNIX, i.e. SGID bit from parent * dir. */ - if (mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) && (mode & ~psbuf->st_ex_mode)) { - SMB_VFS_CHMOD(conn, name, - psbuf->st_ex_mode | (mode & ~psbuf->st_ex_mode)); + if ((mode & ~(S_IRWXU|S_IRWXG|S_IRWXO)) && + (mode & ~smb_dname->st.st_ex_mode)) { + SMB_VFS_CHMOD(conn, smb_dname->base_name, + (smb_dname->st.st_ex_mode | + (mode & ~smb_dname->st.st_ex_mode))); } } /* Change the owner if required. */ if (lp_inherit_owner(SNUM(conn))) { - change_dir_owner_to_parent(conn, parent_dir, name, psbuf); + change_dir_owner_to_parent(conn, parent_dir, + smb_dname->base_name, + &smb_dname->st); } notify_fname(conn, NOTIFY_ACTION_ADDED, FILE_NOTIFY_CHANGE_DIR_NAME, - name); + smb_dname->base_name); return NT_STATUS_OK; } @@ -2503,10 +2503,8 @@ static NTSTATUS open_directory(connection_struct *conn, /* If directory exists error. If directory doesn't * exist create. */ - status = mkdir_internal(conn, - smb_dname->base_name, - file_attributes, - &smb_dname->st); + status = mkdir_internal(conn, smb_dname, + file_attributes); if (!NT_STATUS_IS_OK(status)) { DEBUG(2, ("open_directory: unable to create " @@ -2525,10 +2523,8 @@ static NTSTATUS open_directory(connection_struct *conn, * exist create. */ - status = mkdir_internal(conn, - smb_dname->base_name, - file_attributes, - &smb_dname->st); + status = mkdir_internal(conn, smb_dname, + file_attributes); if (NT_STATUS_IS_OK(status)) { info = FILE_WAS_CREATED; diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index e37cdcb6b4..4a5610e5e1 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -1216,7 +1216,7 @@ void reply_setatr(struct smb_request *req) else mode &= ~aDIR; - if (file_set_dosmode(conn, fname, mode, &smb_fname->st, NULL, + if (file_set_dosmode(conn, smb_fname, mode, NULL, false) != 0) { reply_unixerror(req, ERRDOS, ERRnoaccess); goto out; diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index dfb682ee21..2c74c8f49e 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -5063,15 +5063,26 @@ static NTSTATUS smb_set_file_dosmode(connection_struct *conn, /* check the mode isn't different, before changing it */ if ((dosmode != 0) && (dosmode != dos_mode(conn, fname, psbuf))) { + struct smb_filename *smb_fname = NULL; + NTSTATUS status; + + status = create_synthetic_smb_fname_split(talloc_tos(), fname, + psbuf, &smb_fname); + if (!NT_STATUS_IS_OK(status)) { + return status; + } DEBUG(10,("smb_set_file_dosmode: file %s : setting dos mode 0x%x\n", fname, (unsigned int)dosmode )); - if(file_set_dosmode(conn, fname, dosmode, psbuf, NULL, false)) { + if(file_set_dosmode(conn, smb_fname, dosmode, NULL, false)) { DEBUG(2,("smb_set_file_dosmode: file_set_dosmode of %s failed (%s)\n", fname, strerror(errno))); + TALLOC_FREE(smb_fname); return map_nt_error_from_unix(errno); } + *psbuf = smb_fname->st; + TALLOC_FREE(smb_fname); } return NT_STATUS_OK; } @@ -6320,7 +6331,7 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, return status; } - id = vfs_file_id_from_sbuf(conn, psbuf); + id = vfs_file_id_from_sbuf(conn, &sbuf); for(all_fsps = file_find_di_first(id); all_fsps; all_fsps = file_find_di_next(all_fsps)) { /* @@ -6349,7 +6360,7 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, false); if (modify_mtime) { notify_fname(conn, NOTIFY_ACTION_MODIFIED, - FILE_NOTIFY_CHANGE_LAST_WRITE, fname); + FILE_NOTIFY_CHANGE_LAST_WRITE, smb_fname->base_name); } return status; } |