s4:kdc Fill in more data fields
[Samba/ekacnet.git] / source3 / smbd / dosmode.c
blobe5d6bc32e855537a4b907c990ac82a431ba57011
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 "librpc/gen_ndr/ndr_xattr.h"
24 static uint32_t filter_mode_by_protocol(uint32_t mode)
26 if (get_Protocol() <= PROTOCOL_LANMAN2) {
27 DEBUG(10,("filter_mode_by_protocol: "
28 "filtering result 0x%x to 0x%x\n",
29 (unsigned int)mode,
30 (unsigned int)(mode & 0x3f) ));
31 mode &= 0x3f;
33 return mode;
36 static int set_sparse_flag(const SMB_STRUCT_STAT * const sbuf)
38 #if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
39 if (sbuf->st_ex_size > sbuf->st_ex_blocks * (SMB_OFF_T)STAT_ST_BLOCKSIZE) {
40 return FILE_ATTRIBUTE_SPARSE;
42 #endif
43 return 0;
46 static int set_link_read_only_flag(const SMB_STRUCT_STAT *const sbuf)
48 #ifdef S_ISLNK
49 #if LINKS_READ_ONLY
50 if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
51 return aRONLY;
52 #endif
53 #endif
54 return 0;
57 /****************************************************************************
58 Change a dos mode to a unix mode.
59 Base permission for files:
60 if creating file and inheriting (i.e. parent_dir != NULL)
61 apply read/write bits from parent directory.
62 else
63 everybody gets read bit set
64 dos readonly is represented in unix by removing everyone's write bit
65 dos archive is represented in unix by the user's execute bit
66 dos system is represented in unix by the group's execute bit
67 dos hidden is represented in unix by the other's execute bit
68 if !inheriting {
69 Then apply create mask,
70 then add force bits.
72 Base permission for directories:
73 dos directory is represented in unix by unix's dir bit and the exec bit
74 if !inheriting {
75 Then apply create mask,
76 then add force bits.
78 ****************************************************************************/
80 mode_t unix_mode(connection_struct *conn, int dosmode,
81 const struct smb_filename *smb_fname,
82 const char *inherit_from_dir)
84 mode_t result = (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
85 mode_t dir_mode = 0; /* Mode of the inherit_from directory if
86 * inheriting. */
88 if (!lp_store_dos_attributes(SNUM(conn)) && IS_DOS_READONLY(dosmode)) {
89 result &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
92 if ((inherit_from_dir != NULL) && lp_inherit_perms(SNUM(conn))) {
93 struct smb_filename *smb_fname_parent = NULL;
94 NTSTATUS status;
96 DEBUG(2, ("unix_mode(%s) inheriting from %s\n",
97 smb_fname_str_dbg(smb_fname),
98 inherit_from_dir));
100 status = create_synthetic_smb_fname(talloc_tos(),
101 inherit_from_dir, NULL,
102 NULL, &smb_fname_parent);
103 if (!NT_STATUS_IS_OK(status)) {
104 DEBUG(1,("unix_mode(%s) failed, [dir %s]: %s\n",
105 smb_fname_str_dbg(smb_fname),
106 inherit_from_dir, nt_errstr(status)));
107 return(0);
110 if (SMB_VFS_STAT(conn, smb_fname_parent) != 0) {
111 DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n",
112 smb_fname_str_dbg(smb_fname),
113 inherit_from_dir, strerror(errno)));
114 TALLOC_FREE(smb_fname_parent);
115 return(0); /* *** shouldn't happen! *** */
118 /* Save for later - but explicitly remove setuid bit for safety. */
119 dir_mode = smb_fname_parent->st.st_ex_mode & ~S_ISUID;
120 DEBUG(2,("unix_mode(%s) inherit mode %o\n",
121 smb_fname_str_dbg(smb_fname), (int)dir_mode));
122 /* Clear "result" */
123 result = 0;
124 TALLOC_FREE(smb_fname_parent);
127 if (IS_DOS_DIR(dosmode)) {
128 /* We never make directories read only for the owner as under DOS a user
129 can always create a file in a read-only directory. */
130 result |= (S_IFDIR | S_IWUSR);
132 if (dir_mode) {
133 /* Inherit mode of parent directory. */
134 result |= dir_mode;
135 } else {
136 /* Provisionally add all 'x' bits */
137 result |= (S_IXUSR | S_IXGRP | S_IXOTH);
139 /* Apply directory mask */
140 result &= lp_dir_mask(SNUM(conn));
141 /* Add in force bits */
142 result |= lp_force_dir_mode(SNUM(conn));
144 } else {
145 if (lp_map_archive(SNUM(conn)) && IS_DOS_ARCHIVE(dosmode))
146 result |= S_IXUSR;
148 if (lp_map_system(SNUM(conn)) && IS_DOS_SYSTEM(dosmode))
149 result |= S_IXGRP;
151 if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode))
152 result |= S_IXOTH;
154 if (dir_mode) {
155 /* Inherit 666 component of parent directory mode */
156 result |= dir_mode & (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
157 } else {
158 /* Apply mode mask */
159 result &= lp_create_mask(SNUM(conn));
160 /* Add in force bits */
161 result |= lp_force_create_mode(SNUM(conn));
165 DEBUG(3,("unix_mode(%s) returning 0%o\n", smb_fname_str_dbg(smb_fname),
166 (int)result));
167 return(result);
170 /****************************************************************************
171 Change a unix mode to a dos mode.
172 ****************************************************************************/
174 static uint32 dos_mode_from_sbuf(connection_struct *conn,
175 const struct smb_filename *smb_fname)
177 int result = 0;
178 enum mapreadonly_options ro_opts = (enum mapreadonly_options)lp_map_readonly(SNUM(conn));
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 |= aRONLY;
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 |= aRONLY;
190 } /* Else never set the readonly bit. */
192 if (MAP_ARCHIVE(conn) && ((smb_fname->st.st_ex_mode & S_IXUSR) != 0))
193 result |= aARCH;
195 if (MAP_SYSTEM(conn) && ((smb_fname->st.st_ex_mode & S_IXGRP) != 0))
196 result |= aSYSTEM;
198 if (MAP_HIDDEN(conn) && ((smb_fname->st.st_ex_mode & S_IXOTH) != 0))
199 result |= aHIDDEN;
201 if (S_ISDIR(smb_fname->st.st_ex_mode))
202 result = aDIR | (result & aRONLY);
204 result |= set_sparse_flag(&smb_fname->st);
205 result |= set_link_read_only_flag(&smb_fname->st);
207 DEBUG(8,("dos_mode_from_sbuf returning "));
209 if (result & aHIDDEN) DEBUG(8, ("h"));
210 if (result & aRONLY ) DEBUG(8, ("r"));
211 if (result & aSYSTEM) DEBUG(8, ("s"));
212 if (result & aDIR ) DEBUG(8, ("d"));
213 if (result & aARCH ) DEBUG(8, ("a"));
215 DEBUG(8,("\n"));
216 return result;
219 /****************************************************************************
220 Get DOS attributes from an EA.
221 This can also pull the create time into the stat struct inside smb_fname.
222 ****************************************************************************/
224 static bool get_ea_dos_attribute(connection_struct *conn,
225 struct smb_filename *smb_fname,
226 uint32 *pattr)
228 struct xattr_DOSATTRIB dosattrib;
229 enum ndr_err_code ndr_err;
230 DATA_BLOB blob;
231 ssize_t sizeret;
232 fstring attrstr;
233 uint32_t dosattr;
235 if (!lp_store_dos_attributes(SNUM(conn))) {
236 return False;
239 /* Don't reset pattr to zero as we may already have filename-based attributes we
240 need to preserve. */
242 sizeret = SMB_VFS_GETXATTR(conn, smb_fname->base_name,
243 SAMBA_XATTR_DOS_ATTRIB, attrstr,
244 sizeof(attrstr));
245 if (sizeret == -1) {
246 if (errno == ENOSYS
247 #if defined(ENOTSUP)
248 || errno == ENOTSUP) {
249 #else
251 #endif
252 DEBUG(1,("get_ea_dos_attributes: Cannot get attribute "
253 "from EA on file %s: Error = %s\n",
254 smb_fname_str_dbg(smb_fname),
255 strerror(errno)));
256 set_store_dos_attributes(SNUM(conn), False);
258 return False;
261 blob.data = (uint8_t *)attrstr;
262 blob.length = sizeret;
264 ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), NULL, &dosattrib,
265 (ndr_pull_flags_fn_t)ndr_pull_xattr_DOSATTRIB);
267 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
268 DEBUG(1,("get_ea_dos_attributes: bad ndr decode "
269 "from EA on file %s: Error = %s\n",
270 smb_fname_str_dbg(smb_fname),
271 ndr_errstr(ndr_err)));
272 return false;
275 DEBUG(10,("get_ea_dos_attribute: %s attr = %s\n",
276 smb_fname_str_dbg(smb_fname), dosattrib.attrib_hex));
278 switch (dosattrib.version) {
279 case 0xFFFF:
280 dosattr = dosattrib.info.compatinfoFFFF.attrib;
281 break;
282 case 1:
283 dosattr = dosattrib.info.info1.attrib;
284 if (!null_nttime(dosattrib.info.info1.create_time)) {
285 struct timespec create_time =
286 nt_time_to_unix_timespec(
287 &dosattrib.info.info1.create_time);
289 update_stat_ex_create_time(&smb_fname->st,
290 create_time);
292 DEBUG(10,("get_ea_dos_attributes: file %s case 1 "
293 "set btime %s\n",
294 smb_fname_str_dbg(smb_fname),
295 time_to_asc(convert_timespec_to_time_t(
296 create_time)) ));
298 break;
299 case 2:
300 dosattr = dosattrib.info.oldinfo2.attrib;
301 /* Don't know what flags to check for this case. */
302 break;
303 case 3:
304 dosattr = dosattrib.info.info3.attrib;
305 if ((dosattrib.info.info3.valid_flags & XATTR_DOSINFO_CREATE_TIME) &&
306 !null_nttime(dosattrib.info.info3.create_time)) {
307 struct timespec create_time =
308 nt_time_to_unix_timespec(
309 &dosattrib.info.info3.create_time);
311 update_stat_ex_create_time(&smb_fname->st,
312 create_time);
314 DEBUG(10,("get_ea_dos_attributes: file %s case 3 "
315 "set btime %s\n",
316 smb_fname_str_dbg(smb_fname),
317 time_to_asc(convert_timespec_to_time_t(
318 create_time)) ));
320 break;
321 default:
322 DEBUG(1,("get_ea_dos_attributes: Badly formed DOSATTRIB on "
323 "file %s - %s\n", smb_fname_str_dbg(smb_fname),
324 attrstr));
325 return false;
328 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
329 dosattr |= aDIR;
331 *pattr = (uint32)(dosattr & SAMBA_ATTRIBUTES_MASK);
333 DEBUG(8,("get_ea_dos_attribute returning (0x%x)", dosattr));
335 if (dosattr & aHIDDEN) DEBUG(8, ("h"));
336 if (dosattr & aRONLY ) DEBUG(8, ("r"));
337 if (dosattr & aSYSTEM) DEBUG(8, ("s"));
338 if (dosattr & aDIR ) DEBUG(8, ("d"));
339 if (dosattr & aARCH ) DEBUG(8, ("a"));
341 DEBUG(8,("\n"));
343 return True;
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,
353 uint32 dosmode)
355 struct xattr_DOSATTRIB dosattrib;
356 enum ndr_err_code ndr_err;
357 DATA_BLOB blob;
358 files_struct *fsp = NULL;
359 bool ret = false;
361 if (!lp_store_dos_attributes(SNUM(conn))) {
362 return False;
365 ZERO_STRUCT(dosattrib);
366 ZERO_STRUCT(blob);
368 dosattrib.version = 3;
369 dosattrib.info.info3.valid_flags = XATTR_DOSINFO_ATTRIB|
370 XATTR_DOSINFO_CREATE_TIME;
371 dosattrib.info.info3.attrib = dosmode;
372 unix_timespec_to_nt_time(&dosattrib.info.info3.create_time,
373 smb_fname->st.st_ex_btime);
375 ndr_err = ndr_push_struct_blob(
376 &blob, talloc_tos(), NULL, &dosattrib,
377 (ndr_push_flags_fn_t)ndr_push_xattr_DOSATTRIB);
379 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
380 DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n",
381 ndr_errstr(ndr_err)));
382 return false;
385 if (blob.data == NULL || blob.length == 0) {
386 return false;
389 if (SMB_VFS_SETXATTR(conn, smb_fname->base_name,
390 SAMBA_XATTR_DOS_ATTRIB, blob.data, blob.length,
391 0) == -1) {
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;
417 * We need to open the file with write access whilst
418 * still in our current user context. This ensures we
419 * are not violating security in doing the setxattr.
422 if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, smb_fname,
423 &fsp)))
424 return ret;
425 become_root();
426 if (SMB_VFS_SETXATTR(conn, smb_fname->base_name,
427 SAMBA_XATTR_DOS_ATTRIB, blob.data,
428 blob.length, 0) == 0) {
429 ret = true;
431 unbecome_root();
432 close_file_fchmod(NULL, fsp);
433 return ret;
435 DEBUG(10,("set_ea_dos_attribute: set EA 0x%x on file %s\n",
436 (unsigned int)dosmode,
437 smb_fname_str_dbg(smb_fname)));
438 return true;
441 /****************************************************************************
442 Change a unix mode to a dos mode for an ms dfs link.
443 ****************************************************************************/
445 uint32 dos_mode_msdfs(connection_struct *conn,
446 const struct smb_filename *smb_fname)
448 uint32 result = 0;
450 DEBUG(8,("dos_mode_msdfs: %s\n", smb_fname_str_dbg(smb_fname)));
452 if (!VALID_STAT(smb_fname->st)) {
453 return 0;
456 /* First do any modifications that depend on the path name. */
457 /* hide files with a name starting with a . */
458 if (lp_hide_dot_files(SNUM(conn))) {
459 const char *p = strrchr_m(smb_fname->base_name, '/');
460 if (p) {
461 p++;
462 } else {
463 p = smb_fname->base_name;
466 /* Only . and .. are not hidden. */
467 if (p[0] == '.' && !((p[1] == '\0') ||
468 (p[1] == '.' && p[2] == '\0'))) {
469 result |= aHIDDEN;
473 result |= dos_mode_from_sbuf(conn, smb_fname);
475 /* Optimization : Only call is_hidden_path if it's not already
476 hidden. */
477 if (!(result & aHIDDEN) &&
478 IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
479 result |= aHIDDEN;
482 if (result == 0) {
483 result = FILE_ATTRIBUTE_NORMAL;
486 result = filter_mode_by_protocol(result);
488 DEBUG(8,("dos_mode_msdfs returning "));
490 if (result & aHIDDEN) DEBUG(8, ("h"));
491 if (result & aRONLY ) DEBUG(8, ("r"));
492 if (result & aSYSTEM) DEBUG(8, ("s"));
493 if (result & aDIR ) DEBUG(8, ("d"));
494 if (result & aARCH ) DEBUG(8, ("a"));
495 if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
497 DEBUG(8,("\n"));
499 return(result);
502 #ifdef HAVE_STAT_DOS_FLAGS
503 /****************************************************************************
504 Convert dos attributes (FILE_ATTRIBUTE_*) to dos stat flags (UF_*)
505 ****************************************************************************/
507 int dos_attributes_to_stat_dos_flags(uint32_t dosmode)
509 uint32_t dos_stat_flags = 0;
511 if (dosmode & aARCH)
512 dos_stat_flags |= UF_DOS_ARCHIVE;
513 if (dosmode & aHIDDEN)
514 dos_stat_flags |= UF_DOS_HIDDEN;
515 if (dosmode & aRONLY)
516 dos_stat_flags |= UF_DOS_RO;
517 if (dosmode & aSYSTEM)
518 dos_stat_flags |= UF_DOS_SYSTEM;
519 if (dosmode & FILE_ATTRIBUTE_NONINDEXED)
520 dos_stat_flags |= UF_DOS_NOINDEX;
522 return dos_stat_flags;
525 /****************************************************************************
526 Gets DOS attributes, accessed via st_ex_flags in the stat struct.
527 ****************************************************************************/
529 static bool get_stat_dos_flags(connection_struct *conn,
530 const struct smb_filename *smb_fname,
531 uint32_t *dosmode)
533 SMB_ASSERT(VALID_STAT(smb_fname->st));
534 SMB_ASSERT(dosmode);
536 if (!lp_store_dos_attributes(SNUM(conn))) {
537 return false;
540 DEBUG(5, ("Getting stat dos attributes for %s.\n",
541 smb_fname_str_dbg(smb_fname)));
543 if (smb_fname->st.st_ex_flags & UF_DOS_ARCHIVE)
544 *dosmode |= aARCH;
545 if (smb_fname->st.st_ex_flags & UF_DOS_HIDDEN)
546 *dosmode |= aHIDDEN;
547 if (smb_fname->st.st_ex_flags & UF_DOS_RO)
548 *dosmode |= aRONLY;
549 if (smb_fname->st.st_ex_flags & UF_DOS_SYSTEM)
550 *dosmode |= aSYSTEM;
551 if (smb_fname->st.st_ex_flags & UF_DOS_NOINDEX)
552 *dosmode |= FILE_ATTRIBUTE_NONINDEXED;
553 if (S_ISDIR(smb_fname->st.st_ex_mode))
554 *dosmode |= aDIR;
556 *dosmode |= set_sparse_flag(&smb_fname->st);
557 *dosmode |= set_link_read_only_flag(&smb_fname->st);
559 return true;
562 /****************************************************************************
563 Sets DOS attributes, stored in st_ex_flags of the inode.
564 ****************************************************************************/
566 static bool set_stat_dos_flags(connection_struct *conn,
567 const struct smb_filename *smb_fname,
568 uint32_t dosmode,
569 bool *attributes_changed)
571 uint32_t new_flags = 0;
572 int error = 0;
574 SMB_ASSERT(VALID_STAT(smb_fname->st));
575 SMB_ASSERT(attributes_changed);
577 *attributes_changed = false;
579 if (!lp_store_dos_attributes(SNUM(conn))) {
580 return false;
583 DEBUG(5, ("Setting stat dos attributes for %s.\n",
584 smb_fname_str_dbg(smb_fname)));
586 new_flags = (smb_fname->st.st_ex_flags & ~UF_DOS_FLAGS) |
587 dos_attributes_to_stat_dos_flags(dosmode);
589 /* Return early if no flags changed. */
590 if (new_flags == smb_fname->st.st_ex_flags)
591 return true;
593 DEBUG(5, ("Setting stat dos attributes=0x%x, prev=0x%x\n", new_flags,
594 smb_fname->st.st_ex_flags));
596 /* Set new flags with chflags. */
597 error = SMB_VFS_CHFLAGS(conn, smb_fname->base_name, new_flags);
598 if (error) {
599 DEBUG(0, ("Failed setting new stat dos attributes (0x%x) on "
600 "file %s! errno=%d\n", new_flags,
601 smb_fname_str_dbg(smb_fname), errno));
602 return false;
605 *attributes_changed = true;
606 return true;
608 #endif /* HAVE_STAT_DOS_FLAGS */
610 /****************************************************************************
611 Change a unix mode to a dos mode.
612 May also read the create timespec into the stat struct in smb_fname
613 if "store dos attributes" is true.
614 ****************************************************************************/
616 uint32 dos_mode(connection_struct *conn, struct smb_filename *smb_fname)
618 uint32 result = 0;
619 bool offline, used_stat_dos_flags = false;
621 DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname)));
623 if (!VALID_STAT(smb_fname->st)) {
624 return 0;
627 /* First do any modifications that depend on the path name. */
628 /* hide files with a name starting with a . */
629 if (lp_hide_dot_files(SNUM(conn))) {
630 const char *p = strrchr_m(smb_fname->base_name,'/');
631 if (p) {
632 p++;
633 } else {
634 p = smb_fname->base_name;
637 /* Only . and .. are not hidden. */
638 if (p[0] == '.' && !((p[1] == '\0') ||
639 (p[1] == '.' && p[2] == '\0'))) {
640 result |= aHIDDEN;
644 #ifdef HAVE_STAT_DOS_FLAGS
645 used_stat_dos_flags = get_stat_dos_flags(conn, smb_fname, &result);
646 #endif
647 if (!used_stat_dos_flags) {
648 /* Get the DOS attributes from an EA by preference. */
649 if (get_ea_dos_attribute(conn, smb_fname, &result)) {
650 result |= set_sparse_flag(&smb_fname->st);
651 } else {
652 result |= dos_mode_from_sbuf(conn, smb_fname);
656 offline = SMB_VFS_IS_OFFLINE(conn, smb_fname->base_name, &smb_fname->st);
657 if (S_ISREG(smb_fname->st.st_ex_mode) && offline) {
658 result |= FILE_ATTRIBUTE_OFFLINE;
661 /* Optimization : Only call is_hidden_path if it's not already
662 hidden. */
663 if (!(result & aHIDDEN) &&
664 IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
665 result |= aHIDDEN;
668 if (result == 0) {
669 result = FILE_ATTRIBUTE_NORMAL;
672 result = filter_mode_by_protocol(result);
674 DEBUG(8,("dos_mode returning "));
676 if (result & aHIDDEN) DEBUG(8, ("h"));
677 if (result & aRONLY ) DEBUG(8, ("r"));
678 if (result & aSYSTEM) DEBUG(8, ("s"));
679 if (result & aDIR ) DEBUG(8, ("d"));
680 if (result & aARCH ) DEBUG(8, ("a"));
681 if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
683 DEBUG(8,("\n"));
685 return(result);
688 /*******************************************************************
689 chmod a file - but preserve some bits.
690 If "store dos attributes" is also set it will store the create time
691 from the stat struct in smb_fname (in NTTIME format) in the EA
692 attribute also.
693 ********************************************************************/
695 int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname,
696 uint32 dosmode, const char *parent_dir, bool newfile)
698 int mask=0;
699 mode_t tmp;
700 mode_t unixmode;
701 int ret = -1, lret = -1;
702 uint32_t old_mode;
703 struct timespec new_create_timespec;
705 /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
706 dosmode &= (SAMBA_ATTRIBUTES_MASK | FILE_ATTRIBUTE_OFFLINE);
708 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
709 dosmode, smb_fname_str_dbg(smb_fname)));
711 unixmode = smb_fname->st.st_ex_mode;
713 get_acl_group_bits(conn, smb_fname->base_name,
714 &smb_fname->st.st_ex_mode);
716 if (S_ISDIR(smb_fname->st.st_ex_mode))
717 dosmode |= aDIR;
718 else
719 dosmode &= ~aDIR;
721 new_create_timespec = smb_fname->st.st_ex_btime;
723 old_mode = dos_mode(conn, smb_fname);
725 if (dosmode & FILE_ATTRIBUTE_OFFLINE) {
726 if (!(old_mode & FILE_ATTRIBUTE_OFFLINE)) {
727 lret = SMB_VFS_SET_OFFLINE(conn, smb_fname->base_name);
728 if (lret == -1) {
729 DEBUG(0, ("set_dos_mode: client has asked to "
730 "set FILE_ATTRIBUTE_OFFLINE to "
731 "%s/%s but there was an error while "
732 "setting it or it is not "
733 "supported.\n", parent_dir,
734 smb_fname_str_dbg(smb_fname)));
739 dosmode &= ~FILE_ATTRIBUTE_OFFLINE;
740 old_mode &= ~FILE_ATTRIBUTE_OFFLINE;
742 if (old_mode == dosmode &&
743 (timespec_compare(&new_create_timespec,
744 &smb_fname->st.st_ex_btime) == 0)) {
745 smb_fname->st.st_ex_mode = unixmode;
746 return(0);
749 smb_fname->st.st_ex_btime = new_create_timespec;
751 #ifdef HAVE_STAT_DOS_FLAGS
753 bool attributes_changed;
755 if (set_stat_dos_flags(conn, smb_fname, dosmode,
756 &attributes_changed))
758 if (!newfile && attributes_changed) {
759 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
760 FILE_NOTIFY_CHANGE_ATTRIBUTES,
761 smb_fname->base_name);
763 smb_fname->st.st_ex_mode = unixmode;
764 return 0;
767 #endif
768 /* Store the DOS attributes in an EA by preference. */
769 if (set_ea_dos_attribute(conn, smb_fname, dosmode)) {
770 if (!newfile) {
771 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
772 FILE_NOTIFY_CHANGE_ATTRIBUTES,
773 smb_fname->base_name);
775 smb_fname->st.st_ex_mode = unixmode;
776 return 0;
779 unixmode = unix_mode(conn, dosmode, smb_fname, parent_dir);
781 /* preserve the s bits */
782 mask |= (S_ISUID | S_ISGID);
784 /* preserve the t bit */
785 #ifdef S_ISVTX
786 mask |= S_ISVTX;
787 #endif
789 /* possibly preserve the x bits */
790 if (!MAP_ARCHIVE(conn))
791 mask |= S_IXUSR;
792 if (!MAP_SYSTEM(conn))
793 mask |= S_IXGRP;
794 if (!MAP_HIDDEN(conn))
795 mask |= S_IXOTH;
797 unixmode |= (smb_fname->st.st_ex_mode & mask);
799 /* if we previously had any r bits set then leave them alone */
800 if ((tmp = smb_fname->st.st_ex_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
801 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
802 unixmode |= tmp;
805 /* if we previously had any w bits set then leave them alone
806 whilst adding in the new w bits, if the new mode is not rdonly */
807 if (!IS_DOS_READONLY(dosmode)) {
808 unixmode |= (smb_fname->st.st_ex_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
811 ret = SMB_VFS_CHMOD(conn, smb_fname->base_name, unixmode);
812 if (ret == 0) {
813 if(!newfile || (lret != -1)) {
814 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
815 FILE_NOTIFY_CHANGE_ATTRIBUTES,
816 smb_fname->base_name);
818 smb_fname->st.st_ex_mode = unixmode;
819 return 0;
822 if((errno != EPERM) && (errno != EACCES))
823 return -1;
825 if(!lp_dos_filemode(SNUM(conn)))
826 return -1;
828 /* We want DOS semantics, ie allow non owner with write permission to change the
829 bits on a file. Just like file_ntimes below.
832 /* Check if we have write access. */
833 if (CAN_WRITE(conn)) {
835 * We need to open the file with write access whilst
836 * still in our current user context. This ensures we
837 * are not violating security in doing the fchmod.
838 * This file open does *not* break any oplocks we are
839 * holding. We need to review this.... may need to
840 * break batch oplocks open by others. JRA.
842 files_struct *fsp;
843 if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, smb_fname,
844 &fsp)))
845 return -1;
846 become_root();
847 ret = SMB_VFS_FCHMOD(fsp, unixmode);
848 unbecome_root();
849 close_file_fchmod(NULL, fsp);
850 if (!newfile) {
851 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
852 FILE_NOTIFY_CHANGE_ATTRIBUTES,
853 smb_fname->base_name);
855 if (ret == 0) {
856 smb_fname->st.st_ex_mode = unixmode;
860 return( ret );
863 /*******************************************************************
864 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
865 than POSIX.
866 *******************************************************************/
868 int file_ntimes(connection_struct *conn, const struct smb_filename *smb_fname,
869 struct smb_file_time *ft)
871 int ret = -1;
873 errno = 0;
875 DEBUG(6, ("file_ntime: actime: %s",
876 time_to_asc(convert_timespec_to_time_t(ft->atime))));
877 DEBUG(6, ("file_ntime: modtime: %s",
878 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
879 DEBUG(6, ("file_ntime: ctime: %s",
880 time_to_asc(convert_timespec_to_time_t(ft->ctime))));
881 DEBUG(6, ("file_ntime: createtime: %s",
882 time_to_asc(convert_timespec_to_time_t(ft->create_time))));
884 /* Don't update the time on read-only shares */
885 /* We need this as set_filetime (which can be called on
886 close and other paths) can end up calling this function
887 without the NEED_WRITE protection. Found by :
888 Leo Weppelman <leo@wau.mis.ah.nl>
891 if (!CAN_WRITE(conn)) {
892 return 0;
895 if(SMB_VFS_NTIMES(conn, smb_fname, ft) == 0) {
896 return 0;
899 if((errno != EPERM) && (errno != EACCES)) {
900 return -1;
903 if(!lp_dos_filetimes(SNUM(conn))) {
904 return -1;
907 /* We have permission (given by the Samba admin) to
908 break POSIX semantics and allow a user to change
909 the time on a file they don't own but can write to
910 (as DOS does).
913 /* Check if we have write access. */
914 if (can_write_to_file(conn, smb_fname)) {
915 /* We are allowed to become root and change the filetime. */
916 become_root();
917 ret = SMB_VFS_NTIMES(conn, smb_fname, ft);
918 unbecome_root();
921 return ret;
924 /******************************************************************
925 Force a "sticky" write time on a pathname. This will always be
926 returned on all future write time queries and set on close.
927 ******************************************************************/
929 bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime)
931 if (null_timespec(mtime)) {
932 return true;
935 if (!set_sticky_write_time(fileid, mtime)) {
936 return false;
939 return true;
942 /******************************************************************
943 Force a "sticky" write time on an fsp. This will always be
944 returned on all future write time queries and set on close.
945 ******************************************************************/
947 bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime)
949 if (null_timespec(mtime)) {
950 return true;
953 fsp->write_time_forced = true;
954 TALLOC_FREE(fsp->update_write_time_event);
956 return set_sticky_write_time_path(fsp->file_id, mtime);
959 /******************************************************************
960 Set a create time EA.
961 ******************************************************************/
963 NTSTATUS set_create_timespec_ea(connection_struct *conn,
964 const struct smb_filename *psmb_fname,
965 struct timespec create_time)
967 NTSTATUS status;
968 struct smb_filename *smb_fname = NULL;
969 uint32_t dosmode;
970 int ret;
972 if (!lp_store_dos_attributes(SNUM(conn))) {
973 return NT_STATUS_OK;
976 status = create_synthetic_smb_fname(talloc_tos(),
977 psmb_fname->base_name,
978 NULL, &psmb_fname->st,
979 &smb_fname);
981 if (!NT_STATUS_IS_OK(status)) {
982 return status;
985 dosmode = dos_mode(conn, smb_fname);
987 smb_fname->st.st_ex_btime = create_time;
989 ret = file_set_dosmode(conn, smb_fname, dosmode, NULL, false);
990 if (ret == -1) {
991 map_nt_error_from_unix(errno);
994 DEBUG(10,("set_create_timespec_ea: wrote create time EA for file %s\n",
995 smb_fname_str_dbg(smb_fname)));
997 return NT_STATUS_OK;
1000 /******************************************************************
1001 Return a create time.
1002 ******************************************************************/
1004 struct timespec get_create_timespec(connection_struct *conn,
1005 struct files_struct *fsp,
1006 const struct smb_filename *smb_fname)
1008 return smb_fname->st.st_ex_btime;
1011 /******************************************************************
1012 Return a change time (may look at EA in future).
1013 ******************************************************************/
1015 struct timespec get_change_timespec(connection_struct *conn,
1016 struct files_struct *fsp,
1017 const struct smb_filename *smb_fname)
1019 return smb_fname->st.st_ex_mtime;