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 "../libcli/security/security.h"
25 #include "smbd/smbd.h"
26 #include "lib/param/loadparm.h"
28 static uint32_t filter_mode_by_protocol(uint32_t mode)
30 if (get_Protocol() <= PROTOCOL_LANMAN2) {
31 DEBUG(10,("filter_mode_by_protocol: "
32 "filtering result 0x%x to 0x%x\n",
34 (unsigned int)(mode & 0x3f) ));
40 static int set_link_read_only_flag(const SMB_STRUCT_STAT *const sbuf)
44 if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
45 return FILE_ATTRIBUTE_READONLY;
51 /****************************************************************************
52 Change a dos mode to a unix mode.
53 Base permission for files:
54 if creating file and inheriting (i.e. parent_dir != NULL)
55 apply read/write bits from parent directory.
57 everybody gets read bit set
58 dos readonly is represented in unix by removing everyone's write bit
59 dos archive is represented in unix by the user's execute bit
60 dos system is represented in unix by the group's execute bit
61 dos hidden is represented in unix by the other's execute bit
63 Then apply create mask,
66 Base permission for directories:
67 dos directory is represented in unix by unix's dir bit and the exec bit
69 Then apply create mask,
72 ****************************************************************************/
74 mode_t unix_mode(connection_struct *conn, int dosmode,
75 const struct smb_filename *smb_fname,
76 const char *inherit_from_dir)
78 mode_t result = (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
79 mode_t dir_mode = 0; /* Mode of the inherit_from directory if
82 if (!lp_store_dos_attributes(SNUM(conn)) && IS_DOS_READONLY(dosmode)) {
83 result &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
86 if ((inherit_from_dir != NULL) && lp_inherit_perms(SNUM(conn))) {
87 struct smb_filename *smb_fname_parent;
89 DEBUG(2, ("unix_mode(%s) inheriting from %s\n",
90 smb_fname_str_dbg(smb_fname),
93 smb_fname_parent = synthetic_smb_fname(
94 talloc_tos(), inherit_from_dir, NULL, NULL);
95 if (smb_fname_parent == NULL) {
96 DEBUG(1,("unix_mode(%s) failed, [dir %s]: No memory\n",
97 smb_fname_str_dbg(smb_fname),
102 if (SMB_VFS_STAT(conn, smb_fname_parent) != 0) {
103 DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n",
104 smb_fname_str_dbg(smb_fname),
105 inherit_from_dir, strerror(errno)));
106 TALLOC_FREE(smb_fname_parent);
107 return(0); /* *** shouldn't happen! *** */
110 /* Save for later - but explicitly remove setuid bit for safety. */
111 dir_mode = smb_fname_parent->st.st_ex_mode & ~S_ISUID;
112 DEBUG(2,("unix_mode(%s) inherit mode %o\n",
113 smb_fname_str_dbg(smb_fname), (int)dir_mode));
116 TALLOC_FREE(smb_fname_parent);
119 if (IS_DOS_DIR(dosmode)) {
120 /* We never make directories read only for the owner as under DOS a user
121 can always create a file in a read-only directory. */
122 result |= (S_IFDIR | S_IWUSR);
125 /* Inherit mode of parent directory. */
128 /* Provisionally add all 'x' bits */
129 result |= (S_IXUSR | S_IXGRP | S_IXOTH);
131 /* Apply directory mask */
132 result &= lp_dir_mask(SNUM(conn));
133 /* Add in force bits */
134 result |= lp_force_dir_mode(SNUM(conn));
137 if (lp_map_archive(SNUM(conn)) && IS_DOS_ARCHIVE(dosmode))
140 if (lp_map_system(SNUM(conn)) && IS_DOS_SYSTEM(dosmode))
143 if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode))
147 /* Inherit 666 component of parent directory mode */
148 result |= dir_mode & (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
150 /* Apply mode mask */
151 result &= lp_create_mask(SNUM(conn));
152 /* Add in force bits */
153 result |= lp_force_create_mode(SNUM(conn));
157 DEBUG(3,("unix_mode(%s) returning 0%o\n", smb_fname_str_dbg(smb_fname),
162 /****************************************************************************
163 Change a unix mode to a dos mode.
164 ****************************************************************************/
166 static uint32 dos_mode_from_sbuf(connection_struct *conn,
167 const struct smb_filename *smb_fname)
170 enum mapreadonly_options ro_opts = (enum mapreadonly_options)lp_map_readonly(SNUM(conn));
172 #if defined(UF_IMMUTABLE) && defined(SF_IMMUTABLE)
173 /* if we can find out if a file is immutable we should report it r/o */
174 if (smb_fname->st.st_ex_flags & (UF_IMMUTABLE | SF_IMMUTABLE)) {
175 result |= FILE_ATTRIBUTE_READONLY;
178 if (ro_opts == MAP_READONLY_YES) {
179 /* Original Samba method - map inverse of user "w" bit. */
180 if ((smb_fname->st.st_ex_mode & S_IWUSR) == 0) {
181 result |= FILE_ATTRIBUTE_READONLY;
183 } else if (ro_opts == MAP_READONLY_PERMISSIONS) {
184 /* Check actual permissions for read-only. */
185 if (!can_write_to_file(conn, smb_fname)) {
186 result |= FILE_ATTRIBUTE_READONLY;
188 } /* Else never set the readonly bit. */
190 if (MAP_ARCHIVE(conn) && ((smb_fname->st.st_ex_mode & S_IXUSR) != 0))
191 result |= FILE_ATTRIBUTE_ARCHIVE;
193 if (MAP_SYSTEM(conn) && ((smb_fname->st.st_ex_mode & S_IXGRP) != 0))
194 result |= FILE_ATTRIBUTE_SYSTEM;
196 if (MAP_HIDDEN(conn) && ((smb_fname->st.st_ex_mode & S_IXOTH) != 0))
197 result |= FILE_ATTRIBUTE_HIDDEN;
199 if (S_ISDIR(smb_fname->st.st_ex_mode))
200 result = FILE_ATTRIBUTE_DIRECTORY | (result & FILE_ATTRIBUTE_READONLY);
202 result |= set_link_read_only_flag(&smb_fname->st);
204 DEBUG(8,("dos_mode_from_sbuf returning "));
206 if (result & FILE_ATTRIBUTE_HIDDEN) DEBUG(8, ("h"));
207 if (result & FILE_ATTRIBUTE_READONLY ) DEBUG(8, ("r"));
208 if (result & FILE_ATTRIBUTE_SYSTEM) DEBUG(8, ("s"));
209 if (result & FILE_ATTRIBUTE_DIRECTORY ) DEBUG(8, ("d"));
210 if (result & FILE_ATTRIBUTE_ARCHIVE ) DEBUG(8, ("a"));
216 /****************************************************************************
217 Get DOS attributes from an EA.
218 This can also pull the create time into the stat struct inside smb_fname.
219 ****************************************************************************/
221 static bool get_ea_dos_attribute(connection_struct *conn,
222 struct smb_filename *smb_fname,
225 struct xattr_DOSATTRIB dosattrib;
226 enum ndr_err_code ndr_err;
232 if (!lp_store_dos_attributes(SNUM(conn))) {
236 /* Don't reset pattr to zero as we may already have filename-based attributes we
239 sizeret = SMB_VFS_GETXATTR(conn, smb_fname->base_name,
240 SAMBA_XATTR_DOS_ATTRIB, attrstr,
245 || errno == ENOTSUP) {
249 DEBUG(1,("get_ea_dos_attribute: Cannot get attribute "
250 "from EA on file %s: Error = %s\n",
251 smb_fname_str_dbg(smb_fname),
253 set_store_dos_attributes(SNUM(conn), False);
258 blob.data = (uint8_t *)attrstr;
259 blob.length = sizeret;
261 ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &dosattrib,
262 (ndr_pull_flags_fn_t)ndr_pull_xattr_DOSATTRIB);
264 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
265 DEBUG(1,("get_ea_dos_attribute: bad ndr decode "
266 "from EA on file %s: Error = %s\n",
267 smb_fname_str_dbg(smb_fname),
268 ndr_errstr(ndr_err)));
272 DEBUG(10,("get_ea_dos_attribute: %s attr = %s\n",
273 smb_fname_str_dbg(smb_fname), dosattrib.attrib_hex));
275 switch (dosattrib.version) {
277 dosattr = dosattrib.info.compatinfoFFFF.attrib;
280 dosattr = dosattrib.info.info1.attrib;
281 if (!null_nttime(dosattrib.info.info1.create_time)) {
282 struct timespec create_time =
283 nt_time_to_unix_timespec(
284 &dosattrib.info.info1.create_time);
286 update_stat_ex_create_time(&smb_fname->st,
289 DEBUG(10,("get_ea_dos_attribute: file %s case 1 "
291 smb_fname_str_dbg(smb_fname),
292 time_to_asc(convert_timespec_to_time_t(
297 dosattr = dosattrib.info.oldinfo2.attrib;
298 /* Don't know what flags to check for this case. */
301 dosattr = dosattrib.info.info3.attrib;
302 if ((dosattrib.info.info3.valid_flags & XATTR_DOSINFO_CREATE_TIME) &&
303 !null_nttime(dosattrib.info.info3.create_time)) {
304 struct timespec create_time =
305 nt_time_to_unix_timespec(
306 &dosattrib.info.info3.create_time);
308 update_stat_ex_create_time(&smb_fname->st,
311 DEBUG(10,("get_ea_dos_attribute: file %s case 3 "
313 smb_fname_str_dbg(smb_fname),
314 time_to_asc(convert_timespec_to_time_t(
319 DEBUG(1,("get_ea_dos_attribute: Badly formed DOSATTRIB on "
320 "file %s - %s\n", smb_fname_str_dbg(smb_fname),
325 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
326 dosattr |= FILE_ATTRIBUTE_DIRECTORY;
328 /* FILE_ATTRIBUTE_SPARSE is valid on get but not on set. */
329 *pattr = (uint32)(dosattr & (SAMBA_ATTRIBUTES_MASK|FILE_ATTRIBUTE_SPARSE));
331 DEBUG(8,("get_ea_dos_attribute returning (0x%x)", dosattr));
333 if (dosattr & FILE_ATTRIBUTE_HIDDEN) DEBUG(8, ("h"));
334 if (dosattr & FILE_ATTRIBUTE_READONLY ) DEBUG(8, ("r"));
335 if (dosattr & FILE_ATTRIBUTE_SYSTEM) DEBUG(8, ("s"));
336 if (dosattr & FILE_ATTRIBUTE_DIRECTORY ) DEBUG(8, ("d"));
337 if (dosattr & FILE_ATTRIBUTE_ARCHIVE ) DEBUG(8, ("a"));
344 /****************************************************************************
345 Set DOS attributes in an EA.
346 Also sets the create time.
347 ****************************************************************************/
349 static bool set_ea_dos_attribute(connection_struct *conn,
350 struct smb_filename *smb_fname,
353 struct xattr_DOSATTRIB dosattrib;
354 enum ndr_err_code ndr_err;
357 if (!lp_store_dos_attributes(SNUM(conn))) {
361 ZERO_STRUCT(dosattrib);
364 dosattrib.version = 3;
365 dosattrib.info.info3.valid_flags = XATTR_DOSINFO_ATTRIB|
366 XATTR_DOSINFO_CREATE_TIME;
367 dosattrib.info.info3.attrib = dosmode;
368 unix_timespec_to_nt_time(&dosattrib.info.info3.create_time,
369 smb_fname->st.st_ex_btime);
371 DEBUG(10,("set_ea_dos_attributes: set attribute 0x%x, btime = %s on file %s\n",
372 (unsigned int)dosmode,
373 time_to_asc(convert_timespec_to_time_t(smb_fname->st.st_ex_btime)),
374 smb_fname_str_dbg(smb_fname) ));
376 ndr_err = ndr_push_struct_blob(
377 &blob, talloc_tos(), &dosattrib,
378 (ndr_push_flags_fn_t)ndr_push_xattr_DOSATTRIB);
380 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
381 DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n",
382 ndr_errstr(ndr_err)));
386 if (blob.data == NULL || blob.length == 0) {
390 if (SMB_VFS_SETXATTR(conn, smb_fname->base_name,
391 SAMBA_XATTR_DOS_ATTRIB, blob.data, blob.length,
394 files_struct *fsp = NULL;
396 if((errno != EPERM) && (errno != EACCES)) {
399 || errno == ENOTSUP) {
403 DEBUG(1,("set_ea_dos_attributes: Cannot set "
404 "attribute EA on file %s: Error = %s\n",
405 smb_fname_str_dbg(smb_fname),
407 set_store_dos_attributes(SNUM(conn), False);
412 /* We want DOS semantics, ie allow non owner with write permission to change the
413 bits on a file. Just like file_ntimes below.
416 /* Check if we have write access. */
417 if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
421 * We need to open the file with write access whilst
422 * still in our current user context. This ensures we
423 * are not violating security in doing the setxattr.
426 if (!NT_STATUS_IS_OK(open_file_fchmod(conn, smb_fname,
430 if (SMB_VFS_FSETXATTR(fsp,
431 SAMBA_XATTR_DOS_ATTRIB, blob.data,
432 blob.length, 0) == 0) {
436 close_file(NULL, fsp, NORMAL_CLOSE);
439 DEBUG(10,("set_ea_dos_attribute: set EA 0x%x on file %s\n",
440 (unsigned int)dosmode,
441 smb_fname_str_dbg(smb_fname)));
445 /****************************************************************************
446 Change a unix mode to a dos mode for an ms dfs link.
447 ****************************************************************************/
449 uint32 dos_mode_msdfs(connection_struct *conn,
450 const struct smb_filename *smb_fname)
454 DEBUG(8,("dos_mode_msdfs: %s\n", smb_fname_str_dbg(smb_fname)));
456 if (!VALID_STAT(smb_fname->st)) {
460 /* First do any modifications that depend on the path name. */
461 /* hide files with a name starting with a . */
462 if (lp_hide_dot_files(SNUM(conn))) {
463 const char *p = strrchr_m(smb_fname->base_name, '/');
467 p = smb_fname->base_name;
470 /* Only . and .. are not hidden. */
471 if (p[0] == '.' && !((p[1] == '\0') ||
472 (p[1] == '.' && p[2] == '\0'))) {
473 result |= FILE_ATTRIBUTE_HIDDEN;
477 result |= dos_mode_from_sbuf(conn, smb_fname);
479 /* Optimization : Only call is_hidden_path if it's not already
481 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
482 IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
483 result |= FILE_ATTRIBUTE_HIDDEN;
487 result = FILE_ATTRIBUTE_NORMAL;
490 result = filter_mode_by_protocol(result);
492 DEBUG(8,("dos_mode_msdfs returning "));
494 if (result & FILE_ATTRIBUTE_HIDDEN) DEBUG(8, ("h"));
495 if (result & FILE_ATTRIBUTE_READONLY ) DEBUG(8, ("r"));
496 if (result & FILE_ATTRIBUTE_SYSTEM) DEBUG(8, ("s"));
497 if (result & FILE_ATTRIBUTE_DIRECTORY ) DEBUG(8, ("d"));
498 if (result & FILE_ATTRIBUTE_ARCHIVE ) DEBUG(8, ("a"));
499 if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
506 #ifdef HAVE_STAT_DOS_FLAGS
507 /****************************************************************************
508 Convert dos attributes (FILE_ATTRIBUTE_*) to dos stat flags (UF_*)
509 ****************************************************************************/
511 int dos_attributes_to_stat_dos_flags(uint32_t dosmode)
513 uint32_t dos_stat_flags = 0;
515 if (dosmode & FILE_ATTRIBUTE_ARCHIVE)
516 dos_stat_flags |= UF_DOS_ARCHIVE;
517 if (dosmode & FILE_ATTRIBUTE_HIDDEN)
518 dos_stat_flags |= UF_DOS_HIDDEN;
519 if (dosmode & FILE_ATTRIBUTE_READONLY)
520 dos_stat_flags |= UF_DOS_RO;
521 if (dosmode & FILE_ATTRIBUTE_SYSTEM)
522 dos_stat_flags |= UF_DOS_SYSTEM;
523 if (dosmode & FILE_ATTRIBUTE_NONINDEXED)
524 dos_stat_flags |= UF_DOS_NOINDEX;
526 return dos_stat_flags;
529 /****************************************************************************
530 Gets DOS attributes, accessed via st_ex_flags in the stat struct.
531 ****************************************************************************/
533 static bool get_stat_dos_flags(connection_struct *conn,
534 const struct smb_filename *smb_fname,
537 SMB_ASSERT(VALID_STAT(smb_fname->st));
540 if (!lp_store_dos_attributes(SNUM(conn))) {
544 DEBUG(5, ("Getting stat dos attributes for %s.\n",
545 smb_fname_str_dbg(smb_fname)));
547 if (smb_fname->st.st_ex_flags & UF_DOS_ARCHIVE)
548 *dosmode |= FILE_ATTRIBUTE_ARCHIVE;
549 if (smb_fname->st.st_ex_flags & UF_DOS_HIDDEN)
550 *dosmode |= FILE_ATTRIBUTE_HIDDEN;
551 if (smb_fname->st.st_ex_flags & UF_DOS_RO)
552 *dosmode |= FILE_ATTRIBUTE_READONLY;
553 if (smb_fname->st.st_ex_flags & UF_DOS_SYSTEM)
554 *dosmode |= FILE_ATTRIBUTE_SYSTEM;
555 if (smb_fname->st.st_ex_flags & UF_DOS_NOINDEX)
556 *dosmode |= FILE_ATTRIBUTE_NONINDEXED;
557 if (smb_fname->st.st_ex_flags & FILE_ATTRIBUTE_SPARSE)
558 *dosmode |= FILE_ATTRIBUTE_SPARSE;
559 if (S_ISDIR(smb_fname->st.st_ex_mode))
560 *dosmode |= FILE_ATTRIBUTE_DIRECTORY;
562 *dosmode |= set_link_read_only_flag(&smb_fname->st);
567 /****************************************************************************
568 Sets DOS attributes, stored in st_ex_flags of the inode.
569 ****************************************************************************/
571 static bool set_stat_dos_flags(connection_struct *conn,
572 const struct smb_filename *smb_fname,
574 bool *attributes_changed)
576 uint32_t new_flags = 0;
579 SMB_ASSERT(VALID_STAT(smb_fname->st));
580 SMB_ASSERT(attributes_changed);
582 *attributes_changed = false;
584 if (!lp_store_dos_attributes(SNUM(conn))) {
588 DEBUG(5, ("Setting stat dos attributes for %s.\n",
589 smb_fname_str_dbg(smb_fname)));
591 new_flags = (smb_fname->st.st_ex_flags & ~UF_DOS_FLAGS) |
592 dos_attributes_to_stat_dos_flags(dosmode);
594 /* Return early if no flags changed. */
595 if (new_flags == smb_fname->st.st_ex_flags)
598 DEBUG(5, ("Setting stat dos attributes=0x%x, prev=0x%x\n", new_flags,
599 smb_fname->st.st_ex_flags));
601 /* Set new flags with chflags. */
602 error = SMB_VFS_CHFLAGS(conn, smb_fname->base_name, new_flags);
604 DEBUG(0, ("Failed setting new stat dos attributes (0x%x) on "
605 "file %s! errno=%d\n", new_flags,
606 smb_fname_str_dbg(smb_fname), errno));
610 *attributes_changed = true;
613 #endif /* HAVE_STAT_DOS_FLAGS */
615 /****************************************************************************
616 Change a unix mode to a dos mode.
617 May also read the create timespec into the stat struct in smb_fname
618 if "store dos attributes" is true.
619 ****************************************************************************/
621 uint32 dos_mode(connection_struct *conn, struct smb_filename *smb_fname)
624 bool offline, used_stat_dos_flags = false;
626 DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname)));
628 if (!VALID_STAT(smb_fname->st)) {
632 /* First do any modifications that depend on the path name. */
633 /* hide files with a name starting with a . */
634 if (lp_hide_dot_files(SNUM(conn))) {
635 const char *p = strrchr_m(smb_fname->base_name,'/');
639 p = smb_fname->base_name;
642 /* Only . and .. are not hidden. */
643 if (p[0] == '.' && !((p[1] == '\0') ||
644 (p[1] == '.' && p[2] == '\0'))) {
645 result |= FILE_ATTRIBUTE_HIDDEN;
649 #ifdef HAVE_STAT_DOS_FLAGS
650 used_stat_dos_flags = get_stat_dos_flags(conn, smb_fname, &result);
652 if (!used_stat_dos_flags) {
653 /* Get the DOS attributes from an EA by preference. */
654 if (!get_ea_dos_attribute(conn, smb_fname, &result)) {
655 result |= dos_mode_from_sbuf(conn, smb_fname);
659 offline = SMB_VFS_IS_OFFLINE(conn, smb_fname, &smb_fname->st);
660 if (S_ISREG(smb_fname->st.st_ex_mode) && offline) {
661 result |= FILE_ATTRIBUTE_OFFLINE;
664 /* Optimization : Only call is_hidden_path if it's not already
666 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
667 IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
668 result |= FILE_ATTRIBUTE_HIDDEN;
672 result = FILE_ATTRIBUTE_NORMAL;
675 result = filter_mode_by_protocol(result);
677 DEBUG(8,("dos_mode returning "));
679 if (result & FILE_ATTRIBUTE_HIDDEN) DEBUG(8, ("h"));
680 if (result & FILE_ATTRIBUTE_READONLY ) DEBUG(8, ("r"));
681 if (result & FILE_ATTRIBUTE_SYSTEM) DEBUG(8, ("s"));
682 if (result & FILE_ATTRIBUTE_DIRECTORY ) DEBUG(8, ("d"));
683 if (result & FILE_ATTRIBUTE_ARCHIVE ) DEBUG(8, ("a"));
684 if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
685 if (result & FILE_ATTRIBUTE_OFFLINE ) DEBUG(8, ("[offline]"));
692 /*******************************************************************
693 chmod a file - but preserve some bits.
694 If "store dos attributes" is also set it will store the create time
695 from the stat struct in smb_fname (in NTTIME format) in the EA
697 ********************************************************************/
699 int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname,
700 uint32 dosmode, const char *parent_dir, bool newfile)
705 int ret = -1, lret = -1;
707 struct timespec new_create_timespec;
709 /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
710 dosmode &= (SAMBA_ATTRIBUTES_MASK | FILE_ATTRIBUTE_OFFLINE);
712 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
713 dosmode, smb_fname_str_dbg(smb_fname)));
715 unixmode = smb_fname->st.st_ex_mode;
717 get_acl_group_bits(conn, smb_fname->base_name,
718 &smb_fname->st.st_ex_mode);
720 if (S_ISDIR(smb_fname->st.st_ex_mode))
721 dosmode |= FILE_ATTRIBUTE_DIRECTORY;
723 dosmode &= ~FILE_ATTRIBUTE_DIRECTORY;
725 new_create_timespec = smb_fname->st.st_ex_btime;
727 old_mode = dos_mode(conn, smb_fname);
729 if (dosmode & FILE_ATTRIBUTE_OFFLINE) {
730 if (!(old_mode & FILE_ATTRIBUTE_OFFLINE)) {
731 lret = SMB_VFS_SET_OFFLINE(conn, smb_fname);
733 DEBUG(0, ("set_dos_mode: client has asked to "
734 "set FILE_ATTRIBUTE_OFFLINE to "
735 "%s/%s but there was an error while "
736 "setting it or it is not "
737 "supported.\n", parent_dir,
738 smb_fname_str_dbg(smb_fname)));
743 dosmode &= ~FILE_ATTRIBUTE_OFFLINE;
744 old_mode &= ~FILE_ATTRIBUTE_OFFLINE;
746 smb_fname->st.st_ex_btime = new_create_timespec;
748 #ifdef HAVE_STAT_DOS_FLAGS
750 bool attributes_changed;
752 if (set_stat_dos_flags(conn, smb_fname, dosmode,
753 &attributes_changed))
755 if (!newfile && attributes_changed) {
756 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
757 FILE_NOTIFY_CHANGE_ATTRIBUTES,
758 smb_fname->base_name);
760 smb_fname->st.st_ex_mode = unixmode;
765 /* Store the DOS attributes in an EA by preference. */
766 if (set_ea_dos_attribute(conn, smb_fname, dosmode)) {
768 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
769 FILE_NOTIFY_CHANGE_ATTRIBUTES,
770 smb_fname->base_name);
772 smb_fname->st.st_ex_mode = unixmode;
776 unixmode = unix_mode(conn, dosmode, smb_fname, parent_dir);
778 /* preserve the file type bits */
781 /* preserve the s bits */
782 mask |= (S_ISUID | S_ISGID);
784 /* preserve the t bit */
789 /* possibly preserve the x bits */
790 if (!MAP_ARCHIVE(conn))
792 if (!MAP_SYSTEM(conn))
794 if (!MAP_HIDDEN(conn))
797 unixmode |= (smb_fname->st.st_ex_mode & mask);
799 /* if we previously had any r bits set then leave them alone */
800 if ((tmp = smb_fname->st.st_ex_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
801 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
805 /* if we previously had any w bits set then leave them alone
806 whilst adding in the new w bits, if the new mode is not rdonly */
807 if (!IS_DOS_READONLY(dosmode)) {
808 unixmode |= (smb_fname->st.st_ex_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
812 * From the chmod 2 man page:
814 * "If the calling process is not privileged, and the group of the file
815 * does not match the effective group ID of the process or one of its
816 * supplementary group IDs, the S_ISGID bit will be turned off, but
817 * this will not cause an error to be returned."
819 * Simply refuse to do the chmod in this case.
822 if (S_ISDIR(smb_fname->st.st_ex_mode) && (unixmode & S_ISGID) &&
823 geteuid() != sec_initial_uid() &&
824 !current_user_in_group(conn, smb_fname->st.st_ex_gid)) {
825 DEBUG(3,("file_set_dosmode: setgid bit cannot be "
826 "set for directory %s\n",
827 smb_fname_str_dbg(smb_fname)));
832 ret = SMB_VFS_CHMOD(conn, smb_fname->base_name, unixmode);
834 if(!newfile || (lret != -1)) {
835 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
836 FILE_NOTIFY_CHANGE_ATTRIBUTES,
837 smb_fname->base_name);
839 smb_fname->st.st_ex_mode = unixmode;
843 if((errno != EPERM) && (errno != EACCES))
846 if(!lp_dos_filemode(SNUM(conn)))
849 /* We want DOS semantics, ie allow non owner with write permission to change the
850 bits on a file. Just like file_ntimes below.
853 /* Check if we have write access. */
854 if (CAN_WRITE(conn)) {
856 * We need to open the file with write access whilst
857 * still in our current user context. This ensures we
858 * are not violating security in doing the fchmod.
861 if (!NT_STATUS_IS_OK(open_file_fchmod(conn, smb_fname,
865 ret = SMB_VFS_FCHMOD(fsp, unixmode);
867 close_file(NULL, fsp, NORMAL_CLOSE);
869 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
870 FILE_NOTIFY_CHANGE_ATTRIBUTES,
871 smb_fname->base_name);
874 smb_fname->st.st_ex_mode = unixmode;
882 NTSTATUS file_set_sparse(connection_struct *conn,
886 uint32_t old_dosmode;
887 uint32_t new_dosmode;
890 if (!CAN_WRITE(conn)) {
891 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
892 "on readonly share[%s]\n",
893 smb_fname_str_dbg(fsp->fsp_name),
895 lp_servicename(talloc_tos(), SNUM(conn))));
896 return NT_STATUS_MEDIA_WRITE_PROTECTED;
899 if (!(fsp->access_mask & FILE_WRITE_DATA) &&
900 !(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
901 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
902 "access_mask[0x%08X] - access denied\n",
903 smb_fname_str_dbg(fsp->fsp_name),
906 return NT_STATUS_ACCESS_DENIED;
909 DEBUG(10,("file_set_sparse: setting sparse bit %u on file %s\n",
910 sparse, smb_fname_str_dbg(fsp->fsp_name)));
912 if (!lp_store_dos_attributes(SNUM(conn))) {
913 return NT_STATUS_INVALID_DEVICE_REQUEST;
916 status = vfs_stat_fsp(fsp);
917 if (!NT_STATUS_IS_OK(status)) {
921 old_dosmode = dos_mode(conn, fsp->fsp_name);
923 if (sparse && !(old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
924 new_dosmode = old_dosmode | FILE_ATTRIBUTE_SPARSE;
925 } else if (!sparse && (old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
926 new_dosmode = old_dosmode & ~FILE_ATTRIBUTE_SPARSE;
931 /* Store the DOS attributes in an EA. */
932 if (!set_ea_dos_attribute(conn, fsp->fsp_name,
937 return map_nt_error_from_unix(errno);
940 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
941 FILE_NOTIFY_CHANGE_ATTRIBUTES,
942 fsp->fsp_name->base_name);
944 fsp->is_sparse = sparse;
949 /*******************************************************************
950 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
952 *******************************************************************/
954 int file_ntimes(connection_struct *conn, const struct smb_filename *smb_fname,
955 struct smb_file_time *ft)
961 DEBUG(6, ("file_ntime: actime: %s",
962 time_to_asc(convert_timespec_to_time_t(ft->atime))));
963 DEBUG(6, ("file_ntime: modtime: %s",
964 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
965 DEBUG(6, ("file_ntime: ctime: %s",
966 time_to_asc(convert_timespec_to_time_t(ft->ctime))));
967 DEBUG(6, ("file_ntime: createtime: %s",
968 time_to_asc(convert_timespec_to_time_t(ft->create_time))));
970 /* Don't update the time on read-only shares */
971 /* We need this as set_filetime (which can be called on
972 close and other paths) can end up calling this function
973 without the NEED_WRITE protection. Found by :
974 Leo Weppelman <leo@wau.mis.ah.nl>
977 if (!CAN_WRITE(conn)) {
981 if(SMB_VFS_NTIMES(conn, smb_fname, ft) == 0) {
985 if((errno != EPERM) && (errno != EACCES)) {
989 if(!lp_dos_filetimes(SNUM(conn))) {
993 /* We have permission (given by the Samba admin) to
994 break POSIX semantics and allow a user to change
995 the time on a file they don't own but can write to
999 /* Check if we have write access. */
1000 if (can_write_to_file(conn, smb_fname)) {
1001 /* We are allowed to become root and change the filetime. */
1003 ret = SMB_VFS_NTIMES(conn, smb_fname, ft);
1010 /******************************************************************
1011 Force a "sticky" write time on a pathname. This will always be
1012 returned on all future write time queries and set on close.
1013 ******************************************************************/
1015 bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime)
1017 if (null_timespec(mtime)) {
1021 if (!set_sticky_write_time(fileid, mtime)) {
1028 /******************************************************************
1029 Force a "sticky" write time on an fsp. This will always be
1030 returned on all future write time queries and set on close.
1031 ******************************************************************/
1033 bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime)
1035 if (null_timespec(mtime)) {
1039 fsp->write_time_forced = true;
1040 TALLOC_FREE(fsp->update_write_time_event);
1042 return set_sticky_write_time_path(fsp->file_id, mtime);
1045 /******************************************************************
1046 Set a create time EA.
1047 ******************************************************************/
1049 NTSTATUS set_create_timespec_ea(connection_struct *conn,
1050 const struct smb_filename *psmb_fname,
1051 struct timespec create_time)
1054 struct smb_filename *smb_fname = NULL;
1058 if (!lp_store_dos_attributes(SNUM(conn))) {
1059 return NT_STATUS_OK;
1062 status = create_synthetic_smb_fname(talloc_tos(),
1063 psmb_fname->base_name,
1064 NULL, &psmb_fname->st,
1067 if (!NT_STATUS_IS_OK(status)) {
1071 dosmode = dos_mode(conn, smb_fname);
1073 smb_fname->st.st_ex_btime = create_time;
1075 ret = file_set_dosmode(conn, smb_fname, dosmode, NULL, false);
1077 map_nt_error_from_unix(errno);
1080 DEBUG(10,("set_create_timespec_ea: wrote create time EA for file %s\n",
1081 smb_fname_str_dbg(smb_fname)));
1083 return NT_STATUS_OK;
1086 /******************************************************************
1087 Return a create time.
1088 ******************************************************************/
1090 struct timespec get_create_timespec(connection_struct *conn,
1091 struct files_struct *fsp,
1092 const struct smb_filename *smb_fname)
1094 return smb_fname->st.st_ex_btime;
1097 /******************************************************************
1098 Return a change time (may look at EA in future).
1099 ******************************************************************/
1101 struct timespec get_change_timespec(connection_struct *conn,
1102 struct files_struct *fsp,
1103 const struct smb_filename *smb_fname)
1105 return smb_fname->st.st_ex_mtime;