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 get_ea_dos_attribute(connection_struct *conn,
264 struct smb_filename *smb_fname,
267 struct xattr_DOSATTRIB dosattrib;
268 enum ndr_err_code ndr_err;
274 if (!lp_store_dos_attributes(SNUM(conn))) {
275 return NT_STATUS_NOT_IMPLEMENTED;
278 /* Don't reset pattr to zero as we may already have filename-based attributes we
281 sizeret = SMB_VFS_GETXATTR(conn, smb_fname,
282 SAMBA_XATTR_DOS_ATTRIB, attrstr,
284 if (sizeret == -1 && errno == EACCES) {
288 * According to MS-FSA 2.1.5.1.2.1 "Algorithm to Check Access to
289 * an Existing File" FILE_LIST_DIRECTORY on a directory implies
290 * FILE_READ_ATTRIBUTES for directory entries. Being able to
291 * stat() a file implies FILE_LIST_DIRECTORY for the directory
292 * containing the file.
295 if (!VALID_STAT(smb_fname->st)) {
297 * Safety net: dos_mode() already checks this, but as we
298 * become root based on this, add an additional layer of
301 DBG_ERR("Rejecting root override, invalid stat [%s]\n",
302 smb_fname_str_dbg(smb_fname));
303 return NT_STATUS_ACCESS_DENIED;
307 sizeret = SMB_VFS_GETXATTR(conn, smb_fname,
308 SAMBA_XATTR_DOS_ATTRIB,
316 if (saved_errno != 0) {
321 DBG_INFO("Cannot get attribute "
322 "from EA on file %s: Error = %s\n",
323 smb_fname_str_dbg(smb_fname), strerror(errno));
324 return map_nt_error_from_unix(errno);
327 blob.data = (uint8_t *)attrstr;
328 blob.length = sizeret;
330 ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &dosattrib,
331 (ndr_pull_flags_fn_t)ndr_pull_xattr_DOSATTRIB);
333 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
334 DEBUG(1,("get_ea_dos_attribute: bad ndr decode "
335 "from EA on file %s: Error = %s\n",
336 smb_fname_str_dbg(smb_fname),
337 ndr_errstr(ndr_err)));
338 return ndr_map_error2ntstatus(ndr_err);
341 DEBUG(10,("get_ea_dos_attribute: %s attr = %s\n",
342 smb_fname_str_dbg(smb_fname), dosattrib.attrib_hex));
344 switch (dosattrib.version) {
346 dosattr = dosattrib.info.compatinfoFFFF.attrib;
349 dosattr = dosattrib.info.info1.attrib;
350 if (!null_nttime(dosattrib.info.info1.create_time)) {
351 struct timespec create_time =
352 nt_time_to_unix_timespec(
353 dosattrib.info.info1.create_time);
355 update_stat_ex_create_time(&smb_fname->st,
358 DEBUG(10,("get_ea_dos_attribute: file %s case 1 "
360 smb_fname_str_dbg(smb_fname),
361 time_to_asc(convert_timespec_to_time_t(
366 dosattr = dosattrib.info.oldinfo2.attrib;
367 /* Don't know what flags to check for this case. */
370 dosattr = dosattrib.info.info3.attrib;
371 if ((dosattrib.info.info3.valid_flags & XATTR_DOSINFO_CREATE_TIME) &&
372 !null_nttime(dosattrib.info.info3.create_time)) {
373 struct timespec create_time =
374 nt_time_to_unix_timespec(
375 dosattrib.info.info3.create_time);
377 update_stat_ex_create_time(&smb_fname->st,
380 DEBUG(10,("get_ea_dos_attribute: file %s case 3 "
382 smb_fname_str_dbg(smb_fname),
383 time_to_asc(convert_timespec_to_time_t(
388 DEBUG(1,("get_ea_dos_attribute: Badly formed DOSATTRIB on "
389 "file %s - %s\n", smb_fname_str_dbg(smb_fname),
391 /* Should this be INTERNAL_ERROR? */
392 return NT_STATUS_INVALID_PARAMETER;
395 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
396 dosattr |= FILE_ATTRIBUTE_DIRECTORY;
398 /* FILE_ATTRIBUTE_SPARSE is valid on get but not on set. */
399 *pattr |= (uint32_t)(dosattr & (SAMBA_ATTRIBUTES_MASK|FILE_ATTRIBUTE_SPARSE));
401 dos_mode_debug_print(__func__, *pattr);
406 /****************************************************************************
407 Set DOS attributes in an EA.
408 Also sets the create time.
409 ****************************************************************************/
411 NTSTATUS set_ea_dos_attribute(connection_struct *conn,
412 const struct smb_filename *smb_fname,
415 struct xattr_DOSATTRIB dosattrib;
416 enum ndr_err_code ndr_err;
419 if (!lp_store_dos_attributes(SNUM(conn))) {
420 return NT_STATUS_NOT_IMPLEMENTED;
424 * Don't store FILE_ATTRIBUTE_OFFLINE, it's dealt with in
425 * vfs_default via DMAPI if that is enabled.
427 dosmode &= ~FILE_ATTRIBUTE_OFFLINE;
429 ZERO_STRUCT(dosattrib);
432 dosattrib.version = 3;
433 dosattrib.info.info3.valid_flags = XATTR_DOSINFO_ATTRIB|
434 XATTR_DOSINFO_CREATE_TIME;
435 dosattrib.info.info3.attrib = dosmode;
436 dosattrib.info.info3.create_time = unix_timespec_to_nt_time(
437 smb_fname->st.st_ex_btime);
439 DEBUG(10,("set_ea_dos_attributes: set attribute 0x%x, btime = %s on file %s\n",
440 (unsigned int)dosmode,
441 time_to_asc(convert_timespec_to_time_t(smb_fname->st.st_ex_btime)),
442 smb_fname_str_dbg(smb_fname) ));
444 ndr_err = ndr_push_struct_blob(
445 &blob, talloc_tos(), &dosattrib,
446 (ndr_push_flags_fn_t)ndr_push_xattr_DOSATTRIB);
448 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
449 DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n",
450 ndr_errstr(ndr_err)));
451 return ndr_map_error2ntstatus(ndr_err);
454 if (blob.data == NULL || blob.length == 0) {
455 /* Should this be INTERNAL_ERROR? */
456 return NT_STATUS_INVALID_PARAMETER;
459 if (SMB_VFS_SETXATTR(conn, smb_fname,
460 SAMBA_XATTR_DOS_ATTRIB, blob.data, blob.length,
462 NTSTATUS status = NT_STATUS_OK;
463 bool need_close = false;
464 files_struct *fsp = NULL;
466 if((errno != EPERM) && (errno != EACCES)) {
467 DBG_INFO("Cannot set "
468 "attribute EA on file %s: Error = %s\n",
469 smb_fname_str_dbg(smb_fname), strerror(errno));
470 return map_nt_error_from_unix(errno);
473 /* We want DOS semantics, ie allow non owner with write permission to change the
474 bits on a file. Just like file_ntimes below.
477 /* Check if we have write access. */
478 if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
479 return NT_STATUS_ACCESS_DENIED;
481 if (!can_write_to_file(conn, smb_fname)) {
482 return NT_STATUS_ACCESS_DENIED;
486 * We need to get an open file handle to do the
487 * metadata operation under root.
490 status = get_file_handle_for_metadata(conn,
494 if (!NT_STATUS_IS_OK(status)) {
499 if (SMB_VFS_FSETXATTR(fsp,
500 SAMBA_XATTR_DOS_ATTRIB, blob.data,
501 blob.length, 0) == 0) {
502 status = NT_STATUS_OK;
506 close_file(NULL, fsp, NORMAL_CLOSE);
510 DEBUG(10,("set_ea_dos_attribute: set EA 0x%x on file %s\n",
511 (unsigned int)dosmode,
512 smb_fname_str_dbg(smb_fname)));
516 /****************************************************************************
517 Change a unix mode to a dos mode for an ms dfs link.
518 ****************************************************************************/
520 uint32_t dos_mode_msdfs(connection_struct *conn,
521 const struct smb_filename *smb_fname)
525 DEBUG(8,("dos_mode_msdfs: %s\n", smb_fname_str_dbg(smb_fname)));
527 if (!VALID_STAT(smb_fname->st)) {
531 /* First do any modifications that depend on the path name. */
532 /* hide files with a name starting with a . */
533 if (lp_hide_dot_files(SNUM(conn))) {
534 const char *p = strrchr_m(smb_fname->base_name, '/');
538 p = smb_fname->base_name;
541 /* Only . and .. are not hidden. */
542 if (p[0] == '.' && !((p[1] == '\0') ||
543 (p[1] == '.' && p[2] == '\0'))) {
544 result |= FILE_ATTRIBUTE_HIDDEN;
548 result |= dos_mode_from_sbuf(conn, smb_fname);
550 /* Optimization : Only call is_hidden_path if it's not already
552 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
553 IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
554 result |= FILE_ATTRIBUTE_HIDDEN;
558 result = FILE_ATTRIBUTE_NORMAL;
561 result = filter_mode_by_protocol(result);
564 * Add in that it is a reparse point
566 result |= FILE_ATTRIBUTE_REPARSE_POINT;
568 dos_mode_debug_print(__func__, result);
574 * check whether a file or directory is flagged as compressed.
576 static NTSTATUS dos_mode_check_compressed(connection_struct *conn,
577 struct smb_filename *smb_fname,
581 uint16_t compression_fmt;
582 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
583 if (tmp_ctx == NULL) {
584 status = NT_STATUS_NO_MEMORY;
588 status = SMB_VFS_GET_COMPRESSION(conn, tmp_ctx, NULL, smb_fname,
590 if (!NT_STATUS_IS_OK(status)) {
594 if (compression_fmt == COMPRESSION_FORMAT_LZNT1) {
595 *is_compressed = true;
597 *is_compressed = false;
599 status = NT_STATUS_OK;
602 talloc_free(tmp_ctx);
607 static uint32_t dos_mode_from_name(connection_struct *conn,
608 const struct smb_filename *smb_fname,
611 const char *p = NULL;
612 uint32_t result = dosmode;
614 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
615 lp_hide_dot_files(SNUM(conn)))
617 p = strrchr_m(smb_fname->base_name, '/');
621 p = smb_fname->base_name;
624 /* Only . and .. are not hidden. */
626 !((p[1] == '\0') || (p[1] == '.' && p[2] == '\0')))
628 result |= FILE_ATTRIBUTE_HIDDEN;
632 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
633 IS_HIDDEN_PATH(conn, smb_fname->base_name))
635 result |= FILE_ATTRIBUTE_HIDDEN;
641 /****************************************************************************
642 Change a unix mode to a dos mode.
643 May also read the create timespec into the stat struct in smb_fname
644 if "store dos attributes" is true.
645 ****************************************************************************/
647 uint32_t dos_mode(connection_struct *conn, struct smb_filename *smb_fname)
650 NTSTATUS status = NT_STATUS_OK;
652 DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname)));
654 if (!VALID_STAT(smb_fname->st)) {
658 /* Get the DOS attributes via the VFS if we can */
659 status = SMB_VFS_GET_DOS_ATTRIBUTES(conn, smb_fname, &result);
660 if (!NT_STATUS_IS_OK(status)) {
662 * Only fall back to using UNIX modes if we get NOT_IMPLEMENTED.
664 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
665 result |= dos_mode_from_sbuf(conn, smb_fname);
669 if (conn->fs_capabilities & FILE_FILE_COMPRESSION) {
670 bool compressed = false;
671 status = dos_mode_check_compressed(conn, smb_fname,
673 if (NT_STATUS_IS_OK(status) && compressed) {
674 result |= FILE_ATTRIBUTE_COMPRESSED;
678 result |= dos_mode_from_name(conn, smb_fname, result);
680 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
681 result |= FILE_ATTRIBUTE_DIRECTORY;
682 } else if (result == 0) {
683 result = FILE_ATTRIBUTE_NORMAL;
686 result = filter_mode_by_protocol(result);
688 dos_mode_debug_print(__func__, result);
693 /*******************************************************************
694 chmod a file - but preserve some bits.
695 If "store dos attributes" is also set it will store the create time
696 from the stat struct in smb_fname (in NTTIME format) in the EA
698 ********************************************************************/
700 int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname,
701 uint32_t dosmode, const char *parent_dir, bool newfile)
706 int ret = -1, lret = -1;
707 files_struct *fsp = NULL;
708 bool need_close = false;
711 if (!CAN_WRITE(conn)) {
716 dosmode &= SAMBA_ATTRIBUTES_MASK;
718 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
719 dosmode, smb_fname_str_dbg(smb_fname)));
721 unixmode = smb_fname->st.st_ex_mode;
723 get_acl_group_bits(conn, smb_fname,
724 &smb_fname->st.st_ex_mode);
726 if (S_ISDIR(smb_fname->st.st_ex_mode))
727 dosmode |= FILE_ATTRIBUTE_DIRECTORY;
729 dosmode &= ~FILE_ATTRIBUTE_DIRECTORY;
731 /* Store the DOS attributes in an EA by preference. */
732 status = SMB_VFS_SET_DOS_ATTRIBUTES(conn, smb_fname, dosmode);
733 if (NT_STATUS_IS_OK(status)) {
735 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
736 FILE_NOTIFY_CHANGE_ATTRIBUTES,
737 smb_fname->base_name);
739 smb_fname->st.st_ex_mode = unixmode;
743 * Only fall back to using UNIX modes if
744 * we get NOT_IMPLEMENTED.
746 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
747 errno = map_errno_from_nt_status(status);
752 /* Fall back to UNIX modes. */
753 unixmode = unix_mode(conn, dosmode, smb_fname, parent_dir);
755 /* preserve the file type bits */
758 /* preserve the s bits */
759 mask |= (S_ISUID | S_ISGID);
761 /* preserve the t bit */
766 /* possibly preserve the x bits */
767 if (!MAP_ARCHIVE(conn))
769 if (!MAP_SYSTEM(conn))
771 if (!MAP_HIDDEN(conn))
774 unixmode |= (smb_fname->st.st_ex_mode & mask);
776 /* if we previously had any r bits set then leave them alone */
777 if ((tmp = smb_fname->st.st_ex_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
778 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
782 /* if we previously had any w bits set then leave them alone
783 whilst adding in the new w bits, if the new mode is not rdonly */
784 if (!IS_DOS_READONLY(dosmode)) {
785 unixmode |= (smb_fname->st.st_ex_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
789 * From the chmod 2 man page:
791 * "If the calling process is not privileged, and the group of the file
792 * does not match the effective group ID of the process or one of its
793 * supplementary group IDs, the S_ISGID bit will be turned off, but
794 * this will not cause an error to be returned."
796 * Simply refuse to do the chmod in this case.
799 if (S_ISDIR(smb_fname->st.st_ex_mode) && (unixmode & S_ISGID) &&
800 geteuid() != sec_initial_uid() &&
801 !current_user_in_group(conn, smb_fname->st.st_ex_gid)) {
802 DEBUG(3,("file_set_dosmode: setgid bit cannot be "
803 "set for directory %s\n",
804 smb_fname_str_dbg(smb_fname)));
809 ret = SMB_VFS_CHMOD(conn, smb_fname, unixmode);
811 if(!newfile || (lret != -1)) {
812 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
813 FILE_NOTIFY_CHANGE_ATTRIBUTES,
814 smb_fname->base_name);
816 smb_fname->st.st_ex_mode = unixmode;
820 if((errno != EPERM) && (errno != EACCES))
823 if(!lp_dos_filemode(SNUM(conn)))
826 /* We want DOS semantics, ie allow non owner with write permission to change the
827 bits on a file. Just like file_ntimes below.
830 if (!can_write_to_file(conn, smb_fname)) {
836 * We need to get an open file handle to do the
837 * metadata operation under root.
840 status = get_file_handle_for_metadata(conn,
844 if (!NT_STATUS_IS_OK(status)) {
845 errno = map_errno_from_nt_status(status);
850 ret = SMB_VFS_FCHMOD(fsp, unixmode);
853 close_file(NULL, fsp, NORMAL_CLOSE);
856 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
857 FILE_NOTIFY_CHANGE_ATTRIBUTES,
858 smb_fname->base_name);
861 smb_fname->st.st_ex_mode = unixmode;
868 NTSTATUS file_set_sparse(connection_struct *conn,
872 uint32_t old_dosmode;
873 uint32_t new_dosmode;
876 if (!CAN_WRITE(conn)) {
877 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
878 "on readonly share[%s]\n",
879 smb_fname_str_dbg(fsp->fsp_name),
881 lp_servicename(talloc_tos(), SNUM(conn))));
882 return NT_STATUS_MEDIA_WRITE_PROTECTED;
886 * Windows Server 2008 & 2012 permit FSCTL_SET_SPARSE if any of the
887 * following access flags are granted.
889 if ((fsp->access_mask & (FILE_WRITE_DATA
890 | FILE_WRITE_ATTRIBUTES
891 | SEC_FILE_APPEND_DATA)) == 0) {
892 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
893 "access_mask[0x%08X] - access denied\n",
894 smb_fname_str_dbg(fsp->fsp_name),
897 return NT_STATUS_ACCESS_DENIED;
900 if (fsp->is_directory) {
901 DEBUG(9, ("invalid attempt to %s sparse flag on dir %s\n",
902 (sparse ? "set" : "clear"),
903 smb_fname_str_dbg(fsp->fsp_name)));
904 return NT_STATUS_INVALID_PARAMETER;
907 if (IS_IPC(conn) || IS_PRINT(conn)) {
908 DEBUG(9, ("attempt to %s sparse flag over invalid conn\n",
909 (sparse ? "set" : "clear")));
910 return NT_STATUS_INVALID_PARAMETER;
913 DEBUG(10,("file_set_sparse: setting sparse bit %u on file %s\n",
914 sparse, smb_fname_str_dbg(fsp->fsp_name)));
916 if (!lp_store_dos_attributes(SNUM(conn))) {
917 return NT_STATUS_INVALID_DEVICE_REQUEST;
920 status = vfs_stat_fsp(fsp);
921 if (!NT_STATUS_IS_OK(status)) {
925 old_dosmode = dos_mode(conn, fsp->fsp_name);
927 if (sparse && !(old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
928 new_dosmode = old_dosmode | FILE_ATTRIBUTE_SPARSE;
929 } else if (!sparse && (old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
930 new_dosmode = old_dosmode & ~FILE_ATTRIBUTE_SPARSE;
935 /* Store the DOS attributes in an EA. */
936 status = SMB_VFS_FSET_DOS_ATTRIBUTES(conn, fsp, new_dosmode);
937 if (!NT_STATUS_IS_OK(status)) {
941 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
942 FILE_NOTIFY_CHANGE_ATTRIBUTES,
943 fsp->fsp_name->base_name);
945 fsp->is_sparse = sparse;
950 /*******************************************************************
951 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
953 *******************************************************************/
955 int file_ntimes(connection_struct *conn, const struct smb_filename *smb_fname,
956 struct smb_file_time *ft)
962 DEBUG(6, ("file_ntime: actime: %s",
963 time_to_asc(convert_timespec_to_time_t(ft->atime))));
964 DEBUG(6, ("file_ntime: modtime: %s",
965 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
966 DEBUG(6, ("file_ntime: ctime: %s",
967 time_to_asc(convert_timespec_to_time_t(ft->ctime))));
968 DEBUG(6, ("file_ntime: createtime: %s",
969 time_to_asc(convert_timespec_to_time_t(ft->create_time))));
971 /* Don't update the time on read-only shares */
972 /* We need this as set_filetime (which can be called on
973 close and other paths) can end up calling this function
974 without the NEED_WRITE protection. Found by :
975 Leo Weppelman <leo@wau.mis.ah.nl>
978 if (!CAN_WRITE(conn)) {
982 if(SMB_VFS_NTIMES(conn, smb_fname, ft) == 0) {
986 if((errno != EPERM) && (errno != EACCES)) {
990 if(!lp_dos_filetimes(SNUM(conn))) {
994 /* We have permission (given by the Samba admin) to
995 break POSIX semantics and allow a user to change
996 the time on a file they don't own but can write to
1000 /* Check if we have write access. */
1001 if (can_write_to_file(conn, smb_fname)) {
1002 /* We are allowed to become root and change the filetime. */
1004 ret = SMB_VFS_NTIMES(conn, smb_fname, ft);
1011 /******************************************************************
1012 Force a "sticky" write time on a pathname. This will always be
1013 returned on all future write time queries and set on close.
1014 ******************************************************************/
1016 bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime)
1018 if (null_timespec(mtime)) {
1022 if (!set_sticky_write_time(fileid, mtime)) {
1029 /******************************************************************
1030 Force a "sticky" write time on an fsp. This will always be
1031 returned on all future write time queries and set on close.
1032 ******************************************************************/
1034 bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime)
1036 if (null_timespec(mtime)) {
1040 fsp->write_time_forced = true;
1041 TALLOC_FREE(fsp->update_write_time_event);
1043 return set_sticky_write_time_path(fsp->file_id, mtime);
1046 /******************************************************************
1047 Set a create time EA.
1048 ******************************************************************/
1050 NTSTATUS set_create_timespec_ea(connection_struct *conn,
1051 const struct smb_filename *psmb_fname,
1052 struct timespec create_time)
1054 struct smb_filename *smb_fname;
1058 if (!lp_store_dos_attributes(SNUM(conn))) {
1059 return NT_STATUS_OK;
1062 smb_fname = synthetic_smb_fname(talloc_tos(),
1063 psmb_fname->base_name,
1068 if (smb_fname == NULL) {
1069 return NT_STATUS_NO_MEMORY;
1072 dosmode = dos_mode(conn, smb_fname);
1074 smb_fname->st.st_ex_btime = create_time;
1076 ret = file_set_dosmode(conn, smb_fname, dosmode, NULL, false);
1078 return map_nt_error_from_unix(errno);
1081 DEBUG(10,("set_create_timespec_ea: wrote create time EA for file %s\n",
1082 smb_fname_str_dbg(smb_fname)));
1084 return NT_STATUS_OK;
1087 /******************************************************************
1088 Return a create time.
1089 ******************************************************************/
1091 struct timespec get_create_timespec(connection_struct *conn,
1092 struct files_struct *fsp,
1093 const struct smb_filename *smb_fname)
1095 return smb_fname->st.st_ex_btime;
1098 /******************************************************************
1099 Return a change time (may look at EA in future).
1100 ******************************************************************/
1102 struct timespec get_change_timespec(connection_struct *conn,
1103 struct files_struct *fsp,
1104 const struct smb_filename *smb_fname)
1106 return smb_fname->st.st_ex_mtime;
1109 /****************************************************************************
1110 Get a real open file handle we can do meta-data operations on. As it's
1111 going to be used under root access only on meta-data we should look for
1112 any existing open file handle first, and use that in preference (also to
1113 avoid kernel self-oplock breaks). If not use an INTERNAL_OPEN_ONLY handle.
1114 ****************************************************************************/
1116 static NTSTATUS get_file_handle_for_metadata(connection_struct *conn,
1117 const struct smb_filename *smb_fname,
1118 files_struct **ret_fsp,
1123 struct file_id file_id;
1124 struct smb_filename *smb_fname_cp = NULL;
1126 *need_close = false;
1128 if (!VALID_STAT(smb_fname->st)) {
1129 return NT_STATUS_INVALID_PARAMETER;
1132 file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1134 for(fsp = file_find_di_first(conn->sconn, file_id);
1136 fsp = file_find_di_next(fsp)) {
1137 if (fsp->fh->fd != -1) {
1139 return NT_STATUS_OK;
1143 smb_fname_cp = cp_smb_filename(talloc_tos(),
1145 if (smb_fname_cp == NULL) {
1146 return NT_STATUS_NO_MEMORY;
1149 /* Opens an INTERNAL_OPEN_ONLY write handle. */
1150 status = SMB_VFS_CREATE_FILE(
1153 0, /* root_dir_fid */
1154 smb_fname_cp, /* fname */
1155 FILE_WRITE_DATA, /* access_mask */
1156 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
1158 FILE_OPEN, /* create_disposition*/
1159 0, /* create_options */
1160 0, /* file_attributes */
1161 INTERNAL_OPEN_ONLY, /* oplock_request */
1163 0, /* allocation_size */
1164 0, /* private_flags */
1167 ret_fsp, /* result */
1169 NULL, NULL); /* create context */
1171 TALLOC_FREE(smb_fname_cp);
1173 if (NT_STATUS_IS_OK(status)) {