VERSION: Disable git snapshots for the 4.1.4 release.
[Samba.git] / source3 / smbd / dosmode.c
blob2d07dd9aa74527f7d5589efb51e7555781571861
1 /*
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/>.
21 #include "includes.h"
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",
33 (unsigned int)mode,
34 (unsigned int)(mode & 0x3f) ));
35 mode &= 0x3f;
37 return mode;
40 static int set_link_read_only_flag(const SMB_STRUCT_STAT *const sbuf)
42 #ifdef S_ISLNK
43 #if LINKS_READ_ONLY
44 if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
45 return FILE_ATTRIBUTE_READONLY;
46 #endif
47 #endif
48 return 0;
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.
56 else
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
62 if !inheriting {
63 Then apply create mask,
64 then add force bits.
66 Base permission for directories:
67 dos directory is represented in unix by unix's dir bit and the exec bit
68 if !inheriting {
69 Then apply create mask,
70 then add force bits.
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
80 * inheriting. */
82 if (!lp_store_dos_attributes(SNUM(conn)) && IS_DOS_READONLY(dosmode)) {
83 result &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
86 if ((inherit_from_dir != NULL) && lp_inherit_perms(SNUM(conn))) {
87 struct smb_filename *smb_fname_parent;
89 DEBUG(2, ("unix_mode(%s) inheriting from %s\n",
90 smb_fname_str_dbg(smb_fname),
91 inherit_from_dir));
93 smb_fname_parent = synthetic_smb_fname(
94 talloc_tos(), inherit_from_dir, NULL, NULL);
95 if (smb_fname_parent == NULL) {
96 DEBUG(1,("unix_mode(%s) failed, [dir %s]: No memory\n",
97 smb_fname_str_dbg(smb_fname),
98 inherit_from_dir));
99 return(0);
102 if (SMB_VFS_STAT(conn, smb_fname_parent) != 0) {
103 DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n",
104 smb_fname_str_dbg(smb_fname),
105 inherit_from_dir, strerror(errno)));
106 TALLOC_FREE(smb_fname_parent);
107 return(0); /* *** shouldn't happen! *** */
110 /* Save for later - but explicitly remove setuid bit for safety. */
111 dir_mode = smb_fname_parent->st.st_ex_mode & ~S_ISUID;
112 DEBUG(2,("unix_mode(%s) inherit mode %o\n",
113 smb_fname_str_dbg(smb_fname), (int)dir_mode));
114 /* Clear "result" */
115 result = 0;
116 TALLOC_FREE(smb_fname_parent);
119 if (IS_DOS_DIR(dosmode)) {
120 /* We never make directories read only for the owner as under DOS a user
121 can always create a file in a read-only directory. */
122 result |= (S_IFDIR | S_IWUSR);
124 if (dir_mode) {
125 /* Inherit mode of parent directory. */
126 result |= dir_mode;
127 } else {
128 /* Provisionally add all 'x' bits */
129 result |= (S_IXUSR | S_IXGRP | S_IXOTH);
131 /* Apply directory mask */
132 result &= lp_dir_mask(SNUM(conn));
133 /* Add in force bits */
134 result |= lp_force_dir_mode(SNUM(conn));
136 } else {
137 if (lp_map_archive(SNUM(conn)) && IS_DOS_ARCHIVE(dosmode))
138 result |= S_IXUSR;
140 if (lp_map_system(SNUM(conn)) && IS_DOS_SYSTEM(dosmode))
141 result |= S_IXGRP;
143 if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode))
144 result |= S_IXOTH;
146 if (dir_mode) {
147 /* Inherit 666 component of parent directory mode */
148 result |= dir_mode & (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
149 } else {
150 /* Apply mode mask */
151 result &= lp_create_mask(SNUM(conn));
152 /* Add in force bits */
153 result |= lp_force_create_mode(SNUM(conn));
157 DEBUG(3,("unix_mode(%s) returning 0%o\n", smb_fname_str_dbg(smb_fname),
158 (int)result));
159 return(result);
162 /****************************************************************************
163 Change a unix mode to a dos mode.
164 ****************************************************************************/
166 static uint32 dos_mode_from_sbuf(connection_struct *conn,
167 const struct smb_filename *smb_fname)
169 int result = 0;
170 enum mapreadonly_options ro_opts = (enum mapreadonly_options)lp_map_readonly(SNUM(conn));
172 #if defined(UF_IMMUTABLE) && defined(SF_IMMUTABLE)
173 /* if we can find out if a file is immutable we should report it r/o */
174 if (smb_fname->st.st_ex_flags & (UF_IMMUTABLE | SF_IMMUTABLE)) {
175 result |= FILE_ATTRIBUTE_READONLY;
177 #endif
178 if (ro_opts == MAP_READONLY_YES) {
179 /* Original Samba method - map inverse of user "w" bit. */
180 if ((smb_fname->st.st_ex_mode & S_IWUSR) == 0) {
181 result |= FILE_ATTRIBUTE_READONLY;
183 } else if (ro_opts == MAP_READONLY_PERMISSIONS) {
184 /* Check actual permissions for read-only. */
185 if (!can_write_to_file(conn, smb_fname)) {
186 result |= FILE_ATTRIBUTE_READONLY;
188 } /* Else never set the readonly bit. */
190 if (MAP_ARCHIVE(conn) && ((smb_fname->st.st_ex_mode & S_IXUSR) != 0))
191 result |= FILE_ATTRIBUTE_ARCHIVE;
193 if (MAP_SYSTEM(conn) && ((smb_fname->st.st_ex_mode & S_IXGRP) != 0))
194 result |= FILE_ATTRIBUTE_SYSTEM;
196 if (MAP_HIDDEN(conn) && ((smb_fname->st.st_ex_mode & S_IXOTH) != 0))
197 result |= FILE_ATTRIBUTE_HIDDEN;
199 if (S_ISDIR(smb_fname->st.st_ex_mode))
200 result = FILE_ATTRIBUTE_DIRECTORY | (result & FILE_ATTRIBUTE_READONLY);
202 result |= set_link_read_only_flag(&smb_fname->st);
204 DEBUG(8,("dos_mode_from_sbuf returning "));
206 if (result & FILE_ATTRIBUTE_HIDDEN) DEBUG(8, ("h"));
207 if (result & FILE_ATTRIBUTE_READONLY ) DEBUG(8, ("r"));
208 if (result & FILE_ATTRIBUTE_SYSTEM) DEBUG(8, ("s"));
209 if (result & FILE_ATTRIBUTE_DIRECTORY ) DEBUG(8, ("d"));
210 if (result & FILE_ATTRIBUTE_ARCHIVE ) DEBUG(8, ("a"));
212 DEBUG(8,("\n"));
213 return result;
216 /****************************************************************************
217 Get DOS attributes from an EA.
218 This can also pull the create time into the stat struct inside smb_fname.
219 ****************************************************************************/
221 static bool get_ea_dos_attribute(connection_struct *conn,
222 struct smb_filename *smb_fname,
223 uint32 *pattr)
225 struct xattr_DOSATTRIB dosattrib;
226 enum ndr_err_code ndr_err;
227 DATA_BLOB blob;
228 ssize_t sizeret;
229 fstring attrstr;
230 uint32_t dosattr;
232 if (!lp_store_dos_attributes(SNUM(conn))) {
233 return False;
236 /* Don't reset pattr to zero as we may already have filename-based attributes we
237 need to preserve. */
239 sizeret = SMB_VFS_GETXATTR(conn, smb_fname->base_name,
240 SAMBA_XATTR_DOS_ATTRIB, attrstr,
241 sizeof(attrstr));
242 if (sizeret == -1) {
243 if (errno == ENOSYS
244 #if defined(ENOTSUP)
245 || errno == ENOTSUP) {
246 #else
248 #endif
249 DEBUG(1,("get_ea_dos_attribute: Cannot get attribute "
250 "from EA on file %s: Error = %s\n",
251 smb_fname_str_dbg(smb_fname),
252 strerror(errno)));
253 set_store_dos_attributes(SNUM(conn), False);
255 return False;
258 blob.data = (uint8_t *)attrstr;
259 blob.length = sizeret;
261 ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &dosattrib,
262 (ndr_pull_flags_fn_t)ndr_pull_xattr_DOSATTRIB);
264 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
265 DEBUG(1,("get_ea_dos_attribute: bad ndr decode "
266 "from EA on file %s: Error = %s\n",
267 smb_fname_str_dbg(smb_fname),
268 ndr_errstr(ndr_err)));
269 return false;
272 DEBUG(10,("get_ea_dos_attribute: %s attr = %s\n",
273 smb_fname_str_dbg(smb_fname), dosattrib.attrib_hex));
275 switch (dosattrib.version) {
276 case 0xFFFF:
277 dosattr = dosattrib.info.compatinfoFFFF.attrib;
278 break;
279 case 1:
280 dosattr = dosattrib.info.info1.attrib;
281 if (!null_nttime(dosattrib.info.info1.create_time)) {
282 struct timespec create_time =
283 nt_time_to_unix_timespec(
284 &dosattrib.info.info1.create_time);
286 update_stat_ex_create_time(&smb_fname->st,
287 create_time);
289 DEBUG(10,("get_ea_dos_attribute: file %s case 1 "
290 "set btime %s\n",
291 smb_fname_str_dbg(smb_fname),
292 time_to_asc(convert_timespec_to_time_t(
293 create_time)) ));
295 break;
296 case 2:
297 dosattr = dosattrib.info.oldinfo2.attrib;
298 /* Don't know what flags to check for this case. */
299 break;
300 case 3:
301 dosattr = dosattrib.info.info3.attrib;
302 if ((dosattrib.info.info3.valid_flags & XATTR_DOSINFO_CREATE_TIME) &&
303 !null_nttime(dosattrib.info.info3.create_time)) {
304 struct timespec create_time =
305 nt_time_to_unix_timespec(
306 &dosattrib.info.info3.create_time);
308 update_stat_ex_create_time(&smb_fname->st,
309 create_time);
311 DEBUG(10,("get_ea_dos_attribute: file %s case 3 "
312 "set btime %s\n",
313 smb_fname_str_dbg(smb_fname),
314 time_to_asc(convert_timespec_to_time_t(
315 create_time)) ));
317 break;
318 default:
319 DEBUG(1,("get_ea_dos_attribute: Badly formed DOSATTRIB on "
320 "file %s - %s\n", smb_fname_str_dbg(smb_fname),
321 attrstr));
322 return false;
325 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
326 dosattr |= FILE_ATTRIBUTE_DIRECTORY;
328 /* FILE_ATTRIBUTE_SPARSE is valid on get but not on set. */
329 *pattr = (uint32)(dosattr & (SAMBA_ATTRIBUTES_MASK|FILE_ATTRIBUTE_SPARSE));
331 DEBUG(8,("get_ea_dos_attribute returning (0x%x)", dosattr));
333 if (dosattr & FILE_ATTRIBUTE_HIDDEN) DEBUG(8, ("h"));
334 if (dosattr & FILE_ATTRIBUTE_READONLY ) DEBUG(8, ("r"));
335 if (dosattr & FILE_ATTRIBUTE_SYSTEM) DEBUG(8, ("s"));
336 if (dosattr & FILE_ATTRIBUTE_DIRECTORY ) DEBUG(8, ("d"));
337 if (dosattr & FILE_ATTRIBUTE_ARCHIVE ) DEBUG(8, ("a"));
339 DEBUG(8,("\n"));
341 return True;
344 /****************************************************************************
345 Set DOS attributes in an EA.
346 Also sets the create time.
347 ****************************************************************************/
349 static bool set_ea_dos_attribute(connection_struct *conn,
350 struct smb_filename *smb_fname,
351 uint32 dosmode)
353 struct xattr_DOSATTRIB dosattrib;
354 enum ndr_err_code ndr_err;
355 DATA_BLOB blob;
357 ZERO_STRUCT(dosattrib);
358 ZERO_STRUCT(blob);
360 dosattrib.version = 3;
361 dosattrib.info.info3.valid_flags = XATTR_DOSINFO_ATTRIB|
362 XATTR_DOSINFO_CREATE_TIME;
363 dosattrib.info.info3.attrib = dosmode;
364 unix_timespec_to_nt_time(&dosattrib.info.info3.create_time,
365 smb_fname->st.st_ex_btime);
367 DEBUG(10,("set_ea_dos_attributes: set attribute 0x%x, btime = %s on file %s\n",
368 (unsigned int)dosmode,
369 time_to_asc(convert_timespec_to_time_t(smb_fname->st.st_ex_btime)),
370 smb_fname_str_dbg(smb_fname) ));
372 ndr_err = ndr_push_struct_blob(
373 &blob, talloc_tos(), &dosattrib,
374 (ndr_push_flags_fn_t)ndr_push_xattr_DOSATTRIB);
376 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
377 DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n",
378 ndr_errstr(ndr_err)));
379 return false;
382 if (blob.data == NULL || blob.length == 0) {
383 return false;
386 if (SMB_VFS_SETXATTR(conn, smb_fname->base_name,
387 SAMBA_XATTR_DOS_ATTRIB, blob.data, blob.length,
388 0) == -1) {
389 bool ret = false;
390 files_struct *fsp = NULL;
392 if((errno != EPERM) && (errno != EACCES)) {
393 if (errno == ENOSYS
394 #if defined(ENOTSUP)
395 || errno == ENOTSUP) {
396 #else
398 #endif
399 DEBUG(1,("set_ea_dos_attributes: Cannot set "
400 "attribute EA on file %s: Error = %s\n",
401 smb_fname_str_dbg(smb_fname),
402 strerror(errno) ));
403 set_store_dos_attributes(SNUM(conn), False);
405 return false;
408 /* We want DOS semantics, ie allow non owner with write permission to change the
409 bits on a file. Just like file_ntimes below.
412 /* Check if we have write access. */
413 if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
414 return false;
416 if (!can_write_to_file(conn, smb_fname)) {
417 return false;
421 * We need to open the file with write access whilst
422 * still in our current user context. This ensures we
423 * are not violating security in doing the setxattr.
426 if (!NT_STATUS_IS_OK(open_file_fchmod(conn, smb_fname,
427 &fsp)))
428 return false;
429 become_root();
430 if (SMB_VFS_FSETXATTR(fsp,
431 SAMBA_XATTR_DOS_ATTRIB, blob.data,
432 blob.length, 0) == 0) {
433 ret = true;
435 unbecome_root();
436 close_file(NULL, fsp, NORMAL_CLOSE);
437 return ret;
439 DEBUG(10,("set_ea_dos_attribute: set EA 0x%x on file %s\n",
440 (unsigned int)dosmode,
441 smb_fname_str_dbg(smb_fname)));
442 return true;
445 /****************************************************************************
446 Change a unix mode to a dos mode for an ms dfs link.
447 ****************************************************************************/
449 uint32 dos_mode_msdfs(connection_struct *conn,
450 const struct smb_filename *smb_fname)
452 uint32 result = 0;
454 DEBUG(8,("dos_mode_msdfs: %s\n", smb_fname_str_dbg(smb_fname)));
456 if (!VALID_STAT(smb_fname->st)) {
457 return 0;
460 /* First do any modifications that depend on the path name. */
461 /* hide files with a name starting with a . */
462 if (lp_hide_dot_files(SNUM(conn))) {
463 const char *p = strrchr_m(smb_fname->base_name, '/');
464 if (p) {
465 p++;
466 } else {
467 p = smb_fname->base_name;
470 /* Only . and .. are not hidden. */
471 if (p[0] == '.' && !((p[1] == '\0') ||
472 (p[1] == '.' && p[2] == '\0'))) {
473 result |= FILE_ATTRIBUTE_HIDDEN;
477 result |= dos_mode_from_sbuf(conn, smb_fname);
479 /* Optimization : Only call is_hidden_path if it's not already
480 hidden. */
481 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
482 IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
483 result |= FILE_ATTRIBUTE_HIDDEN;
486 if (result == 0) {
487 result = FILE_ATTRIBUTE_NORMAL;
490 result = filter_mode_by_protocol(result);
493 * Add in that it is a reparse point
495 result |= FILE_ATTRIBUTE_REPARSE_POINT;
497 DEBUG(8,("dos_mode_msdfs returning "));
499 if (result & FILE_ATTRIBUTE_HIDDEN) DEBUG(8, ("h"));
500 if (result & FILE_ATTRIBUTE_READONLY ) DEBUG(8, ("r"));
501 if (result & FILE_ATTRIBUTE_SYSTEM) DEBUG(8, ("s"));
502 if (result & FILE_ATTRIBUTE_DIRECTORY ) DEBUG(8, ("d"));
503 if (result & FILE_ATTRIBUTE_ARCHIVE ) DEBUG(8, ("a"));
504 if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
506 DEBUG(8,("\n"));
508 return(result);
511 #ifdef HAVE_STAT_DOS_FLAGS
512 /****************************************************************************
513 Convert dos attributes (FILE_ATTRIBUTE_*) to dos stat flags (UF_*)
514 ****************************************************************************/
516 int dos_attributes_to_stat_dos_flags(uint32_t dosmode)
518 uint32_t dos_stat_flags = 0;
520 if (dosmode & FILE_ATTRIBUTE_ARCHIVE)
521 dos_stat_flags |= UF_DOS_ARCHIVE;
522 if (dosmode & FILE_ATTRIBUTE_HIDDEN)
523 dos_stat_flags |= UF_DOS_HIDDEN;
524 if (dosmode & FILE_ATTRIBUTE_READONLY)
525 dos_stat_flags |= UF_DOS_RO;
526 if (dosmode & FILE_ATTRIBUTE_SYSTEM)
527 dos_stat_flags |= UF_DOS_SYSTEM;
528 if (dosmode & FILE_ATTRIBUTE_NONINDEXED)
529 dos_stat_flags |= UF_DOS_NOINDEX;
531 return dos_stat_flags;
534 /****************************************************************************
535 Gets DOS attributes, accessed via st_ex_flags in the stat struct.
536 ****************************************************************************/
538 static bool get_stat_dos_flags(connection_struct *conn,
539 const struct smb_filename *smb_fname,
540 uint32_t *dosmode)
542 SMB_ASSERT(VALID_STAT(smb_fname->st));
543 SMB_ASSERT(dosmode);
545 if (!lp_store_dos_attributes(SNUM(conn))) {
546 return false;
549 DEBUG(5, ("Getting stat dos attributes for %s.\n",
550 smb_fname_str_dbg(smb_fname)));
552 if (smb_fname->st.st_ex_flags & UF_DOS_ARCHIVE)
553 *dosmode |= FILE_ATTRIBUTE_ARCHIVE;
554 if (smb_fname->st.st_ex_flags & UF_DOS_HIDDEN)
555 *dosmode |= FILE_ATTRIBUTE_HIDDEN;
556 if (smb_fname->st.st_ex_flags & UF_DOS_RO)
557 *dosmode |= FILE_ATTRIBUTE_READONLY;
558 if (smb_fname->st.st_ex_flags & UF_DOS_SYSTEM)
559 *dosmode |= FILE_ATTRIBUTE_SYSTEM;
560 if (smb_fname->st.st_ex_flags & UF_DOS_NOINDEX)
561 *dosmode |= FILE_ATTRIBUTE_NONINDEXED;
562 if (smb_fname->st.st_ex_flags & FILE_ATTRIBUTE_SPARSE)
563 *dosmode |= FILE_ATTRIBUTE_SPARSE;
564 if (S_ISDIR(smb_fname->st.st_ex_mode))
565 *dosmode |= FILE_ATTRIBUTE_DIRECTORY;
567 *dosmode |= set_link_read_only_flag(&smb_fname->st);
569 return true;
572 /****************************************************************************
573 Sets DOS attributes, stored in st_ex_flags of the inode.
574 ****************************************************************************/
576 static bool set_stat_dos_flags(connection_struct *conn,
577 const struct smb_filename *smb_fname,
578 uint32_t dosmode,
579 bool *attributes_changed)
581 uint32_t new_flags = 0;
582 int error = 0;
584 SMB_ASSERT(VALID_STAT(smb_fname->st));
585 SMB_ASSERT(attributes_changed);
587 *attributes_changed = false;
589 if (!lp_store_dos_attributes(SNUM(conn))) {
590 return false;
593 DEBUG(5, ("Setting stat dos attributes for %s.\n",
594 smb_fname_str_dbg(smb_fname)));
596 new_flags = (smb_fname->st.st_ex_flags & ~UF_DOS_FLAGS) |
597 dos_attributes_to_stat_dos_flags(dosmode);
599 /* Return early if no flags changed. */
600 if (new_flags == smb_fname->st.st_ex_flags)
601 return true;
603 DEBUG(5, ("Setting stat dos attributes=0x%x, prev=0x%x\n", new_flags,
604 smb_fname->st.st_ex_flags));
606 /* Set new flags with chflags. */
607 error = SMB_VFS_CHFLAGS(conn, smb_fname->base_name, new_flags);
608 if (error) {
609 DEBUG(0, ("Failed setting new stat dos attributes (0x%x) on "
610 "file %s! errno=%d\n", new_flags,
611 smb_fname_str_dbg(smb_fname), errno));
612 return false;
615 *attributes_changed = true;
616 return true;
618 #endif /* HAVE_STAT_DOS_FLAGS */
620 /****************************************************************************
621 Change a unix mode to a dos mode.
622 May also read the create timespec into the stat struct in smb_fname
623 if "store dos attributes" is true.
624 ****************************************************************************/
626 uint32 dos_mode(connection_struct *conn, struct smb_filename *smb_fname)
628 uint32 result = 0;
629 bool offline, used_stat_dos_flags = false;
631 DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname)));
633 if (!VALID_STAT(smb_fname->st)) {
634 return 0;
637 /* First do any modifications that depend on the path name. */
638 /* hide files with a name starting with a . */
639 if (lp_hide_dot_files(SNUM(conn))) {
640 const char *p = strrchr_m(smb_fname->base_name,'/');
641 if (p) {
642 p++;
643 } else {
644 p = smb_fname->base_name;
647 /* Only . and .. are not hidden. */
648 if (p[0] == '.' && !((p[1] == '\0') ||
649 (p[1] == '.' && p[2] == '\0'))) {
650 result |= FILE_ATTRIBUTE_HIDDEN;
654 #ifdef HAVE_STAT_DOS_FLAGS
655 used_stat_dos_flags = get_stat_dos_flags(conn, smb_fname, &result);
656 #endif
657 if (!used_stat_dos_flags) {
658 /* Get the DOS attributes from an EA by preference. */
659 if (!get_ea_dos_attribute(conn, smb_fname, &result)) {
660 result |= dos_mode_from_sbuf(conn, smb_fname);
664 offline = SMB_VFS_IS_OFFLINE(conn, smb_fname, &smb_fname->st);
665 if (S_ISREG(smb_fname->st.st_ex_mode) && offline) {
666 result |= FILE_ATTRIBUTE_OFFLINE;
669 /* Optimization : Only call is_hidden_path if it's not already
670 hidden. */
671 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
672 IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
673 result |= FILE_ATTRIBUTE_HIDDEN;
676 if (result == 0) {
677 result = FILE_ATTRIBUTE_NORMAL;
680 result = filter_mode_by_protocol(result);
682 DEBUG(8,("dos_mode returning "));
684 if (result & FILE_ATTRIBUTE_HIDDEN) DEBUG(8, ("h"));
685 if (result & FILE_ATTRIBUTE_READONLY ) DEBUG(8, ("r"));
686 if (result & FILE_ATTRIBUTE_SYSTEM) DEBUG(8, ("s"));
687 if (result & FILE_ATTRIBUTE_DIRECTORY ) DEBUG(8, ("d"));
688 if (result & FILE_ATTRIBUTE_ARCHIVE ) DEBUG(8, ("a"));
689 if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
690 if (result & FILE_ATTRIBUTE_OFFLINE ) DEBUG(8, ("[offline]"));
692 DEBUG(8,("\n"));
694 return(result);
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
701 attribute also.
702 ********************************************************************/
704 int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname,
705 uint32 dosmode, const char *parent_dir, bool newfile)
707 int mask=0;
708 mode_t tmp;
709 mode_t unixmode;
710 int ret = -1, lret = -1;
711 uint32_t old_mode;
712 struct timespec new_create_timespec;
713 files_struct *fsp = NULL;
715 if (!CAN_WRITE(conn)) {
716 errno = EROFS;
717 return -1;
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;
733 else
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 !(old_mode & FILE_ATTRIBUTE_OFFLINE)) {
742 lret = SMB_VFS_SET_OFFLINE(conn, smb_fname);
743 if (lret == -1) {
744 if (errno == ENOTSUP) {
745 DEBUG(10, ("Setting FILE_ATTRIBUTE_OFFLINE for "
746 "%s/%s is not supported.\n",
747 parent_dir,
748 smb_fname_str_dbg(smb_fname)));
749 } else {
750 DEBUG(0, ("An error occurred while setting "
751 "FILE_ATTRIBUTE_OFFLINE for "
752 "%s/%s: %s", parent_dir,
753 smb_fname_str_dbg(smb_fname),
754 strerror(errno)));
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;
777 return 0;
780 #endif
781 /* Store the DOS attributes in an EA by preference. */
782 if (lp_store_dos_attributes(SNUM(conn))) {
784 * Don't fall back to using UNIX modes. Finally
785 * follow the smb.conf manpage.
787 if (!set_ea_dos_attribute(conn, smb_fname, dosmode)) {
788 return -1;
790 if (!newfile) {
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;
796 return 0;
799 unixmode = unix_mode(conn, dosmode, smb_fname, parent_dir);
801 /* preserve the file type bits */
802 mask |= S_IFMT;
804 /* preserve the s bits */
805 mask |= (S_ISUID | S_ISGID);
807 /* preserve the t bit */
808 #ifdef S_ISVTX
809 mask |= S_ISVTX;
810 #endif
812 /* possibly preserve the x bits */
813 if (!MAP_ARCHIVE(conn))
814 mask |= S_IXUSR;
815 if (!MAP_SYSTEM(conn))
816 mask |= S_IXGRP;
817 if (!MAP_HIDDEN(conn))
818 mask |= S_IXOTH;
820 unixmode |= (smb_fname->st.st_ex_mode & mask);
822 /* if we previously had any r bits set then leave them alone */
823 if ((tmp = smb_fname->st.st_ex_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
824 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
825 unixmode |= tmp;
828 /* if we previously had any w bits set then leave them alone
829 whilst adding in the new w bits, if the new mode is not rdonly */
830 if (!IS_DOS_READONLY(dosmode)) {
831 unixmode |= (smb_fname->st.st_ex_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
835 * From the chmod 2 man page:
837 * "If the calling process is not privileged, and the group of the file
838 * does not match the effective group ID of the process or one of its
839 * supplementary group IDs, the S_ISGID bit will be turned off, but
840 * this will not cause an error to be returned."
842 * Simply refuse to do the chmod in this case.
845 if (S_ISDIR(smb_fname->st.st_ex_mode) && (unixmode & S_ISGID) &&
846 geteuid() != sec_initial_uid() &&
847 !current_user_in_group(conn, smb_fname->st.st_ex_gid)) {
848 DEBUG(3,("file_set_dosmode: setgid bit cannot be "
849 "set for directory %s\n",
850 smb_fname_str_dbg(smb_fname)));
851 errno = EPERM;
852 return -1;
855 ret = SMB_VFS_CHMOD(conn, smb_fname->base_name, unixmode);
856 if (ret == 0) {
857 if(!newfile || (lret != -1)) {
858 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
859 FILE_NOTIFY_CHANGE_ATTRIBUTES,
860 smb_fname->base_name);
862 smb_fname->st.st_ex_mode = unixmode;
863 return 0;
866 if((errno != EPERM) && (errno != EACCES))
867 return -1;
869 if(!lp_dos_filemode(SNUM(conn)))
870 return -1;
872 /* We want DOS semantics, ie allow non owner with write permission to change the
873 bits on a file. Just like file_ntimes below.
876 if (!can_write_to_file(conn, smb_fname)) {
877 errno = EACCES;
878 return -1;
882 * We need to open the file with write access whilst
883 * still in our current user context. This ensures we
884 * are not violating security in doing the fchmod.
886 if (!NT_STATUS_IS_OK(open_file_fchmod(conn, smb_fname,
887 &fsp)))
888 return -1;
889 become_root();
890 ret = SMB_VFS_FCHMOD(fsp, unixmode);
891 unbecome_root();
892 close_file(NULL, fsp, NORMAL_CLOSE);
893 if (!newfile) {
894 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
895 FILE_NOTIFY_CHANGE_ATTRIBUTES,
896 smb_fname->base_name);
898 if (ret == 0) {
899 smb_fname->st.st_ex_mode = unixmode;
902 return( ret );
906 NTSTATUS file_set_sparse(connection_struct *conn,
907 files_struct *fsp,
908 bool sparse)
910 uint32_t old_dosmode;
911 uint32_t new_dosmode;
912 NTSTATUS status;
914 if (!CAN_WRITE(conn)) {
915 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
916 "on readonly share[%s]\n",
917 smb_fname_str_dbg(fsp->fsp_name),
918 sparse,
919 lp_servicename(talloc_tos(), SNUM(conn))));
920 return NT_STATUS_MEDIA_WRITE_PROTECTED;
923 if (!(fsp->access_mask & FILE_WRITE_DATA) &&
924 !(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
925 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
926 "access_mask[0x%08X] - access denied\n",
927 smb_fname_str_dbg(fsp->fsp_name),
928 sparse,
929 fsp->access_mask));
930 return NT_STATUS_ACCESS_DENIED;
933 DEBUG(10,("file_set_sparse: setting sparse bit %u on file %s\n",
934 sparse, smb_fname_str_dbg(fsp->fsp_name)));
936 if (!lp_store_dos_attributes(SNUM(conn))) {
937 return NT_STATUS_INVALID_DEVICE_REQUEST;
940 status = vfs_stat_fsp(fsp);
941 if (!NT_STATUS_IS_OK(status)) {
942 return status;
945 old_dosmode = dos_mode(conn, fsp->fsp_name);
947 if (sparse && !(old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
948 new_dosmode = old_dosmode | FILE_ATTRIBUTE_SPARSE;
949 } else if (!sparse && (old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
950 new_dosmode = old_dosmode & ~FILE_ATTRIBUTE_SPARSE;
951 } else {
952 return NT_STATUS_OK;
955 /* Store the DOS attributes in an EA. */
956 if (!set_ea_dos_attribute(conn, fsp->fsp_name,
957 new_dosmode)) {
958 if (errno == 0) {
959 errno = EIO;
961 return map_nt_error_from_unix(errno);
964 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
965 FILE_NOTIFY_CHANGE_ATTRIBUTES,
966 fsp->fsp_name->base_name);
968 fsp->is_sparse = sparse;
970 return NT_STATUS_OK;
973 /*******************************************************************
974 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
975 than POSIX.
976 *******************************************************************/
978 int file_ntimes(connection_struct *conn, const struct smb_filename *smb_fname,
979 struct smb_file_time *ft)
981 int ret = -1;
983 errno = 0;
985 DEBUG(6, ("file_ntime: actime: %s",
986 time_to_asc(convert_timespec_to_time_t(ft->atime))));
987 DEBUG(6, ("file_ntime: modtime: %s",
988 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
989 DEBUG(6, ("file_ntime: ctime: %s",
990 time_to_asc(convert_timespec_to_time_t(ft->ctime))));
991 DEBUG(6, ("file_ntime: createtime: %s",
992 time_to_asc(convert_timespec_to_time_t(ft->create_time))));
994 /* Don't update the time on read-only shares */
995 /* We need this as set_filetime (which can be called on
996 close and other paths) can end up calling this function
997 without the NEED_WRITE protection. Found by :
998 Leo Weppelman <leo@wau.mis.ah.nl>
1001 if (!CAN_WRITE(conn)) {
1002 return 0;
1005 if(SMB_VFS_NTIMES(conn, smb_fname, ft) == 0) {
1006 return 0;
1009 if((errno != EPERM) && (errno != EACCES)) {
1010 return -1;
1013 if(!lp_dos_filetimes(SNUM(conn))) {
1014 return -1;
1017 /* We have permission (given by the Samba admin) to
1018 break POSIX semantics and allow a user to change
1019 the time on a file they don't own but can write to
1020 (as DOS does).
1023 /* Check if we have write access. */
1024 if (can_write_to_file(conn, smb_fname)) {
1025 /* We are allowed to become root and change the filetime. */
1026 become_root();
1027 ret = SMB_VFS_NTIMES(conn, smb_fname, ft);
1028 unbecome_root();
1031 return ret;
1034 /******************************************************************
1035 Force a "sticky" write time on a pathname. This will always be
1036 returned on all future write time queries and set on close.
1037 ******************************************************************/
1039 bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime)
1041 if (null_timespec(mtime)) {
1042 return true;
1045 if (!set_sticky_write_time(fileid, mtime)) {
1046 return false;
1049 return true;
1052 /******************************************************************
1053 Force a "sticky" write time on an fsp. This will always be
1054 returned on all future write time queries and set on close.
1055 ******************************************************************/
1057 bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime)
1059 if (null_timespec(mtime)) {
1060 return true;
1063 fsp->write_time_forced = true;
1064 TALLOC_FREE(fsp->update_write_time_event);
1066 return set_sticky_write_time_path(fsp->file_id, mtime);
1069 /******************************************************************
1070 Set a create time EA.
1071 ******************************************************************/
1073 NTSTATUS set_create_timespec_ea(connection_struct *conn,
1074 const struct smb_filename *psmb_fname,
1075 struct timespec create_time)
1077 struct smb_filename *smb_fname;
1078 uint32_t dosmode;
1079 int ret;
1081 if (!lp_store_dos_attributes(SNUM(conn))) {
1082 return NT_STATUS_OK;
1085 smb_fname = synthetic_smb_fname(talloc_tos(), psmb_fname->base_name,
1086 NULL, &psmb_fname->st);
1088 if (smb_fname == NULL) {
1089 return NT_STATUS_NO_MEMORY;
1092 dosmode = dos_mode(conn, smb_fname);
1094 smb_fname->st.st_ex_btime = create_time;
1096 ret = file_set_dosmode(conn, smb_fname, dosmode, NULL, false);
1097 if (ret == -1) {
1098 map_nt_error_from_unix(errno);
1101 DEBUG(10,("set_create_timespec_ea: wrote create time EA for file %s\n",
1102 smb_fname_str_dbg(smb_fname)));
1104 return NT_STATUS_OK;
1107 /******************************************************************
1108 Return a create time.
1109 ******************************************************************/
1111 struct timespec get_create_timespec(connection_struct *conn,
1112 struct files_struct *fsp,
1113 const struct smb_filename *smb_fname)
1115 return smb_fname->st.st_ex_btime;
1118 /******************************************************************
1119 Return a change time (may look at EA in future).
1120 ******************************************************************/
1122 struct timespec get_change_timespec(connection_struct *conn,
1123 struct files_struct *fsp,
1124 const struct smb_filename *smb_fname)
1126 return smb_fname->st.st_ex_mtime;