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->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));
288 return map_nt_error_from_unix(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)));
302 return ndr_map_error2ntstatus(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),
355 /* Should this be INTERNAL_ERROR? */
356 return NT_STATUS_INVALID_PARAMETER;
359 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
360 dosattr |= FILE_ATTRIBUTE_DIRECTORY;
362 /* FILE_ATTRIBUTE_SPARSE is valid on get but not on set. */
363 *pattr |= (uint32_t)(dosattr & (SAMBA_ATTRIBUTES_MASK|FILE_ATTRIBUTE_SPARSE));
365 dos_mode_debug_print(__func__, *pattr);
370 /****************************************************************************
371 Set DOS attributes in an EA.
372 Also sets the create time.
373 ****************************************************************************/
375 NTSTATUS set_ea_dos_attribute(connection_struct *conn,
376 const struct smb_filename *smb_fname,
379 struct xattr_DOSATTRIB dosattrib;
380 enum ndr_err_code ndr_err;
383 if (!lp_store_dos_attributes(SNUM(conn))) {
384 return NT_STATUS_NOT_IMPLEMENTED;
387 ZERO_STRUCT(dosattrib);
390 dosattrib.version = 3;
391 dosattrib.info.info3.valid_flags = XATTR_DOSINFO_ATTRIB|
392 XATTR_DOSINFO_CREATE_TIME;
393 dosattrib.info.info3.attrib = dosmode;
394 dosattrib.info.info3.create_time = unix_timespec_to_nt_time(
395 smb_fname->st.st_ex_btime);
397 DEBUG(10,("set_ea_dos_attributes: set attribute 0x%x, btime = %s on file %s\n",
398 (unsigned int)dosmode,
399 time_to_asc(convert_timespec_to_time_t(smb_fname->st.st_ex_btime)),
400 smb_fname_str_dbg(smb_fname) ));
402 ndr_err = ndr_push_struct_blob(
403 &blob, talloc_tos(), &dosattrib,
404 (ndr_push_flags_fn_t)ndr_push_xattr_DOSATTRIB);
406 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
407 DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n",
408 ndr_errstr(ndr_err)));
409 return ndr_map_error2ntstatus(ndr_err);
412 if (blob.data == NULL || blob.length == 0) {
413 /* Should this be INTERNAL_ERROR? */
414 return NT_STATUS_INVALID_PARAMETER;
417 if (SMB_VFS_SETXATTR(conn, smb_fname->base_name,
418 SAMBA_XATTR_DOS_ATTRIB, blob.data, blob.length,
420 NTSTATUS status = NT_STATUS_OK;
421 bool need_close = false;
422 files_struct *fsp = NULL;
424 if((errno != EPERM) && (errno != EACCES)) {
425 DBG_INFO("Cannot set "
426 "attribute EA on file %s: Error = %s\n",
427 smb_fname_str_dbg(smb_fname), strerror(errno));
428 return map_nt_error_from_unix(errno);
431 /* We want DOS semantics, ie allow non owner with write permission to change the
432 bits on a file. Just like file_ntimes below.
435 /* Check if we have write access. */
436 if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
437 return NT_STATUS_ACCESS_DENIED;
439 if (!can_write_to_file(conn, smb_fname)) {
440 return NT_STATUS_ACCESS_DENIED;
444 * We need to get an open file handle to do the
445 * metadata operation under root.
448 status = get_file_handle_for_metadata(conn,
452 if (!NT_STATUS_IS_OK(status)) {
457 if (SMB_VFS_FSETXATTR(fsp,
458 SAMBA_XATTR_DOS_ATTRIB, blob.data,
459 blob.length, 0) == 0) {
460 status = NT_STATUS_OK;
464 close_file(NULL, fsp, NORMAL_CLOSE);
468 DEBUG(10,("set_ea_dos_attribute: set EA 0x%x on file %s\n",
469 (unsigned int)dosmode,
470 smb_fname_str_dbg(smb_fname)));
474 /****************************************************************************
475 Change a unix mode to a dos mode for an ms dfs link.
476 ****************************************************************************/
478 uint32_t dos_mode_msdfs(connection_struct *conn,
479 const struct smb_filename *smb_fname)
483 DEBUG(8,("dos_mode_msdfs: %s\n", smb_fname_str_dbg(smb_fname)));
485 if (!VALID_STAT(smb_fname->st)) {
489 /* First do any modifications that depend on the path name. */
490 /* hide files with a name starting with a . */
491 if (lp_hide_dot_files(SNUM(conn))) {
492 const char *p = strrchr_m(smb_fname->base_name, '/');
496 p = smb_fname->base_name;
499 /* Only . and .. are not hidden. */
500 if (p[0] == '.' && !((p[1] == '\0') ||
501 (p[1] == '.' && p[2] == '\0'))) {
502 result |= FILE_ATTRIBUTE_HIDDEN;
506 result |= dos_mode_from_sbuf(conn, smb_fname);
508 /* Optimization : Only call is_hidden_path if it's not already
510 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
511 IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
512 result |= FILE_ATTRIBUTE_HIDDEN;
516 result = FILE_ATTRIBUTE_NORMAL;
519 result = filter_mode_by_protocol(result);
522 * Add in that it is a reparse point
524 result |= FILE_ATTRIBUTE_REPARSE_POINT;
526 dos_mode_debug_print(__func__, result);
532 * check whether a file or directory is flagged as compressed.
534 static NTSTATUS dos_mode_check_compressed(connection_struct *conn,
535 struct smb_filename *smb_fname,
539 uint16_t compression_fmt;
540 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
541 if (tmp_ctx == NULL) {
542 status = NT_STATUS_NO_MEMORY;
546 status = SMB_VFS_GET_COMPRESSION(conn, tmp_ctx, NULL, smb_fname,
548 if (!NT_STATUS_IS_OK(status)) {
552 if (compression_fmt == COMPRESSION_FORMAT_LZNT1) {
553 *is_compressed = true;
555 *is_compressed = false;
557 status = NT_STATUS_OK;
560 talloc_free(tmp_ctx);
565 static uint32_t dos_mode_from_name(connection_struct *conn,
566 const struct smb_filename *smb_fname,
569 const char *p = NULL;
570 uint32_t result = dosmode;
572 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
573 lp_hide_dot_files(SNUM(conn)))
575 p = strrchr_m(smb_fname->base_name, '/');
579 p = smb_fname->base_name;
582 /* Only . and .. are not hidden. */
584 !((p[1] == '\0') || (p[1] == '.' && p[2] == '\0')))
586 result |= FILE_ATTRIBUTE_HIDDEN;
590 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
591 IS_HIDDEN_PATH(conn, smb_fname->base_name))
593 result |= FILE_ATTRIBUTE_HIDDEN;
599 /****************************************************************************
600 Change a unix mode to a dos mode.
601 May also read the create timespec into the stat struct in smb_fname
602 if "store dos attributes" is true.
603 ****************************************************************************/
605 uint32_t dos_mode(connection_struct *conn, struct smb_filename *smb_fname)
609 NTSTATUS status = NT_STATUS_OK;
611 DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname)));
613 if (!VALID_STAT(smb_fname->st)) {
617 /* Get the DOS attributes via the VFS if we can */
618 status = SMB_VFS_GET_DOS_ATTRIBUTES(conn, smb_fname, &result);
619 if (!NT_STATUS_IS_OK(status)) {
620 result |= dos_mode_from_sbuf(conn, smb_fname);
623 offline = SMB_VFS_IS_OFFLINE(conn, smb_fname, &smb_fname->st);
624 if (S_ISREG(smb_fname->st.st_ex_mode) && offline) {
625 result |= FILE_ATTRIBUTE_OFFLINE;
628 if (conn->fs_capabilities & FILE_FILE_COMPRESSION) {
629 bool compressed = false;
630 status = dos_mode_check_compressed(conn, smb_fname,
632 if (NT_STATUS_IS_OK(status) && compressed) {
633 result |= FILE_ATTRIBUTE_COMPRESSED;
637 result |= dos_mode_from_name(conn, smb_fname, result);
640 result = FILE_ATTRIBUTE_NORMAL;
643 result = filter_mode_by_protocol(result);
645 dos_mode_debug_print(__func__, result);
650 /*******************************************************************
651 chmod a file - but preserve some bits.
652 If "store dos attributes" is also set it will store the create time
653 from the stat struct in smb_fname (in NTTIME format) in the EA
655 ********************************************************************/
657 int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname,
658 uint32_t dosmode, const char *parent_dir, bool newfile)
663 int ret = -1, lret = -1;
665 struct timespec new_create_timespec;
666 files_struct *fsp = NULL;
667 bool need_close = false;
670 if (!CAN_WRITE(conn)) {
675 /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
676 dosmode &= (SAMBA_ATTRIBUTES_MASK | FILE_ATTRIBUTE_OFFLINE);
678 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
679 dosmode, smb_fname_str_dbg(smb_fname)));
681 unixmode = smb_fname->st.st_ex_mode;
683 get_acl_group_bits(conn, smb_fname->base_name,
684 &smb_fname->st.st_ex_mode);
686 if (S_ISDIR(smb_fname->st.st_ex_mode))
687 dosmode |= FILE_ATTRIBUTE_DIRECTORY;
689 dosmode &= ~FILE_ATTRIBUTE_DIRECTORY;
691 new_create_timespec = smb_fname->st.st_ex_btime;
693 old_mode = dos_mode(conn, smb_fname);
695 if ((dosmode & FILE_ATTRIBUTE_OFFLINE) &&
696 !(old_mode & FILE_ATTRIBUTE_OFFLINE)) {
697 lret = SMB_VFS_SET_OFFLINE(conn, smb_fname);
699 if (errno == ENOTSUP) {
700 DEBUG(10, ("Setting FILE_ATTRIBUTE_OFFLINE for "
701 "%s/%s is not supported.\n",
703 smb_fname_str_dbg(smb_fname)));
705 DEBUG(0, ("An error occurred while setting "
706 "FILE_ATTRIBUTE_OFFLINE for "
707 "%s/%s: %s", parent_dir,
708 smb_fname_str_dbg(smb_fname),
714 dosmode &= ~FILE_ATTRIBUTE_OFFLINE;
715 old_mode &= ~FILE_ATTRIBUTE_OFFLINE;
717 smb_fname->st.st_ex_btime = new_create_timespec;
719 /* Store the DOS attributes in an EA by preference. */
720 status = SMB_VFS_SET_DOS_ATTRIBUTES(conn, smb_fname, dosmode);
721 if (NT_STATUS_IS_OK(status)) {
723 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
724 FILE_NOTIFY_CHANGE_ATTRIBUTES,
725 smb_fname->base_name);
727 smb_fname->st.st_ex_mode = unixmode;
731 * Only fall back to using UNIX modes if
732 * we get NOT_IMPLEMENTED.
734 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
735 errno = map_errno_from_nt_status(status);
740 /* Fall back to UNIX modes. */
741 unixmode = unix_mode(conn, dosmode, smb_fname, parent_dir);
743 /* preserve the file type bits */
746 /* preserve the s bits */
747 mask |= (S_ISUID | S_ISGID);
749 /* preserve the t bit */
754 /* possibly preserve the x bits */
755 if (!MAP_ARCHIVE(conn))
757 if (!MAP_SYSTEM(conn))
759 if (!MAP_HIDDEN(conn))
762 unixmode |= (smb_fname->st.st_ex_mode & mask);
764 /* if we previously had any r bits set then leave them alone */
765 if ((tmp = smb_fname->st.st_ex_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
766 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
770 /* if we previously had any w bits set then leave them alone
771 whilst adding in the new w bits, if the new mode is not rdonly */
772 if (!IS_DOS_READONLY(dosmode)) {
773 unixmode |= (smb_fname->st.st_ex_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
777 * From the chmod 2 man page:
779 * "If the calling process is not privileged, and the group of the file
780 * does not match the effective group ID of the process or one of its
781 * supplementary group IDs, the S_ISGID bit will be turned off, but
782 * this will not cause an error to be returned."
784 * Simply refuse to do the chmod in this case.
787 if (S_ISDIR(smb_fname->st.st_ex_mode) && (unixmode & S_ISGID) &&
788 geteuid() != sec_initial_uid() &&
789 !current_user_in_group(conn, smb_fname->st.st_ex_gid)) {
790 DEBUG(3,("file_set_dosmode: setgid bit cannot be "
791 "set for directory %s\n",
792 smb_fname_str_dbg(smb_fname)));
797 ret = SMB_VFS_CHMOD(conn, smb_fname, unixmode);
799 if(!newfile || (lret != -1)) {
800 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
801 FILE_NOTIFY_CHANGE_ATTRIBUTES,
802 smb_fname->base_name);
804 smb_fname->st.st_ex_mode = unixmode;
808 if((errno != EPERM) && (errno != EACCES))
811 if(!lp_dos_filemode(SNUM(conn)))
814 /* We want DOS semantics, ie allow non owner with write permission to change the
815 bits on a file. Just like file_ntimes below.
818 if (!can_write_to_file(conn, smb_fname)) {
824 * We need to get an open file handle to do the
825 * metadata operation under root.
828 status = get_file_handle_for_metadata(conn,
832 if (!NT_STATUS_IS_OK(status)) {
833 errno = map_errno_from_nt_status(status);
838 ret = SMB_VFS_FCHMOD(fsp, unixmode);
841 close_file(NULL, fsp, NORMAL_CLOSE);
844 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
845 FILE_NOTIFY_CHANGE_ATTRIBUTES,
846 smb_fname->base_name);
849 smb_fname->st.st_ex_mode = unixmode;
856 NTSTATUS file_set_sparse(connection_struct *conn,
860 uint32_t old_dosmode;
861 uint32_t new_dosmode;
864 if (!CAN_WRITE(conn)) {
865 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
866 "on readonly share[%s]\n",
867 smb_fname_str_dbg(fsp->fsp_name),
869 lp_servicename(talloc_tos(), SNUM(conn))));
870 return NT_STATUS_MEDIA_WRITE_PROTECTED;
874 * Windows Server 2008 & 2012 permit FSCTL_SET_SPARSE if any of the
875 * following access flags are granted.
877 if ((fsp->access_mask & (FILE_WRITE_DATA
878 | FILE_WRITE_ATTRIBUTES
879 | SEC_FILE_APPEND_DATA)) == 0) {
880 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
881 "access_mask[0x%08X] - access denied\n",
882 smb_fname_str_dbg(fsp->fsp_name),
885 return NT_STATUS_ACCESS_DENIED;
888 if (fsp->is_directory) {
889 DEBUG(9, ("invalid attempt to %s sparse flag on dir %s\n",
890 (sparse ? "set" : "clear"),
891 smb_fname_str_dbg(fsp->fsp_name)));
892 return NT_STATUS_INVALID_PARAMETER;
895 if (IS_IPC(conn) || IS_PRINT(conn)) {
896 DEBUG(9, ("attempt to %s sparse flag over invalid conn\n",
897 (sparse ? "set" : "clear")));
898 return NT_STATUS_INVALID_PARAMETER;
901 DEBUG(10,("file_set_sparse: setting sparse bit %u on file %s\n",
902 sparse, smb_fname_str_dbg(fsp->fsp_name)));
904 if (!lp_store_dos_attributes(SNUM(conn))) {
905 return NT_STATUS_INVALID_DEVICE_REQUEST;
908 status = vfs_stat_fsp(fsp);
909 if (!NT_STATUS_IS_OK(status)) {
913 old_dosmode = dos_mode(conn, fsp->fsp_name);
915 if (sparse && !(old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
916 new_dosmode = old_dosmode | FILE_ATTRIBUTE_SPARSE;
917 } else if (!sparse && (old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
918 new_dosmode = old_dosmode & ~FILE_ATTRIBUTE_SPARSE;
923 /* Store the DOS attributes in an EA. */
924 status = SMB_VFS_FSET_DOS_ATTRIBUTES(conn, fsp, new_dosmode);
925 if (!NT_STATUS_IS_OK(status)) {
929 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
930 FILE_NOTIFY_CHANGE_ATTRIBUTES,
931 fsp->fsp_name->base_name);
933 fsp->is_sparse = sparse;
938 /*******************************************************************
939 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
941 *******************************************************************/
943 int file_ntimes(connection_struct *conn, const struct smb_filename *smb_fname,
944 struct smb_file_time *ft)
950 DEBUG(6, ("file_ntime: actime: %s",
951 time_to_asc(convert_timespec_to_time_t(ft->atime))));
952 DEBUG(6, ("file_ntime: modtime: %s",
953 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
954 DEBUG(6, ("file_ntime: ctime: %s",
955 time_to_asc(convert_timespec_to_time_t(ft->ctime))));
956 DEBUG(6, ("file_ntime: createtime: %s",
957 time_to_asc(convert_timespec_to_time_t(ft->create_time))));
959 /* Don't update the time on read-only shares */
960 /* We need this as set_filetime (which can be called on
961 close and other paths) can end up calling this function
962 without the NEED_WRITE protection. Found by :
963 Leo Weppelman <leo@wau.mis.ah.nl>
966 if (!CAN_WRITE(conn)) {
970 if(SMB_VFS_NTIMES(conn, smb_fname, ft) == 0) {
974 if((errno != EPERM) && (errno != EACCES)) {
978 if(!lp_dos_filetimes(SNUM(conn))) {
982 /* We have permission (given by the Samba admin) to
983 break POSIX semantics and allow a user to change
984 the time on a file they don't own but can write to
988 /* Check if we have write access. */
989 if (can_write_to_file(conn, smb_fname)) {
990 /* We are allowed to become root and change the filetime. */
992 ret = SMB_VFS_NTIMES(conn, smb_fname, ft);
999 /******************************************************************
1000 Force a "sticky" write time on a pathname. This will always be
1001 returned on all future write time queries and set on close.
1002 ******************************************************************/
1004 bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime)
1006 if (null_timespec(mtime)) {
1010 if (!set_sticky_write_time(fileid, mtime)) {
1017 /******************************************************************
1018 Force a "sticky" write time on an fsp. This will always be
1019 returned on all future write time queries and set on close.
1020 ******************************************************************/
1022 bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime)
1024 if (null_timespec(mtime)) {
1028 fsp->write_time_forced = true;
1029 TALLOC_FREE(fsp->update_write_time_event);
1031 return set_sticky_write_time_path(fsp->file_id, mtime);
1034 /******************************************************************
1035 Set a create time EA.
1036 ******************************************************************/
1038 NTSTATUS set_create_timespec_ea(connection_struct *conn,
1039 const struct smb_filename *psmb_fname,
1040 struct timespec create_time)
1042 struct smb_filename *smb_fname;
1046 if (!lp_store_dos_attributes(SNUM(conn))) {
1047 return NT_STATUS_OK;
1050 smb_fname = synthetic_smb_fname(talloc_tos(),
1051 psmb_fname->base_name,
1056 if (smb_fname == NULL) {
1057 return NT_STATUS_NO_MEMORY;
1060 dosmode = dos_mode(conn, smb_fname);
1062 smb_fname->st.st_ex_btime = create_time;
1064 ret = file_set_dosmode(conn, smb_fname, dosmode, NULL, false);
1066 return map_nt_error_from_unix(errno);
1069 DEBUG(10,("set_create_timespec_ea: wrote create time EA for file %s\n",
1070 smb_fname_str_dbg(smb_fname)));
1072 return NT_STATUS_OK;
1075 /******************************************************************
1076 Return a create time.
1077 ******************************************************************/
1079 struct timespec get_create_timespec(connection_struct *conn,
1080 struct files_struct *fsp,
1081 const struct smb_filename *smb_fname)
1083 return smb_fname->st.st_ex_btime;
1086 /******************************************************************
1087 Return a change time (may look at EA in future).
1088 ******************************************************************/
1090 struct timespec get_change_timespec(connection_struct *conn,
1091 struct files_struct *fsp,
1092 const struct smb_filename *smb_fname)
1094 return smb_fname->st.st_ex_mtime;
1097 /****************************************************************************
1098 Get a real open file handle we can do meta-data operations on. As it's
1099 going to be used under root access only on meta-data we should look for
1100 any existing open file handle first, and use that in preference (also to
1101 avoid kernel self-oplock breaks). If not use an INTERNAL_OPEN_ONLY handle.
1102 ****************************************************************************/
1104 static NTSTATUS get_file_handle_for_metadata(connection_struct *conn,
1105 const struct smb_filename *smb_fname,
1106 files_struct **ret_fsp,
1111 struct file_id file_id;
1112 struct smb_filename *smb_fname_cp = NULL;
1114 *need_close = false;
1116 if (!VALID_STAT(smb_fname->st)) {
1117 return NT_STATUS_INVALID_PARAMETER;
1120 file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1122 for(fsp = file_find_di_first(conn->sconn, file_id);
1124 fsp = file_find_di_next(fsp)) {
1125 if (fsp->fh->fd != -1) {
1127 return NT_STATUS_OK;
1131 smb_fname_cp = cp_smb_filename(talloc_tos(),
1133 if (smb_fname_cp == NULL) {
1134 return NT_STATUS_NO_MEMORY;
1137 /* Opens an INTERNAL_OPEN_ONLY write handle. */
1138 status = SMB_VFS_CREATE_FILE(
1141 0, /* root_dir_fid */
1142 smb_fname_cp, /* fname */
1143 FILE_WRITE_DATA, /* access_mask */
1144 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
1146 FILE_OPEN, /* create_disposition*/
1147 0, /* create_options */
1148 0, /* file_attributes */
1149 INTERNAL_OPEN_ONLY, /* oplock_request */
1151 0, /* allocation_size */
1152 0, /* private_flags */
1155 ret_fsp, /* result */
1157 NULL, NULL); /* create context */
1159 TALLOC_FREE(smb_fname_cp);
1161 if (NT_STATUS_IS_OK(status)) {