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
);
498 DEBUG(8,("dos_mode_msdfs returning "));
500 if (result
& FILE_ATTRIBUTE_HIDDEN
) DEBUG(8, ("h"));
501 if (result
& FILE_ATTRIBUTE_READONLY
) DEBUG(8, ("r"));
502 if (result
& FILE_ATTRIBUTE_SYSTEM
) DEBUG(8, ("s"));
503 if (result
& FILE_ATTRIBUTE_DIRECTORY
) DEBUG(8, ("d"));
504 if (result
& FILE_ATTRIBUTE_ARCHIVE
) DEBUG(8, ("a"));
505 if (result
& FILE_ATTRIBUTE_SPARSE
) DEBUG(8, ("[sparse]"));
512 #ifdef HAVE_STAT_DOS_FLAGS
513 /****************************************************************************
514 Convert dos attributes (FILE_ATTRIBUTE_*) to dos stat flags (UF_*)
515 ****************************************************************************/
517 int dos_attributes_to_stat_dos_flags(uint32_t dosmode
)
519 uint32_t dos_stat_flags
= 0;
521 if (dosmode
& FILE_ATTRIBUTE_ARCHIVE
)
522 dos_stat_flags
|= UF_DOS_ARCHIVE
;
523 if (dosmode
& FILE_ATTRIBUTE_HIDDEN
)
524 dos_stat_flags
|= UF_DOS_HIDDEN
;
525 if (dosmode
& FILE_ATTRIBUTE_READONLY
)
526 dos_stat_flags
|= UF_DOS_RO
;
527 if (dosmode
& FILE_ATTRIBUTE_SYSTEM
)
528 dos_stat_flags
|= UF_DOS_SYSTEM
;
529 if (dosmode
& FILE_ATTRIBUTE_NONINDEXED
)
530 dos_stat_flags
|= UF_DOS_NOINDEX
;
532 return dos_stat_flags
;
535 /****************************************************************************
536 Gets DOS attributes, accessed via st_ex_flags in the stat struct.
537 ****************************************************************************/
539 static bool get_stat_dos_flags(connection_struct
*conn
,
540 const struct smb_filename
*smb_fname
,
543 SMB_ASSERT(VALID_STAT(smb_fname
->st
));
546 if (!lp_store_dos_attributes(SNUM(conn
))) {
550 DEBUG(5, ("Getting stat dos attributes for %s.\n",
551 smb_fname_str_dbg(smb_fname
)));
553 if (smb_fname
->st
.st_ex_flags
& UF_DOS_ARCHIVE
)
554 *dosmode
|= FILE_ATTRIBUTE_ARCHIVE
;
555 if (smb_fname
->st
.st_ex_flags
& UF_DOS_HIDDEN
)
556 *dosmode
|= FILE_ATTRIBUTE_HIDDEN
;
557 if (smb_fname
->st
.st_ex_flags
& UF_DOS_RO
)
558 *dosmode
|= FILE_ATTRIBUTE_READONLY
;
559 if (smb_fname
->st
.st_ex_flags
& UF_DOS_SYSTEM
)
560 *dosmode
|= FILE_ATTRIBUTE_SYSTEM
;
561 if (smb_fname
->st
.st_ex_flags
& UF_DOS_NOINDEX
)
562 *dosmode
|= FILE_ATTRIBUTE_NONINDEXED
;
563 if (smb_fname
->st
.st_ex_flags
& FILE_ATTRIBUTE_SPARSE
)
564 *dosmode
|= FILE_ATTRIBUTE_SPARSE
;
565 if (S_ISDIR(smb_fname
->st
.st_ex_mode
))
566 *dosmode
|= FILE_ATTRIBUTE_DIRECTORY
;
568 *dosmode
|= set_link_read_only_flag(&smb_fname
->st
);
573 /****************************************************************************
574 Sets DOS attributes, stored in st_ex_flags of the inode.
575 ****************************************************************************/
577 static bool set_stat_dos_flags(connection_struct
*conn
,
578 const struct smb_filename
*smb_fname
,
580 bool *attributes_changed
)
582 uint32_t new_flags
= 0;
585 SMB_ASSERT(VALID_STAT(smb_fname
->st
));
586 SMB_ASSERT(attributes_changed
);
588 *attributes_changed
= false;
590 if (!lp_store_dos_attributes(SNUM(conn
))) {
594 DEBUG(5, ("Setting stat dos attributes for %s.\n",
595 smb_fname_str_dbg(smb_fname
)));
597 new_flags
= (smb_fname
->st
.st_ex_flags
& ~UF_DOS_FLAGS
) |
598 dos_attributes_to_stat_dos_flags(dosmode
);
600 /* Return early if no flags changed. */
601 if (new_flags
== smb_fname
->st
.st_ex_flags
)
604 DEBUG(5, ("Setting stat dos attributes=0x%x, prev=0x%x\n", new_flags
,
605 smb_fname
->st
.st_ex_flags
));
607 /* Set new flags with chflags. */
608 error
= SMB_VFS_CHFLAGS(conn
, smb_fname
->base_name
, new_flags
);
610 DEBUG(0, ("Failed setting new stat dos attributes (0x%x) on "
611 "file %s! errno=%d\n", new_flags
,
612 smb_fname_str_dbg(smb_fname
), errno
));
616 *attributes_changed
= true;
619 #endif /* HAVE_STAT_DOS_FLAGS */
621 /****************************************************************************
622 Change a unix mode to a dos mode.
623 May also read the create timespec into the stat struct in smb_fname
624 if "store dos attributes" is true.
625 ****************************************************************************/
627 uint32
dos_mode(connection_struct
*conn
, struct smb_filename
*smb_fname
)
630 bool offline
, used_stat_dos_flags
= false;
632 DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname
)));
634 if (!VALID_STAT(smb_fname
->st
)) {
638 /* First do any modifications that depend on the path name. */
639 /* hide files with a name starting with a . */
640 if (lp_hide_dot_files(SNUM(conn
))) {
641 const char *p
= strrchr_m(smb_fname
->base_name
,'/');
645 p
= smb_fname
->base_name
;
648 /* Only . and .. are not hidden. */
649 if (p
[0] == '.' && !((p
[1] == '\0') ||
650 (p
[1] == '.' && p
[2] == '\0'))) {
651 result
|= FILE_ATTRIBUTE_HIDDEN
;
655 #ifdef HAVE_STAT_DOS_FLAGS
656 used_stat_dos_flags
= get_stat_dos_flags(conn
, smb_fname
, &result
);
658 if (!used_stat_dos_flags
) {
659 /* Get the DOS attributes from an EA by preference. */
660 if (!get_ea_dos_attribute(conn
, smb_fname
, &result
)) {
661 result
|= dos_mode_from_sbuf(conn
, smb_fname
);
665 offline
= SMB_VFS_IS_OFFLINE(conn
, smb_fname
, &smb_fname
->st
);
666 if (S_ISREG(smb_fname
->st
.st_ex_mode
) && offline
) {
667 result
|= FILE_ATTRIBUTE_OFFLINE
;
670 /* Optimization : Only call is_hidden_path if it's not already
672 if (!(result
& FILE_ATTRIBUTE_HIDDEN
) &&
673 IS_HIDDEN_PATH(conn
, smb_fname
->base_name
)) {
674 result
|= FILE_ATTRIBUTE_HIDDEN
;
678 result
= FILE_ATTRIBUTE_NORMAL
;
681 result
= filter_mode_by_protocol(result
);
683 DEBUG(8,("dos_mode returning "));
685 if (result
& FILE_ATTRIBUTE_HIDDEN
) DEBUG(8, ("h"));
686 if (result
& FILE_ATTRIBUTE_READONLY
) DEBUG(8, ("r"));
687 if (result
& FILE_ATTRIBUTE_SYSTEM
) DEBUG(8, ("s"));
688 if (result
& FILE_ATTRIBUTE_DIRECTORY
) DEBUG(8, ("d"));
689 if (result
& FILE_ATTRIBUTE_ARCHIVE
) DEBUG(8, ("a"));
690 if (result
& FILE_ATTRIBUTE_SPARSE
) DEBUG(8, ("[sparse]"));
697 /*******************************************************************
698 chmod a file - but preserve some bits.
699 If "store dos attributes" is also set it will store the create time
700 from the stat struct in smb_fname (in NTTIME format) in the EA
702 ********************************************************************/
704 int file_set_dosmode(connection_struct
*conn
, struct smb_filename
*smb_fname
,
705 uint32 dosmode
, const char *parent_dir
, bool newfile
)
710 int ret
= -1, lret
= -1;
712 struct timespec new_create_timespec
;
713 files_struct
*fsp
= NULL
;
715 if (!CAN_WRITE(conn
)) {
720 /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
721 dosmode
&= (SAMBA_ATTRIBUTES_MASK
| FILE_ATTRIBUTE_OFFLINE
);
723 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
724 dosmode
, smb_fname_str_dbg(smb_fname
)));
726 unixmode
= smb_fname
->st
.st_ex_mode
;
728 get_acl_group_bits(conn
, smb_fname
->base_name
,
729 &smb_fname
->st
.st_ex_mode
);
731 if (S_ISDIR(smb_fname
->st
.st_ex_mode
))
732 dosmode
|= FILE_ATTRIBUTE_DIRECTORY
;
734 dosmode
&= ~FILE_ATTRIBUTE_DIRECTORY
;
736 new_create_timespec
= smb_fname
->st
.st_ex_btime
;
738 old_mode
= dos_mode(conn
, smb_fname
);
740 if (dosmode
& FILE_ATTRIBUTE_OFFLINE
) {
741 if (!(old_mode
& FILE_ATTRIBUTE_OFFLINE
)) {
742 lret
= SMB_VFS_SET_OFFLINE(conn
, smb_fname
);
744 DEBUG(0, ("set_dos_mode: client has asked to "
745 "set FILE_ATTRIBUTE_OFFLINE to "
746 "%s/%s but there was an error while "
747 "setting it or it is not "
748 "supported.\n", parent_dir
,
749 smb_fname_str_dbg(smb_fname
)));
754 dosmode
&= ~FILE_ATTRIBUTE_OFFLINE
;
755 old_mode
&= ~FILE_ATTRIBUTE_OFFLINE
;
757 smb_fname
->st
.st_ex_btime
= new_create_timespec
;
759 #ifdef HAVE_STAT_DOS_FLAGS
761 bool attributes_changed
;
763 if (set_stat_dos_flags(conn
, smb_fname
, dosmode
,
764 &attributes_changed
))
766 if (!newfile
&& attributes_changed
) {
767 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
768 FILE_NOTIFY_CHANGE_ATTRIBUTES
,
769 smb_fname
->base_name
);
771 smb_fname
->st
.st_ex_mode
= unixmode
;
776 /* Store the DOS attributes in an EA by preference. */
777 if (set_ea_dos_attribute(conn
, smb_fname
, dosmode
)) {
779 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
780 FILE_NOTIFY_CHANGE_ATTRIBUTES
,
781 smb_fname
->base_name
);
783 smb_fname
->st
.st_ex_mode
= unixmode
;
787 unixmode
= unix_mode(conn
, dosmode
, smb_fname
, parent_dir
);
789 /* preserve the s bits */
790 mask
|= (S_ISUID
| S_ISGID
);
792 /* preserve the t bit */
797 /* possibly preserve the x bits */
798 if (!MAP_ARCHIVE(conn
))
800 if (!MAP_SYSTEM(conn
))
802 if (!MAP_HIDDEN(conn
))
805 unixmode
|= (smb_fname
->st
.st_ex_mode
& mask
);
807 /* if we previously had any r bits set then leave them alone */
808 if ((tmp
= smb_fname
->st
.st_ex_mode
& (S_IRUSR
|S_IRGRP
|S_IROTH
))) {
809 unixmode
&= ~(S_IRUSR
|S_IRGRP
|S_IROTH
);
813 /* if we previously had any w bits set then leave them alone
814 whilst adding in the new w bits, if the new mode is not rdonly */
815 if (!IS_DOS_READONLY(dosmode
)) {
816 unixmode
|= (smb_fname
->st
.st_ex_mode
& (S_IWUSR
|S_IWGRP
|S_IWOTH
));
820 * From the chmod 2 man page:
822 * "If the calling process is not privileged, and the group of the file
823 * does not match the effective group ID of the process or one of its
824 * supplementary group IDs, the S_ISGID bit will be turned off, but
825 * this will not cause an error to be returned."
827 * Simply refuse to do the chmod in this case.
830 if (S_ISDIR(smb_fname
->st
.st_ex_mode
) && (unixmode
& S_ISGID
) &&
831 geteuid() != sec_initial_uid() &&
832 !current_user_in_group(conn
, smb_fname
->st
.st_ex_gid
)) {
833 DEBUG(3,("file_set_dosmode: setgid bit cannot be "
834 "set for directory %s\n",
835 smb_fname_str_dbg(smb_fname
)));
840 ret
= SMB_VFS_CHMOD(conn
, smb_fname
->base_name
, unixmode
);
842 if(!newfile
|| (lret
!= -1)) {
843 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
844 FILE_NOTIFY_CHANGE_ATTRIBUTES
,
845 smb_fname
->base_name
);
847 smb_fname
->st
.st_ex_mode
= unixmode
;
851 if((errno
!= EPERM
) && (errno
!= EACCES
))
854 if(!lp_dos_filemode(SNUM(conn
)))
857 /* We want DOS semantics, ie allow non owner with write permission to change the
858 bits on a file. Just like file_ntimes below.
861 if (!can_write_to_file(conn
, smb_fname
)) {
867 * We need to open the file with write access whilst
868 * still in our current user context. This ensures we
869 * are not violating security in doing the fchmod.
871 if (!NT_STATUS_IS_OK(open_file_fchmod(conn
, smb_fname
,
875 ret
= SMB_VFS_FCHMOD(fsp
, unixmode
);
877 close_file(NULL
, fsp
, NORMAL_CLOSE
);
879 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
880 FILE_NOTIFY_CHANGE_ATTRIBUTES
,
881 smb_fname
->base_name
);
884 smb_fname
->st
.st_ex_mode
= unixmode
;
891 NTSTATUS
file_set_sparse(connection_struct
*conn
,
895 uint32_t old_dosmode
;
896 uint32_t new_dosmode
;
899 if (!CAN_WRITE(conn
)) {
900 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
901 "on readonly share[%s]\n",
902 smb_fname_str_dbg(fsp
->fsp_name
),
904 lp_servicename(talloc_tos(), SNUM(conn
))));
905 return NT_STATUS_MEDIA_WRITE_PROTECTED
;
908 if (!(fsp
->access_mask
& FILE_WRITE_DATA
) &&
909 !(fsp
->access_mask
& FILE_WRITE_ATTRIBUTES
)) {
910 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
911 "access_mask[0x%08X] - access denied\n",
912 smb_fname_str_dbg(fsp
->fsp_name
),
915 return NT_STATUS_ACCESS_DENIED
;
918 DEBUG(10,("file_set_sparse: setting sparse bit %u on file %s\n",
919 sparse
, smb_fname_str_dbg(fsp
->fsp_name
)));
921 if (!lp_store_dos_attributes(SNUM(conn
))) {
922 return NT_STATUS_INVALID_DEVICE_REQUEST
;
925 status
= vfs_stat_fsp(fsp
);
926 if (!NT_STATUS_IS_OK(status
)) {
930 old_dosmode
= dos_mode(conn
, fsp
->fsp_name
);
932 if (sparse
&& !(old_dosmode
& FILE_ATTRIBUTE_SPARSE
)) {
933 new_dosmode
= old_dosmode
| FILE_ATTRIBUTE_SPARSE
;
934 } else if (!sparse
&& (old_dosmode
& FILE_ATTRIBUTE_SPARSE
)) {
935 new_dosmode
= old_dosmode
& ~FILE_ATTRIBUTE_SPARSE
;
940 /* Store the DOS attributes in an EA. */
941 if (!set_ea_dos_attribute(conn
, fsp
->fsp_name
,
946 return map_nt_error_from_unix(errno
);
949 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
950 FILE_NOTIFY_CHANGE_ATTRIBUTES
,
951 fsp
->fsp_name
->base_name
);
953 fsp
->is_sparse
= sparse
;
958 /*******************************************************************
959 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
961 *******************************************************************/
963 int file_ntimes(connection_struct
*conn
, const struct smb_filename
*smb_fname
,
964 struct smb_file_time
*ft
)
970 DEBUG(6, ("file_ntime: actime: %s",
971 time_to_asc(convert_timespec_to_time_t(ft
->atime
))));
972 DEBUG(6, ("file_ntime: modtime: %s",
973 time_to_asc(convert_timespec_to_time_t(ft
->mtime
))));
974 DEBUG(6, ("file_ntime: ctime: %s",
975 time_to_asc(convert_timespec_to_time_t(ft
->ctime
))));
976 DEBUG(6, ("file_ntime: createtime: %s",
977 time_to_asc(convert_timespec_to_time_t(ft
->create_time
))));
979 /* Don't update the time on read-only shares */
980 /* We need this as set_filetime (which can be called on
981 close and other paths) can end up calling this function
982 without the NEED_WRITE protection. Found by :
983 Leo Weppelman <leo@wau.mis.ah.nl>
986 if (!CAN_WRITE(conn
)) {
990 if(SMB_VFS_NTIMES(conn
, smb_fname
, ft
) == 0) {
994 if((errno
!= EPERM
) && (errno
!= EACCES
)) {
998 if(!lp_dos_filetimes(SNUM(conn
))) {
1002 /* We have permission (given by the Samba admin) to
1003 break POSIX semantics and allow a user to change
1004 the time on a file they don't own but can write to
1008 /* Check if we have write access. */
1009 if (can_write_to_file(conn
, smb_fname
)) {
1010 /* We are allowed to become root and change the filetime. */
1012 ret
= SMB_VFS_NTIMES(conn
, smb_fname
, ft
);
1019 /******************************************************************
1020 Force a "sticky" write time on a pathname. This will always be
1021 returned on all future write time queries and set on close.
1022 ******************************************************************/
1024 bool set_sticky_write_time_path(struct file_id fileid
, struct timespec mtime
)
1026 if (null_timespec(mtime
)) {
1030 if (!set_sticky_write_time(fileid
, mtime
)) {
1037 /******************************************************************
1038 Force a "sticky" write time on an fsp. This will always be
1039 returned on all future write time queries and set on close.
1040 ******************************************************************/
1042 bool set_sticky_write_time_fsp(struct files_struct
*fsp
, struct timespec mtime
)
1044 if (null_timespec(mtime
)) {
1048 fsp
->write_time_forced
= true;
1049 TALLOC_FREE(fsp
->update_write_time_event
);
1051 return set_sticky_write_time_path(fsp
->file_id
, mtime
);
1054 /******************************************************************
1055 Set a create time EA.
1056 ******************************************************************/
1058 NTSTATUS
set_create_timespec_ea(connection_struct
*conn
,
1059 const struct smb_filename
*psmb_fname
,
1060 struct timespec create_time
)
1063 struct smb_filename
*smb_fname
= NULL
;
1067 if (!lp_store_dos_attributes(SNUM(conn
))) {
1068 return NT_STATUS_OK
;
1071 status
= create_synthetic_smb_fname(talloc_tos(),
1072 psmb_fname
->base_name
,
1073 NULL
, &psmb_fname
->st
,
1076 if (!NT_STATUS_IS_OK(status
)) {
1080 dosmode
= dos_mode(conn
, smb_fname
);
1082 smb_fname
->st
.st_ex_btime
= create_time
;
1084 ret
= file_set_dosmode(conn
, smb_fname
, dosmode
, NULL
, false);
1086 map_nt_error_from_unix(errno
);
1089 DEBUG(10,("set_create_timespec_ea: wrote create time EA for file %s\n",
1090 smb_fname_str_dbg(smb_fname
)));
1092 return NT_STATUS_OK
;
1095 /******************************************************************
1096 Return a create time.
1097 ******************************************************************/
1099 struct timespec
get_create_timespec(connection_struct
*conn
,
1100 struct files_struct
*fsp
,
1101 const struct smb_filename
*smb_fname
)
1103 return smb_fname
->st
.st_ex_btime
;
1106 /******************************************************************
1107 Return a change time (may look at EA in future).
1108 ******************************************************************/
1110 struct timespec
get_change_timespec(connection_struct
*conn
,
1111 struct files_struct
*fsp
,
1112 const struct smb_filename
*smb_fname
)
1114 return smb_fname
->st
.st_ex_mtime
;