2 Unix SMB/CIFS implementation.
3 dos mode handling functions
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) James Peach 2006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "system/filesys.h"
23 #include "librpc/gen_ndr/ndr_xattr.h"
24 #include "librpc/gen_ndr/ioctl.h"
25 #include "../libcli/security/security.h"
26 #include "smbd/smbd.h"
27 #include "lib/param/loadparm.h"
29 static NTSTATUS get_file_handle_for_metadata(connection_struct *conn,
30 const struct smb_filename *smb_fname,
31 files_struct **ret_fsp,
34 static void dos_mode_debug_print(const char *func, uint32_t mode)
38 if (DEBUGLEVEL < DBGLVL_INFO) {
44 if (mode & FILE_ATTRIBUTE_HIDDEN) {
45 fstrcat(modestr, "h");
47 if (mode & FILE_ATTRIBUTE_READONLY) {
48 fstrcat(modestr, "r");
50 if (mode & FILE_ATTRIBUTE_SYSTEM) {
51 fstrcat(modestr, "s");
53 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
54 fstrcat(modestr, "d");
56 if (mode & FILE_ATTRIBUTE_ARCHIVE) {
57 fstrcat(modestr, "a");
59 if (mode & FILE_ATTRIBUTE_SPARSE) {
60 fstrcat(modestr, "[sparse]");
62 if (mode & FILE_ATTRIBUTE_OFFLINE) {
63 fstrcat(modestr, "[offline]");
65 if (mode & FILE_ATTRIBUTE_COMPRESSED) {
66 fstrcat(modestr, "[compressed]");
69 DBG_INFO("%s returning (0x%x): \"%s\"\n", func, (unsigned)mode,
73 static uint32_t filter_mode_by_protocol(uint32_t mode)
75 if (get_Protocol() <= PROTOCOL_LANMAN2) {
76 DEBUG(10,("filter_mode_by_protocol: "
77 "filtering result 0x%x to 0x%x\n",
79 (unsigned int)(mode & 0x3f) ));
85 static int set_link_read_only_flag(const SMB_STRUCT_STAT *const sbuf)
89 if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
90 return FILE_ATTRIBUTE_READONLY;
96 /****************************************************************************
97 Change a dos mode to a unix mode.
98 Base permission for files:
99 if creating file and inheriting (i.e. parent_dir != NULL)
100 apply read/write bits from parent directory.
102 everybody gets read bit set
103 dos readonly is represented in unix by removing everyone's write bit
104 dos archive is represented in unix by the user's execute bit
105 dos system is represented in unix by the group's execute bit
106 dos hidden is represented in unix by the other's execute bit
108 Then apply create mask,
111 Base permission for directories:
112 dos directory is represented in unix by unix's dir bit and the exec bit
114 Then apply create mask,
117 ****************************************************************************/
119 mode_t unix_mode(connection_struct *conn, int dosmode,
120 const struct smb_filename *smb_fname,
121 const char *inherit_from_dir)
123 mode_t result = (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
124 mode_t dir_mode = 0; /* Mode of the inherit_from directory if
127 if (!lp_store_dos_attributes(SNUM(conn)) && IS_DOS_READONLY(dosmode)) {
128 result &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
131 if ((inherit_from_dir != NULL) && lp_inherit_permissions(SNUM(conn))) {
132 struct smb_filename *smb_fname_parent;
134 DEBUG(2, ("unix_mode(%s) inheriting from %s\n",
135 smb_fname_str_dbg(smb_fname),
138 smb_fname_parent = synthetic_smb_fname(talloc_tos(),
143 if (smb_fname_parent == NULL) {
144 DEBUG(1,("unix_mode(%s) failed, [dir %s]: No memory\n",
145 smb_fname_str_dbg(smb_fname),
150 if (SMB_VFS_STAT(conn, smb_fname_parent) != 0) {
151 DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n",
152 smb_fname_str_dbg(smb_fname),
153 inherit_from_dir, strerror(errno)));
154 TALLOC_FREE(smb_fname_parent);
155 return(0); /* *** shouldn't happen! *** */
158 /* Save for later - but explicitly remove setuid bit for safety. */
159 dir_mode = smb_fname_parent->st.st_ex_mode & ~S_ISUID;
160 DEBUG(2,("unix_mode(%s) inherit mode %o\n",
161 smb_fname_str_dbg(smb_fname), (int)dir_mode));
164 TALLOC_FREE(smb_fname_parent);
167 if (IS_DOS_DIR(dosmode)) {
168 /* We never make directories read only for the owner as under DOS a user
169 can always create a file in a read-only directory. */
170 result |= (S_IFDIR | S_IWUSR);
173 /* Inherit mode of parent directory. */
176 /* Provisionally add all 'x' bits */
177 result |= (S_IXUSR | S_IXGRP | S_IXOTH);
179 /* Apply directory mask */
180 result &= lp_directory_mask(SNUM(conn));
181 /* Add in force bits */
182 result |= lp_force_directory_mode(SNUM(conn));
185 if (lp_map_archive(SNUM(conn)) && IS_DOS_ARCHIVE(dosmode))
188 if (lp_map_system(SNUM(conn)) && IS_DOS_SYSTEM(dosmode))
191 if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode))
195 /* Inherit 666 component of parent directory mode */
196 result |= dir_mode & (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
198 /* Apply mode mask */
199 result &= lp_create_mask(SNUM(conn));
200 /* Add in force bits */
201 result |= lp_force_create_mode(SNUM(conn));
205 DBG_INFO("unix_mode(%s) returning 0%o\n",
206 smb_fname_str_dbg(smb_fname), (int)result);
211 /****************************************************************************
212 Change a unix mode to a dos mode.
213 ****************************************************************************/
215 static uint32_t dos_mode_from_sbuf(connection_struct *conn,
216 const struct smb_filename *smb_fname)
219 enum mapreadonly_options ro_opts = (enum mapreadonly_options)lp_map_readonly(SNUM(conn));
221 #if defined(UF_IMMUTABLE) && defined(SF_IMMUTABLE)
222 /* if we can find out if a file is immutable we should report it r/o */
223 if (smb_fname->st.st_ex_flags & (UF_IMMUTABLE | SF_IMMUTABLE)) {
224 result |= FILE_ATTRIBUTE_READONLY;
227 if (ro_opts == MAP_READONLY_YES) {
228 /* Original Samba method - map inverse of user "w" bit. */
229 if ((smb_fname->st.st_ex_mode & S_IWUSR) == 0) {
230 result |= FILE_ATTRIBUTE_READONLY;
232 } else if (ro_opts == MAP_READONLY_PERMISSIONS) {
233 /* Check actual permissions for read-only. */
234 if (!can_write_to_file(conn, smb_fname)) {
235 result |= FILE_ATTRIBUTE_READONLY;
237 } /* Else never set the readonly bit. */
239 if (MAP_ARCHIVE(conn) && ((smb_fname->st.st_ex_mode & S_IXUSR) != 0))
240 result |= FILE_ATTRIBUTE_ARCHIVE;
242 if (MAP_SYSTEM(conn) && ((smb_fname->st.st_ex_mode & S_IXGRP) != 0))
243 result |= FILE_ATTRIBUTE_SYSTEM;
245 if (MAP_HIDDEN(conn) && ((smb_fname->st.st_ex_mode & S_IXOTH) != 0))
246 result |= FILE_ATTRIBUTE_HIDDEN;
248 if (S_ISDIR(smb_fname->st.st_ex_mode))
249 result = FILE_ATTRIBUTE_DIRECTORY | (result & FILE_ATTRIBUTE_READONLY);
251 result |= set_link_read_only_flag(&smb_fname->st);
253 dos_mode_debug_print(__func__, result);
258 /****************************************************************************
259 Get DOS attributes from an EA.
260 This can also pull the create time into the stat struct inside smb_fname.
261 ****************************************************************************/
263 NTSTATUS parse_dos_attribute_blob(struct smb_filename *smb_fname,
267 struct xattr_DOSATTRIB dosattrib;
268 enum ndr_err_code ndr_err;
271 ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &dosattrib,
272 (ndr_pull_flags_fn_t)ndr_pull_xattr_DOSATTRIB);
274 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
275 DBG_WARNING("bad ndr decode "
276 "from EA on file %s: Error = %s\n",
277 smb_fname_str_dbg(smb_fname),
278 ndr_errstr(ndr_err));
279 return ndr_map_error2ntstatus(ndr_err);
282 DBG_DEBUG("%s attr = %s\n",
283 smb_fname_str_dbg(smb_fname), dosattrib.attrib_hex);
285 switch (dosattrib.version) {
287 dosattr = dosattrib.info.compatinfoFFFF.attrib;
290 dosattr = dosattrib.info.info1.attrib;
291 if (!null_nttime(dosattrib.info.info1.create_time)) {
292 struct timespec create_time =
293 nt_time_to_unix_timespec(
294 dosattrib.info.info1.create_time);
296 update_stat_ex_create_time(&smb_fname->st,
299 DBG_DEBUG("file %s case 1 set btime %s\n",
300 smb_fname_str_dbg(smb_fname),
301 time_to_asc(convert_timespec_to_time_t(
306 dosattr = dosattrib.info.oldinfo2.attrib;
307 /* Don't know what flags to check for this case. */
310 dosattr = dosattrib.info.info3.attrib;
311 if ((dosattrib.info.info3.valid_flags & XATTR_DOSINFO_CREATE_TIME) &&
312 !null_nttime(dosattrib.info.info3.create_time)) {
313 struct timespec create_time =
314 nt_time_to_unix_timespec(
315 dosattrib.info.info3.create_time);
317 update_stat_ex_create_time(&smb_fname->st,
320 DBG_DEBUG("file %s case 3 set btime %s\n",
321 smb_fname_str_dbg(smb_fname),
322 time_to_asc(convert_timespec_to_time_t(
327 DBG_WARNING("Badly formed DOSATTRIB on file %s - %s\n",
328 smb_fname_str_dbg(smb_fname), blob.data);
329 /* Should this be INTERNAL_ERROR? */
330 return NT_STATUS_INVALID_PARAMETER;
333 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
334 dosattr |= FILE_ATTRIBUTE_DIRECTORY;
337 /* FILE_ATTRIBUTE_SPARSE is valid on get but not on set. */
338 *pattr |= (uint32_t)(dosattr & (SAMBA_ATTRIBUTES_MASK|FILE_ATTRIBUTE_SPARSE));
340 dos_mode_debug_print(__func__, *pattr);
345 NTSTATUS get_ea_dos_attribute(connection_struct *conn,
346 struct smb_filename *smb_fname,
354 if (!lp_store_dos_attributes(SNUM(conn))) {
355 return NT_STATUS_NOT_IMPLEMENTED;
358 /* Don't reset pattr to zero as we may already have filename-based attributes we
361 sizeret = SMB_VFS_GETXATTR(conn, smb_fname,
362 SAMBA_XATTR_DOS_ATTRIB, attrstr,
364 if (sizeret == -1 && errno == EACCES) {
368 * According to MS-FSA 2.1.5.1.2.1 "Algorithm to Check Access to
369 * an Existing File" FILE_LIST_DIRECTORY on a directory implies
370 * FILE_READ_ATTRIBUTES for directory entries. Being able to
371 * stat() a file implies FILE_LIST_DIRECTORY for the directory
372 * containing the file.
375 if (!VALID_STAT(smb_fname->st)) {
377 * Safety net: dos_mode() already checks this, but as we
378 * become root based on this, add an additional layer of
381 DBG_ERR("Rejecting root override, invalid stat [%s]\n",
382 smb_fname_str_dbg(smb_fname));
383 return NT_STATUS_ACCESS_DENIED;
387 sizeret = SMB_VFS_GETXATTR(conn, smb_fname,
388 SAMBA_XATTR_DOS_ATTRIB,
396 if (saved_errno != 0) {
401 DBG_INFO("Cannot get attribute "
402 "from EA on file %s: Error = %s\n",
403 smb_fname_str_dbg(smb_fname), strerror(errno));
404 return map_nt_error_from_unix(errno);
407 blob.data = (uint8_t *)attrstr;
408 blob.length = sizeret;
410 status = parse_dos_attribute_blob(smb_fname, blob, pattr);
411 if (!NT_STATUS_IS_OK(status)) {
418 /****************************************************************************
419 Set DOS attributes in an EA.
420 Also sets the create time.
421 ****************************************************************************/
423 NTSTATUS set_ea_dos_attribute(connection_struct *conn,
424 const struct smb_filename *smb_fname,
427 struct xattr_DOSATTRIB dosattrib;
428 enum ndr_err_code ndr_err;
432 if (!lp_store_dos_attributes(SNUM(conn))) {
433 return NT_STATUS_NOT_IMPLEMENTED;
437 * Don't store FILE_ATTRIBUTE_OFFLINE, it's dealt with in
438 * vfs_default via DMAPI if that is enabled.
440 dosmode &= ~FILE_ATTRIBUTE_OFFLINE;
442 ZERO_STRUCT(dosattrib);
445 dosattrib.version = 3;
446 dosattrib.info.info3.valid_flags = XATTR_DOSINFO_ATTRIB|
447 XATTR_DOSINFO_CREATE_TIME;
448 dosattrib.info.info3.attrib = dosmode;
449 dosattrib.info.info3.create_time = unix_timespec_to_nt_time(
450 smb_fname->st.st_ex_btime);
452 DEBUG(10,("set_ea_dos_attributes: set attribute 0x%x, btime = %s on file %s\n",
453 (unsigned int)dosmode,
454 time_to_asc(convert_timespec_to_time_t(smb_fname->st.st_ex_btime)),
455 smb_fname_str_dbg(smb_fname) ));
457 ndr_err = ndr_push_struct_blob(
458 &blob, talloc_tos(), &dosattrib,
459 (ndr_push_flags_fn_t)ndr_push_xattr_DOSATTRIB);
461 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
462 DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n",
463 ndr_errstr(ndr_err)));
464 return ndr_map_error2ntstatus(ndr_err);
467 if (blob.data == NULL || blob.length == 0) {
468 /* Should this be INTERNAL_ERROR? */
469 return NT_STATUS_INVALID_PARAMETER;
472 ret = SMB_VFS_SETXATTR(conn, smb_fname,
473 SAMBA_XATTR_DOS_ATTRIB,
474 blob.data, blob.length, 0);
476 NTSTATUS status = NT_STATUS_OK;
477 bool need_close = false;
478 files_struct *fsp = NULL;
479 bool set_dosmode_ok = false;
481 if ((errno != EPERM) && (errno != EACCES)) {
482 DBG_INFO("Cannot set "
483 "attribute EA on file %s: Error = %s\n",
484 smb_fname_str_dbg(smb_fname), strerror(errno));
485 return map_nt_error_from_unix(errno);
488 /* We want DOS semantics, ie allow non owner with write permission to change the
489 bits on a file. Just like file_ntimes below.
492 /* Check if we have write access. */
493 if (!CAN_WRITE(conn)) {
494 return NT_STATUS_ACCESS_DENIED;
497 status = smbd_check_access_rights(conn, smb_fname, false,
498 FILE_WRITE_ATTRIBUTES);
499 if (NT_STATUS_IS_OK(status)) {
500 set_dosmode_ok = true;
503 if (!set_dosmode_ok && lp_dos_filemode(SNUM(conn))) {
504 set_dosmode_ok = can_write_to_file(conn, smb_fname);
507 if (!set_dosmode_ok) {
508 return NT_STATUS_ACCESS_DENIED;
512 * We need to get an open file handle to do the
513 * metadata operation under root.
516 status = get_file_handle_for_metadata(conn,
520 if (!NT_STATUS_IS_OK(status)) {
525 ret = SMB_VFS_FSETXATTR(fsp,
526 SAMBA_XATTR_DOS_ATTRIB,
527 blob.data, blob.length, 0);
529 status = NT_STATUS_OK;
533 close_file(NULL, fsp, NORMAL_CLOSE);
537 DEBUG(10,("set_ea_dos_attribute: set EA 0x%x on file %s\n",
538 (unsigned int)dosmode,
539 smb_fname_str_dbg(smb_fname)));
543 /****************************************************************************
544 Change a unix mode to a dos mode for an ms dfs link.
545 ****************************************************************************/
547 uint32_t dos_mode_msdfs(connection_struct *conn,
548 const struct smb_filename *smb_fname)
552 DEBUG(8,("dos_mode_msdfs: %s\n", smb_fname_str_dbg(smb_fname)));
554 if (!VALID_STAT(smb_fname->st)) {
558 /* First do any modifications that depend on the path name. */
559 /* hide files with a name starting with a . */
560 if (lp_hide_dot_files(SNUM(conn))) {
561 const char *p = strrchr_m(smb_fname->base_name, '/');
565 p = smb_fname->base_name;
568 /* Only . and .. are not hidden. */
569 if (p[0] == '.' && !((p[1] == '\0') ||
570 (p[1] == '.' && p[2] == '\0'))) {
571 result |= FILE_ATTRIBUTE_HIDDEN;
575 result |= dos_mode_from_sbuf(conn, smb_fname);
577 /* Optimization : Only call is_hidden_path if it's not already
579 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
580 IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
581 result |= FILE_ATTRIBUTE_HIDDEN;
585 result = FILE_ATTRIBUTE_NORMAL;
588 result = filter_mode_by_protocol(result);
591 * Add in that it is a reparse point
593 result |= FILE_ATTRIBUTE_REPARSE_POINT;
595 dos_mode_debug_print(__func__, result);
601 * check whether a file or directory is flagged as compressed.
603 static NTSTATUS dos_mode_check_compressed(connection_struct *conn,
604 struct smb_filename *smb_fname,
608 uint16_t compression_fmt;
609 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
610 if (tmp_ctx == NULL) {
611 status = NT_STATUS_NO_MEMORY;
615 status = SMB_VFS_GET_COMPRESSION(conn, tmp_ctx, NULL, smb_fname,
617 if (!NT_STATUS_IS_OK(status)) {
621 if (compression_fmt == COMPRESSION_FORMAT_LZNT1) {
622 *is_compressed = true;
624 *is_compressed = false;
626 status = NT_STATUS_OK;
629 talloc_free(tmp_ctx);
634 static uint32_t dos_mode_from_name(connection_struct *conn,
635 const struct smb_filename *smb_fname,
638 const char *p = NULL;
639 uint32_t result = dosmode;
641 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
642 lp_hide_dot_files(SNUM(conn)))
644 p = strrchr_m(smb_fname->base_name, '/');
648 p = smb_fname->base_name;
651 /* Only . and .. are not hidden. */
653 !((p[1] == '\0') || (p[1] == '.' && p[2] == '\0')))
655 result |= FILE_ATTRIBUTE_HIDDEN;
659 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
660 IS_HIDDEN_PATH(conn, smb_fname->base_name))
662 result |= FILE_ATTRIBUTE_HIDDEN;
668 static uint32_t dos_mode_post(uint32_t dosmode,
669 connection_struct *conn,
670 struct smb_filename *smb_fname,
676 * According to MS-FSA a stream name does not have
677 * separate DOS attribute metadata, so we must return
678 * the DOS attribute from the base filename. With one caveat,
679 * a non-default stream name can never be a directory.
681 * As this is common to all streams data stores, we handle
682 * it here instead of inside all stream VFS modules.
684 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13380
687 if (is_ntfs_stream_smb_fname(smb_fname)) {
688 /* is_ntfs_stream_smb_fname() returns false for a POSIX path. */
689 if (!is_ntfs_default_stream_smb_fname(smb_fname)) {
691 * Non-default stream name, not a posix path.
693 dosmode &= ~(FILE_ATTRIBUTE_DIRECTORY);
697 if (conn->fs_capabilities & FILE_FILE_COMPRESSION) {
698 bool compressed = false;
700 status = dos_mode_check_compressed(conn, smb_fname,
702 if (NT_STATUS_IS_OK(status) && compressed) {
703 dosmode |= FILE_ATTRIBUTE_COMPRESSED;
707 dosmode |= dos_mode_from_name(conn, smb_fname, dosmode);
709 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
710 dosmode |= FILE_ATTRIBUTE_DIRECTORY;
711 } else if (dosmode == 0) {
712 dosmode = FILE_ATTRIBUTE_NORMAL;
715 dosmode = filter_mode_by_protocol(dosmode);
717 dos_mode_debug_print(func, dosmode);
721 /****************************************************************************
722 Change a unix mode to a dos mode.
723 May also read the create timespec into the stat struct in smb_fname
724 if "store dos attributes" is true.
725 ****************************************************************************/
727 uint32_t dos_mode(connection_struct *conn, struct smb_filename *smb_fname)
730 NTSTATUS status = NT_STATUS_OK;
732 DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname)));
734 if (!VALID_STAT(smb_fname->st)) {
738 /* Get the DOS attributes via the VFS if we can */
739 status = SMB_VFS_GET_DOS_ATTRIBUTES(conn, smb_fname, &result);
740 if (!NT_STATUS_IS_OK(status)) {
742 * Only fall back to using UNIX modes if we get NOT_IMPLEMENTED.
744 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
745 result |= dos_mode_from_sbuf(conn, smb_fname);
749 result = dos_mode_post(result, conn, smb_fname, __func__);
753 /*******************************************************************
754 chmod a file - but preserve some bits.
755 If "store dos attributes" is also set it will store the create time
756 from the stat struct in smb_fname (in NTTIME format) in the EA
758 ********************************************************************/
760 int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname,
761 uint32_t dosmode, const char *parent_dir, bool newfile)
766 int ret = -1, lret = -1;
767 files_struct *fsp = NULL;
768 bool need_close = false;
771 if (!CAN_WRITE(conn)) {
776 dosmode &= SAMBA_ATTRIBUTES_MASK;
778 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
779 dosmode, smb_fname_str_dbg(smb_fname)));
781 unixmode = smb_fname->st.st_ex_mode;
783 get_acl_group_bits(conn, smb_fname,
784 &smb_fname->st.st_ex_mode);
786 if (S_ISDIR(smb_fname->st.st_ex_mode))
787 dosmode |= FILE_ATTRIBUTE_DIRECTORY;
789 dosmode &= ~FILE_ATTRIBUTE_DIRECTORY;
791 /* Store the DOS attributes in an EA by preference. */
792 status = SMB_VFS_SET_DOS_ATTRIBUTES(conn, smb_fname, dosmode);
793 if (NT_STATUS_IS_OK(status)) {
795 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
796 FILE_NOTIFY_CHANGE_ATTRIBUTES,
797 smb_fname->base_name);
799 smb_fname->st.st_ex_mode = unixmode;
803 * Only fall back to using UNIX modes if
804 * we get NOT_IMPLEMENTED.
806 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
807 errno = map_errno_from_nt_status(status);
812 /* Fall back to UNIX modes. */
813 unixmode = unix_mode(conn, dosmode, smb_fname, parent_dir);
815 /* preserve the file type bits */
818 /* preserve the s bits */
819 mask |= (S_ISUID | S_ISGID);
821 /* preserve the t bit */
826 /* possibly preserve the x bits */
827 if (!MAP_ARCHIVE(conn))
829 if (!MAP_SYSTEM(conn))
831 if (!MAP_HIDDEN(conn))
834 unixmode |= (smb_fname->st.st_ex_mode & mask);
836 /* if we previously had any r bits set then leave them alone */
837 if ((tmp = smb_fname->st.st_ex_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
838 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
842 /* if we previously had any w bits set then leave them alone
843 whilst adding in the new w bits, if the new mode is not rdonly */
844 if (!IS_DOS_READONLY(dosmode)) {
845 unixmode |= (smb_fname->st.st_ex_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
849 * From the chmod 2 man page:
851 * "If the calling process is not privileged, and the group of the file
852 * does not match the effective group ID of the process or one of its
853 * supplementary group IDs, the S_ISGID bit will be turned off, but
854 * this will not cause an error to be returned."
856 * Simply refuse to do the chmod in this case.
859 if (S_ISDIR(smb_fname->st.st_ex_mode) && (unixmode & S_ISGID) &&
860 geteuid() != sec_initial_uid() &&
861 !current_user_in_group(conn, smb_fname->st.st_ex_gid)) {
862 DEBUG(3,("file_set_dosmode: setgid bit cannot be "
863 "set for directory %s\n",
864 smb_fname_str_dbg(smb_fname)));
869 ret = SMB_VFS_CHMOD(conn, smb_fname, unixmode);
871 if(!newfile || (lret != -1)) {
872 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
873 FILE_NOTIFY_CHANGE_ATTRIBUTES,
874 smb_fname->base_name);
876 smb_fname->st.st_ex_mode = unixmode;
880 if((errno != EPERM) && (errno != EACCES))
883 if(!lp_dos_filemode(SNUM(conn)))
886 /* We want DOS semantics, ie allow non owner with write permission to change the
887 bits on a file. Just like file_ntimes below.
890 if (!can_write_to_file(conn, smb_fname)) {
896 * We need to get an open file handle to do the
897 * metadata operation under root.
900 status = get_file_handle_for_metadata(conn,
904 if (!NT_STATUS_IS_OK(status)) {
905 errno = map_errno_from_nt_status(status);
910 ret = SMB_VFS_FCHMOD(fsp, unixmode);
913 close_file(NULL, fsp, NORMAL_CLOSE);
916 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
917 FILE_NOTIFY_CHANGE_ATTRIBUTES,
918 smb_fname->base_name);
921 smb_fname->st.st_ex_mode = unixmode;
928 NTSTATUS file_set_sparse(connection_struct *conn,
932 uint32_t old_dosmode;
933 uint32_t new_dosmode;
936 if (!CAN_WRITE(conn)) {
937 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
938 "on readonly share[%s]\n",
939 smb_fname_str_dbg(fsp->fsp_name),
941 lp_servicename(talloc_tos(), SNUM(conn))));
942 return NT_STATUS_MEDIA_WRITE_PROTECTED;
946 * Windows Server 2008 & 2012 permit FSCTL_SET_SPARSE if any of the
947 * following access flags are granted.
949 if ((fsp->access_mask & (FILE_WRITE_DATA
950 | FILE_WRITE_ATTRIBUTES
951 | SEC_FILE_APPEND_DATA)) == 0) {
952 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
953 "access_mask[0x%08X] - access denied\n",
954 smb_fname_str_dbg(fsp->fsp_name),
957 return NT_STATUS_ACCESS_DENIED;
960 if (fsp->is_directory) {
961 DEBUG(9, ("invalid attempt to %s sparse flag on dir %s\n",
962 (sparse ? "set" : "clear"),
963 smb_fname_str_dbg(fsp->fsp_name)));
964 return NT_STATUS_INVALID_PARAMETER;
967 if (IS_IPC(conn) || IS_PRINT(conn)) {
968 DEBUG(9, ("attempt to %s sparse flag over invalid conn\n",
969 (sparse ? "set" : "clear")));
970 return NT_STATUS_INVALID_PARAMETER;
973 DEBUG(10,("file_set_sparse: setting sparse bit %u on file %s\n",
974 sparse, smb_fname_str_dbg(fsp->fsp_name)));
976 if (!lp_store_dos_attributes(SNUM(conn))) {
977 return NT_STATUS_INVALID_DEVICE_REQUEST;
980 status = vfs_stat_fsp(fsp);
981 if (!NT_STATUS_IS_OK(status)) {
985 old_dosmode = dos_mode(conn, fsp->fsp_name);
987 if (sparse && !(old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
988 new_dosmode = old_dosmode | FILE_ATTRIBUTE_SPARSE;
989 } else if (!sparse && (old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
990 new_dosmode = old_dosmode & ~FILE_ATTRIBUTE_SPARSE;
995 /* Store the DOS attributes in an EA. */
996 status = SMB_VFS_FSET_DOS_ATTRIBUTES(conn, fsp, new_dosmode);
997 if (!NT_STATUS_IS_OK(status)) {
1001 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
1002 FILE_NOTIFY_CHANGE_ATTRIBUTES,
1003 fsp->fsp_name->base_name);
1005 fsp->is_sparse = sparse;
1007 return NT_STATUS_OK;
1010 /*******************************************************************
1011 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
1013 *******************************************************************/
1015 int file_ntimes(connection_struct *conn, const struct smb_filename *smb_fname,
1016 struct smb_file_time *ft)
1022 DEBUG(6, ("file_ntime: actime: %s",
1023 time_to_asc(convert_timespec_to_time_t(ft->atime))));
1024 DEBUG(6, ("file_ntime: modtime: %s",
1025 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
1026 DEBUG(6, ("file_ntime: ctime: %s",
1027 time_to_asc(convert_timespec_to_time_t(ft->ctime))));
1028 DEBUG(6, ("file_ntime: createtime: %s",
1029 time_to_asc(convert_timespec_to_time_t(ft->create_time))));
1031 /* Don't update the time on read-only shares */
1032 /* We need this as set_filetime (which can be called on
1033 close and other paths) can end up calling this function
1034 without the NEED_WRITE protection. Found by :
1035 Leo Weppelman <leo@wau.mis.ah.nl>
1038 if (!CAN_WRITE(conn)) {
1042 if(SMB_VFS_NTIMES(conn, smb_fname, ft) == 0) {
1046 if((errno != EPERM) && (errno != EACCES)) {
1050 if(!lp_dos_filetimes(SNUM(conn))) {
1054 /* We have permission (given by the Samba admin) to
1055 break POSIX semantics and allow a user to change
1056 the time on a file they don't own but can write to
1060 /* Check if we have write access. */
1061 if (can_write_to_file(conn, smb_fname)) {
1062 /* We are allowed to become root and change the filetime. */
1064 ret = SMB_VFS_NTIMES(conn, smb_fname, ft);
1071 /******************************************************************
1072 Force a "sticky" write time on a pathname. This will always be
1073 returned on all future write time queries and set on close.
1074 ******************************************************************/
1076 bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime)
1078 if (null_timespec(mtime)) {
1082 if (!set_sticky_write_time(fileid, mtime)) {
1089 /******************************************************************
1090 Force a "sticky" write time on an fsp. This will always be
1091 returned on all future write time queries and set on close.
1092 ******************************************************************/
1094 bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime)
1096 if (null_timespec(mtime)) {
1100 fsp->write_time_forced = true;
1101 TALLOC_FREE(fsp->update_write_time_event);
1103 return set_sticky_write_time_path(fsp->file_id, mtime);
1106 /******************************************************************
1107 Set a create time EA.
1108 ******************************************************************/
1110 NTSTATUS set_create_timespec_ea(connection_struct *conn,
1111 const struct smb_filename *psmb_fname,
1112 struct timespec create_time)
1114 struct smb_filename *smb_fname;
1118 if (!lp_store_dos_attributes(SNUM(conn))) {
1119 return NT_STATUS_OK;
1122 smb_fname = synthetic_smb_fname(talloc_tos(),
1123 psmb_fname->base_name,
1128 if (smb_fname == NULL) {
1129 return NT_STATUS_NO_MEMORY;
1132 dosmode = dos_mode(conn, smb_fname);
1134 smb_fname->st.st_ex_btime = create_time;
1136 ret = file_set_dosmode(conn, smb_fname, dosmode, NULL, false);
1138 return map_nt_error_from_unix(errno);
1141 DEBUG(10,("set_create_timespec_ea: wrote create time EA for file %s\n",
1142 smb_fname_str_dbg(smb_fname)));
1144 return NT_STATUS_OK;
1147 /******************************************************************
1148 Return a create time.
1149 ******************************************************************/
1151 struct timespec get_create_timespec(connection_struct *conn,
1152 struct files_struct *fsp,
1153 const struct smb_filename *smb_fname)
1155 return smb_fname->st.st_ex_btime;
1158 /******************************************************************
1159 Return a change time (may look at EA in future).
1160 ******************************************************************/
1162 struct timespec get_change_timespec(connection_struct *conn,
1163 struct files_struct *fsp,
1164 const struct smb_filename *smb_fname)
1166 return smb_fname->st.st_ex_mtime;
1169 /****************************************************************************
1170 Get a real open file handle we can do meta-data operations on. As it's
1171 going to be used under root access only on meta-data we should look for
1172 any existing open file handle first, and use that in preference (also to
1173 avoid kernel self-oplock breaks). If not use an INTERNAL_OPEN_ONLY handle.
1174 ****************************************************************************/
1176 static NTSTATUS get_file_handle_for_metadata(connection_struct *conn,
1177 const struct smb_filename *smb_fname,
1178 files_struct **ret_fsp,
1183 struct file_id file_id;
1184 struct smb_filename *smb_fname_cp = NULL;
1186 *need_close = false;
1188 if (!VALID_STAT(smb_fname->st)) {
1189 return NT_STATUS_INVALID_PARAMETER;
1192 file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1194 for(fsp = file_find_di_first(conn->sconn, file_id);
1196 fsp = file_find_di_next(fsp)) {
1197 if (fsp->fh->fd != -1) {
1199 return NT_STATUS_OK;
1203 smb_fname_cp = cp_smb_filename(talloc_tos(),
1205 if (smb_fname_cp == NULL) {
1206 return NT_STATUS_NO_MEMORY;
1209 /* Opens an INTERNAL_OPEN_ONLY write handle. */
1210 status = SMB_VFS_CREATE_FILE(
1213 0, /* root_dir_fid */
1214 smb_fname_cp, /* fname */
1215 FILE_WRITE_ATTRIBUTES, /* access_mask */
1216 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
1218 FILE_OPEN, /* create_disposition*/
1219 0, /* create_options */
1220 0, /* file_attributes */
1221 INTERNAL_OPEN_ONLY, /* oplock_request */
1223 0, /* allocation_size */
1224 0, /* private_flags */
1227 ret_fsp, /* result */
1229 NULL, NULL); /* create context */
1231 TALLOC_FREE(smb_fname_cp);
1233 if (NT_STATUS_IS_OK(status)) {