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 void dos_mode_debug_print(uint32_t mode
)
30 DEBUG(8,("dos_mode returning "));
32 if (mode
& FILE_ATTRIBUTE_HIDDEN
) {
35 if (mode
& FILE_ATTRIBUTE_READONLY
) {
38 if (mode
& FILE_ATTRIBUTE_SYSTEM
) {
41 if (mode
& FILE_ATTRIBUTE_DIRECTORY
) {
44 if (mode
& FILE_ATTRIBUTE_ARCHIVE
) {
47 if (mode
& FILE_ATTRIBUTE_SPARSE
) {
48 DEBUG(8, ("[sparse]"));
50 if (mode
& FILE_ATTRIBUTE_OFFLINE
) {
51 DEBUG(8, ("[offline]"));
57 static uint32_t filter_mode_by_protocol(uint32_t mode
)
59 if (get_Protocol() <= PROTOCOL_LANMAN2
) {
60 DEBUG(10,("filter_mode_by_protocol: "
61 "filtering result 0x%x to 0x%x\n",
63 (unsigned int)(mode
& 0x3f) ));
69 static int set_link_read_only_flag(const SMB_STRUCT_STAT
*const sbuf
)
73 if (S_ISLNK(sbuf
->st_mode
) && S_ISDIR(sbuf
->st_mode
))
74 return FILE_ATTRIBUTE_READONLY
;
80 /****************************************************************************
81 Change a dos mode to a unix mode.
82 Base permission for files:
83 if creating file and inheriting (i.e. parent_dir != NULL)
84 apply read/write bits from parent directory.
86 everybody gets read bit set
87 dos readonly is represented in unix by removing everyone's write bit
88 dos archive is represented in unix by the user's execute bit
89 dos system is represented in unix by the group's execute bit
90 dos hidden is represented in unix by the other's execute bit
92 Then apply create mask,
95 Base permission for directories:
96 dos directory is represented in unix by unix's dir bit and the exec bit
98 Then apply create mask,
101 ****************************************************************************/
103 mode_t
unix_mode(connection_struct
*conn
, int dosmode
,
104 const struct smb_filename
*smb_fname
,
105 const char *inherit_from_dir
)
107 mode_t result
= (S_IRUSR
| S_IRGRP
| S_IROTH
| S_IWUSR
| S_IWGRP
| S_IWOTH
);
108 mode_t dir_mode
= 0; /* Mode of the inherit_from directory if
111 if (!lp_store_dos_attributes(SNUM(conn
)) && IS_DOS_READONLY(dosmode
)) {
112 result
&= ~(S_IWUSR
| S_IWGRP
| S_IWOTH
);
115 if ((inherit_from_dir
!= NULL
) && lp_inherit_perms(SNUM(conn
))) {
116 struct smb_filename
*smb_fname_parent
;
118 DEBUG(2, ("unix_mode(%s) inheriting from %s\n",
119 smb_fname_str_dbg(smb_fname
),
122 smb_fname_parent
= synthetic_smb_fname(
123 talloc_tos(), inherit_from_dir
, NULL
, NULL
);
124 if (smb_fname_parent
== NULL
) {
125 DEBUG(1,("unix_mode(%s) failed, [dir %s]: No memory\n",
126 smb_fname_str_dbg(smb_fname
),
131 if (SMB_VFS_STAT(conn
, smb_fname_parent
) != 0) {
132 DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n",
133 smb_fname_str_dbg(smb_fname
),
134 inherit_from_dir
, strerror(errno
)));
135 TALLOC_FREE(smb_fname_parent
);
136 return(0); /* *** shouldn't happen! *** */
139 /* Save for later - but explicitly remove setuid bit for safety. */
140 dir_mode
= smb_fname_parent
->st
.st_ex_mode
& ~S_ISUID
;
141 DEBUG(2,("unix_mode(%s) inherit mode %o\n",
142 smb_fname_str_dbg(smb_fname
), (int)dir_mode
));
145 TALLOC_FREE(smb_fname_parent
);
148 if (IS_DOS_DIR(dosmode
)) {
149 /* We never make directories read only for the owner as under DOS a user
150 can always create a file in a read-only directory. */
151 result
|= (S_IFDIR
| S_IWUSR
);
154 /* Inherit mode of parent directory. */
157 /* Provisionally add all 'x' bits */
158 result
|= (S_IXUSR
| S_IXGRP
| S_IXOTH
);
160 /* Apply directory mask */
161 result
&= lp_dir_mask(SNUM(conn
));
162 /* Add in force bits */
163 result
|= lp_force_dir_mode(SNUM(conn
));
166 if (lp_map_archive(SNUM(conn
)) && IS_DOS_ARCHIVE(dosmode
))
169 if (lp_map_system(SNUM(conn
)) && IS_DOS_SYSTEM(dosmode
))
172 if (lp_map_hidden(SNUM(conn
)) && IS_DOS_HIDDEN(dosmode
))
176 /* Inherit 666 component of parent directory mode */
177 result
|= dir_mode
& (S_IRUSR
| S_IRGRP
| S_IROTH
| S_IWUSR
| S_IWGRP
| S_IWOTH
);
179 /* Apply mode mask */
180 result
&= lp_create_mask(SNUM(conn
));
181 /* Add in force bits */
182 result
|= lp_force_create_mode(SNUM(conn
));
186 DEBUG(3,("unix_mode(%s) returning 0%o\n", smb_fname_str_dbg(smb_fname
),
191 /****************************************************************************
192 Change a unix mode to a dos mode.
193 ****************************************************************************/
195 static uint32
dos_mode_from_sbuf(connection_struct
*conn
,
196 const struct smb_filename
*smb_fname
)
199 enum mapreadonly_options ro_opts
= (enum mapreadonly_options
)lp_map_readonly(SNUM(conn
));
201 #if defined(UF_IMMUTABLE) && defined(SF_IMMUTABLE)
202 /* if we can find out if a file is immutable we should report it r/o */
203 if (smb_fname
->st
.st_ex_flags
& (UF_IMMUTABLE
| SF_IMMUTABLE
)) {
204 result
|= FILE_ATTRIBUTE_READONLY
;
207 if (ro_opts
== MAP_READONLY_YES
) {
208 /* Original Samba method - map inverse of user "w" bit. */
209 if ((smb_fname
->st
.st_ex_mode
& S_IWUSR
) == 0) {
210 result
|= FILE_ATTRIBUTE_READONLY
;
212 } else if (ro_opts
== MAP_READONLY_PERMISSIONS
) {
213 /* Check actual permissions for read-only. */
214 if (!can_write_to_file(conn
, smb_fname
)) {
215 result
|= FILE_ATTRIBUTE_READONLY
;
217 } /* Else never set the readonly bit. */
219 if (MAP_ARCHIVE(conn
) && ((smb_fname
->st
.st_ex_mode
& S_IXUSR
) != 0))
220 result
|= FILE_ATTRIBUTE_ARCHIVE
;
222 if (MAP_SYSTEM(conn
) && ((smb_fname
->st
.st_ex_mode
& S_IXGRP
) != 0))
223 result
|= FILE_ATTRIBUTE_SYSTEM
;
225 if (MAP_HIDDEN(conn
) && ((smb_fname
->st
.st_ex_mode
& S_IXOTH
) != 0))
226 result
|= FILE_ATTRIBUTE_HIDDEN
;
228 if (S_ISDIR(smb_fname
->st
.st_ex_mode
))
229 result
= FILE_ATTRIBUTE_DIRECTORY
| (result
& FILE_ATTRIBUTE_READONLY
);
231 result
|= set_link_read_only_flag(&smb_fname
->st
);
233 DEBUG(8,("dos_mode_from_sbuf returning "));
235 if (result
& FILE_ATTRIBUTE_HIDDEN
) DEBUG(8, ("h"));
236 if (result
& FILE_ATTRIBUTE_READONLY
) DEBUG(8, ("r"));
237 if (result
& FILE_ATTRIBUTE_SYSTEM
) DEBUG(8, ("s"));
238 if (result
& FILE_ATTRIBUTE_DIRECTORY
) DEBUG(8, ("d"));
239 if (result
& FILE_ATTRIBUTE_ARCHIVE
) DEBUG(8, ("a"));
245 /****************************************************************************
246 Get DOS attributes from an EA.
247 This can also pull the create time into the stat struct inside smb_fname.
248 ****************************************************************************/
250 static bool get_ea_dos_attribute(connection_struct
*conn
,
251 struct smb_filename
*smb_fname
,
254 struct xattr_DOSATTRIB dosattrib
;
255 enum ndr_err_code ndr_err
;
261 if (!lp_store_dos_attributes(SNUM(conn
))) {
265 /* Don't reset pattr to zero as we may already have filename-based attributes we
268 sizeret
= SMB_VFS_GETXATTR(conn
, smb_fname
->base_name
,
269 SAMBA_XATTR_DOS_ATTRIB
, attrstr
,
274 || errno
== ENOTSUP
) {
278 DEBUG(1,("get_ea_dos_attribute: Cannot get attribute "
279 "from EA on file %s: Error = %s\n",
280 smb_fname_str_dbg(smb_fname
),
282 set_store_dos_attributes(SNUM(conn
), False
);
287 blob
.data
= (uint8_t *)attrstr
;
288 blob
.length
= sizeret
;
290 ndr_err
= ndr_pull_struct_blob(&blob
, talloc_tos(), &dosattrib
,
291 (ndr_pull_flags_fn_t
)ndr_pull_xattr_DOSATTRIB
);
293 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
294 DEBUG(1,("get_ea_dos_attribute: bad ndr decode "
295 "from EA on file %s: Error = %s\n",
296 smb_fname_str_dbg(smb_fname
),
297 ndr_errstr(ndr_err
)));
301 DEBUG(10,("get_ea_dos_attribute: %s attr = %s\n",
302 smb_fname_str_dbg(smb_fname
), dosattrib
.attrib_hex
));
304 switch (dosattrib
.version
) {
306 dosattr
= dosattrib
.info
.compatinfoFFFF
.attrib
;
309 dosattr
= dosattrib
.info
.info1
.attrib
;
310 if (!null_nttime(dosattrib
.info
.info1
.create_time
)) {
311 struct timespec create_time
=
312 nt_time_to_unix_timespec(
313 &dosattrib
.info
.info1
.create_time
);
315 update_stat_ex_create_time(&smb_fname
->st
,
318 DEBUG(10,("get_ea_dos_attribute: file %s case 1 "
320 smb_fname_str_dbg(smb_fname
),
321 time_to_asc(convert_timespec_to_time_t(
326 dosattr
= dosattrib
.info
.oldinfo2
.attrib
;
327 /* Don't know what flags to check for this case. */
330 dosattr
= dosattrib
.info
.info3
.attrib
;
331 if ((dosattrib
.info
.info3
.valid_flags
& XATTR_DOSINFO_CREATE_TIME
) &&
332 !null_nttime(dosattrib
.info
.info3
.create_time
)) {
333 struct timespec create_time
=
334 nt_time_to_unix_timespec(
335 &dosattrib
.info
.info3
.create_time
);
337 update_stat_ex_create_time(&smb_fname
->st
,
340 DEBUG(10,("get_ea_dos_attribute: file %s case 3 "
342 smb_fname_str_dbg(smb_fname
),
343 time_to_asc(convert_timespec_to_time_t(
348 DEBUG(1,("get_ea_dos_attribute: Badly formed DOSATTRIB on "
349 "file %s - %s\n", smb_fname_str_dbg(smb_fname
),
354 if (S_ISDIR(smb_fname
->st
.st_ex_mode
)) {
355 dosattr
|= FILE_ATTRIBUTE_DIRECTORY
;
357 /* FILE_ATTRIBUTE_SPARSE is valid on get but not on set. */
358 *pattr
= (uint32
)(dosattr
& (SAMBA_ATTRIBUTES_MASK
|FILE_ATTRIBUTE_SPARSE
));
360 DEBUG(8,("get_ea_dos_attribute returning (0x%x)", dosattr
));
362 if (dosattr
& FILE_ATTRIBUTE_HIDDEN
) DEBUG(8, ("h"));
363 if (dosattr
& FILE_ATTRIBUTE_READONLY
) DEBUG(8, ("r"));
364 if (dosattr
& FILE_ATTRIBUTE_SYSTEM
) DEBUG(8, ("s"));
365 if (dosattr
& FILE_ATTRIBUTE_DIRECTORY
) DEBUG(8, ("d"));
366 if (dosattr
& FILE_ATTRIBUTE_ARCHIVE
) DEBUG(8, ("a"));
373 /****************************************************************************
374 Set DOS attributes in an EA.
375 Also sets the create time.
376 ****************************************************************************/
378 static bool set_ea_dos_attribute(connection_struct
*conn
,
379 struct smb_filename
*smb_fname
,
382 struct xattr_DOSATTRIB dosattrib
;
383 enum ndr_err_code ndr_err
;
386 ZERO_STRUCT(dosattrib
);
389 dosattrib
.version
= 3;
390 dosattrib
.info
.info3
.valid_flags
= XATTR_DOSINFO_ATTRIB
|
391 XATTR_DOSINFO_CREATE_TIME
;
392 dosattrib
.info
.info3
.attrib
= dosmode
;
393 unix_timespec_to_nt_time(&dosattrib
.info
.info3
.create_time
,
394 smb_fname
->st
.st_ex_btime
);
396 DEBUG(10,("set_ea_dos_attributes: set attribute 0x%x, btime = %s on file %s\n",
397 (unsigned int)dosmode
,
398 time_to_asc(convert_timespec_to_time_t(smb_fname
->st
.st_ex_btime
)),
399 smb_fname_str_dbg(smb_fname
) ));
401 ndr_err
= ndr_push_struct_blob(
402 &blob
, talloc_tos(), &dosattrib
,
403 (ndr_push_flags_fn_t
)ndr_push_xattr_DOSATTRIB
);
405 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
406 DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n",
407 ndr_errstr(ndr_err
)));
411 if (blob
.data
== NULL
|| blob
.length
== 0) {
415 if (SMB_VFS_SETXATTR(conn
, smb_fname
->base_name
,
416 SAMBA_XATTR_DOS_ATTRIB
, blob
.data
, blob
.length
,
419 files_struct
*fsp
= NULL
;
421 if((errno
!= EPERM
) && (errno
!= EACCES
)) {
424 || errno
== ENOTSUP
) {
428 DEBUG(1,("set_ea_dos_attributes: Cannot set "
429 "attribute EA on file %s: Error = %s\n",
430 smb_fname_str_dbg(smb_fname
),
432 set_store_dos_attributes(SNUM(conn
), False
);
437 /* We want DOS semantics, ie allow non owner with write permission to change the
438 bits on a file. Just like file_ntimes below.
441 /* Check if we have write access. */
442 if(!CAN_WRITE(conn
) || !lp_dos_filemode(SNUM(conn
)))
445 if (!can_write_to_file(conn
, smb_fname
)) {
450 * We need to open the file with write access whilst
451 * still in our current user context. This ensures we
452 * are not violating security in doing the setxattr.
455 if (!NT_STATUS_IS_OK(open_file_fchmod(conn
, smb_fname
,
459 if (SMB_VFS_FSETXATTR(fsp
,
460 SAMBA_XATTR_DOS_ATTRIB
, blob
.data
,
461 blob
.length
, 0) == 0) {
465 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
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 DEBUG(8,("dos_mode_msdfs returning "));
528 if (result
& FILE_ATTRIBUTE_HIDDEN
) DEBUG(8, ("h"));
529 if (result
& FILE_ATTRIBUTE_READONLY
) DEBUG(8, ("r"));
530 if (result
& FILE_ATTRIBUTE_SYSTEM
) DEBUG(8, ("s"));
531 if (result
& FILE_ATTRIBUTE_DIRECTORY
) DEBUG(8, ("d"));
532 if (result
& FILE_ATTRIBUTE_ARCHIVE
) DEBUG(8, ("a"));
533 if (result
& FILE_ATTRIBUTE_SPARSE
) DEBUG(8, ("[sparse]"));
540 #ifdef HAVE_STAT_DOS_FLAGS
541 /****************************************************************************
542 Convert dos attributes (FILE_ATTRIBUTE_*) to dos stat flags (UF_*)
543 ****************************************************************************/
545 int dos_attributes_to_stat_dos_flags(uint32_t dosmode
)
547 uint32_t dos_stat_flags
= 0;
549 if (dosmode
& FILE_ATTRIBUTE_ARCHIVE
)
550 dos_stat_flags
|= UF_DOS_ARCHIVE
;
551 if (dosmode
& FILE_ATTRIBUTE_HIDDEN
)
552 dos_stat_flags
|= UF_DOS_HIDDEN
;
553 if (dosmode
& FILE_ATTRIBUTE_READONLY
)
554 dos_stat_flags
|= UF_DOS_RO
;
555 if (dosmode
& FILE_ATTRIBUTE_SYSTEM
)
556 dos_stat_flags
|= UF_DOS_SYSTEM
;
557 if (dosmode
& FILE_ATTRIBUTE_NONINDEXED
)
558 dos_stat_flags
|= UF_DOS_NOINDEX
;
560 return dos_stat_flags
;
563 /****************************************************************************
564 Gets DOS attributes, accessed via st_ex_flags in the stat struct.
565 ****************************************************************************/
567 static bool get_stat_dos_flags(connection_struct
*conn
,
568 const struct smb_filename
*smb_fname
,
571 SMB_ASSERT(VALID_STAT(smb_fname
->st
));
574 if (!lp_store_dos_attributes(SNUM(conn
))) {
578 DEBUG(5, ("Getting stat dos attributes for %s.\n",
579 smb_fname_str_dbg(smb_fname
)));
581 if (smb_fname
->st
.st_ex_flags
& UF_DOS_ARCHIVE
)
582 *dosmode
|= FILE_ATTRIBUTE_ARCHIVE
;
583 if (smb_fname
->st
.st_ex_flags
& UF_DOS_HIDDEN
)
584 *dosmode
|= FILE_ATTRIBUTE_HIDDEN
;
585 if (smb_fname
->st
.st_ex_flags
& UF_DOS_RO
)
586 *dosmode
|= FILE_ATTRIBUTE_READONLY
;
587 if (smb_fname
->st
.st_ex_flags
& UF_DOS_SYSTEM
)
588 *dosmode
|= FILE_ATTRIBUTE_SYSTEM
;
589 if (smb_fname
->st
.st_ex_flags
& UF_DOS_NOINDEX
)
590 *dosmode
|= FILE_ATTRIBUTE_NONINDEXED
;
591 if (smb_fname
->st
.st_ex_flags
& FILE_ATTRIBUTE_SPARSE
)
592 *dosmode
|= FILE_ATTRIBUTE_SPARSE
;
593 if (S_ISDIR(smb_fname
->st
.st_ex_mode
))
594 *dosmode
|= FILE_ATTRIBUTE_DIRECTORY
;
596 *dosmode
|= set_link_read_only_flag(&smb_fname
->st
);
601 /****************************************************************************
602 Sets DOS attributes, stored in st_ex_flags of the inode.
603 ****************************************************************************/
605 static bool set_stat_dos_flags(connection_struct
*conn
,
606 const struct smb_filename
*smb_fname
,
608 bool *attributes_changed
)
610 uint32_t new_flags
= 0;
613 SMB_ASSERT(VALID_STAT(smb_fname
->st
));
614 SMB_ASSERT(attributes_changed
);
616 *attributes_changed
= false;
618 if (!lp_store_dos_attributes(SNUM(conn
))) {
622 DEBUG(5, ("Setting stat dos attributes for %s.\n",
623 smb_fname_str_dbg(smb_fname
)));
625 new_flags
= (smb_fname
->st
.st_ex_flags
& ~UF_DOS_FLAGS
) |
626 dos_attributes_to_stat_dos_flags(dosmode
);
628 /* Return early if no flags changed. */
629 if (new_flags
== smb_fname
->st
.st_ex_flags
)
632 DEBUG(5, ("Setting stat dos attributes=0x%x, prev=0x%x\n", new_flags
,
633 smb_fname
->st
.st_ex_flags
));
635 /* Set new flags with chflags. */
636 error
= SMB_VFS_CHFLAGS(conn
, smb_fname
->base_name
, new_flags
);
638 DEBUG(0, ("Failed setting new stat dos attributes (0x%x) on "
639 "file %s! errno=%d\n", new_flags
,
640 smb_fname_str_dbg(smb_fname
), errno
));
644 *attributes_changed
= true;
647 #endif /* HAVE_STAT_DOS_FLAGS */
649 /****************************************************************************
650 Change a unix mode to a dos mode.
651 May also read the create timespec into the stat struct in smb_fname
652 if "store dos attributes" is true.
653 ****************************************************************************/
655 uint32
dos_mode(connection_struct
*conn
, struct smb_filename
*smb_fname
)
658 bool offline
, used_stat_dos_flags
= false;
660 DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname
)));
662 if (!VALID_STAT(smb_fname
->st
)) {
666 /* First do any modifications that depend on the path name. */
667 /* hide files with a name starting with a . */
668 if (lp_hide_dot_files(SNUM(conn
))) {
669 const char *p
= strrchr_m(smb_fname
->base_name
,'/');
673 p
= smb_fname
->base_name
;
676 /* Only . and .. are not hidden. */
677 if (p
[0] == '.' && !((p
[1] == '\0') ||
678 (p
[1] == '.' && p
[2] == '\0'))) {
679 result
|= FILE_ATTRIBUTE_HIDDEN
;
683 #ifdef HAVE_STAT_DOS_FLAGS
684 used_stat_dos_flags
= get_stat_dos_flags(conn
, smb_fname
, &result
);
686 if (!used_stat_dos_flags
) {
687 /* Get the DOS attributes from an EA by preference. */
688 if (!get_ea_dos_attribute(conn
, smb_fname
, &result
)) {
689 result
|= dos_mode_from_sbuf(conn
, smb_fname
);
693 offline
= SMB_VFS_IS_OFFLINE(conn
, smb_fname
, &smb_fname
->st
);
694 if (S_ISREG(smb_fname
->st
.st_ex_mode
) && offline
) {
695 result
|= FILE_ATTRIBUTE_OFFLINE
;
698 /* Optimization : Only call is_hidden_path if it's not already
700 if (!(result
& FILE_ATTRIBUTE_HIDDEN
) &&
701 IS_HIDDEN_PATH(conn
, smb_fname
->base_name
)) {
702 result
|= FILE_ATTRIBUTE_HIDDEN
;
706 result
= FILE_ATTRIBUTE_NORMAL
;
709 result
= filter_mode_by_protocol(result
);
711 dos_mode_debug_print(result
);
716 /*******************************************************************
717 chmod a file - but preserve some bits.
718 If "store dos attributes" is also set it will store the create time
719 from the stat struct in smb_fname (in NTTIME format) in the EA
721 ********************************************************************/
723 int file_set_dosmode(connection_struct
*conn
, struct smb_filename
*smb_fname
,
724 uint32 dosmode
, const char *parent_dir
, bool newfile
)
729 int ret
= -1, lret
= -1;
731 struct timespec new_create_timespec
;
732 files_struct
*fsp
= NULL
;
734 if (!CAN_WRITE(conn
)) {
739 /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
740 dosmode
&= (SAMBA_ATTRIBUTES_MASK
| FILE_ATTRIBUTE_OFFLINE
);
742 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
743 dosmode
, smb_fname_str_dbg(smb_fname
)));
745 unixmode
= smb_fname
->st
.st_ex_mode
;
747 get_acl_group_bits(conn
, smb_fname
->base_name
,
748 &smb_fname
->st
.st_ex_mode
);
750 if (S_ISDIR(smb_fname
->st
.st_ex_mode
))
751 dosmode
|= FILE_ATTRIBUTE_DIRECTORY
;
753 dosmode
&= ~FILE_ATTRIBUTE_DIRECTORY
;
755 new_create_timespec
= smb_fname
->st
.st_ex_btime
;
757 old_mode
= dos_mode(conn
, smb_fname
);
759 if ((dosmode
& FILE_ATTRIBUTE_OFFLINE
) &&
760 !(old_mode
& FILE_ATTRIBUTE_OFFLINE
)) {
761 lret
= SMB_VFS_SET_OFFLINE(conn
, smb_fname
);
763 if (errno
== ENOTSUP
) {
764 DEBUG(10, ("Setting FILE_ATTRIBUTE_OFFLINE for "
765 "%s/%s is not supported.\n",
767 smb_fname_str_dbg(smb_fname
)));
769 DEBUG(0, ("An error occurred while setting "
770 "FILE_ATTRIBUTE_OFFLINE for "
771 "%s/%s: %s", parent_dir
,
772 smb_fname_str_dbg(smb_fname
),
778 dosmode
&= ~FILE_ATTRIBUTE_OFFLINE
;
779 old_mode
&= ~FILE_ATTRIBUTE_OFFLINE
;
781 smb_fname
->st
.st_ex_btime
= new_create_timespec
;
783 #ifdef HAVE_STAT_DOS_FLAGS
785 bool attributes_changed
;
787 if (set_stat_dos_flags(conn
, smb_fname
, dosmode
,
788 &attributes_changed
))
790 if (!newfile
&& attributes_changed
) {
791 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
792 FILE_NOTIFY_CHANGE_ATTRIBUTES
,
793 smb_fname
->base_name
);
795 smb_fname
->st
.st_ex_mode
= unixmode
;
800 /* Store the DOS attributes in an EA by preference. */
801 if (lp_store_dos_attributes(SNUM(conn
))) {
803 * Don't fall back to using UNIX modes. Finally
804 * follow the smb.conf manpage.
806 if (!set_ea_dos_attribute(conn
, smb_fname
, dosmode
)) {
810 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
811 FILE_NOTIFY_CHANGE_ATTRIBUTES
,
812 smb_fname
->base_name
);
814 smb_fname
->st
.st_ex_mode
= unixmode
;
818 unixmode
= unix_mode(conn
, dosmode
, smb_fname
, parent_dir
);
820 /* preserve the file type bits */
823 /* preserve the s bits */
824 mask
|= (S_ISUID
| S_ISGID
);
826 /* preserve the t bit */
831 /* possibly preserve the x bits */
832 if (!MAP_ARCHIVE(conn
))
834 if (!MAP_SYSTEM(conn
))
836 if (!MAP_HIDDEN(conn
))
839 unixmode
|= (smb_fname
->st
.st_ex_mode
& mask
);
841 /* if we previously had any r bits set then leave them alone */
842 if ((tmp
= smb_fname
->st
.st_ex_mode
& (S_IRUSR
|S_IRGRP
|S_IROTH
))) {
843 unixmode
&= ~(S_IRUSR
|S_IRGRP
|S_IROTH
);
847 /* if we previously had any w bits set then leave them alone
848 whilst adding in the new w bits, if the new mode is not rdonly */
849 if (!IS_DOS_READONLY(dosmode
)) {
850 unixmode
|= (smb_fname
->st
.st_ex_mode
& (S_IWUSR
|S_IWGRP
|S_IWOTH
));
854 * From the chmod 2 man page:
856 * "If the calling process is not privileged, and the group of the file
857 * does not match the effective group ID of the process or one of its
858 * supplementary group IDs, the S_ISGID bit will be turned off, but
859 * this will not cause an error to be returned."
861 * Simply refuse to do the chmod in this case.
864 if (S_ISDIR(smb_fname
->st
.st_ex_mode
) && (unixmode
& S_ISGID
) &&
865 geteuid() != sec_initial_uid() &&
866 !current_user_in_group(conn
, smb_fname
->st
.st_ex_gid
)) {
867 DEBUG(3,("file_set_dosmode: setgid bit cannot be "
868 "set for directory %s\n",
869 smb_fname_str_dbg(smb_fname
)));
874 ret
= SMB_VFS_CHMOD(conn
, smb_fname
->base_name
, unixmode
);
876 if(!newfile
|| (lret
!= -1)) {
877 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
878 FILE_NOTIFY_CHANGE_ATTRIBUTES
,
879 smb_fname
->base_name
);
881 smb_fname
->st
.st_ex_mode
= unixmode
;
885 if((errno
!= EPERM
) && (errno
!= EACCES
))
888 if(!lp_dos_filemode(SNUM(conn
)))
891 /* We want DOS semantics, ie allow non owner with write permission to change the
892 bits on a file. Just like file_ntimes below.
895 if (!can_write_to_file(conn
, smb_fname
)) {
901 * We need to open the file with write access whilst
902 * still in our current user context. This ensures we
903 * are not violating security in doing the fchmod.
905 if (!NT_STATUS_IS_OK(open_file_fchmod(conn
, smb_fname
,
909 ret
= SMB_VFS_FCHMOD(fsp
, unixmode
);
911 close_file(NULL
, fsp
, NORMAL_CLOSE
);
913 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
914 FILE_NOTIFY_CHANGE_ATTRIBUTES
,
915 smb_fname
->base_name
);
918 smb_fname
->st
.st_ex_mode
= unixmode
;
925 NTSTATUS
file_set_sparse(connection_struct
*conn
,
929 uint32_t old_dosmode
;
930 uint32_t new_dosmode
;
933 if (!CAN_WRITE(conn
)) {
934 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
935 "on readonly share[%s]\n",
936 smb_fname_str_dbg(fsp
->fsp_name
),
938 lp_servicename(talloc_tos(), SNUM(conn
))));
939 return NT_STATUS_MEDIA_WRITE_PROTECTED
;
942 if (!(fsp
->access_mask
& FILE_WRITE_DATA
) &&
943 !(fsp
->access_mask
& FILE_WRITE_ATTRIBUTES
)) {
944 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
945 "access_mask[0x%08X] - access denied\n",
946 smb_fname_str_dbg(fsp
->fsp_name
),
949 return NT_STATUS_ACCESS_DENIED
;
952 DEBUG(10,("file_set_sparse: setting sparse bit %u on file %s\n",
953 sparse
, smb_fname_str_dbg(fsp
->fsp_name
)));
955 if (!lp_store_dos_attributes(SNUM(conn
))) {
956 return NT_STATUS_INVALID_DEVICE_REQUEST
;
959 status
= vfs_stat_fsp(fsp
);
960 if (!NT_STATUS_IS_OK(status
)) {
964 old_dosmode
= dos_mode(conn
, fsp
->fsp_name
);
966 if (sparse
&& !(old_dosmode
& FILE_ATTRIBUTE_SPARSE
)) {
967 new_dosmode
= old_dosmode
| FILE_ATTRIBUTE_SPARSE
;
968 } else if (!sparse
&& (old_dosmode
& FILE_ATTRIBUTE_SPARSE
)) {
969 new_dosmode
= old_dosmode
& ~FILE_ATTRIBUTE_SPARSE
;
974 /* Store the DOS attributes in an EA. */
975 if (!set_ea_dos_attribute(conn
, fsp
->fsp_name
,
980 return map_nt_error_from_unix(errno
);
983 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
984 FILE_NOTIFY_CHANGE_ATTRIBUTES
,
985 fsp
->fsp_name
->base_name
);
987 fsp
->is_sparse
= sparse
;
992 /*******************************************************************
993 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
995 *******************************************************************/
997 int file_ntimes(connection_struct
*conn
, const struct smb_filename
*smb_fname
,
998 struct smb_file_time
*ft
)
1004 DEBUG(6, ("file_ntime: actime: %s",
1005 time_to_asc(convert_timespec_to_time_t(ft
->atime
))));
1006 DEBUG(6, ("file_ntime: modtime: %s",
1007 time_to_asc(convert_timespec_to_time_t(ft
->mtime
))));
1008 DEBUG(6, ("file_ntime: ctime: %s",
1009 time_to_asc(convert_timespec_to_time_t(ft
->ctime
))));
1010 DEBUG(6, ("file_ntime: createtime: %s",
1011 time_to_asc(convert_timespec_to_time_t(ft
->create_time
))));
1013 /* Don't update the time on read-only shares */
1014 /* We need this as set_filetime (which can be called on
1015 close and other paths) can end up calling this function
1016 without the NEED_WRITE protection. Found by :
1017 Leo Weppelman <leo@wau.mis.ah.nl>
1020 if (!CAN_WRITE(conn
)) {
1024 if(SMB_VFS_NTIMES(conn
, smb_fname
, ft
) == 0) {
1028 if((errno
!= EPERM
) && (errno
!= EACCES
)) {
1032 if(!lp_dos_filetimes(SNUM(conn
))) {
1036 /* We have permission (given by the Samba admin) to
1037 break POSIX semantics and allow a user to change
1038 the time on a file they don't own but can write to
1042 /* Check if we have write access. */
1043 if (can_write_to_file(conn
, smb_fname
)) {
1044 /* We are allowed to become root and change the filetime. */
1046 ret
= SMB_VFS_NTIMES(conn
, smb_fname
, ft
);
1053 /******************************************************************
1054 Force a "sticky" write time on a pathname. This will always be
1055 returned on all future write time queries and set on close.
1056 ******************************************************************/
1058 bool set_sticky_write_time_path(struct file_id fileid
, struct timespec mtime
)
1060 if (null_timespec(mtime
)) {
1064 if (!set_sticky_write_time(fileid
, mtime
)) {
1071 /******************************************************************
1072 Force a "sticky" write time on an fsp. This will always be
1073 returned on all future write time queries and set on close.
1074 ******************************************************************/
1076 bool set_sticky_write_time_fsp(struct files_struct
*fsp
, struct timespec mtime
)
1078 if (null_timespec(mtime
)) {
1082 fsp
->write_time_forced
= true;
1083 TALLOC_FREE(fsp
->update_write_time_event
);
1085 return set_sticky_write_time_path(fsp
->file_id
, mtime
);
1088 /******************************************************************
1089 Set a create time EA.
1090 ******************************************************************/
1092 NTSTATUS
set_create_timespec_ea(connection_struct
*conn
,
1093 const struct smb_filename
*psmb_fname
,
1094 struct timespec create_time
)
1096 struct smb_filename
*smb_fname
;
1100 if (!lp_store_dos_attributes(SNUM(conn
))) {
1101 return NT_STATUS_OK
;
1104 smb_fname
= synthetic_smb_fname(talloc_tos(), psmb_fname
->base_name
,
1105 NULL
, &psmb_fname
->st
);
1107 if (smb_fname
== NULL
) {
1108 return NT_STATUS_NO_MEMORY
;
1111 dosmode
= dos_mode(conn
, smb_fname
);
1113 smb_fname
->st
.st_ex_btime
= create_time
;
1115 ret
= file_set_dosmode(conn
, smb_fname
, dosmode
, NULL
, false);
1117 map_nt_error_from_unix(errno
);
1120 DEBUG(10,("set_create_timespec_ea: wrote create time EA for file %s\n",
1121 smb_fname_str_dbg(smb_fname
)));
1123 return NT_STATUS_OK
;
1126 /******************************************************************
1127 Return a create time.
1128 ******************************************************************/
1130 struct timespec
get_create_timespec(connection_struct
*conn
,
1131 struct files_struct
*fsp
,
1132 const struct smb_filename
*smb_fname
)
1134 return smb_fname
->st
.st_ex_btime
;
1137 /******************************************************************
1138 Return a change time (may look at EA in future).
1139 ******************************************************************/
1141 struct timespec
get_change_timespec(connection_struct
*conn
,
1142 struct files_struct
*fsp
,
1143 const struct smb_filename
*smb_fname
)
1145 return smb_fname
->st
.st_ex_mtime
;