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(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 static bool 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))) {
278 /* Don't reset pattr to zero as we may already have filename-based attributes we
281 sizeret = SMB_VFS_GETXATTR(conn, smb_fname->base_name,
282 SAMBA_XATTR_DOS_ATTRIB, attrstr,
285 DBG_INFO("Cannot get attribute "
286 "from EA on file %s: Error = %s\n",
287 smb_fname_str_dbg(smb_fname), strerror(errno));
291 blob.data = (uint8_t *)attrstr;
292 blob.length = sizeret;
294 ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &dosattrib,
295 (ndr_pull_flags_fn_t)ndr_pull_xattr_DOSATTRIB);
297 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
298 DEBUG(1,("get_ea_dos_attribute: bad ndr decode "
299 "from EA on file %s: Error = %s\n",
300 smb_fname_str_dbg(smb_fname),
301 ndr_errstr(ndr_err)));
305 DEBUG(10,("get_ea_dos_attribute: %s attr = %s\n",
306 smb_fname_str_dbg(smb_fname), dosattrib.attrib_hex));
308 switch (dosattrib.version) {
310 dosattr = dosattrib.info.compatinfoFFFF.attrib;
313 dosattr = dosattrib.info.info1.attrib;
314 if (!null_nttime(dosattrib.info.info1.create_time)) {
315 struct timespec create_time =
316 nt_time_to_unix_timespec(
317 dosattrib.info.info1.create_time);
319 update_stat_ex_create_time(&smb_fname->st,
322 DEBUG(10,("get_ea_dos_attribute: file %s case 1 "
324 smb_fname_str_dbg(smb_fname),
325 time_to_asc(convert_timespec_to_time_t(
330 dosattr = dosattrib.info.oldinfo2.attrib;
331 /* Don't know what flags to check for this case. */
334 dosattr = dosattrib.info.info3.attrib;
335 if ((dosattrib.info.info3.valid_flags & XATTR_DOSINFO_CREATE_TIME) &&
336 !null_nttime(dosattrib.info.info3.create_time)) {
337 struct timespec create_time =
338 nt_time_to_unix_timespec(
339 dosattrib.info.info3.create_time);
341 update_stat_ex_create_time(&smb_fname->st,
344 DEBUG(10,("get_ea_dos_attribute: file %s case 3 "
346 smb_fname_str_dbg(smb_fname),
347 time_to_asc(convert_timespec_to_time_t(
352 DEBUG(1,("get_ea_dos_attribute: Badly formed DOSATTRIB on "
353 "file %s - %s\n", smb_fname_str_dbg(smb_fname),
358 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
359 dosattr |= FILE_ATTRIBUTE_DIRECTORY;
361 /* FILE_ATTRIBUTE_SPARSE is valid on get but not on set. */
362 *pattr |= (uint32_t)(dosattr & (SAMBA_ATTRIBUTES_MASK|FILE_ATTRIBUTE_SPARSE));
364 dos_mode_debug_print(__func__, *pattr);
369 /****************************************************************************
370 Set DOS attributes in an EA.
371 Also sets the create time.
372 ****************************************************************************/
374 static bool set_ea_dos_attribute(connection_struct *conn,
375 struct smb_filename *smb_fname,
378 struct xattr_DOSATTRIB dosattrib;
379 enum ndr_err_code ndr_err;
382 ZERO_STRUCT(dosattrib);
385 dosattrib.version = 3;
386 dosattrib.info.info3.valid_flags = XATTR_DOSINFO_ATTRIB|
387 XATTR_DOSINFO_CREATE_TIME;
388 dosattrib.info.info3.attrib = dosmode;
389 dosattrib.info.info3.create_time = unix_timespec_to_nt_time(
390 smb_fname->st.st_ex_btime);
392 DEBUG(10,("set_ea_dos_attributes: set attribute 0x%x, btime = %s on file %s\n",
393 (unsigned int)dosmode,
394 time_to_asc(convert_timespec_to_time_t(smb_fname->st.st_ex_btime)),
395 smb_fname_str_dbg(smb_fname) ));
397 ndr_err = ndr_push_struct_blob(
398 &blob, talloc_tos(), &dosattrib,
399 (ndr_push_flags_fn_t)ndr_push_xattr_DOSATTRIB);
401 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
402 DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n",
403 ndr_errstr(ndr_err)));
407 if (blob.data == NULL || blob.length == 0) {
411 if (SMB_VFS_SETXATTR(conn, smb_fname->base_name,
412 SAMBA_XATTR_DOS_ATTRIB, blob.data, blob.length,
415 bool need_close = false;
416 files_struct *fsp = NULL;
418 if((errno != EPERM) && (errno != EACCES)) {
419 DBG_INFO("Cannot set "
420 "attribute EA on file %s: Error = %s\n",
421 smb_fname_str_dbg(smb_fname), strerror(errno));
425 /* We want DOS semantics, ie allow non owner with write permission to change the
426 bits on a file. Just like file_ntimes below.
429 /* Check if we have write access. */
430 if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
433 if (!can_write_to_file(conn, smb_fname)) {
438 * We need to get an open file handle to do the
439 * metadata operation under root.
442 if (!NT_STATUS_IS_OK(get_file_handle_for_metadata(conn,
450 if (SMB_VFS_FSETXATTR(fsp,
451 SAMBA_XATTR_DOS_ATTRIB, blob.data,
452 blob.length, 0) == 0) {
457 close_file(NULL, fsp, NORMAL_CLOSE);
461 DEBUG(10,("set_ea_dos_attribute: set EA 0x%x on file %s\n",
462 (unsigned int)dosmode,
463 smb_fname_str_dbg(smb_fname)));
467 /****************************************************************************
468 Change a unix mode to a dos mode for an ms dfs link.
469 ****************************************************************************/
471 uint32_t dos_mode_msdfs(connection_struct *conn,
472 const struct smb_filename *smb_fname)
476 DEBUG(8,("dos_mode_msdfs: %s\n", smb_fname_str_dbg(smb_fname)));
478 if (!VALID_STAT(smb_fname->st)) {
482 /* First do any modifications that depend on the path name. */
483 /* hide files with a name starting with a . */
484 if (lp_hide_dot_files(SNUM(conn))) {
485 const char *p = strrchr_m(smb_fname->base_name, '/');
489 p = smb_fname->base_name;
492 /* Only . and .. are not hidden. */
493 if (p[0] == '.' && !((p[1] == '\0') ||
494 (p[1] == '.' && p[2] == '\0'))) {
495 result |= FILE_ATTRIBUTE_HIDDEN;
499 result |= dos_mode_from_sbuf(conn, smb_fname);
501 /* Optimization : Only call is_hidden_path if it's not already
503 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
504 IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
505 result |= FILE_ATTRIBUTE_HIDDEN;
509 result = FILE_ATTRIBUTE_NORMAL;
512 result = filter_mode_by_protocol(result);
515 * Add in that it is a reparse point
517 result |= FILE_ATTRIBUTE_REPARSE_POINT;
519 dos_mode_debug_print(__func__, result);
525 * check whether a file or directory is flagged as compressed.
527 static NTSTATUS dos_mode_check_compressed(connection_struct *conn,
528 struct smb_filename *smb_fname,
532 uint16_t compression_fmt;
533 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
534 if (tmp_ctx == NULL) {
535 status = NT_STATUS_NO_MEMORY;
539 status = SMB_VFS_GET_COMPRESSION(conn, tmp_ctx, NULL, smb_fname,
541 if (!NT_STATUS_IS_OK(status)) {
545 if (compression_fmt == COMPRESSION_FORMAT_LZNT1) {
546 *is_compressed = true;
548 *is_compressed = false;
550 status = NT_STATUS_OK;
553 talloc_free(tmp_ctx);
558 /****************************************************************************
559 Change a unix mode to a dos mode.
560 May also read the create timespec into the stat struct in smb_fname
561 if "store dos attributes" is true.
562 ****************************************************************************/
564 uint32_t dos_mode(connection_struct *conn, struct smb_filename *smb_fname)
569 DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname)));
571 if (!VALID_STAT(smb_fname->st)) {
575 /* First do any modifications that depend on the path name. */
576 /* hide files with a name starting with a . */
577 if (lp_hide_dot_files(SNUM(conn))) {
578 const char *p = strrchr_m(smb_fname->base_name,'/');
582 p = smb_fname->base_name;
585 /* Only . and .. are not hidden. */
586 if (p[0] == '.' && !((p[1] == '\0') ||
587 (p[1] == '.' && p[2] == '\0'))) {
588 result |= FILE_ATTRIBUTE_HIDDEN;
592 /* Get the DOS attributes from an EA by preference. */
593 if (!get_ea_dos_attribute(conn, smb_fname, &result)) {
594 result |= dos_mode_from_sbuf(conn, smb_fname);
597 offline = SMB_VFS_IS_OFFLINE(conn, smb_fname, &smb_fname->st);
598 if (S_ISREG(smb_fname->st.st_ex_mode) && offline) {
599 result |= FILE_ATTRIBUTE_OFFLINE;
602 if (conn->fs_capabilities & FILE_FILE_COMPRESSION) {
603 bool compressed = false;
604 NTSTATUS status = dos_mode_check_compressed(conn, smb_fname,
606 if (NT_STATUS_IS_OK(status) && compressed) {
607 result |= FILE_ATTRIBUTE_COMPRESSED;
611 /* Optimization : Only call is_hidden_path if it's not already
613 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
614 IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
615 result |= FILE_ATTRIBUTE_HIDDEN;
619 result = FILE_ATTRIBUTE_NORMAL;
622 result = filter_mode_by_protocol(result);
624 dos_mode_debug_print(__func__, result);
629 /*******************************************************************
630 chmod a file - but preserve some bits.
631 If "store dos attributes" is also set it will store the create time
632 from the stat struct in smb_fname (in NTTIME format) in the EA
634 ********************************************************************/
636 int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname,
637 uint32_t dosmode, const char *parent_dir, bool newfile)
642 int ret = -1, lret = -1;
644 struct timespec new_create_timespec;
645 files_struct *fsp = NULL;
646 bool need_close = false;
649 if (!CAN_WRITE(conn)) {
654 /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
655 dosmode &= (SAMBA_ATTRIBUTES_MASK | FILE_ATTRIBUTE_OFFLINE);
657 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
658 dosmode, smb_fname_str_dbg(smb_fname)));
660 unixmode = smb_fname->st.st_ex_mode;
662 get_acl_group_bits(conn, smb_fname->base_name,
663 &smb_fname->st.st_ex_mode);
665 if (S_ISDIR(smb_fname->st.st_ex_mode))
666 dosmode |= FILE_ATTRIBUTE_DIRECTORY;
668 dosmode &= ~FILE_ATTRIBUTE_DIRECTORY;
670 new_create_timespec = smb_fname->st.st_ex_btime;
672 old_mode = dos_mode(conn, smb_fname);
674 if ((dosmode & FILE_ATTRIBUTE_OFFLINE) &&
675 !(old_mode & FILE_ATTRIBUTE_OFFLINE)) {
676 lret = SMB_VFS_SET_OFFLINE(conn, smb_fname);
678 if (errno == ENOTSUP) {
679 DEBUG(10, ("Setting FILE_ATTRIBUTE_OFFLINE for "
680 "%s/%s is not supported.\n",
682 smb_fname_str_dbg(smb_fname)));
684 DEBUG(0, ("An error occurred while setting "
685 "FILE_ATTRIBUTE_OFFLINE for "
686 "%s/%s: %s", parent_dir,
687 smb_fname_str_dbg(smb_fname),
693 dosmode &= ~FILE_ATTRIBUTE_OFFLINE;
694 old_mode &= ~FILE_ATTRIBUTE_OFFLINE;
696 smb_fname->st.st_ex_btime = new_create_timespec;
698 /* Store the DOS attributes in an EA by preference. */
699 if (lp_store_dos_attributes(SNUM(conn))) {
701 * Don't fall back to using UNIX modes. Finally
702 * follow the smb.conf manpage.
704 if (!set_ea_dos_attribute(conn, smb_fname, dosmode)) {
708 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
709 FILE_NOTIFY_CHANGE_ATTRIBUTES,
710 smb_fname->base_name);
712 smb_fname->st.st_ex_mode = unixmode;
716 unixmode = unix_mode(conn, dosmode, smb_fname, parent_dir);
718 /* preserve the file type bits */
721 /* preserve the s bits */
722 mask |= (S_ISUID | S_ISGID);
724 /* preserve the t bit */
729 /* possibly preserve the x bits */
730 if (!MAP_ARCHIVE(conn))
732 if (!MAP_SYSTEM(conn))
734 if (!MAP_HIDDEN(conn))
737 unixmode |= (smb_fname->st.st_ex_mode & mask);
739 /* if we previously had any r bits set then leave them alone */
740 if ((tmp = smb_fname->st.st_ex_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
741 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
745 /* if we previously had any w bits set then leave them alone
746 whilst adding in the new w bits, if the new mode is not rdonly */
747 if (!IS_DOS_READONLY(dosmode)) {
748 unixmode |= (smb_fname->st.st_ex_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
752 * From the chmod 2 man page:
754 * "If the calling process is not privileged, and the group of the file
755 * does not match the effective group ID of the process or one of its
756 * supplementary group IDs, the S_ISGID bit will be turned off, but
757 * this will not cause an error to be returned."
759 * Simply refuse to do the chmod in this case.
762 if (S_ISDIR(smb_fname->st.st_ex_mode) && (unixmode & S_ISGID) &&
763 geteuid() != sec_initial_uid() &&
764 !current_user_in_group(conn, smb_fname->st.st_ex_gid)) {
765 DEBUG(3,("file_set_dosmode: setgid bit cannot be "
766 "set for directory %s\n",
767 smb_fname_str_dbg(smb_fname)));
772 ret = SMB_VFS_CHMOD(conn, smb_fname, unixmode);
774 if(!newfile || (lret != -1)) {
775 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
776 FILE_NOTIFY_CHANGE_ATTRIBUTES,
777 smb_fname->base_name);
779 smb_fname->st.st_ex_mode = unixmode;
783 if((errno != EPERM) && (errno != EACCES))
786 if(!lp_dos_filemode(SNUM(conn)))
789 /* We want DOS semantics, ie allow non owner with write permission to change the
790 bits on a file. Just like file_ntimes below.
793 if (!can_write_to_file(conn, smb_fname)) {
799 * We need to get an open file handle to do the
800 * metadata operation under root.
803 status = get_file_handle_for_metadata(conn,
807 if (!NT_STATUS_IS_OK(status)) {
808 errno = map_errno_from_nt_status(status);
813 ret = SMB_VFS_FCHMOD(fsp, unixmode);
816 close_file(NULL, fsp, NORMAL_CLOSE);
819 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
820 FILE_NOTIFY_CHANGE_ATTRIBUTES,
821 smb_fname->base_name);
824 smb_fname->st.st_ex_mode = unixmode;
831 NTSTATUS file_set_sparse(connection_struct *conn,
835 uint32_t old_dosmode;
836 uint32_t new_dosmode;
839 if (!CAN_WRITE(conn)) {
840 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
841 "on readonly share[%s]\n",
842 smb_fname_str_dbg(fsp->fsp_name),
844 lp_servicename(talloc_tos(), SNUM(conn))));
845 return NT_STATUS_MEDIA_WRITE_PROTECTED;
849 * Windows Server 2008 & 2012 permit FSCTL_SET_SPARSE if any of the
850 * following access flags are granted.
852 if ((fsp->access_mask & (FILE_WRITE_DATA
853 | FILE_WRITE_ATTRIBUTES
854 | SEC_FILE_APPEND_DATA)) == 0) {
855 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
856 "access_mask[0x%08X] - access denied\n",
857 smb_fname_str_dbg(fsp->fsp_name),
860 return NT_STATUS_ACCESS_DENIED;
863 if (fsp->is_directory) {
864 DEBUG(9, ("invalid attempt to %s sparse flag on dir %s\n",
865 (sparse ? "set" : "clear"),
866 smb_fname_str_dbg(fsp->fsp_name)));
867 return NT_STATUS_INVALID_PARAMETER;
870 if (IS_IPC(conn) || IS_PRINT(conn)) {
871 DEBUG(9, ("attempt to %s sparse flag over invalid conn\n",
872 (sparse ? "set" : "clear")));
873 return NT_STATUS_INVALID_PARAMETER;
876 DEBUG(10,("file_set_sparse: setting sparse bit %u on file %s\n",
877 sparse, smb_fname_str_dbg(fsp->fsp_name)));
879 if (!lp_store_dos_attributes(SNUM(conn))) {
880 return NT_STATUS_INVALID_DEVICE_REQUEST;
883 status = vfs_stat_fsp(fsp);
884 if (!NT_STATUS_IS_OK(status)) {
888 old_dosmode = dos_mode(conn, fsp->fsp_name);
890 if (sparse && !(old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
891 new_dosmode = old_dosmode | FILE_ATTRIBUTE_SPARSE;
892 } else if (!sparse && (old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
893 new_dosmode = old_dosmode & ~FILE_ATTRIBUTE_SPARSE;
898 /* Store the DOS attributes in an EA. */
899 if (!set_ea_dos_attribute(conn, fsp->fsp_name,
904 return map_nt_error_from_unix(errno);
907 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
908 FILE_NOTIFY_CHANGE_ATTRIBUTES,
909 fsp->fsp_name->base_name);
911 fsp->is_sparse = sparse;
916 /*******************************************************************
917 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
919 *******************************************************************/
921 int file_ntimes(connection_struct *conn, const struct smb_filename *smb_fname,
922 struct smb_file_time *ft)
928 DEBUG(6, ("file_ntime: actime: %s",
929 time_to_asc(convert_timespec_to_time_t(ft->atime))));
930 DEBUG(6, ("file_ntime: modtime: %s",
931 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
932 DEBUG(6, ("file_ntime: ctime: %s",
933 time_to_asc(convert_timespec_to_time_t(ft->ctime))));
934 DEBUG(6, ("file_ntime: createtime: %s",
935 time_to_asc(convert_timespec_to_time_t(ft->create_time))));
937 /* Don't update the time on read-only shares */
938 /* We need this as set_filetime (which can be called on
939 close and other paths) can end up calling this function
940 without the NEED_WRITE protection. Found by :
941 Leo Weppelman <leo@wau.mis.ah.nl>
944 if (!CAN_WRITE(conn)) {
948 if(SMB_VFS_NTIMES(conn, smb_fname, ft) == 0) {
952 if((errno != EPERM) && (errno != EACCES)) {
956 if(!lp_dos_filetimes(SNUM(conn))) {
960 /* We have permission (given by the Samba admin) to
961 break POSIX semantics and allow a user to change
962 the time on a file they don't own but can write to
966 /* Check if we have write access. */
967 if (can_write_to_file(conn, smb_fname)) {
968 /* We are allowed to become root and change the filetime. */
970 ret = SMB_VFS_NTIMES(conn, smb_fname, ft);
977 /******************************************************************
978 Force a "sticky" write time on a pathname. This will always be
979 returned on all future write time queries and set on close.
980 ******************************************************************/
982 bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime)
984 if (null_timespec(mtime)) {
988 if (!set_sticky_write_time(fileid, mtime)) {
995 /******************************************************************
996 Force a "sticky" write time on an fsp. This will always be
997 returned on all future write time queries and set on close.
998 ******************************************************************/
1000 bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime)
1002 if (null_timespec(mtime)) {
1006 fsp->write_time_forced = true;
1007 TALLOC_FREE(fsp->update_write_time_event);
1009 return set_sticky_write_time_path(fsp->file_id, mtime);
1012 /******************************************************************
1013 Set a create time EA.
1014 ******************************************************************/
1016 NTSTATUS set_create_timespec_ea(connection_struct *conn,
1017 const struct smb_filename *psmb_fname,
1018 struct timespec create_time)
1020 struct smb_filename *smb_fname;
1024 if (!lp_store_dos_attributes(SNUM(conn))) {
1025 return NT_STATUS_OK;
1028 smb_fname = synthetic_smb_fname(talloc_tos(),
1029 psmb_fname->base_name,
1034 if (smb_fname == NULL) {
1035 return NT_STATUS_NO_MEMORY;
1038 dosmode = dos_mode(conn, smb_fname);
1040 smb_fname->st.st_ex_btime = create_time;
1042 ret = file_set_dosmode(conn, smb_fname, dosmode, NULL, false);
1044 return map_nt_error_from_unix(errno);
1047 DEBUG(10,("set_create_timespec_ea: wrote create time EA for file %s\n",
1048 smb_fname_str_dbg(smb_fname)));
1050 return NT_STATUS_OK;
1053 /******************************************************************
1054 Return a create time.
1055 ******************************************************************/
1057 struct timespec get_create_timespec(connection_struct *conn,
1058 struct files_struct *fsp,
1059 const struct smb_filename *smb_fname)
1061 return smb_fname->st.st_ex_btime;
1064 /******************************************************************
1065 Return a change time (may look at EA in future).
1066 ******************************************************************/
1068 struct timespec get_change_timespec(connection_struct *conn,
1069 struct files_struct *fsp,
1070 const struct smb_filename *smb_fname)
1072 return smb_fname->st.st_ex_mtime;
1075 /****************************************************************************
1076 Get a real open file handle we can do meta-data operations on. As it's
1077 going to be used under root access only on meta-data we should look for
1078 any existing open file handle first, and use that in preference (also to
1079 avoid kernel self-oplock breaks). If not use an INTERNAL_OPEN_ONLY handle.
1080 ****************************************************************************/
1082 static NTSTATUS get_file_handle_for_metadata(connection_struct *conn,
1083 struct smb_filename *smb_fname,
1084 files_struct **ret_fsp,
1089 struct file_id file_id;
1091 *need_close = false;
1093 if (!VALID_STAT(smb_fname->st)) {
1094 return NT_STATUS_INVALID_PARAMETER;
1097 file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1099 for(fsp = file_find_di_first(conn->sconn, file_id);
1101 fsp = file_find_di_next(fsp)) {
1102 if (fsp->fh->fd != -1) {
1104 return NT_STATUS_OK;
1108 /* Opens an INTERNAL_OPEN_ONLY write handle. */
1109 status = SMB_VFS_CREATE_FILE(
1112 0, /* root_dir_fid */
1113 smb_fname, /* fname */
1114 FILE_WRITE_DATA, /* access_mask */
1115 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
1117 FILE_OPEN, /* create_disposition*/
1118 0, /* create_options */
1119 0, /* file_attributes */
1120 INTERNAL_OPEN_ONLY, /* oplock_request */
1122 0, /* allocation_size */
1123 0, /* private_flags */
1126 ret_fsp, /* result */
1128 NULL, NULL); /* create context */
1130 if (NT_STATUS_IS_OK(status)) {