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 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(
139 talloc_tos(), inherit_from_dir, NULL, NULL);
140 if (smb_fname_parent == NULL) {
141 DEBUG(1,("unix_mode(%s) failed, [dir %s]: No memory\n",
142 smb_fname_str_dbg(smb_fname),
147 if (SMB_VFS_STAT(conn, smb_fname_parent) != 0) {
148 DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n",
149 smb_fname_str_dbg(smb_fname),
150 inherit_from_dir, strerror(errno)));
151 TALLOC_FREE(smb_fname_parent);
152 return(0); /* *** shouldn't happen! *** */
155 /* Save for later - but explicitly remove setuid bit for safety. */
156 dir_mode = smb_fname_parent->st.st_ex_mode & ~S_ISUID;
157 DEBUG(2,("unix_mode(%s) inherit mode %o\n",
158 smb_fname_str_dbg(smb_fname), (int)dir_mode));
161 TALLOC_FREE(smb_fname_parent);
164 if (IS_DOS_DIR(dosmode)) {
165 /* We never make directories read only for the owner as under DOS a user
166 can always create a file in a read-only directory. */
167 result |= (S_IFDIR | S_IWUSR);
170 /* Inherit mode of parent directory. */
173 /* Provisionally add all 'x' bits */
174 result |= (S_IXUSR | S_IXGRP | S_IXOTH);
176 /* Apply directory mask */
177 result &= lp_directory_mask(SNUM(conn));
178 /* Add in force bits */
179 result |= lp_force_directory_mode(SNUM(conn));
182 if (lp_map_archive(SNUM(conn)) && IS_DOS_ARCHIVE(dosmode))
185 if (lp_map_system(SNUM(conn)) && IS_DOS_SYSTEM(dosmode))
188 if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode))
192 /* Inherit 666 component of parent directory mode */
193 result |= dir_mode & (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
195 /* Apply mode mask */
196 result &= lp_create_mask(SNUM(conn));
197 /* Add in force bits */
198 result |= lp_force_create_mode(SNUM(conn));
202 DBG_INFO("unix_mode(%s) returning 0%o\n",
203 smb_fname_str_dbg(smb_fname), (int)result);
208 /****************************************************************************
209 Change a unix mode to a dos mode.
210 ****************************************************************************/
212 static uint32_t dos_mode_from_sbuf(connection_struct *conn,
213 const struct smb_filename *smb_fname)
216 enum mapreadonly_options ro_opts = (enum mapreadonly_options)lp_map_readonly(SNUM(conn));
218 #if defined(UF_IMMUTABLE) && defined(SF_IMMUTABLE)
219 /* if we can find out if a file is immutable we should report it r/o */
220 if (smb_fname->st.st_ex_flags & (UF_IMMUTABLE | SF_IMMUTABLE)) {
221 result |= FILE_ATTRIBUTE_READONLY;
224 if (ro_opts == MAP_READONLY_YES) {
225 /* Original Samba method - map inverse of user "w" bit. */
226 if ((smb_fname->st.st_ex_mode & S_IWUSR) == 0) {
227 result |= FILE_ATTRIBUTE_READONLY;
229 } else if (ro_opts == MAP_READONLY_PERMISSIONS) {
230 /* Check actual permissions for read-only. */
231 if (!can_write_to_file(conn, smb_fname)) {
232 result |= FILE_ATTRIBUTE_READONLY;
234 } /* Else never set the readonly bit. */
236 if (MAP_ARCHIVE(conn) && ((smb_fname->st.st_ex_mode & S_IXUSR) != 0))
237 result |= FILE_ATTRIBUTE_ARCHIVE;
239 if (MAP_SYSTEM(conn) && ((smb_fname->st.st_ex_mode & S_IXGRP) != 0))
240 result |= FILE_ATTRIBUTE_SYSTEM;
242 if (MAP_HIDDEN(conn) && ((smb_fname->st.st_ex_mode & S_IXOTH) != 0))
243 result |= FILE_ATTRIBUTE_HIDDEN;
245 if (S_ISDIR(smb_fname->st.st_ex_mode))
246 result = FILE_ATTRIBUTE_DIRECTORY | (result & FILE_ATTRIBUTE_READONLY);
248 result |= set_link_read_only_flag(&smb_fname->st);
250 dos_mode_debug_print(__func__, result);
255 /****************************************************************************
256 Get DOS attributes from an EA.
257 This can also pull the create time into the stat struct inside smb_fname.
258 ****************************************************************************/
260 static bool get_ea_dos_attribute(connection_struct *conn,
261 struct smb_filename *smb_fname,
264 struct xattr_DOSATTRIB dosattrib;
265 enum ndr_err_code ndr_err;
271 if (!lp_store_dos_attributes(SNUM(conn))) {
275 /* Don't reset pattr to zero as we may already have filename-based attributes we
278 sizeret = SMB_VFS_GETXATTR(conn, smb_fname->base_name,
279 SAMBA_XATTR_DOS_ATTRIB, attrstr,
282 DBG_INFO("Cannot get attribute "
283 "from EA on file %s: Error = %s\n",
284 smb_fname_str_dbg(smb_fname), strerror(errno));
288 blob.data = (uint8_t *)attrstr;
289 blob.length = sizeret;
291 ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &dosattrib,
292 (ndr_pull_flags_fn_t)ndr_pull_xattr_DOSATTRIB);
294 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
295 DEBUG(1,("get_ea_dos_attribute: bad ndr decode "
296 "from EA on file %s: Error = %s\n",
297 smb_fname_str_dbg(smb_fname),
298 ndr_errstr(ndr_err)));
302 DEBUG(10,("get_ea_dos_attribute: %s attr = %s\n",
303 smb_fname_str_dbg(smb_fname), dosattrib.attrib_hex));
305 switch (dosattrib.version) {
307 dosattr = dosattrib.info.compatinfoFFFF.attrib;
310 dosattr = dosattrib.info.info1.attrib;
311 if (!null_nttime(dosattrib.info.info1.create_time)) {
312 struct timespec create_time =
313 nt_time_to_unix_timespec(
314 dosattrib.info.info1.create_time);
316 update_stat_ex_create_time(&smb_fname->st,
319 DEBUG(10,("get_ea_dos_attribute: file %s case 1 "
321 smb_fname_str_dbg(smb_fname),
322 time_to_asc(convert_timespec_to_time_t(
327 dosattr = dosattrib.info.oldinfo2.attrib;
328 /* Don't know what flags to check for this case. */
331 dosattr = dosattrib.info.info3.attrib;
332 if ((dosattrib.info.info3.valid_flags & XATTR_DOSINFO_CREATE_TIME) &&
333 !null_nttime(dosattrib.info.info3.create_time)) {
334 struct timespec create_time =
335 nt_time_to_unix_timespec(
336 dosattrib.info.info3.create_time);
338 update_stat_ex_create_time(&smb_fname->st,
341 DEBUG(10,("get_ea_dos_attribute: file %s case 3 "
343 smb_fname_str_dbg(smb_fname),
344 time_to_asc(convert_timespec_to_time_t(
349 DEBUG(1,("get_ea_dos_attribute: Badly formed DOSATTRIB on "
350 "file %s - %s\n", smb_fname_str_dbg(smb_fname),
355 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
356 dosattr |= FILE_ATTRIBUTE_DIRECTORY;
358 /* FILE_ATTRIBUTE_SPARSE is valid on get but not on set. */
359 *pattr |= (uint32_t)(dosattr & (SAMBA_ATTRIBUTES_MASK|FILE_ATTRIBUTE_SPARSE));
361 dos_mode_debug_print(__func__, *pattr);
366 /****************************************************************************
367 Set DOS attributes in an EA.
368 Also sets the create time.
369 ****************************************************************************/
371 static bool set_ea_dos_attribute(connection_struct *conn,
372 struct smb_filename *smb_fname,
375 struct xattr_DOSATTRIB dosattrib;
376 enum ndr_err_code ndr_err;
379 ZERO_STRUCT(dosattrib);
382 dosattrib.version = 3;
383 dosattrib.info.info3.valid_flags = XATTR_DOSINFO_ATTRIB|
384 XATTR_DOSINFO_CREATE_TIME;
385 dosattrib.info.info3.attrib = dosmode;
386 dosattrib.info.info3.create_time = unix_timespec_to_nt_time(
387 smb_fname->st.st_ex_btime);
389 DEBUG(10,("set_ea_dos_attributes: set attribute 0x%x, btime = %s on file %s\n",
390 (unsigned int)dosmode,
391 time_to_asc(convert_timespec_to_time_t(smb_fname->st.st_ex_btime)),
392 smb_fname_str_dbg(smb_fname) ));
394 ndr_err = ndr_push_struct_blob(
395 &blob, talloc_tos(), &dosattrib,
396 (ndr_push_flags_fn_t)ndr_push_xattr_DOSATTRIB);
398 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
399 DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n",
400 ndr_errstr(ndr_err)));
404 if (blob.data == NULL || blob.length == 0) {
408 if (SMB_VFS_SETXATTR(conn, smb_fname->base_name,
409 SAMBA_XATTR_DOS_ATTRIB, blob.data, blob.length,
412 bool need_close = false;
413 files_struct *fsp = NULL;
415 if((errno != EPERM) && (errno != EACCES)) {
416 DBG_INFO("Cannot set "
417 "attribute EA on file %s: Error = %s\n",
418 smb_fname_str_dbg(smb_fname), strerror(errno));
422 /* We want DOS semantics, ie allow non owner with write permission to change the
423 bits on a file. Just like file_ntimes below.
426 /* Check if we have write access. */
427 if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
430 if (!can_write_to_file(conn, smb_fname)) {
435 * We need to get an open file handle to do the
436 * metadata operation under root.
439 if (!NT_STATUS_IS_OK(get_file_handle_for_metadata(conn,
447 if (SMB_VFS_FSETXATTR(fsp,
448 SAMBA_XATTR_DOS_ATTRIB, blob.data,
449 blob.length, 0) == 0) {
454 close_file(NULL, fsp, NORMAL_CLOSE);
458 DEBUG(10,("set_ea_dos_attribute: set EA 0x%x on file %s\n",
459 (unsigned int)dosmode,
460 smb_fname_str_dbg(smb_fname)));
464 /****************************************************************************
465 Change a unix mode to a dos mode for an ms dfs link.
466 ****************************************************************************/
468 uint32_t dos_mode_msdfs(connection_struct *conn,
469 const struct smb_filename *smb_fname)
473 DEBUG(8,("dos_mode_msdfs: %s\n", smb_fname_str_dbg(smb_fname)));
475 if (!VALID_STAT(smb_fname->st)) {
479 /* First do any modifications that depend on the path name. */
480 /* hide files with a name starting with a . */
481 if (lp_hide_dot_files(SNUM(conn))) {
482 const char *p = strrchr_m(smb_fname->base_name, '/');
486 p = smb_fname->base_name;
489 /* Only . and .. are not hidden. */
490 if (p[0] == '.' && !((p[1] == '\0') ||
491 (p[1] == '.' && p[2] == '\0'))) {
492 result |= FILE_ATTRIBUTE_HIDDEN;
496 result |= dos_mode_from_sbuf(conn, smb_fname);
498 /* Optimization : Only call is_hidden_path if it's not already
500 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
501 IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
502 result |= FILE_ATTRIBUTE_HIDDEN;
506 result = FILE_ATTRIBUTE_NORMAL;
509 result = filter_mode_by_protocol(result);
512 * Add in that it is a reparse point
514 result |= FILE_ATTRIBUTE_REPARSE_POINT;
516 dos_mode_debug_print(__func__, result);
522 * check whether a file or directory is flagged as compressed.
524 static NTSTATUS dos_mode_check_compressed(connection_struct *conn,
525 struct smb_filename *smb_fname,
529 uint16_t compression_fmt;
530 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
531 if (tmp_ctx == NULL) {
532 status = NT_STATUS_NO_MEMORY;
536 status = SMB_VFS_GET_COMPRESSION(conn, tmp_ctx, NULL, smb_fname,
538 if (!NT_STATUS_IS_OK(status)) {
542 if (compression_fmt == COMPRESSION_FORMAT_LZNT1) {
543 *is_compressed = true;
545 *is_compressed = false;
547 status = NT_STATUS_OK;
550 talloc_free(tmp_ctx);
555 /****************************************************************************
556 Change a unix mode to a dos mode.
557 May also read the create timespec into the stat struct in smb_fname
558 if "store dos attributes" is true.
559 ****************************************************************************/
561 uint32_t dos_mode(connection_struct *conn, struct smb_filename *smb_fname)
566 DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname)));
568 if (!VALID_STAT(smb_fname->st)) {
572 /* First do any modifications that depend on the path name. */
573 /* hide files with a name starting with a . */
574 if (lp_hide_dot_files(SNUM(conn))) {
575 const char *p = strrchr_m(smb_fname->base_name,'/');
579 p = smb_fname->base_name;
582 /* Only . and .. are not hidden. */
583 if (p[0] == '.' && !((p[1] == '\0') ||
584 (p[1] == '.' && p[2] == '\0'))) {
585 result |= FILE_ATTRIBUTE_HIDDEN;
589 /* Get the DOS attributes from an EA by preference. */
590 if (!get_ea_dos_attribute(conn, smb_fname, &result)) {
591 result |= dos_mode_from_sbuf(conn, smb_fname);
594 offline = SMB_VFS_IS_OFFLINE(conn, smb_fname, &smb_fname->st);
595 if (S_ISREG(smb_fname->st.st_ex_mode) && offline) {
596 result |= FILE_ATTRIBUTE_OFFLINE;
599 if (conn->fs_capabilities & FILE_FILE_COMPRESSION) {
600 bool compressed = false;
601 NTSTATUS status = dos_mode_check_compressed(conn, smb_fname,
603 if (NT_STATUS_IS_OK(status) && compressed) {
604 result |= FILE_ATTRIBUTE_COMPRESSED;
608 /* Optimization : Only call is_hidden_path if it's not already
610 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
611 IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
612 result |= FILE_ATTRIBUTE_HIDDEN;
616 result = FILE_ATTRIBUTE_NORMAL;
619 result = filter_mode_by_protocol(result);
621 dos_mode_debug_print(__func__, result);
626 /*******************************************************************
627 chmod a file - but preserve some bits.
628 If "store dos attributes" is also set it will store the create time
629 from the stat struct in smb_fname (in NTTIME format) in the EA
631 ********************************************************************/
633 int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname,
634 uint32_t dosmode, const char *parent_dir, bool newfile)
639 int ret = -1, lret = -1;
641 struct timespec new_create_timespec;
642 files_struct *fsp = NULL;
643 bool need_close = false;
646 if (!CAN_WRITE(conn)) {
651 /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
652 dosmode &= (SAMBA_ATTRIBUTES_MASK | FILE_ATTRIBUTE_OFFLINE);
654 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
655 dosmode, smb_fname_str_dbg(smb_fname)));
657 unixmode = smb_fname->st.st_ex_mode;
659 get_acl_group_bits(conn, smb_fname->base_name,
660 &smb_fname->st.st_ex_mode);
662 if (S_ISDIR(smb_fname->st.st_ex_mode))
663 dosmode |= FILE_ATTRIBUTE_DIRECTORY;
665 dosmode &= ~FILE_ATTRIBUTE_DIRECTORY;
667 new_create_timespec = smb_fname->st.st_ex_btime;
669 old_mode = dos_mode(conn, smb_fname);
671 if ((dosmode & FILE_ATTRIBUTE_OFFLINE) &&
672 !(old_mode & FILE_ATTRIBUTE_OFFLINE)) {
673 lret = SMB_VFS_SET_OFFLINE(conn, smb_fname);
675 if (errno == ENOTSUP) {
676 DEBUG(10, ("Setting FILE_ATTRIBUTE_OFFLINE for "
677 "%s/%s is not supported.\n",
679 smb_fname_str_dbg(smb_fname)));
681 DEBUG(0, ("An error occurred while setting "
682 "FILE_ATTRIBUTE_OFFLINE for "
683 "%s/%s: %s", parent_dir,
684 smb_fname_str_dbg(smb_fname),
690 dosmode &= ~FILE_ATTRIBUTE_OFFLINE;
691 old_mode &= ~FILE_ATTRIBUTE_OFFLINE;
693 smb_fname->st.st_ex_btime = new_create_timespec;
695 /* Store the DOS attributes in an EA by preference. */
696 if (lp_store_dos_attributes(SNUM(conn))) {
698 * Don't fall back to using UNIX modes. Finally
699 * follow the smb.conf manpage.
701 if (!set_ea_dos_attribute(conn, smb_fname, dosmode)) {
705 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
706 FILE_NOTIFY_CHANGE_ATTRIBUTES,
707 smb_fname->base_name);
709 smb_fname->st.st_ex_mode = unixmode;
713 unixmode = unix_mode(conn, dosmode, smb_fname, parent_dir);
715 /* preserve the file type bits */
718 /* preserve the s bits */
719 mask |= (S_ISUID | S_ISGID);
721 /* preserve the t bit */
726 /* possibly preserve the x bits */
727 if (!MAP_ARCHIVE(conn))
729 if (!MAP_SYSTEM(conn))
731 if (!MAP_HIDDEN(conn))
734 unixmode |= (smb_fname->st.st_ex_mode & mask);
736 /* if we previously had any r bits set then leave them alone */
737 if ((tmp = smb_fname->st.st_ex_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
738 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
742 /* if we previously had any w bits set then leave them alone
743 whilst adding in the new w bits, if the new mode is not rdonly */
744 if (!IS_DOS_READONLY(dosmode)) {
745 unixmode |= (smb_fname->st.st_ex_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
749 * From the chmod 2 man page:
751 * "If the calling process is not privileged, and the group of the file
752 * does not match the effective group ID of the process or one of its
753 * supplementary group IDs, the S_ISGID bit will be turned off, but
754 * this will not cause an error to be returned."
756 * Simply refuse to do the chmod in this case.
759 if (S_ISDIR(smb_fname->st.st_ex_mode) && (unixmode & S_ISGID) &&
760 geteuid() != sec_initial_uid() &&
761 !current_user_in_group(conn, smb_fname->st.st_ex_gid)) {
762 DEBUG(3,("file_set_dosmode: setgid bit cannot be "
763 "set for directory %s\n",
764 smb_fname_str_dbg(smb_fname)));
769 ret = SMB_VFS_CHMOD(conn, smb_fname, unixmode);
771 if(!newfile || (lret != -1)) {
772 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
773 FILE_NOTIFY_CHANGE_ATTRIBUTES,
774 smb_fname->base_name);
776 smb_fname->st.st_ex_mode = unixmode;
780 if((errno != EPERM) && (errno != EACCES))
783 if(!lp_dos_filemode(SNUM(conn)))
786 /* We want DOS semantics, ie allow non owner with write permission to change the
787 bits on a file. Just like file_ntimes below.
790 if (!can_write_to_file(conn, smb_fname)) {
796 * We need to get an open file handle to do the
797 * metadata operation under root.
800 status = get_file_handle_for_metadata(conn,
804 if (!NT_STATUS_IS_OK(status)) {
805 errno = map_errno_from_nt_status(status);
810 ret = SMB_VFS_FCHMOD(fsp, unixmode);
813 close_file(NULL, fsp, NORMAL_CLOSE);
816 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
817 FILE_NOTIFY_CHANGE_ATTRIBUTES,
818 smb_fname->base_name);
821 smb_fname->st.st_ex_mode = unixmode;
828 NTSTATUS file_set_sparse(connection_struct *conn,
832 uint32_t old_dosmode;
833 uint32_t new_dosmode;
836 if (!CAN_WRITE(conn)) {
837 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
838 "on readonly share[%s]\n",
839 smb_fname_str_dbg(fsp->fsp_name),
841 lp_servicename(talloc_tos(), SNUM(conn))));
842 return NT_STATUS_MEDIA_WRITE_PROTECTED;
846 * Windows Server 2008 & 2012 permit FSCTL_SET_SPARSE if any of the
847 * following access flags are granted.
849 if ((fsp->access_mask & (FILE_WRITE_DATA
850 | FILE_WRITE_ATTRIBUTES
851 | SEC_FILE_APPEND_DATA)) == 0) {
852 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
853 "access_mask[0x%08X] - access denied\n",
854 smb_fname_str_dbg(fsp->fsp_name),
857 return NT_STATUS_ACCESS_DENIED;
860 if (fsp->is_directory) {
861 DEBUG(9, ("invalid attempt to %s sparse flag on dir %s\n",
862 (sparse ? "set" : "clear"),
863 smb_fname_str_dbg(fsp->fsp_name)));
864 return NT_STATUS_INVALID_PARAMETER;
867 if (IS_IPC(conn) || IS_PRINT(conn)) {
868 DEBUG(9, ("attempt to %s sparse flag over invalid conn\n",
869 (sparse ? "set" : "clear")));
870 return NT_STATUS_INVALID_PARAMETER;
873 DEBUG(10,("file_set_sparse: setting sparse bit %u on file %s\n",
874 sparse, smb_fname_str_dbg(fsp->fsp_name)));
876 if (!lp_store_dos_attributes(SNUM(conn))) {
877 return NT_STATUS_INVALID_DEVICE_REQUEST;
880 status = vfs_stat_fsp(fsp);
881 if (!NT_STATUS_IS_OK(status)) {
885 old_dosmode = dos_mode(conn, fsp->fsp_name);
887 if (sparse && !(old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
888 new_dosmode = old_dosmode | FILE_ATTRIBUTE_SPARSE;
889 } else if (!sparse && (old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
890 new_dosmode = old_dosmode & ~FILE_ATTRIBUTE_SPARSE;
895 /* Store the DOS attributes in an EA. */
896 if (!set_ea_dos_attribute(conn, fsp->fsp_name,
901 return map_nt_error_from_unix(errno);
904 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
905 FILE_NOTIFY_CHANGE_ATTRIBUTES,
906 fsp->fsp_name->base_name);
908 fsp->is_sparse = sparse;
913 /*******************************************************************
914 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
916 *******************************************************************/
918 int file_ntimes(connection_struct *conn, const struct smb_filename *smb_fname,
919 struct smb_file_time *ft)
925 DEBUG(6, ("file_ntime: actime: %s",
926 time_to_asc(convert_timespec_to_time_t(ft->atime))));
927 DEBUG(6, ("file_ntime: modtime: %s",
928 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
929 DEBUG(6, ("file_ntime: ctime: %s",
930 time_to_asc(convert_timespec_to_time_t(ft->ctime))));
931 DEBUG(6, ("file_ntime: createtime: %s",
932 time_to_asc(convert_timespec_to_time_t(ft->create_time))));
934 /* Don't update the time on read-only shares */
935 /* We need this as set_filetime (which can be called on
936 close and other paths) can end up calling this function
937 without the NEED_WRITE protection. Found by :
938 Leo Weppelman <leo@wau.mis.ah.nl>
941 if (!CAN_WRITE(conn)) {
945 if(SMB_VFS_NTIMES(conn, smb_fname, ft) == 0) {
949 if((errno != EPERM) && (errno != EACCES)) {
953 if(!lp_dos_filetimes(SNUM(conn))) {
957 /* We have permission (given by the Samba admin) to
958 break POSIX semantics and allow a user to change
959 the time on a file they don't own but can write to
963 /* Check if we have write access. */
964 if (can_write_to_file(conn, smb_fname)) {
965 /* We are allowed to become root and change the filetime. */
967 ret = SMB_VFS_NTIMES(conn, smb_fname, ft);
974 /******************************************************************
975 Force a "sticky" write time on a pathname. This will always be
976 returned on all future write time queries and set on close.
977 ******************************************************************/
979 bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime)
981 if (null_timespec(mtime)) {
985 if (!set_sticky_write_time(fileid, mtime)) {
992 /******************************************************************
993 Force a "sticky" write time on an fsp. This will always be
994 returned on all future write time queries and set on close.
995 ******************************************************************/
997 bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime)
999 if (null_timespec(mtime)) {
1003 fsp->write_time_forced = true;
1004 TALLOC_FREE(fsp->update_write_time_event);
1006 return set_sticky_write_time_path(fsp->file_id, mtime);
1009 /******************************************************************
1010 Set a create time EA.
1011 ******************************************************************/
1013 NTSTATUS set_create_timespec_ea(connection_struct *conn,
1014 const struct smb_filename *psmb_fname,
1015 struct timespec create_time)
1017 struct smb_filename *smb_fname;
1021 if (!lp_store_dos_attributes(SNUM(conn))) {
1022 return NT_STATUS_OK;
1025 smb_fname = synthetic_smb_fname(talloc_tos(), psmb_fname->base_name,
1026 NULL, &psmb_fname->st);
1028 if (smb_fname == NULL) {
1029 return NT_STATUS_NO_MEMORY;
1032 dosmode = dos_mode(conn, smb_fname);
1034 smb_fname->st.st_ex_btime = create_time;
1036 ret = file_set_dosmode(conn, smb_fname, dosmode, NULL, false);
1038 map_nt_error_from_unix(errno);
1041 DEBUG(10,("set_create_timespec_ea: wrote create time EA for file %s\n",
1042 smb_fname_str_dbg(smb_fname)));
1044 return NT_STATUS_OK;
1047 /******************************************************************
1048 Return a create time.
1049 ******************************************************************/
1051 struct timespec get_create_timespec(connection_struct *conn,
1052 struct files_struct *fsp,
1053 const struct smb_filename *smb_fname)
1055 return smb_fname->st.st_ex_btime;
1058 /******************************************************************
1059 Return a change time (may look at EA in future).
1060 ******************************************************************/
1062 struct timespec get_change_timespec(connection_struct *conn,
1063 struct files_struct *fsp,
1064 const struct smb_filename *smb_fname)
1066 return smb_fname->st.st_ex_mtime;
1069 /****************************************************************************
1070 Get a real open file handle we can do meta-data operations on. As it's
1071 going to be used under root access only on meta-data we should look for
1072 any existing open file handle first, and use that in preference (also to
1073 avoid kernel self-oplock breaks). If not use an INTERNAL_OPEN_ONLY handle.
1074 ****************************************************************************/
1076 static NTSTATUS get_file_handle_for_metadata(connection_struct *conn,
1077 struct smb_filename *smb_fname,
1078 files_struct **ret_fsp,
1083 struct file_id file_id;
1085 *need_close = false;
1087 if (!VALID_STAT(smb_fname->st)) {
1088 return NT_STATUS_INVALID_PARAMETER;
1091 file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1093 for(fsp = file_find_di_first(conn->sconn, file_id);
1095 fsp = file_find_di_next(fsp)) {
1096 if (fsp->fh->fd != -1) {
1098 return NT_STATUS_OK;
1102 /* Opens an INTERNAL_OPEN_ONLY write handle. */
1103 status = SMB_VFS_CREATE_FILE(
1106 0, /* root_dir_fid */
1107 smb_fname, /* fname */
1108 FILE_WRITE_DATA, /* access_mask */
1109 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
1111 FILE_OPEN, /* create_disposition*/
1112 0, /* create_options */
1113 0, /* file_attributes */
1114 INTERNAL_OPEN_ONLY, /* oplock_request */
1116 0, /* allocation_size */
1117 0, /* private_flags */
1120 ret_fsp, /* result */
1122 NULL, NULL); /* create context */
1124 if (NT_STATUS_IS_OK(status)) {