2 Unix SMB/CIFS implementation.
3 dos mode handling functions
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) James Peach 2006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "system/filesys.h"
23 #include "librpc/gen_ndr/ndr_xattr.h"
24 #include "librpc/gen_ndr/ioctl.h"
25 #include "../libcli/security/security.h"
26 #include "smbd/smbd.h"
27 #include "lib/param/loadparm.h"
29 static void dos_mode_debug_print(uint32_t mode
)
31 DEBUG(8,("dos_mode returning "));
33 if (mode
& FILE_ATTRIBUTE_HIDDEN
) {
36 if (mode
& FILE_ATTRIBUTE_READONLY
) {
39 if (mode
& FILE_ATTRIBUTE_SYSTEM
) {
42 if (mode
& FILE_ATTRIBUTE_DIRECTORY
) {
45 if (mode
& FILE_ATTRIBUTE_ARCHIVE
) {
48 if (mode
& FILE_ATTRIBUTE_SPARSE
) {
49 DEBUG(8, ("[sparse]"));
51 if (mode
& FILE_ATTRIBUTE_OFFLINE
) {
52 DEBUG(8, ("[offline]"));
54 if (mode
& FILE_ATTRIBUTE_COMPRESSED
) {
55 DEBUG(8, ("[compressed]"));
61 static uint32_t filter_mode_by_protocol(uint32_t mode
)
63 if (get_Protocol() <= PROTOCOL_LANMAN2
) {
64 DEBUG(10,("filter_mode_by_protocol: "
65 "filtering result 0x%x to 0x%x\n",
67 (unsigned int)(mode
& 0x3f) ));
73 static int set_link_read_only_flag(const SMB_STRUCT_STAT
*const sbuf
)
77 if (S_ISLNK(sbuf
->st_mode
) && S_ISDIR(sbuf
->st_mode
))
78 return FILE_ATTRIBUTE_READONLY
;
84 /****************************************************************************
85 Change a dos mode to a unix mode.
86 Base permission for files:
87 if creating file and inheriting (i.e. parent_dir != NULL)
88 apply read/write bits from parent directory.
90 everybody gets read bit set
91 dos readonly is represented in unix by removing everyone's write bit
92 dos archive is represented in unix by the user's execute bit
93 dos system is represented in unix by the group's execute bit
94 dos hidden is represented in unix by the other's execute bit
96 Then apply create mask,
99 Base permission for directories:
100 dos directory is represented in unix by unix's dir bit and the exec bit
102 Then apply create mask,
105 ****************************************************************************/
107 mode_t
unix_mode(connection_struct
*conn
, int dosmode
,
108 const struct smb_filename
*smb_fname
,
109 const char *inherit_from_dir
)
111 mode_t result
= (S_IRUSR
| S_IRGRP
| S_IROTH
| S_IWUSR
| S_IWGRP
| S_IWOTH
);
112 mode_t dir_mode
= 0; /* Mode of the inherit_from directory if
115 if (!lp_store_dos_attributes(SNUM(conn
)) && IS_DOS_READONLY(dosmode
)) {
116 result
&= ~(S_IWUSR
| S_IWGRP
| S_IWOTH
);
119 if ((inherit_from_dir
!= NULL
) && lp_inherit_permissions(SNUM(conn
))) {
120 struct smb_filename
*smb_fname_parent
;
122 DEBUG(2, ("unix_mode(%s) inheriting from %s\n",
123 smb_fname_str_dbg(smb_fname
),
126 smb_fname_parent
= synthetic_smb_fname(
127 talloc_tos(), inherit_from_dir
, NULL
, NULL
);
128 if (smb_fname_parent
== NULL
) {
129 DEBUG(1,("unix_mode(%s) failed, [dir %s]: No memory\n",
130 smb_fname_str_dbg(smb_fname
),
135 if (SMB_VFS_STAT(conn
, smb_fname_parent
) != 0) {
136 DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n",
137 smb_fname_str_dbg(smb_fname
),
138 inherit_from_dir
, strerror(errno
)));
139 TALLOC_FREE(smb_fname_parent
);
140 return(0); /* *** shouldn't happen! *** */
143 /* Save for later - but explicitly remove setuid bit for safety. */
144 dir_mode
= smb_fname_parent
->st
.st_ex_mode
& ~S_ISUID
;
145 DEBUG(2,("unix_mode(%s) inherit mode %o\n",
146 smb_fname_str_dbg(smb_fname
), (int)dir_mode
));
149 TALLOC_FREE(smb_fname_parent
);
152 if (IS_DOS_DIR(dosmode
)) {
153 /* We never make directories read only for the owner as under DOS a user
154 can always create a file in a read-only directory. */
155 result
|= (S_IFDIR
| S_IWUSR
);
158 /* Inherit mode of parent directory. */
161 /* Provisionally add all 'x' bits */
162 result
|= (S_IXUSR
| S_IXGRP
| S_IXOTH
);
164 /* Apply directory mask */
165 result
&= lp_directory_mask(SNUM(conn
));
166 /* Add in force bits */
167 result
|= lp_force_directory_mode(SNUM(conn
));
170 if (lp_map_archive(SNUM(conn
)) && IS_DOS_ARCHIVE(dosmode
))
173 if (lp_map_system(SNUM(conn
)) && IS_DOS_SYSTEM(dosmode
))
176 if (lp_map_hidden(SNUM(conn
)) && IS_DOS_HIDDEN(dosmode
))
180 /* Inherit 666 component of parent directory mode */
181 result
|= dir_mode
& (S_IRUSR
| S_IRGRP
| S_IROTH
| S_IWUSR
| S_IWGRP
| S_IWOTH
);
183 /* Apply mode mask */
184 result
&= lp_create_mask(SNUM(conn
));
185 /* Add in force bits */
186 result
|= lp_force_create_mode(SNUM(conn
));
190 DEBUG(3,("unix_mode(%s) returning 0%o\n", smb_fname_str_dbg(smb_fname
),
195 /****************************************************************************
196 Change a unix mode to a dos mode.
197 ****************************************************************************/
199 static uint32
dos_mode_from_sbuf(connection_struct
*conn
,
200 const struct smb_filename
*smb_fname
)
203 enum mapreadonly_options ro_opts
= (enum mapreadonly_options
)lp_map_readonly(SNUM(conn
));
205 #if defined(UF_IMMUTABLE) && defined(SF_IMMUTABLE)
206 /* if we can find out if a file is immutable we should report it r/o */
207 if (smb_fname
->st
.st_ex_flags
& (UF_IMMUTABLE
| SF_IMMUTABLE
)) {
208 result
|= FILE_ATTRIBUTE_READONLY
;
211 if (ro_opts
== MAP_READONLY_YES
) {
212 /* Original Samba method - map inverse of user "w" bit. */
213 if ((smb_fname
->st
.st_ex_mode
& S_IWUSR
) == 0) {
214 result
|= FILE_ATTRIBUTE_READONLY
;
216 } else if (ro_opts
== MAP_READONLY_PERMISSIONS
) {
217 /* Check actual permissions for read-only. */
218 if (!can_write_to_file(conn
, smb_fname
)) {
219 result
|= FILE_ATTRIBUTE_READONLY
;
221 } /* Else never set the readonly bit. */
223 if (MAP_ARCHIVE(conn
) && ((smb_fname
->st
.st_ex_mode
& S_IXUSR
) != 0))
224 result
|= FILE_ATTRIBUTE_ARCHIVE
;
226 if (MAP_SYSTEM(conn
) && ((smb_fname
->st
.st_ex_mode
& S_IXGRP
) != 0))
227 result
|= FILE_ATTRIBUTE_SYSTEM
;
229 if (MAP_HIDDEN(conn
) && ((smb_fname
->st
.st_ex_mode
& S_IXOTH
) != 0))
230 result
|= FILE_ATTRIBUTE_HIDDEN
;
232 if (S_ISDIR(smb_fname
->st
.st_ex_mode
))
233 result
= FILE_ATTRIBUTE_DIRECTORY
| (result
& FILE_ATTRIBUTE_READONLY
);
235 result
|= set_link_read_only_flag(&smb_fname
->st
);
237 DEBUG(8,("dos_mode_from_sbuf returning "));
239 if (result
& FILE_ATTRIBUTE_HIDDEN
) DEBUG(8, ("h"));
240 if (result
& FILE_ATTRIBUTE_READONLY
) DEBUG(8, ("r"));
241 if (result
& FILE_ATTRIBUTE_SYSTEM
) DEBUG(8, ("s"));
242 if (result
& FILE_ATTRIBUTE_DIRECTORY
) DEBUG(8, ("d"));
243 if (result
& FILE_ATTRIBUTE_ARCHIVE
) DEBUG(8, ("a"));
249 /****************************************************************************
250 Get DOS attributes from an EA.
251 This can also pull the create time into the stat struct inside smb_fname.
252 ****************************************************************************/
254 static bool get_ea_dos_attribute(connection_struct
*conn
,
255 struct smb_filename
*smb_fname
,
258 struct xattr_DOSATTRIB dosattrib
;
259 enum ndr_err_code ndr_err
;
265 if (!lp_store_dos_attributes(SNUM(conn
))) {
269 /* Don't reset pattr to zero as we may already have filename-based attributes we
272 sizeret
= SMB_VFS_GETXATTR(conn
, smb_fname
->base_name
,
273 SAMBA_XATTR_DOS_ATTRIB
, attrstr
,
278 || errno
== ENOTSUP
) {
282 DEBUG(1,("get_ea_dos_attribute: Cannot get attribute "
283 "from EA on file %s: Error = %s\n",
284 smb_fname_str_dbg(smb_fname
),
286 set_store_dos_attributes(SNUM(conn
), False
);
291 blob
.data
= (uint8_t *)attrstr
;
292 blob
.length
= sizeret
;
294 ndr_err
= ndr_pull_struct_blob(&blob
, talloc_tos(), &dosattrib
,
295 (ndr_pull_flags_fn_t
)ndr_pull_xattr_DOSATTRIB
);
297 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
298 DEBUG(1,("get_ea_dos_attribute: bad ndr decode "
299 "from EA on file %s: Error = %s\n",
300 smb_fname_str_dbg(smb_fname
),
301 ndr_errstr(ndr_err
)));
305 DEBUG(10,("get_ea_dos_attribute: %s attr = %s\n",
306 smb_fname_str_dbg(smb_fname
), dosattrib
.attrib_hex
));
308 switch (dosattrib
.version
) {
310 dosattr
= dosattrib
.info
.compatinfoFFFF
.attrib
;
313 dosattr
= dosattrib
.info
.info1
.attrib
;
314 if (!null_nttime(dosattrib
.info
.info1
.create_time
)) {
315 struct timespec create_time
=
316 nt_time_to_unix_timespec(
317 &dosattrib
.info
.info1
.create_time
);
319 update_stat_ex_create_time(&smb_fname
->st
,
322 DEBUG(10,("get_ea_dos_attribute: file %s case 1 "
324 smb_fname_str_dbg(smb_fname
),
325 time_to_asc(convert_timespec_to_time_t(
330 dosattr
= dosattrib
.info
.oldinfo2
.attrib
;
331 /* Don't know what flags to check for this case. */
334 dosattr
= dosattrib
.info
.info3
.attrib
;
335 if ((dosattrib
.info
.info3
.valid_flags
& XATTR_DOSINFO_CREATE_TIME
) &&
336 !null_nttime(dosattrib
.info
.info3
.create_time
)) {
337 struct timespec create_time
=
338 nt_time_to_unix_timespec(
339 &dosattrib
.info
.info3
.create_time
);
341 update_stat_ex_create_time(&smb_fname
->st
,
344 DEBUG(10,("get_ea_dos_attribute: file %s case 3 "
346 smb_fname_str_dbg(smb_fname
),
347 time_to_asc(convert_timespec_to_time_t(
352 DEBUG(1,("get_ea_dos_attribute: Badly formed DOSATTRIB on "
353 "file %s - %s\n", smb_fname_str_dbg(smb_fname
),
358 if (S_ISDIR(smb_fname
->st
.st_ex_mode
)) {
359 dosattr
|= FILE_ATTRIBUTE_DIRECTORY
;
361 /* FILE_ATTRIBUTE_SPARSE is valid on get but not on set. */
362 *pattr
= (uint32
)(dosattr
& (SAMBA_ATTRIBUTES_MASK
|FILE_ATTRIBUTE_SPARSE
));
364 DEBUG(8,("get_ea_dos_attribute returning (0x%x)", dosattr
));
366 if (dosattr
& FILE_ATTRIBUTE_HIDDEN
) DEBUG(8, ("h"));
367 if (dosattr
& FILE_ATTRIBUTE_READONLY
) DEBUG(8, ("r"));
368 if (dosattr
& FILE_ATTRIBUTE_SYSTEM
) DEBUG(8, ("s"));
369 if (dosattr
& FILE_ATTRIBUTE_DIRECTORY
) DEBUG(8, ("d"));
370 if (dosattr
& FILE_ATTRIBUTE_ARCHIVE
) DEBUG(8, ("a"));
377 /****************************************************************************
378 Set DOS attributes in an EA.
379 Also sets the create time.
380 ****************************************************************************/
382 static bool set_ea_dos_attribute(connection_struct
*conn
,
383 struct smb_filename
*smb_fname
,
386 struct xattr_DOSATTRIB dosattrib
;
387 enum ndr_err_code ndr_err
;
390 ZERO_STRUCT(dosattrib
);
393 dosattrib
.version
= 3;
394 dosattrib
.info
.info3
.valid_flags
= XATTR_DOSINFO_ATTRIB
|
395 XATTR_DOSINFO_CREATE_TIME
;
396 dosattrib
.info
.info3
.attrib
= dosmode
;
397 unix_timespec_to_nt_time(&dosattrib
.info
.info3
.create_time
,
398 smb_fname
->st
.st_ex_btime
);
400 DEBUG(10,("set_ea_dos_attributes: set attribute 0x%x, btime = %s on file %s\n",
401 (unsigned int)dosmode
,
402 time_to_asc(convert_timespec_to_time_t(smb_fname
->st
.st_ex_btime
)),
403 smb_fname_str_dbg(smb_fname
) ));
405 ndr_err
= ndr_push_struct_blob(
406 &blob
, talloc_tos(), &dosattrib
,
407 (ndr_push_flags_fn_t
)ndr_push_xattr_DOSATTRIB
);
409 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
410 DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n",
411 ndr_errstr(ndr_err
)));
415 if (blob
.data
== NULL
|| blob
.length
== 0) {
419 if (SMB_VFS_SETXATTR(conn
, smb_fname
->base_name
,
420 SAMBA_XATTR_DOS_ATTRIB
, blob
.data
, blob
.length
,
423 files_struct
*fsp
= NULL
;
425 if((errno
!= EPERM
) && (errno
!= EACCES
)) {
428 || errno
== ENOTSUP
) {
432 DEBUG(1,("set_ea_dos_attributes: Cannot set "
433 "attribute EA on file %s: Error = %s\n",
434 smb_fname_str_dbg(smb_fname
),
436 set_store_dos_attributes(SNUM(conn
), False
);
441 /* We want DOS semantics, ie allow non owner with write permission to change the
442 bits on a file. Just like file_ntimes below.
445 /* Check if we have write access. */
446 if(!CAN_WRITE(conn
) || !lp_dos_filemode(SNUM(conn
)))
449 if (!can_write_to_file(conn
, smb_fname
)) {
454 * We need to open the file with write access whilst
455 * still in our current user context. This ensures we
456 * are not violating security in doing the setxattr.
459 if (!NT_STATUS_IS_OK(open_file_fchmod(conn
, smb_fname
,
463 if (SMB_VFS_FSETXATTR(fsp
,
464 SAMBA_XATTR_DOS_ATTRIB
, blob
.data
,
465 blob
.length
, 0) == 0) {
469 close_file(NULL
, fsp
, NORMAL_CLOSE
);
472 DEBUG(10,("set_ea_dos_attribute: set EA 0x%x on file %s\n",
473 (unsigned int)dosmode
,
474 smb_fname_str_dbg(smb_fname
)));
478 /****************************************************************************
479 Change a unix mode to a dos mode for an ms dfs link.
480 ****************************************************************************/
482 uint32
dos_mode_msdfs(connection_struct
*conn
,
483 const struct smb_filename
*smb_fname
)
487 DEBUG(8,("dos_mode_msdfs: %s\n", smb_fname_str_dbg(smb_fname
)));
489 if (!VALID_STAT(smb_fname
->st
)) {
493 /* First do any modifications that depend on the path name. */
494 /* hide files with a name starting with a . */
495 if (lp_hide_dot_files(SNUM(conn
))) {
496 const char *p
= strrchr_m(smb_fname
->base_name
, '/');
500 p
= smb_fname
->base_name
;
503 /* Only . and .. are not hidden. */
504 if (p
[0] == '.' && !((p
[1] == '\0') ||
505 (p
[1] == '.' && p
[2] == '\0'))) {
506 result
|= FILE_ATTRIBUTE_HIDDEN
;
510 result
|= dos_mode_from_sbuf(conn
, smb_fname
);
512 /* Optimization : Only call is_hidden_path if it's not already
514 if (!(result
& FILE_ATTRIBUTE_HIDDEN
) &&
515 IS_HIDDEN_PATH(conn
, smb_fname
->base_name
)) {
516 result
|= FILE_ATTRIBUTE_HIDDEN
;
520 result
= FILE_ATTRIBUTE_NORMAL
;
523 result
= filter_mode_by_protocol(result
);
526 * Add in that it is a reparse point
528 result
|= FILE_ATTRIBUTE_REPARSE_POINT
;
530 DEBUG(8,("dos_mode_msdfs returning "));
532 if (result
& FILE_ATTRIBUTE_HIDDEN
) DEBUG(8, ("h"));
533 if (result
& FILE_ATTRIBUTE_READONLY
) DEBUG(8, ("r"));
534 if (result
& FILE_ATTRIBUTE_SYSTEM
) DEBUG(8, ("s"));
535 if (result
& FILE_ATTRIBUTE_DIRECTORY
) DEBUG(8, ("d"));
536 if (result
& FILE_ATTRIBUTE_ARCHIVE
) DEBUG(8, ("a"));
537 if (result
& FILE_ATTRIBUTE_SPARSE
) DEBUG(8, ("[sparse]"));
544 #ifdef HAVE_STAT_DOS_FLAGS
545 /****************************************************************************
546 Convert dos attributes (FILE_ATTRIBUTE_*) to dos stat flags (UF_*)
547 ****************************************************************************/
549 int dos_attributes_to_stat_dos_flags(uint32_t dosmode
)
551 uint32_t dos_stat_flags
= 0;
553 if (dosmode
& FILE_ATTRIBUTE_ARCHIVE
)
554 dos_stat_flags
|= UF_DOS_ARCHIVE
;
555 if (dosmode
& FILE_ATTRIBUTE_HIDDEN
)
556 dos_stat_flags
|= UF_DOS_HIDDEN
;
557 if (dosmode
& FILE_ATTRIBUTE_READONLY
)
558 dos_stat_flags
|= UF_DOS_RO
;
559 if (dosmode
& FILE_ATTRIBUTE_SYSTEM
)
560 dos_stat_flags
|= UF_DOS_SYSTEM
;
561 if (dosmode
& FILE_ATTRIBUTE_NONINDEXED
)
562 dos_stat_flags
|= UF_DOS_NOINDEX
;
564 return dos_stat_flags
;
567 /****************************************************************************
568 Gets DOS attributes, accessed via st_ex_flags in the stat struct.
569 ****************************************************************************/
571 static bool get_stat_dos_flags(connection_struct
*conn
,
572 const struct smb_filename
*smb_fname
,
575 SMB_ASSERT(VALID_STAT(smb_fname
->st
));
578 if (!lp_store_dos_attributes(SNUM(conn
))) {
582 DEBUG(5, ("Getting stat dos attributes for %s.\n",
583 smb_fname_str_dbg(smb_fname
)));
585 if (smb_fname
->st
.st_ex_flags
& UF_DOS_ARCHIVE
)
586 *dosmode
|= FILE_ATTRIBUTE_ARCHIVE
;
587 if (smb_fname
->st
.st_ex_flags
& UF_DOS_HIDDEN
)
588 *dosmode
|= FILE_ATTRIBUTE_HIDDEN
;
589 if (smb_fname
->st
.st_ex_flags
& UF_DOS_RO
)
590 *dosmode
|= FILE_ATTRIBUTE_READONLY
;
591 if (smb_fname
->st
.st_ex_flags
& UF_DOS_SYSTEM
)
592 *dosmode
|= FILE_ATTRIBUTE_SYSTEM
;
593 if (smb_fname
->st
.st_ex_flags
& UF_DOS_NOINDEX
)
594 *dosmode
|= FILE_ATTRIBUTE_NONINDEXED
;
595 if (smb_fname
->st
.st_ex_flags
& FILE_ATTRIBUTE_SPARSE
)
596 *dosmode
|= FILE_ATTRIBUTE_SPARSE
;
597 if (S_ISDIR(smb_fname
->st
.st_ex_mode
))
598 *dosmode
|= FILE_ATTRIBUTE_DIRECTORY
;
600 *dosmode
|= set_link_read_only_flag(&smb_fname
->st
);
605 /****************************************************************************
606 Sets DOS attributes, stored in st_ex_flags of the inode.
607 ****************************************************************************/
609 static bool set_stat_dos_flags(connection_struct
*conn
,
610 const struct smb_filename
*smb_fname
,
612 bool *attributes_changed
)
614 uint32_t new_flags
= 0;
617 SMB_ASSERT(VALID_STAT(smb_fname
->st
));
618 SMB_ASSERT(attributes_changed
);
620 *attributes_changed
= false;
622 if (!lp_store_dos_attributes(SNUM(conn
))) {
626 DEBUG(5, ("Setting stat dos attributes for %s.\n",
627 smb_fname_str_dbg(smb_fname
)));
629 new_flags
= (smb_fname
->st
.st_ex_flags
& ~UF_DOS_FLAGS
) |
630 dos_attributes_to_stat_dos_flags(dosmode
);
632 /* Return early if no flags changed. */
633 if (new_flags
== smb_fname
->st
.st_ex_flags
)
636 DEBUG(5, ("Setting stat dos attributes=0x%x, prev=0x%x\n", new_flags
,
637 smb_fname
->st
.st_ex_flags
));
639 /* Set new flags with chflags. */
640 error
= SMB_VFS_CHFLAGS(conn
, smb_fname
->base_name
, new_flags
);
642 DEBUG(0, ("Failed setting new stat dos attributes (0x%x) on "
643 "file %s! errno=%d\n", new_flags
,
644 smb_fname_str_dbg(smb_fname
), errno
));
648 *attributes_changed
= true;
651 #endif /* HAVE_STAT_DOS_FLAGS */
654 * check whether a file or directory is flagged as compressed.
656 static NTSTATUS
dos_mode_check_compressed(connection_struct
*conn
,
657 struct smb_filename
*smb_fname
,
661 uint16_t compression_fmt
;
662 TALLOC_CTX
*tmp_ctx
= talloc_new(NULL
);
663 if (tmp_ctx
== NULL
) {
664 status
= NT_STATUS_NO_MEMORY
;
668 status
= SMB_VFS_GET_COMPRESSION(conn
, tmp_ctx
, NULL
, smb_fname
,
670 if (!NT_STATUS_IS_OK(status
)) {
674 if (compression_fmt
== COMPRESSION_FORMAT_LZNT1
) {
675 *is_compressed
= true;
677 *is_compressed
= false;
679 status
= NT_STATUS_OK
;
682 talloc_free(tmp_ctx
);
687 /****************************************************************************
688 Change a unix mode to a dos mode.
689 May also read the create timespec into the stat struct in smb_fname
690 if "store dos attributes" is true.
691 ****************************************************************************/
693 uint32
dos_mode(connection_struct
*conn
, struct smb_filename
*smb_fname
)
696 bool offline
, used_stat_dos_flags
= false;
698 DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname
)));
700 if (!VALID_STAT(smb_fname
->st
)) {
704 /* First do any modifications that depend on the path name. */
705 /* hide files with a name starting with a . */
706 if (lp_hide_dot_files(SNUM(conn
))) {
707 const char *p
= strrchr_m(smb_fname
->base_name
,'/');
711 p
= smb_fname
->base_name
;
714 /* Only . and .. are not hidden. */
715 if (p
[0] == '.' && !((p
[1] == '\0') ||
716 (p
[1] == '.' && p
[2] == '\0'))) {
717 result
|= FILE_ATTRIBUTE_HIDDEN
;
721 #ifdef HAVE_STAT_DOS_FLAGS
722 used_stat_dos_flags
= get_stat_dos_flags(conn
, smb_fname
, &result
);
724 if (!used_stat_dos_flags
) {
725 /* Get the DOS attributes from an EA by preference. */
726 if (!get_ea_dos_attribute(conn
, smb_fname
, &result
)) {
727 result
|= dos_mode_from_sbuf(conn
, smb_fname
);
731 offline
= SMB_VFS_IS_OFFLINE(conn
, smb_fname
, &smb_fname
->st
);
732 if (S_ISREG(smb_fname
->st
.st_ex_mode
) && offline
) {
733 result
|= FILE_ATTRIBUTE_OFFLINE
;
736 if (conn
->fs_capabilities
& FILE_FILE_COMPRESSION
) {
737 bool compressed
= false;
738 NTSTATUS status
= dos_mode_check_compressed(conn
, smb_fname
,
740 if (NT_STATUS_IS_OK(status
) && compressed
) {
741 result
|= FILE_ATTRIBUTE_COMPRESSED
;
745 /* Optimization : Only call is_hidden_path if it's not already
747 if (!(result
& FILE_ATTRIBUTE_HIDDEN
) &&
748 IS_HIDDEN_PATH(conn
, smb_fname
->base_name
)) {
749 result
|= FILE_ATTRIBUTE_HIDDEN
;
753 result
= FILE_ATTRIBUTE_NORMAL
;
756 result
= filter_mode_by_protocol(result
);
758 dos_mode_debug_print(result
);
763 /*******************************************************************
764 chmod a file - but preserve some bits.
765 If "store dos attributes" is also set it will store the create time
766 from the stat struct in smb_fname (in NTTIME format) in the EA
768 ********************************************************************/
770 int file_set_dosmode(connection_struct
*conn
, struct smb_filename
*smb_fname
,
771 uint32 dosmode
, const char *parent_dir
, bool newfile
)
776 int ret
= -1, lret
= -1;
778 struct timespec new_create_timespec
;
779 files_struct
*fsp
= NULL
;
781 if (!CAN_WRITE(conn
)) {
786 /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
787 dosmode
&= (SAMBA_ATTRIBUTES_MASK
| FILE_ATTRIBUTE_OFFLINE
);
789 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
790 dosmode
, smb_fname_str_dbg(smb_fname
)));
792 unixmode
= smb_fname
->st
.st_ex_mode
;
794 get_acl_group_bits(conn
, smb_fname
->base_name
,
795 &smb_fname
->st
.st_ex_mode
);
797 if (S_ISDIR(smb_fname
->st
.st_ex_mode
))
798 dosmode
|= FILE_ATTRIBUTE_DIRECTORY
;
800 dosmode
&= ~FILE_ATTRIBUTE_DIRECTORY
;
802 new_create_timespec
= smb_fname
->st
.st_ex_btime
;
804 old_mode
= dos_mode(conn
, smb_fname
);
806 if ((dosmode
& FILE_ATTRIBUTE_OFFLINE
) &&
807 !(old_mode
& FILE_ATTRIBUTE_OFFLINE
)) {
808 lret
= SMB_VFS_SET_OFFLINE(conn
, smb_fname
);
810 if (errno
== ENOTSUP
) {
811 DEBUG(10, ("Setting FILE_ATTRIBUTE_OFFLINE for "
812 "%s/%s is not supported.\n",
814 smb_fname_str_dbg(smb_fname
)));
816 DEBUG(0, ("An error occurred while setting "
817 "FILE_ATTRIBUTE_OFFLINE for "
818 "%s/%s: %s", parent_dir
,
819 smb_fname_str_dbg(smb_fname
),
825 dosmode
&= ~FILE_ATTRIBUTE_OFFLINE
;
826 old_mode
&= ~FILE_ATTRIBUTE_OFFLINE
;
828 smb_fname
->st
.st_ex_btime
= new_create_timespec
;
830 #ifdef HAVE_STAT_DOS_FLAGS
832 bool attributes_changed
;
834 if (set_stat_dos_flags(conn
, smb_fname
, dosmode
,
835 &attributes_changed
))
837 if (!newfile
&& attributes_changed
) {
838 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
839 FILE_NOTIFY_CHANGE_ATTRIBUTES
,
840 smb_fname
->base_name
);
842 smb_fname
->st
.st_ex_mode
= unixmode
;
847 /* Store the DOS attributes in an EA by preference. */
848 if (lp_store_dos_attributes(SNUM(conn
))) {
850 * Don't fall back to using UNIX modes. Finally
851 * follow the smb.conf manpage.
853 if (!set_ea_dos_attribute(conn
, smb_fname
, dosmode
)) {
857 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
858 FILE_NOTIFY_CHANGE_ATTRIBUTES
,
859 smb_fname
->base_name
);
861 smb_fname
->st
.st_ex_mode
= unixmode
;
865 unixmode
= unix_mode(conn
, dosmode
, smb_fname
, parent_dir
);
867 /* preserve the file type bits */
870 /* preserve the s bits */
871 mask
|= (S_ISUID
| S_ISGID
);
873 /* preserve the t bit */
878 /* possibly preserve the x bits */
879 if (!MAP_ARCHIVE(conn
))
881 if (!MAP_SYSTEM(conn
))
883 if (!MAP_HIDDEN(conn
))
886 unixmode
|= (smb_fname
->st
.st_ex_mode
& mask
);
888 /* if we previously had any r bits set then leave them alone */
889 if ((tmp
= smb_fname
->st
.st_ex_mode
& (S_IRUSR
|S_IRGRP
|S_IROTH
))) {
890 unixmode
&= ~(S_IRUSR
|S_IRGRP
|S_IROTH
);
894 /* if we previously had any w bits set then leave them alone
895 whilst adding in the new w bits, if the new mode is not rdonly */
896 if (!IS_DOS_READONLY(dosmode
)) {
897 unixmode
|= (smb_fname
->st
.st_ex_mode
& (S_IWUSR
|S_IWGRP
|S_IWOTH
));
901 * From the chmod 2 man page:
903 * "If the calling process is not privileged, and the group of the file
904 * does not match the effective group ID of the process or one of its
905 * supplementary group IDs, the S_ISGID bit will be turned off, but
906 * this will not cause an error to be returned."
908 * Simply refuse to do the chmod in this case.
911 if (S_ISDIR(smb_fname
->st
.st_ex_mode
) && (unixmode
& S_ISGID
) &&
912 geteuid() != sec_initial_uid() &&
913 !current_user_in_group(conn
, smb_fname
->st
.st_ex_gid
)) {
914 DEBUG(3,("file_set_dosmode: setgid bit cannot be "
915 "set for directory %s\n",
916 smb_fname_str_dbg(smb_fname
)));
921 ret
= SMB_VFS_CHMOD(conn
, smb_fname
->base_name
, unixmode
);
923 if(!newfile
|| (lret
!= -1)) {
924 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
925 FILE_NOTIFY_CHANGE_ATTRIBUTES
,
926 smb_fname
->base_name
);
928 smb_fname
->st
.st_ex_mode
= unixmode
;
932 if((errno
!= EPERM
) && (errno
!= EACCES
))
935 if(!lp_dos_filemode(SNUM(conn
)))
938 /* We want DOS semantics, ie allow non owner with write permission to change the
939 bits on a file. Just like file_ntimes below.
942 if (!can_write_to_file(conn
, smb_fname
)) {
948 * We need to open the file with write access whilst
949 * still in our current user context. This ensures we
950 * are not violating security in doing the fchmod.
952 if (!NT_STATUS_IS_OK(open_file_fchmod(conn
, smb_fname
,
956 ret
= SMB_VFS_FCHMOD(fsp
, unixmode
);
958 close_file(NULL
, fsp
, NORMAL_CLOSE
);
960 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
961 FILE_NOTIFY_CHANGE_ATTRIBUTES
,
962 smb_fname
->base_name
);
965 smb_fname
->st
.st_ex_mode
= unixmode
;
972 NTSTATUS
file_set_sparse(connection_struct
*conn
,
976 uint32_t old_dosmode
;
977 uint32_t new_dosmode
;
980 if (!CAN_WRITE(conn
)) {
981 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
982 "on readonly share[%s]\n",
983 smb_fname_str_dbg(fsp
->fsp_name
),
985 lp_servicename(talloc_tos(), SNUM(conn
))));
986 return NT_STATUS_MEDIA_WRITE_PROTECTED
;
989 if (!(fsp
->access_mask
& FILE_WRITE_DATA
) &&
990 !(fsp
->access_mask
& FILE_WRITE_ATTRIBUTES
)) {
991 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
992 "access_mask[0x%08X] - access denied\n",
993 smb_fname_str_dbg(fsp
->fsp_name
),
996 return NT_STATUS_ACCESS_DENIED
;
999 DEBUG(10,("file_set_sparse: setting sparse bit %u on file %s\n",
1000 sparse
, smb_fname_str_dbg(fsp
->fsp_name
)));
1002 if (!lp_store_dos_attributes(SNUM(conn
))) {
1003 return NT_STATUS_INVALID_DEVICE_REQUEST
;
1006 status
= vfs_stat_fsp(fsp
);
1007 if (!NT_STATUS_IS_OK(status
)) {
1011 old_dosmode
= dos_mode(conn
, fsp
->fsp_name
);
1013 if (sparse
&& !(old_dosmode
& FILE_ATTRIBUTE_SPARSE
)) {
1014 new_dosmode
= old_dosmode
| FILE_ATTRIBUTE_SPARSE
;
1015 } else if (!sparse
&& (old_dosmode
& FILE_ATTRIBUTE_SPARSE
)) {
1016 new_dosmode
= old_dosmode
& ~FILE_ATTRIBUTE_SPARSE
;
1018 return NT_STATUS_OK
;
1021 /* Store the DOS attributes in an EA. */
1022 if (!set_ea_dos_attribute(conn
, fsp
->fsp_name
,
1027 return map_nt_error_from_unix(errno
);
1030 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
1031 FILE_NOTIFY_CHANGE_ATTRIBUTES
,
1032 fsp
->fsp_name
->base_name
);
1034 fsp
->is_sparse
= sparse
;
1036 return NT_STATUS_OK
;
1039 /*******************************************************************
1040 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
1042 *******************************************************************/
1044 int file_ntimes(connection_struct
*conn
, const struct smb_filename
*smb_fname
,
1045 struct smb_file_time
*ft
)
1051 DEBUG(6, ("file_ntime: actime: %s",
1052 time_to_asc(convert_timespec_to_time_t(ft
->atime
))));
1053 DEBUG(6, ("file_ntime: modtime: %s",
1054 time_to_asc(convert_timespec_to_time_t(ft
->mtime
))));
1055 DEBUG(6, ("file_ntime: ctime: %s",
1056 time_to_asc(convert_timespec_to_time_t(ft
->ctime
))));
1057 DEBUG(6, ("file_ntime: createtime: %s",
1058 time_to_asc(convert_timespec_to_time_t(ft
->create_time
))));
1060 /* Don't update the time on read-only shares */
1061 /* We need this as set_filetime (which can be called on
1062 close and other paths) can end up calling this function
1063 without the NEED_WRITE protection. Found by :
1064 Leo Weppelman <leo@wau.mis.ah.nl>
1067 if (!CAN_WRITE(conn
)) {
1071 if(SMB_VFS_NTIMES(conn
, smb_fname
, ft
) == 0) {
1075 if((errno
!= EPERM
) && (errno
!= EACCES
)) {
1079 if(!lp_dos_filetimes(SNUM(conn
))) {
1083 /* We have permission (given by the Samba admin) to
1084 break POSIX semantics and allow a user to change
1085 the time on a file they don't own but can write to
1089 /* Check if we have write access. */
1090 if (can_write_to_file(conn
, smb_fname
)) {
1091 /* We are allowed to become root and change the filetime. */
1093 ret
= SMB_VFS_NTIMES(conn
, smb_fname
, ft
);
1100 /******************************************************************
1101 Force a "sticky" write time on a pathname. This will always be
1102 returned on all future write time queries and set on close.
1103 ******************************************************************/
1105 bool set_sticky_write_time_path(struct file_id fileid
, struct timespec mtime
)
1107 if (null_timespec(mtime
)) {
1111 if (!set_sticky_write_time(fileid
, mtime
)) {
1118 /******************************************************************
1119 Force a "sticky" write time on an fsp. This will always be
1120 returned on all future write time queries and set on close.
1121 ******************************************************************/
1123 bool set_sticky_write_time_fsp(struct files_struct
*fsp
, struct timespec mtime
)
1125 if (null_timespec(mtime
)) {
1129 fsp
->write_time_forced
= true;
1130 TALLOC_FREE(fsp
->update_write_time_event
);
1132 return set_sticky_write_time_path(fsp
->file_id
, mtime
);
1135 /******************************************************************
1136 Set a create time EA.
1137 ******************************************************************/
1139 NTSTATUS
set_create_timespec_ea(connection_struct
*conn
,
1140 const struct smb_filename
*psmb_fname
,
1141 struct timespec create_time
)
1143 struct smb_filename
*smb_fname
;
1147 if (!lp_store_dos_attributes(SNUM(conn
))) {
1148 return NT_STATUS_OK
;
1151 smb_fname
= synthetic_smb_fname(talloc_tos(), psmb_fname
->base_name
,
1152 NULL
, &psmb_fname
->st
);
1154 if (smb_fname
== NULL
) {
1155 return NT_STATUS_NO_MEMORY
;
1158 dosmode
= dos_mode(conn
, smb_fname
);
1160 smb_fname
->st
.st_ex_btime
= create_time
;
1162 ret
= file_set_dosmode(conn
, smb_fname
, dosmode
, NULL
, false);
1164 map_nt_error_from_unix(errno
);
1167 DEBUG(10,("set_create_timespec_ea: wrote create time EA for file %s\n",
1168 smb_fname_str_dbg(smb_fname
)));
1170 return NT_STATUS_OK
;
1173 /******************************************************************
1174 Return a create time.
1175 ******************************************************************/
1177 struct timespec
get_create_timespec(connection_struct
*conn
,
1178 struct files_struct
*fsp
,
1179 const struct smb_filename
*smb_fname
)
1181 return smb_fname
->st
.st_ex_btime
;
1184 /******************************************************************
1185 Return a change time (may look at EA in future).
1186 ******************************************************************/
1188 struct timespec
get_change_timespec(connection_struct
*conn
,
1189 struct files_struct
*fsp
,
1190 const struct smb_filename
*smb_fname
)
1192 return smb_fname
->st
.st_ex_mtime
;