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
= NULL
;
90 DEBUG(2, ("unix_mode(%s) inheriting from %s\n",
91 smb_fname_str_dbg(smb_fname
),
94 status
= create_synthetic_smb_fname(talloc_tos(),
95 inherit_from_dir
, NULL
,
96 NULL
, &smb_fname_parent
);
97 if (!NT_STATUS_IS_OK(status
)) {
98 DEBUG(1,("unix_mode(%s) failed, [dir %s]: %s\n",
99 smb_fname_str_dbg(smb_fname
),
100 inherit_from_dir
, nt_errstr(status
)));
104 if (SMB_VFS_STAT(conn
, smb_fname_parent
) != 0) {
105 DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n",
106 smb_fname_str_dbg(smb_fname
),
107 inherit_from_dir
, strerror(errno
)));
108 TALLOC_FREE(smb_fname_parent
);
109 return(0); /* *** shouldn't happen! *** */
112 /* Save for later - but explicitly remove setuid bit for safety. */
113 dir_mode
= smb_fname_parent
->st
.st_ex_mode
& ~S_ISUID
;
114 DEBUG(2,("unix_mode(%s) inherit mode %o\n",
115 smb_fname_str_dbg(smb_fname
), (int)dir_mode
));
118 TALLOC_FREE(smb_fname_parent
);
121 if (IS_DOS_DIR(dosmode
)) {
122 /* We never make directories read only for the owner as under DOS a user
123 can always create a file in a read-only directory. */
124 result
|= (S_IFDIR
| S_IWUSR
);
127 /* Inherit mode of parent directory. */
130 /* Provisionally add all 'x' bits */
131 result
|= (S_IXUSR
| S_IXGRP
| S_IXOTH
);
133 /* Apply directory mask */
134 result
&= lp_dir_mask(SNUM(conn
));
135 /* Add in force bits */
136 result
|= lp_force_dir_mode(SNUM(conn
));
139 if (lp_map_archive(SNUM(conn
)) && IS_DOS_ARCHIVE(dosmode
))
142 if (lp_map_system(SNUM(conn
)) && IS_DOS_SYSTEM(dosmode
))
145 if (lp_map_hidden(SNUM(conn
)) && IS_DOS_HIDDEN(dosmode
))
149 /* Inherit 666 component of parent directory mode */
150 result
|= dir_mode
& (S_IRUSR
| S_IRGRP
| S_IROTH
| S_IWUSR
| S_IWGRP
| S_IWOTH
);
152 /* Apply mode mask */
153 result
&= lp_create_mask(SNUM(conn
));
154 /* Add in force bits */
155 result
|= lp_force_create_mode(SNUM(conn
));
159 DEBUG(3,("unix_mode(%s) returning 0%o\n", smb_fname_str_dbg(smb_fname
),
164 /****************************************************************************
165 Change a unix mode to a dos mode.
166 ****************************************************************************/
168 static uint32
dos_mode_from_sbuf(connection_struct
*conn
,
169 const struct smb_filename
*smb_fname
)
172 enum mapreadonly_options ro_opts
= (enum mapreadonly_options
)lp_map_readonly(SNUM(conn
));
174 #if defined(UF_IMMUTABLE) && defined(SF_IMMUTABLE)
175 /* if we can find out if a file is immutable we should report it r/o */
176 if (smb_fname
->st
.st_ex_flags
& (UF_IMMUTABLE
| SF_IMMUTABLE
)) {
177 result
|= FILE_ATTRIBUTE_READONLY
;
180 if (ro_opts
== MAP_READONLY_YES
) {
181 /* Original Samba method - map inverse of user "w" bit. */
182 if ((smb_fname
->st
.st_ex_mode
& S_IWUSR
) == 0) {
183 result
|= FILE_ATTRIBUTE_READONLY
;
185 } else if (ro_opts
== MAP_READONLY_PERMISSIONS
) {
186 /* Check actual permissions for read-only. */
187 if (!can_write_to_file(conn
, smb_fname
)) {
188 result
|= FILE_ATTRIBUTE_READONLY
;
190 } /* Else never set the readonly bit. */
192 if (MAP_ARCHIVE(conn
) && ((smb_fname
->st
.st_ex_mode
& S_IXUSR
) != 0))
193 result
|= FILE_ATTRIBUTE_ARCHIVE
;
195 if (MAP_SYSTEM(conn
) && ((smb_fname
->st
.st_ex_mode
& S_IXGRP
) != 0))
196 result
|= FILE_ATTRIBUTE_SYSTEM
;
198 if (MAP_HIDDEN(conn
) && ((smb_fname
->st
.st_ex_mode
& S_IXOTH
) != 0))
199 result
|= FILE_ATTRIBUTE_HIDDEN
;
201 if (S_ISDIR(smb_fname
->st
.st_ex_mode
))
202 result
= FILE_ATTRIBUTE_DIRECTORY
| (result
& FILE_ATTRIBUTE_READONLY
);
204 result
|= set_link_read_only_flag(&smb_fname
->st
);
206 DEBUG(8,("dos_mode_from_sbuf returning "));
208 if (result
& FILE_ATTRIBUTE_HIDDEN
) DEBUG(8, ("h"));
209 if (result
& FILE_ATTRIBUTE_READONLY
) DEBUG(8, ("r"));
210 if (result
& FILE_ATTRIBUTE_SYSTEM
) DEBUG(8, ("s"));
211 if (result
& FILE_ATTRIBUTE_DIRECTORY
) DEBUG(8, ("d"));
212 if (result
& FILE_ATTRIBUTE_ARCHIVE
) DEBUG(8, ("a"));
218 /****************************************************************************
219 Get DOS attributes from an EA.
220 This can also pull the create time into the stat struct inside smb_fname.
221 ****************************************************************************/
223 static bool get_ea_dos_attribute(connection_struct
*conn
,
224 struct smb_filename
*smb_fname
,
227 struct xattr_DOSATTRIB dosattrib
;
228 enum ndr_err_code ndr_err
;
234 if (!lp_store_dos_attributes(SNUM(conn
))) {
238 /* Don't reset pattr to zero as we may already have filename-based attributes we
241 sizeret
= SMB_VFS_GETXATTR(conn
, smb_fname
->base_name
,
242 SAMBA_XATTR_DOS_ATTRIB
, attrstr
,
247 || errno
== ENOTSUP
) {
251 DEBUG(1,("get_ea_dos_attribute: Cannot get attribute "
252 "from EA on file %s: Error = %s\n",
253 smb_fname_str_dbg(smb_fname
),
255 set_store_dos_attributes(SNUM(conn
), False
);
260 blob
.data
= (uint8_t *)attrstr
;
261 blob
.length
= sizeret
;
263 ndr_err
= ndr_pull_struct_blob(&blob
, talloc_tos(), &dosattrib
,
264 (ndr_pull_flags_fn_t
)ndr_pull_xattr_DOSATTRIB
);
266 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
267 DEBUG(1,("get_ea_dos_attribute: bad ndr decode "
268 "from EA on file %s: Error = %s\n",
269 smb_fname_str_dbg(smb_fname
),
270 ndr_errstr(ndr_err
)));
274 DEBUG(10,("get_ea_dos_attribute: %s attr = %s\n",
275 smb_fname_str_dbg(smb_fname
), dosattrib
.attrib_hex
));
277 switch (dosattrib
.version
) {
279 dosattr
= dosattrib
.info
.compatinfoFFFF
.attrib
;
282 dosattr
= dosattrib
.info
.info1
.attrib
;
283 if (!null_nttime(dosattrib
.info
.info1
.create_time
)) {
284 struct timespec create_time
=
285 nt_time_to_unix_timespec(
286 &dosattrib
.info
.info1
.create_time
);
288 update_stat_ex_create_time(&smb_fname
->st
,
291 DEBUG(10,("get_ea_dos_attribute: file %s case 1 "
293 smb_fname_str_dbg(smb_fname
),
294 time_to_asc(convert_timespec_to_time_t(
299 dosattr
= dosattrib
.info
.oldinfo2
.attrib
;
300 /* Don't know what flags to check for this case. */
303 dosattr
= dosattrib
.info
.info3
.attrib
;
304 if ((dosattrib
.info
.info3
.valid_flags
& XATTR_DOSINFO_CREATE_TIME
) &&
305 !null_nttime(dosattrib
.info
.info3
.create_time
)) {
306 struct timespec create_time
=
307 nt_time_to_unix_timespec(
308 &dosattrib
.info
.info3
.create_time
);
310 update_stat_ex_create_time(&smb_fname
->st
,
313 DEBUG(10,("get_ea_dos_attribute: file %s case 3 "
315 smb_fname_str_dbg(smb_fname
),
316 time_to_asc(convert_timespec_to_time_t(
321 DEBUG(1,("get_ea_dos_attribute: Badly formed DOSATTRIB on "
322 "file %s - %s\n", smb_fname_str_dbg(smb_fname
),
327 if (S_ISDIR(smb_fname
->st
.st_ex_mode
)) {
328 dosattr
|= FILE_ATTRIBUTE_DIRECTORY
;
330 /* FILE_ATTRIBUTE_SPARSE is valid on get but not on set. */
331 *pattr
= (uint32
)(dosattr
& (SAMBA_ATTRIBUTES_MASK
|FILE_ATTRIBUTE_SPARSE
));
333 DEBUG(8,("get_ea_dos_attribute returning (0x%x)", dosattr
));
335 if (dosattr
& FILE_ATTRIBUTE_HIDDEN
) DEBUG(8, ("h"));
336 if (dosattr
& FILE_ATTRIBUTE_READONLY
) DEBUG(8, ("r"));
337 if (dosattr
& FILE_ATTRIBUTE_SYSTEM
) DEBUG(8, ("s"));
338 if (dosattr
& FILE_ATTRIBUTE_DIRECTORY
) DEBUG(8, ("d"));
339 if (dosattr
& FILE_ATTRIBUTE_ARCHIVE
) DEBUG(8, ("a"));
346 /****************************************************************************
347 Set DOS attributes in an EA.
348 Also sets the create time.
349 ****************************************************************************/
351 static bool set_ea_dos_attribute(connection_struct
*conn
,
352 struct smb_filename
*smb_fname
,
355 struct xattr_DOSATTRIB dosattrib
;
356 enum ndr_err_code ndr_err
;
359 if (!lp_store_dos_attributes(SNUM(conn
))) {
363 ZERO_STRUCT(dosattrib
);
366 dosattrib
.version
= 3;
367 dosattrib
.info
.info3
.valid_flags
= XATTR_DOSINFO_ATTRIB
|
368 XATTR_DOSINFO_CREATE_TIME
;
369 dosattrib
.info
.info3
.attrib
= dosmode
;
370 unix_timespec_to_nt_time(&dosattrib
.info
.info3
.create_time
,
371 smb_fname
->st
.st_ex_btime
);
373 DEBUG(10,("set_ea_dos_attributes: set attribute 0x%x, btime = %s on file %s\n",
374 (unsigned int)dosmode
,
375 time_to_asc(convert_timespec_to_time_t(smb_fname
->st
.st_ex_btime
)),
376 smb_fname_str_dbg(smb_fname
) ));
378 ndr_err
= ndr_push_struct_blob(
379 &blob
, talloc_tos(), &dosattrib
,
380 (ndr_push_flags_fn_t
)ndr_push_xattr_DOSATTRIB
);
382 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
383 DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n",
384 ndr_errstr(ndr_err
)));
388 if (blob
.data
== NULL
|| blob
.length
== 0) {
392 if (SMB_VFS_SETXATTR(conn
, smb_fname
->base_name
,
393 SAMBA_XATTR_DOS_ATTRIB
, blob
.data
, blob
.length
,
396 files_struct
*fsp
= NULL
;
398 if((errno
!= EPERM
) && (errno
!= EACCES
)) {
401 || errno
== ENOTSUP
) {
405 DEBUG(1,("set_ea_dos_attributes: Cannot set "
406 "attribute EA on file %s: Error = %s\n",
407 smb_fname_str_dbg(smb_fname
),
409 set_store_dos_attributes(SNUM(conn
), False
);
414 /* We want DOS semantics, ie allow non owner with write permission to change the
415 bits on a file. Just like file_ntimes below.
418 /* Check if we have write access. */
419 if(!CAN_WRITE(conn
) || !lp_dos_filemode(SNUM(conn
)))
422 if (!can_write_to_file(conn
, smb_fname
)) {
427 * We need to open the file with write access whilst
428 * still in our current user context. This ensures we
429 * are not violating security in doing the setxattr.
432 if (!NT_STATUS_IS_OK(open_file_fchmod(conn
, smb_fname
,
436 if (SMB_VFS_FSETXATTR(fsp
,
437 SAMBA_XATTR_DOS_ATTRIB
, blob
.data
,
438 blob
.length
, 0) == 0) {
442 close_file(NULL
, fsp
, NORMAL_CLOSE
);
445 DEBUG(10,("set_ea_dos_attribute: set EA 0x%x on file %s\n",
446 (unsigned int)dosmode
,
447 smb_fname_str_dbg(smb_fname
)));
451 /****************************************************************************
452 Change a unix mode to a dos mode for an ms dfs link.
453 ****************************************************************************/
455 uint32
dos_mode_msdfs(connection_struct
*conn
,
456 const struct smb_filename
*smb_fname
)
460 DEBUG(8,("dos_mode_msdfs: %s\n", smb_fname_str_dbg(smb_fname
)));
462 if (!VALID_STAT(smb_fname
->st
)) {
466 /* First do any modifications that depend on the path name. */
467 /* hide files with a name starting with a . */
468 if (lp_hide_dot_files(SNUM(conn
))) {
469 const char *p
= strrchr_m(smb_fname
->base_name
, '/');
473 p
= smb_fname
->base_name
;
476 /* Only . and .. are not hidden. */
477 if (p
[0] == '.' && !((p
[1] == '\0') ||
478 (p
[1] == '.' && p
[2] == '\0'))) {
479 result
|= FILE_ATTRIBUTE_HIDDEN
;
483 result
|= dos_mode_from_sbuf(conn
, smb_fname
);
485 /* Optimization : Only call is_hidden_path if it's not already
487 if (!(result
& FILE_ATTRIBUTE_HIDDEN
) &&
488 IS_HIDDEN_PATH(conn
, smb_fname
->base_name
)) {
489 result
|= FILE_ATTRIBUTE_HIDDEN
;
493 result
= FILE_ATTRIBUTE_NORMAL
;
496 result
= filter_mode_by_protocol(result
);
499 * Add in that it is a reparse point
501 result
|= FILE_ATTRIBUTE_REPARSE_POINT
;
503 DEBUG(8,("dos_mode_msdfs returning "));
505 if (result
& FILE_ATTRIBUTE_HIDDEN
) DEBUG(8, ("h"));
506 if (result
& FILE_ATTRIBUTE_READONLY
) DEBUG(8, ("r"));
507 if (result
& FILE_ATTRIBUTE_SYSTEM
) DEBUG(8, ("s"));
508 if (result
& FILE_ATTRIBUTE_DIRECTORY
) DEBUG(8, ("d"));
509 if (result
& FILE_ATTRIBUTE_ARCHIVE
) DEBUG(8, ("a"));
510 if (result
& FILE_ATTRIBUTE_SPARSE
) DEBUG(8, ("[sparse]"));
517 #ifdef HAVE_STAT_DOS_FLAGS
518 /****************************************************************************
519 Convert dos attributes (FILE_ATTRIBUTE_*) to dos stat flags (UF_*)
520 ****************************************************************************/
522 int dos_attributes_to_stat_dos_flags(uint32_t dosmode
)
524 uint32_t dos_stat_flags
= 0;
526 if (dosmode
& FILE_ATTRIBUTE_ARCHIVE
)
527 dos_stat_flags
|= UF_DOS_ARCHIVE
;
528 if (dosmode
& FILE_ATTRIBUTE_HIDDEN
)
529 dos_stat_flags
|= UF_DOS_HIDDEN
;
530 if (dosmode
& FILE_ATTRIBUTE_READONLY
)
531 dos_stat_flags
|= UF_DOS_RO
;
532 if (dosmode
& FILE_ATTRIBUTE_SYSTEM
)
533 dos_stat_flags
|= UF_DOS_SYSTEM
;
534 if (dosmode
& FILE_ATTRIBUTE_NONINDEXED
)
535 dos_stat_flags
|= UF_DOS_NOINDEX
;
537 return dos_stat_flags
;
540 /****************************************************************************
541 Gets DOS attributes, accessed via st_ex_flags in the stat struct.
542 ****************************************************************************/
544 static bool get_stat_dos_flags(connection_struct
*conn
,
545 const struct smb_filename
*smb_fname
,
548 SMB_ASSERT(VALID_STAT(smb_fname
->st
));
551 if (!lp_store_dos_attributes(SNUM(conn
))) {
555 DEBUG(5, ("Getting stat dos attributes for %s.\n",
556 smb_fname_str_dbg(smb_fname
)));
558 if (smb_fname
->st
.st_ex_flags
& UF_DOS_ARCHIVE
)
559 *dosmode
|= FILE_ATTRIBUTE_ARCHIVE
;
560 if (smb_fname
->st
.st_ex_flags
& UF_DOS_HIDDEN
)
561 *dosmode
|= FILE_ATTRIBUTE_HIDDEN
;
562 if (smb_fname
->st
.st_ex_flags
& UF_DOS_RO
)
563 *dosmode
|= FILE_ATTRIBUTE_READONLY
;
564 if (smb_fname
->st
.st_ex_flags
& UF_DOS_SYSTEM
)
565 *dosmode
|= FILE_ATTRIBUTE_SYSTEM
;
566 if (smb_fname
->st
.st_ex_flags
& UF_DOS_NOINDEX
)
567 *dosmode
|= FILE_ATTRIBUTE_NONINDEXED
;
568 if (smb_fname
->st
.st_ex_flags
& FILE_ATTRIBUTE_SPARSE
)
569 *dosmode
|= FILE_ATTRIBUTE_SPARSE
;
570 if (S_ISDIR(smb_fname
->st
.st_ex_mode
))
571 *dosmode
|= FILE_ATTRIBUTE_DIRECTORY
;
573 *dosmode
|= set_link_read_only_flag(&smb_fname
->st
);
578 /****************************************************************************
579 Sets DOS attributes, stored in st_ex_flags of the inode.
580 ****************************************************************************/
582 static bool set_stat_dos_flags(connection_struct
*conn
,
583 const struct smb_filename
*smb_fname
,
585 bool *attributes_changed
)
587 uint32_t new_flags
= 0;
590 SMB_ASSERT(VALID_STAT(smb_fname
->st
));
591 SMB_ASSERT(attributes_changed
);
593 *attributes_changed
= false;
595 if (!lp_store_dos_attributes(SNUM(conn
))) {
599 DEBUG(5, ("Setting stat dos attributes for %s.\n",
600 smb_fname_str_dbg(smb_fname
)));
602 new_flags
= (smb_fname
->st
.st_ex_flags
& ~UF_DOS_FLAGS
) |
603 dos_attributes_to_stat_dos_flags(dosmode
);
605 /* Return early if no flags changed. */
606 if (new_flags
== smb_fname
->st
.st_ex_flags
)
609 DEBUG(5, ("Setting stat dos attributes=0x%x, prev=0x%x\n", new_flags
,
610 smb_fname
->st
.st_ex_flags
));
612 /* Set new flags with chflags. */
613 error
= SMB_VFS_CHFLAGS(conn
, smb_fname
->base_name
, new_flags
);
615 DEBUG(0, ("Failed setting new stat dos attributes (0x%x) on "
616 "file %s! errno=%d\n", new_flags
,
617 smb_fname_str_dbg(smb_fname
), errno
));
621 *attributes_changed
= true;
624 #endif /* HAVE_STAT_DOS_FLAGS */
626 /****************************************************************************
627 Change a unix mode to a dos mode.
628 May also read the create timespec into the stat struct in smb_fname
629 if "store dos attributes" is true.
630 ****************************************************************************/
632 uint32
dos_mode(connection_struct
*conn
, struct smb_filename
*smb_fname
)
635 bool offline
, used_stat_dos_flags
= false;
637 DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname
)));
639 if (!VALID_STAT(smb_fname
->st
)) {
643 /* First do any modifications that depend on the path name. */
644 /* hide files with a name starting with a . */
645 if (lp_hide_dot_files(SNUM(conn
))) {
646 const char *p
= strrchr_m(smb_fname
->base_name
,'/');
650 p
= smb_fname
->base_name
;
653 /* Only . and .. are not hidden. */
654 if (p
[0] == '.' && !((p
[1] == '\0') ||
655 (p
[1] == '.' && p
[2] == '\0'))) {
656 result
|= FILE_ATTRIBUTE_HIDDEN
;
660 #ifdef HAVE_STAT_DOS_FLAGS
661 used_stat_dos_flags
= get_stat_dos_flags(conn
, smb_fname
, &result
);
663 if (!used_stat_dos_flags
) {
664 /* Get the DOS attributes from an EA by preference. */
665 if (!get_ea_dos_attribute(conn
, smb_fname
, &result
)) {
666 result
|= dos_mode_from_sbuf(conn
, smb_fname
);
670 offline
= SMB_VFS_IS_OFFLINE(conn
, smb_fname
, &smb_fname
->st
);
671 if (S_ISREG(smb_fname
->st
.st_ex_mode
) && offline
) {
672 result
|= FILE_ATTRIBUTE_OFFLINE
;
675 /* Optimization : Only call is_hidden_path if it's not already
677 if (!(result
& FILE_ATTRIBUTE_HIDDEN
) &&
678 IS_HIDDEN_PATH(conn
, smb_fname
->base_name
)) {
679 result
|= FILE_ATTRIBUTE_HIDDEN
;
683 result
= FILE_ATTRIBUTE_NORMAL
;
686 result
= filter_mode_by_protocol(result
);
688 DEBUG(8,("dos_mode returning "));
690 if (result
& FILE_ATTRIBUTE_HIDDEN
) DEBUG(8, ("h"));
691 if (result
& FILE_ATTRIBUTE_READONLY
) DEBUG(8, ("r"));
692 if (result
& FILE_ATTRIBUTE_SYSTEM
) DEBUG(8, ("s"));
693 if (result
& FILE_ATTRIBUTE_DIRECTORY
) DEBUG(8, ("d"));
694 if (result
& FILE_ATTRIBUTE_ARCHIVE
) DEBUG(8, ("a"));
695 if (result
& FILE_ATTRIBUTE_SPARSE
) DEBUG(8, ("[sparse]"));
702 /*******************************************************************
703 chmod a file - but preserve some bits.
704 If "store dos attributes" is also set it will store the create time
705 from the stat struct in smb_fname (in NTTIME format) in the EA
707 ********************************************************************/
709 int file_set_dosmode(connection_struct
*conn
, struct smb_filename
*smb_fname
,
710 uint32 dosmode
, const char *parent_dir
, bool newfile
)
715 int ret
= -1, lret
= -1;
717 struct timespec new_create_timespec
;
718 files_struct
*fsp
= NULL
;
720 if (!CAN_WRITE(conn
)) {
725 /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
726 dosmode
&= (SAMBA_ATTRIBUTES_MASK
| FILE_ATTRIBUTE_OFFLINE
);
728 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
729 dosmode
, smb_fname_str_dbg(smb_fname
)));
731 unixmode
= smb_fname
->st
.st_ex_mode
;
733 get_acl_group_bits(conn
, smb_fname
->base_name
,
734 &smb_fname
->st
.st_ex_mode
);
736 if (S_ISDIR(smb_fname
->st
.st_ex_mode
))
737 dosmode
|= FILE_ATTRIBUTE_DIRECTORY
;
739 dosmode
&= ~FILE_ATTRIBUTE_DIRECTORY
;
741 new_create_timespec
= smb_fname
->st
.st_ex_btime
;
743 old_mode
= dos_mode(conn
, smb_fname
);
745 if (dosmode
& FILE_ATTRIBUTE_OFFLINE
) {
746 if (!(old_mode
& FILE_ATTRIBUTE_OFFLINE
)) {
747 lret
= SMB_VFS_SET_OFFLINE(conn
, smb_fname
);
749 DEBUG(0, ("set_dos_mode: client has asked to "
750 "set FILE_ATTRIBUTE_OFFLINE to "
751 "%s/%s but there was an error while "
752 "setting it or it is not "
753 "supported.\n", parent_dir
,
754 smb_fname_str_dbg(smb_fname
)));
759 dosmode
&= ~FILE_ATTRIBUTE_OFFLINE
;
760 old_mode
&= ~FILE_ATTRIBUTE_OFFLINE
;
762 smb_fname
->st
.st_ex_btime
= new_create_timespec
;
764 #ifdef HAVE_STAT_DOS_FLAGS
766 bool attributes_changed
;
768 if (set_stat_dos_flags(conn
, smb_fname
, dosmode
,
769 &attributes_changed
))
771 if (!newfile
&& attributes_changed
) {
772 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
773 FILE_NOTIFY_CHANGE_ATTRIBUTES
,
774 smb_fname
->base_name
);
776 smb_fname
->st
.st_ex_mode
= unixmode
;
781 /* Store the DOS attributes in an EA by preference. */
782 if (set_ea_dos_attribute(conn
, smb_fname
, dosmode
)) {
784 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
785 FILE_NOTIFY_CHANGE_ATTRIBUTES
,
786 smb_fname
->base_name
);
788 smb_fname
->st
.st_ex_mode
= unixmode
;
792 unixmode
= unix_mode(conn
, dosmode
, smb_fname
, parent_dir
);
794 /* preserve the s bits */
795 mask
|= (S_ISUID
| S_ISGID
);
797 /* preserve the t bit */
802 /* possibly preserve the x bits */
803 if (!MAP_ARCHIVE(conn
))
805 if (!MAP_SYSTEM(conn
))
807 if (!MAP_HIDDEN(conn
))
810 unixmode
|= (smb_fname
->st
.st_ex_mode
& mask
);
812 /* if we previously had any r bits set then leave them alone */
813 if ((tmp
= smb_fname
->st
.st_ex_mode
& (S_IRUSR
|S_IRGRP
|S_IROTH
))) {
814 unixmode
&= ~(S_IRUSR
|S_IRGRP
|S_IROTH
);
818 /* if we previously had any w bits set then leave them alone
819 whilst adding in the new w bits, if the new mode is not rdonly */
820 if (!IS_DOS_READONLY(dosmode
)) {
821 unixmode
|= (smb_fname
->st
.st_ex_mode
& (S_IWUSR
|S_IWGRP
|S_IWOTH
));
825 * From the chmod 2 man page:
827 * "If the calling process is not privileged, and the group of the file
828 * does not match the effective group ID of the process or one of its
829 * supplementary group IDs, the S_ISGID bit will be turned off, but
830 * this will not cause an error to be returned."
832 * Simply refuse to do the chmod in this case.
835 if (S_ISDIR(smb_fname
->st
.st_ex_mode
) && (unixmode
& S_ISGID
) &&
836 geteuid() != sec_initial_uid() &&
837 !current_user_in_group(conn
, smb_fname
->st
.st_ex_gid
)) {
838 DEBUG(3,("file_set_dosmode: setgid bit cannot be "
839 "set for directory %s\n",
840 smb_fname_str_dbg(smb_fname
)));
845 ret
= SMB_VFS_CHMOD(conn
, smb_fname
->base_name
, unixmode
);
847 if(!newfile
|| (lret
!= -1)) {
848 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
849 FILE_NOTIFY_CHANGE_ATTRIBUTES
,
850 smb_fname
->base_name
);
852 smb_fname
->st
.st_ex_mode
= unixmode
;
856 if((errno
!= EPERM
) && (errno
!= EACCES
))
859 if(!lp_dos_filemode(SNUM(conn
)))
862 /* We want DOS semantics, ie allow non owner with write permission to change the
863 bits on a file. Just like file_ntimes below.
866 if (!can_write_to_file(conn
, smb_fname
)) {
872 * We need to open the file with write access whilst
873 * still in our current user context. This ensures we
874 * are not violating security in doing the fchmod.
876 if (!NT_STATUS_IS_OK(open_file_fchmod(conn
, smb_fname
,
880 ret
= SMB_VFS_FCHMOD(fsp
, unixmode
);
882 close_file(NULL
, fsp
, NORMAL_CLOSE
);
884 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
885 FILE_NOTIFY_CHANGE_ATTRIBUTES
,
886 smb_fname
->base_name
);
889 smb_fname
->st
.st_ex_mode
= unixmode
;
896 NTSTATUS
file_set_sparse(connection_struct
*conn
,
900 uint32_t old_dosmode
;
901 uint32_t new_dosmode
;
904 if (!CAN_WRITE(conn
)) {
905 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
906 "on readonly share[%s]\n",
907 smb_fname_str_dbg(fsp
->fsp_name
),
909 lp_servicename(talloc_tos(), SNUM(conn
))));
910 return NT_STATUS_MEDIA_WRITE_PROTECTED
;
913 if (!(fsp
->access_mask
& FILE_WRITE_DATA
) &&
914 !(fsp
->access_mask
& FILE_WRITE_ATTRIBUTES
)) {
915 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
916 "access_mask[0x%08X] - access denied\n",
917 smb_fname_str_dbg(fsp
->fsp_name
),
920 return NT_STATUS_ACCESS_DENIED
;
923 DEBUG(10,("file_set_sparse: setting sparse bit %u on file %s\n",
924 sparse
, smb_fname_str_dbg(fsp
->fsp_name
)));
926 if (!lp_store_dos_attributes(SNUM(conn
))) {
927 return NT_STATUS_INVALID_DEVICE_REQUEST
;
930 status
= vfs_stat_fsp(fsp
);
931 if (!NT_STATUS_IS_OK(status
)) {
935 old_dosmode
= dos_mode(conn
, fsp
->fsp_name
);
937 if (sparse
&& !(old_dosmode
& FILE_ATTRIBUTE_SPARSE
)) {
938 new_dosmode
= old_dosmode
| FILE_ATTRIBUTE_SPARSE
;
939 } else if (!sparse
&& (old_dosmode
& FILE_ATTRIBUTE_SPARSE
)) {
940 new_dosmode
= old_dosmode
& ~FILE_ATTRIBUTE_SPARSE
;
945 /* Store the DOS attributes in an EA. */
946 if (!set_ea_dos_attribute(conn
, fsp
->fsp_name
,
951 return map_nt_error_from_unix(errno
);
954 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
955 FILE_NOTIFY_CHANGE_ATTRIBUTES
,
956 fsp
->fsp_name
->base_name
);
958 fsp
->is_sparse
= sparse
;
963 /*******************************************************************
964 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
966 *******************************************************************/
968 int file_ntimes(connection_struct
*conn
, const struct smb_filename
*smb_fname
,
969 struct smb_file_time
*ft
)
975 DEBUG(6, ("file_ntime: actime: %s",
976 time_to_asc(convert_timespec_to_time_t(ft
->atime
))));
977 DEBUG(6, ("file_ntime: modtime: %s",
978 time_to_asc(convert_timespec_to_time_t(ft
->mtime
))));
979 DEBUG(6, ("file_ntime: ctime: %s",
980 time_to_asc(convert_timespec_to_time_t(ft
->ctime
))));
981 DEBUG(6, ("file_ntime: createtime: %s",
982 time_to_asc(convert_timespec_to_time_t(ft
->create_time
))));
984 /* Don't update the time on read-only shares */
985 /* We need this as set_filetime (which can be called on
986 close and other paths) can end up calling this function
987 without the NEED_WRITE protection. Found by :
988 Leo Weppelman <leo@wau.mis.ah.nl>
991 if (!CAN_WRITE(conn
)) {
995 if(SMB_VFS_NTIMES(conn
, smb_fname
, ft
) == 0) {
999 if((errno
!= EPERM
) && (errno
!= EACCES
)) {
1003 if(!lp_dos_filetimes(SNUM(conn
))) {
1007 /* We have permission (given by the Samba admin) to
1008 break POSIX semantics and allow a user to change
1009 the time on a file they don't own but can write to
1013 /* Check if we have write access. */
1014 if (can_write_to_file(conn
, smb_fname
)) {
1015 /* We are allowed to become root and change the filetime. */
1017 ret
= SMB_VFS_NTIMES(conn
, smb_fname
, ft
);
1024 /******************************************************************
1025 Force a "sticky" write time on a pathname. This will always be
1026 returned on all future write time queries and set on close.
1027 ******************************************************************/
1029 bool set_sticky_write_time_path(struct file_id fileid
, struct timespec mtime
)
1031 if (null_timespec(mtime
)) {
1035 if (!set_sticky_write_time(fileid
, mtime
)) {
1042 /******************************************************************
1043 Force a "sticky" write time on an fsp. This will always be
1044 returned on all future write time queries and set on close.
1045 ******************************************************************/
1047 bool set_sticky_write_time_fsp(struct files_struct
*fsp
, struct timespec mtime
)
1049 if (null_timespec(mtime
)) {
1053 fsp
->write_time_forced
= true;
1054 TALLOC_FREE(fsp
->update_write_time_event
);
1056 return set_sticky_write_time_path(fsp
->file_id
, mtime
);
1059 /******************************************************************
1060 Set a create time EA.
1061 ******************************************************************/
1063 NTSTATUS
set_create_timespec_ea(connection_struct
*conn
,
1064 const struct smb_filename
*psmb_fname
,
1065 struct timespec create_time
)
1068 struct smb_filename
*smb_fname
= NULL
;
1072 if (!lp_store_dos_attributes(SNUM(conn
))) {
1073 return NT_STATUS_OK
;
1076 status
= create_synthetic_smb_fname(talloc_tos(),
1077 psmb_fname
->base_name
,
1078 NULL
, &psmb_fname
->st
,
1081 if (!NT_STATUS_IS_OK(status
)) {
1085 dosmode
= dos_mode(conn
, smb_fname
);
1087 smb_fname
->st
.st_ex_btime
= create_time
;
1089 ret
= file_set_dosmode(conn
, smb_fname
, dosmode
, NULL
, false);
1091 map_nt_error_from_unix(errno
);
1094 DEBUG(10,("set_create_timespec_ea: wrote create time EA for file %s\n",
1095 smb_fname_str_dbg(smb_fname
)));
1097 return NT_STATUS_OK
;
1100 /******************************************************************
1101 Return a create time.
1102 ******************************************************************/
1104 struct timespec
get_create_timespec(connection_struct
*conn
,
1105 struct files_struct
*fsp
,
1106 const struct smb_filename
*smb_fname
)
1108 return smb_fname
->st
.st_ex_btime
;
1111 /******************************************************************
1112 Return a change time (may look at EA in future).
1113 ******************************************************************/
1115 struct timespec
get_change_timespec(connection_struct
*conn
,
1116 struct files_struct
*fsp
,
1117 const struct smb_filename
*smb_fname
)
1119 return smb_fname
->st
.st_ex_mtime
;