negoex.idl: use DATA_BLOB for negoex_BYTE_VECTOR
[Samba.git] / source3 / smbd / dosmode.c
blob099600793203b4de978fde039cc21a5c4c258226
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 "librpc/gen_ndr/ioctl.h"
25 #include "../libcli/security/security.h"
26 #include "smbd/smbd.h"
27 #include "lib/param/loadparm.h"
29 static NTSTATUS get_file_handle_for_metadata(connection_struct *conn,
30 struct smb_filename *smb_fname,
31 files_struct **ret_fsp,
32 bool *need_close);
34 static void dos_mode_debug_print(const char *func, uint32_t mode)
36 fstring modestr;
38 if (DEBUGLEVEL < DBGLVL_INFO) {
39 return;
42 modestr[0] = '\0';
44 if (mode & FILE_ATTRIBUTE_HIDDEN) {
45 fstrcat(modestr, "h");
47 if (mode & FILE_ATTRIBUTE_READONLY) {
48 fstrcat(modestr, "r");
50 if (mode & FILE_ATTRIBUTE_SYSTEM) {
51 fstrcat(modestr, "s");
53 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
54 fstrcat(modestr, "d");
56 if (mode & FILE_ATTRIBUTE_ARCHIVE) {
57 fstrcat(modestr, "a");
59 if (mode & FILE_ATTRIBUTE_SPARSE) {
60 fstrcat(modestr, "[sparse]");
62 if (mode & FILE_ATTRIBUTE_OFFLINE) {
63 fstrcat(modestr, "[offline]");
65 if (mode & FILE_ATTRIBUTE_COMPRESSED) {
66 fstrcat(modestr, "[compressed]");
69 DBG_INFO("%s returning (0x%x): \"%s\"\n", func, (unsigned)mode,
70 modestr);
73 static uint32_t filter_mode_by_protocol(uint32_t mode)
75 if (get_Protocol() <= PROTOCOL_LANMAN2) {
76 DEBUG(10,("filter_mode_by_protocol: "
77 "filtering result 0x%x to 0x%x\n",
78 (unsigned int)mode,
79 (unsigned int)(mode & 0x3f) ));
80 mode &= 0x3f;
82 return mode;
85 static int set_link_read_only_flag(const SMB_STRUCT_STAT *const sbuf)
87 #ifdef S_ISLNK
88 #if LINKS_READ_ONLY
89 if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
90 return FILE_ATTRIBUTE_READONLY;
91 #endif
92 #endif
93 return 0;
96 /****************************************************************************
97 Change a dos mode to a unix mode.
98 Base permission for files:
99 if creating file and inheriting (i.e. parent_dir != NULL)
100 apply read/write bits from parent directory.
101 else
102 everybody gets read bit set
103 dos readonly is represented in unix by removing everyone's write bit
104 dos archive is represented in unix by the user's execute bit
105 dos system is represented in unix by the group's execute bit
106 dos hidden is represented in unix by the other's execute bit
107 if !inheriting {
108 Then apply create mask,
109 then add force bits.
111 Base permission for directories:
112 dos directory is represented in unix by unix's dir bit and the exec bit
113 if !inheriting {
114 Then apply create mask,
115 then add force bits.
117 ****************************************************************************/
119 mode_t unix_mode(connection_struct *conn, int dosmode,
120 const struct smb_filename *smb_fname,
121 const char *inherit_from_dir)
123 mode_t result = (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
124 mode_t dir_mode = 0; /* Mode of the inherit_from directory if
125 * inheriting. */
127 if (!lp_store_dos_attributes(SNUM(conn)) && IS_DOS_READONLY(dosmode)) {
128 result &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
131 if ((inherit_from_dir != NULL) && lp_inherit_permissions(SNUM(conn))) {
132 struct smb_filename *smb_fname_parent;
134 DEBUG(2, ("unix_mode(%s) inheriting from %s\n",
135 smb_fname_str_dbg(smb_fname),
136 inherit_from_dir));
138 smb_fname_parent = synthetic_smb_fname(
139 talloc_tos(), inherit_from_dir, NULL, NULL);
140 if (smb_fname_parent == NULL) {
141 DEBUG(1,("unix_mode(%s) failed, [dir %s]: No memory\n",
142 smb_fname_str_dbg(smb_fname),
143 inherit_from_dir));
144 return(0);
147 if (SMB_VFS_STAT(conn, smb_fname_parent) != 0) {
148 DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n",
149 smb_fname_str_dbg(smb_fname),
150 inherit_from_dir, strerror(errno)));
151 TALLOC_FREE(smb_fname_parent);
152 return(0); /* *** shouldn't happen! *** */
155 /* Save for later - but explicitly remove setuid bit for safety. */
156 dir_mode = smb_fname_parent->st.st_ex_mode & ~S_ISUID;
157 DEBUG(2,("unix_mode(%s) inherit mode %o\n",
158 smb_fname_str_dbg(smb_fname), (int)dir_mode));
159 /* Clear "result" */
160 result = 0;
161 TALLOC_FREE(smb_fname_parent);
164 if (IS_DOS_DIR(dosmode)) {
165 /* We never make directories read only for the owner as under DOS a user
166 can always create a file in a read-only directory. */
167 result |= (S_IFDIR | S_IWUSR);
169 if (dir_mode) {
170 /* Inherit mode of parent directory. */
171 result |= dir_mode;
172 } else {
173 /* Provisionally add all 'x' bits */
174 result |= (S_IXUSR | S_IXGRP | S_IXOTH);
176 /* Apply directory mask */
177 result &= lp_directory_mask(SNUM(conn));
178 /* Add in force bits */
179 result |= lp_force_directory_mode(SNUM(conn));
181 } else {
182 if (lp_map_archive(SNUM(conn)) && IS_DOS_ARCHIVE(dosmode))
183 result |= S_IXUSR;
185 if (lp_map_system(SNUM(conn)) && IS_DOS_SYSTEM(dosmode))
186 result |= S_IXGRP;
188 if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode))
189 result |= S_IXOTH;
191 if (dir_mode) {
192 /* Inherit 666 component of parent directory mode */
193 result |= dir_mode & (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
194 } else {
195 /* Apply mode mask */
196 result &= lp_create_mask(SNUM(conn));
197 /* Add in force bits */
198 result |= lp_force_create_mode(SNUM(conn));
202 DBG_INFO("unix_mode(%s) returning 0%o\n",
203 smb_fname_str_dbg(smb_fname), (int)result);
205 return(result);
208 /****************************************************************************
209 Change a unix mode to a dos mode.
210 ****************************************************************************/
212 static uint32_t dos_mode_from_sbuf(connection_struct *conn,
213 const struct smb_filename *smb_fname)
215 int result = 0;
216 enum mapreadonly_options ro_opts = (enum mapreadonly_options)lp_map_readonly(SNUM(conn));
218 #if defined(UF_IMMUTABLE) && defined(SF_IMMUTABLE)
219 /* if we can find out if a file is immutable we should report it r/o */
220 if (smb_fname->st.st_ex_flags & (UF_IMMUTABLE | SF_IMMUTABLE)) {
221 result |= FILE_ATTRIBUTE_READONLY;
223 #endif
224 if (ro_opts == MAP_READONLY_YES) {
225 /* Original Samba method - map inverse of user "w" bit. */
226 if ((smb_fname->st.st_ex_mode & S_IWUSR) == 0) {
227 result |= FILE_ATTRIBUTE_READONLY;
229 } else if (ro_opts == MAP_READONLY_PERMISSIONS) {
230 /* Check actual permissions for read-only. */
231 if (!can_write_to_file(conn, smb_fname)) {
232 result |= FILE_ATTRIBUTE_READONLY;
234 } /* Else never set the readonly bit. */
236 if (MAP_ARCHIVE(conn) && ((smb_fname->st.st_ex_mode & S_IXUSR) != 0))
237 result |= FILE_ATTRIBUTE_ARCHIVE;
239 if (MAP_SYSTEM(conn) && ((smb_fname->st.st_ex_mode & S_IXGRP) != 0))
240 result |= FILE_ATTRIBUTE_SYSTEM;
242 if (MAP_HIDDEN(conn) && ((smb_fname->st.st_ex_mode & S_IXOTH) != 0))
243 result |= FILE_ATTRIBUTE_HIDDEN;
245 if (S_ISDIR(smb_fname->st.st_ex_mode))
246 result = FILE_ATTRIBUTE_DIRECTORY | (result & FILE_ATTRIBUTE_READONLY);
248 result |= set_link_read_only_flag(&smb_fname->st);
250 dos_mode_debug_print(__func__, result);
252 return result;
255 /****************************************************************************
256 Get DOS attributes from an EA.
257 This can also pull the create time into the stat struct inside smb_fname.
258 ****************************************************************************/
260 static bool get_ea_dos_attribute(connection_struct *conn,
261 struct smb_filename *smb_fname,
262 uint32_t *pattr)
264 struct xattr_DOSATTRIB dosattrib;
265 enum ndr_err_code ndr_err;
266 DATA_BLOB blob;
267 ssize_t sizeret;
268 fstring attrstr;
269 uint32_t dosattr;
271 if (!lp_store_dos_attributes(SNUM(conn))) {
272 return False;
275 /* Don't reset pattr to zero as we may already have filename-based attributes we
276 need to preserve. */
278 sizeret = SMB_VFS_GETXATTR(conn, smb_fname->base_name,
279 SAMBA_XATTR_DOS_ATTRIB, attrstr,
280 sizeof(attrstr));
281 if (sizeret == -1) {
282 if (errno == ENOSYS
283 #if defined(ENOTSUP)
284 || errno == ENOTSUP) {
285 #else
287 #endif
288 DEBUG(1,("get_ea_dos_attribute: Cannot get attribute "
289 "from EA on file %s: Error = %s\n",
290 smb_fname_str_dbg(smb_fname),
291 strerror(errno)));
292 set_store_dos_attributes(SNUM(conn), False);
294 return False;
297 blob.data = (uint8_t *)attrstr;
298 blob.length = sizeret;
300 ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &dosattrib,
301 (ndr_pull_flags_fn_t)ndr_pull_xattr_DOSATTRIB);
303 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
304 DEBUG(1,("get_ea_dos_attribute: bad ndr decode "
305 "from EA on file %s: Error = %s\n",
306 smb_fname_str_dbg(smb_fname),
307 ndr_errstr(ndr_err)));
308 return false;
311 DEBUG(10,("get_ea_dos_attribute: %s attr = %s\n",
312 smb_fname_str_dbg(smb_fname), dosattrib.attrib_hex));
314 switch (dosattrib.version) {
315 case 0xFFFF:
316 dosattr = dosattrib.info.compatinfoFFFF.attrib;
317 break;
318 case 1:
319 dosattr = dosattrib.info.info1.attrib;
320 if (!null_nttime(dosattrib.info.info1.create_time)) {
321 struct timespec create_time =
322 nt_time_to_unix_timespec(
323 dosattrib.info.info1.create_time);
325 update_stat_ex_create_time(&smb_fname->st,
326 create_time);
328 DEBUG(10,("get_ea_dos_attribute: file %s case 1 "
329 "set btime %s\n",
330 smb_fname_str_dbg(smb_fname),
331 time_to_asc(convert_timespec_to_time_t(
332 create_time)) ));
334 break;
335 case 2:
336 dosattr = dosattrib.info.oldinfo2.attrib;
337 /* Don't know what flags to check for this case. */
338 break;
339 case 3:
340 dosattr = dosattrib.info.info3.attrib;
341 if ((dosattrib.info.info3.valid_flags & XATTR_DOSINFO_CREATE_TIME) &&
342 !null_nttime(dosattrib.info.info3.create_time)) {
343 struct timespec create_time =
344 nt_time_to_unix_timespec(
345 dosattrib.info.info3.create_time);
347 update_stat_ex_create_time(&smb_fname->st,
348 create_time);
350 DEBUG(10,("get_ea_dos_attribute: file %s case 3 "
351 "set btime %s\n",
352 smb_fname_str_dbg(smb_fname),
353 time_to_asc(convert_timespec_to_time_t(
354 create_time)) ));
356 break;
357 default:
358 DEBUG(1,("get_ea_dos_attribute: Badly formed DOSATTRIB on "
359 "file %s - %s\n", smb_fname_str_dbg(smb_fname),
360 attrstr));
361 return false;
364 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
365 dosattr |= FILE_ATTRIBUTE_DIRECTORY;
367 /* FILE_ATTRIBUTE_SPARSE is valid on get but not on set. */
368 *pattr |= (uint32_t)(dosattr & (SAMBA_ATTRIBUTES_MASK|FILE_ATTRIBUTE_SPARSE));
370 dos_mode_debug_print(__func__, *pattr);
372 return True;
375 /****************************************************************************
376 Set DOS attributes in an EA.
377 Also sets the create time.
378 ****************************************************************************/
380 static bool set_ea_dos_attribute(connection_struct *conn,
381 struct smb_filename *smb_fname,
382 uint32_t dosmode)
384 struct xattr_DOSATTRIB dosattrib;
385 enum ndr_err_code ndr_err;
386 DATA_BLOB blob;
388 ZERO_STRUCT(dosattrib);
389 ZERO_STRUCT(blob);
391 dosattrib.version = 3;
392 dosattrib.info.info3.valid_flags = XATTR_DOSINFO_ATTRIB|
393 XATTR_DOSINFO_CREATE_TIME;
394 dosattrib.info.info3.attrib = dosmode;
395 dosattrib.info.info3.create_time = unix_timespec_to_nt_time(
396 smb_fname->st.st_ex_btime);
398 DEBUG(10,("set_ea_dos_attributes: set attribute 0x%x, btime = %s on file %s\n",
399 (unsigned int)dosmode,
400 time_to_asc(convert_timespec_to_time_t(smb_fname->st.st_ex_btime)),
401 smb_fname_str_dbg(smb_fname) ));
403 ndr_err = ndr_push_struct_blob(
404 &blob, talloc_tos(), &dosattrib,
405 (ndr_push_flags_fn_t)ndr_push_xattr_DOSATTRIB);
407 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
408 DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n",
409 ndr_errstr(ndr_err)));
410 return false;
413 if (blob.data == NULL || blob.length == 0) {
414 return false;
417 if (SMB_VFS_SETXATTR(conn, smb_fname->base_name,
418 SAMBA_XATTR_DOS_ATTRIB, blob.data, blob.length,
419 0) == -1) {
420 bool ret = false;
421 bool need_close = false;
422 files_struct *fsp = NULL;
424 if((errno != EPERM) && (errno != EACCES)) {
425 if (errno == ENOSYS
426 #if defined(ENOTSUP)
427 || errno == ENOTSUP) {
428 #else
430 #endif
431 DEBUG(1,("set_ea_dos_attributes: Cannot set "
432 "attribute EA on file %s: Error = %s\n",
433 smb_fname_str_dbg(smb_fname),
434 strerror(errno) ));
435 set_store_dos_attributes(SNUM(conn), False);
437 return false;
440 /* We want DOS semantics, ie allow non owner with write permission to change the
441 bits on a file. Just like file_ntimes below.
444 /* Check if we have write access. */
445 if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
446 return false;
448 if (!can_write_to_file(conn, smb_fname)) {
449 return false;
453 * We need to get an open file handle to do the
454 * metadata operation under root.
457 if (!NT_STATUS_IS_OK(get_file_handle_for_metadata(conn,
458 smb_fname,
459 &fsp,
460 &need_close))) {
461 return false;
464 become_root();
465 if (SMB_VFS_FSETXATTR(fsp,
466 SAMBA_XATTR_DOS_ATTRIB, blob.data,
467 blob.length, 0) == 0) {
468 ret = true;
470 unbecome_root();
471 if (need_close) {
472 close_file(NULL, fsp, NORMAL_CLOSE);
474 return ret;
476 DEBUG(10,("set_ea_dos_attribute: set EA 0x%x on file %s\n",
477 (unsigned int)dosmode,
478 smb_fname_str_dbg(smb_fname)));
479 return true;
482 /****************************************************************************
483 Change a unix mode to a dos mode for an ms dfs link.
484 ****************************************************************************/
486 uint32_t dos_mode_msdfs(connection_struct *conn,
487 const struct smb_filename *smb_fname)
489 uint32_t result = 0;
491 DEBUG(8,("dos_mode_msdfs: %s\n", smb_fname_str_dbg(smb_fname)));
493 if (!VALID_STAT(smb_fname->st)) {
494 return 0;
497 /* First do any modifications that depend on the path name. */
498 /* hide files with a name starting with a . */
499 if (lp_hide_dot_files(SNUM(conn))) {
500 const char *p = strrchr_m(smb_fname->base_name, '/');
501 if (p) {
502 p++;
503 } else {
504 p = smb_fname->base_name;
507 /* Only . and .. are not hidden. */
508 if (p[0] == '.' && !((p[1] == '\0') ||
509 (p[1] == '.' && p[2] == '\0'))) {
510 result |= FILE_ATTRIBUTE_HIDDEN;
514 result |= dos_mode_from_sbuf(conn, smb_fname);
516 /* Optimization : Only call is_hidden_path if it's not already
517 hidden. */
518 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
519 IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
520 result |= FILE_ATTRIBUTE_HIDDEN;
523 if (result == 0) {
524 result = FILE_ATTRIBUTE_NORMAL;
527 result = filter_mode_by_protocol(result);
530 * Add in that it is a reparse point
532 result |= FILE_ATTRIBUTE_REPARSE_POINT;
534 dos_mode_debug_print(__func__, result);
536 return(result);
540 * check whether a file or directory is flagged as compressed.
542 static NTSTATUS dos_mode_check_compressed(connection_struct *conn,
543 struct smb_filename *smb_fname,
544 bool *is_compressed)
546 NTSTATUS status;
547 uint16_t compression_fmt;
548 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
549 if (tmp_ctx == NULL) {
550 status = NT_STATUS_NO_MEMORY;
551 goto err_out;
554 status = SMB_VFS_GET_COMPRESSION(conn, tmp_ctx, NULL, smb_fname,
555 &compression_fmt);
556 if (!NT_STATUS_IS_OK(status)) {
557 goto err_ctx_free;
560 if (compression_fmt == COMPRESSION_FORMAT_LZNT1) {
561 *is_compressed = true;
562 } else {
563 *is_compressed = false;
565 status = NT_STATUS_OK;
567 err_ctx_free:
568 talloc_free(tmp_ctx);
569 err_out:
570 return status;
573 /****************************************************************************
574 Change a unix mode to a dos mode.
575 May also read the create timespec into the stat struct in smb_fname
576 if "store dos attributes" is true.
577 ****************************************************************************/
579 uint32_t dos_mode(connection_struct *conn, struct smb_filename *smb_fname)
581 uint32_t result = 0;
582 bool offline;
584 DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname)));
586 if (!VALID_STAT(smb_fname->st)) {
587 return 0;
590 /* First do any modifications that depend on the path name. */
591 /* hide files with a name starting with a . */
592 if (lp_hide_dot_files(SNUM(conn))) {
593 const char *p = strrchr_m(smb_fname->base_name,'/');
594 if (p) {
595 p++;
596 } else {
597 p = smb_fname->base_name;
600 /* Only . and .. are not hidden. */
601 if (p[0] == '.' && !((p[1] == '\0') ||
602 (p[1] == '.' && p[2] == '\0'))) {
603 result |= FILE_ATTRIBUTE_HIDDEN;
607 /* Get the DOS attributes from an EA by preference. */
608 if (!get_ea_dos_attribute(conn, smb_fname, &result)) {
609 result |= dos_mode_from_sbuf(conn, smb_fname);
612 offline = SMB_VFS_IS_OFFLINE(conn, smb_fname, &smb_fname->st);
613 if (S_ISREG(smb_fname->st.st_ex_mode) && offline) {
614 result |= FILE_ATTRIBUTE_OFFLINE;
617 if (conn->fs_capabilities & FILE_FILE_COMPRESSION) {
618 bool compressed = false;
619 NTSTATUS status = dos_mode_check_compressed(conn, smb_fname,
620 &compressed);
621 if (NT_STATUS_IS_OK(status) && compressed) {
622 result |= FILE_ATTRIBUTE_COMPRESSED;
626 /* Optimization : Only call is_hidden_path if it's not already
627 hidden. */
628 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
629 IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
630 result |= FILE_ATTRIBUTE_HIDDEN;
633 if (result == 0) {
634 result = FILE_ATTRIBUTE_NORMAL;
637 result = filter_mode_by_protocol(result);
639 dos_mode_debug_print(__func__, result);
641 return result;
644 /*******************************************************************
645 chmod a file - but preserve some bits.
646 If "store dos attributes" is also set it will store the create time
647 from the stat struct in smb_fname (in NTTIME format) in the EA
648 attribute also.
649 ********************************************************************/
651 int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname,
652 uint32_t dosmode, const char *parent_dir, bool newfile)
654 int mask=0;
655 mode_t tmp;
656 mode_t unixmode;
657 int ret = -1, lret = -1;
658 uint32_t old_mode;
659 struct timespec new_create_timespec;
660 files_struct *fsp = NULL;
661 bool need_close = false;
662 NTSTATUS status;
664 if (!CAN_WRITE(conn)) {
665 errno = EROFS;
666 return -1;
669 /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
670 dosmode &= (SAMBA_ATTRIBUTES_MASK | FILE_ATTRIBUTE_OFFLINE);
672 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
673 dosmode, smb_fname_str_dbg(smb_fname)));
675 unixmode = smb_fname->st.st_ex_mode;
677 get_acl_group_bits(conn, smb_fname->base_name,
678 &smb_fname->st.st_ex_mode);
680 if (S_ISDIR(smb_fname->st.st_ex_mode))
681 dosmode |= FILE_ATTRIBUTE_DIRECTORY;
682 else
683 dosmode &= ~FILE_ATTRIBUTE_DIRECTORY;
685 new_create_timespec = smb_fname->st.st_ex_btime;
687 old_mode = dos_mode(conn, smb_fname);
689 if ((dosmode & FILE_ATTRIBUTE_OFFLINE) &&
690 !(old_mode & FILE_ATTRIBUTE_OFFLINE)) {
691 lret = SMB_VFS_SET_OFFLINE(conn, smb_fname);
692 if (lret == -1) {
693 if (errno == ENOTSUP) {
694 DEBUG(10, ("Setting FILE_ATTRIBUTE_OFFLINE for "
695 "%s/%s is not supported.\n",
696 parent_dir,
697 smb_fname_str_dbg(smb_fname)));
698 } else {
699 DEBUG(0, ("An error occurred while setting "
700 "FILE_ATTRIBUTE_OFFLINE for "
701 "%s/%s: %s", parent_dir,
702 smb_fname_str_dbg(smb_fname),
703 strerror(errno)));
708 dosmode &= ~FILE_ATTRIBUTE_OFFLINE;
709 old_mode &= ~FILE_ATTRIBUTE_OFFLINE;
711 smb_fname->st.st_ex_btime = new_create_timespec;
713 /* Store the DOS attributes in an EA by preference. */
714 if (lp_store_dos_attributes(SNUM(conn))) {
716 * Don't fall back to using UNIX modes. Finally
717 * follow the smb.conf manpage.
719 if (!set_ea_dos_attribute(conn, smb_fname, dosmode)) {
720 return -1;
722 if (!newfile) {
723 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
724 FILE_NOTIFY_CHANGE_ATTRIBUTES,
725 smb_fname->base_name);
727 smb_fname->st.st_ex_mode = unixmode;
728 return 0;
731 unixmode = unix_mode(conn, dosmode, smb_fname, parent_dir);
733 /* preserve the file type bits */
734 mask |= S_IFMT;
736 /* preserve the s bits */
737 mask |= (S_ISUID | S_ISGID);
739 /* preserve the t bit */
740 #ifdef S_ISVTX
741 mask |= S_ISVTX;
742 #endif
744 /* possibly preserve the x bits */
745 if (!MAP_ARCHIVE(conn))
746 mask |= S_IXUSR;
747 if (!MAP_SYSTEM(conn))
748 mask |= S_IXGRP;
749 if (!MAP_HIDDEN(conn))
750 mask |= S_IXOTH;
752 unixmode |= (smb_fname->st.st_ex_mode & mask);
754 /* if we previously had any r bits set then leave them alone */
755 if ((tmp = smb_fname->st.st_ex_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
756 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
757 unixmode |= tmp;
760 /* if we previously had any w bits set then leave them alone
761 whilst adding in the new w bits, if the new mode is not rdonly */
762 if (!IS_DOS_READONLY(dosmode)) {
763 unixmode |= (smb_fname->st.st_ex_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
767 * From the chmod 2 man page:
769 * "If the calling process is not privileged, and the group of the file
770 * does not match the effective group ID of the process or one of its
771 * supplementary group IDs, the S_ISGID bit will be turned off, but
772 * this will not cause an error to be returned."
774 * Simply refuse to do the chmod in this case.
777 if (S_ISDIR(smb_fname->st.st_ex_mode) && (unixmode & S_ISGID) &&
778 geteuid() != sec_initial_uid() &&
779 !current_user_in_group(conn, smb_fname->st.st_ex_gid)) {
780 DEBUG(3,("file_set_dosmode: setgid bit cannot be "
781 "set for directory %s\n",
782 smb_fname_str_dbg(smb_fname)));
783 errno = EPERM;
784 return -1;
787 ret = SMB_VFS_CHMOD(conn, smb_fname->base_name, unixmode);
788 if (ret == 0) {
789 if(!newfile || (lret != -1)) {
790 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
791 FILE_NOTIFY_CHANGE_ATTRIBUTES,
792 smb_fname->base_name);
794 smb_fname->st.st_ex_mode = unixmode;
795 return 0;
798 if((errno != EPERM) && (errno != EACCES))
799 return -1;
801 if(!lp_dos_filemode(SNUM(conn)))
802 return -1;
804 /* We want DOS semantics, ie allow non owner with write permission to change the
805 bits on a file. Just like file_ntimes below.
808 if (!can_write_to_file(conn, smb_fname)) {
809 errno = EACCES;
810 return -1;
814 * We need to get an open file handle to do the
815 * metadata operation under root.
818 status = get_file_handle_for_metadata(conn,
819 smb_fname,
820 &fsp,
821 &need_close);
822 if (!NT_STATUS_IS_OK(status)) {
823 errno = map_errno_from_nt_status(status);
824 return -1;
827 become_root();
828 ret = SMB_VFS_FCHMOD(fsp, unixmode);
829 unbecome_root();
830 if (need_close) {
831 close_file(NULL, fsp, NORMAL_CLOSE);
833 if (!newfile) {
834 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
835 FILE_NOTIFY_CHANGE_ATTRIBUTES,
836 smb_fname->base_name);
838 if (ret == 0) {
839 smb_fname->st.st_ex_mode = unixmode;
842 return( ret );
846 NTSTATUS file_set_sparse(connection_struct *conn,
847 files_struct *fsp,
848 bool sparse)
850 uint32_t old_dosmode;
851 uint32_t new_dosmode;
852 NTSTATUS status;
854 if (!CAN_WRITE(conn)) {
855 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
856 "on readonly share[%s]\n",
857 smb_fname_str_dbg(fsp->fsp_name),
858 sparse,
859 lp_servicename(talloc_tos(), SNUM(conn))));
860 return NT_STATUS_MEDIA_WRITE_PROTECTED;
864 * Windows Server 2008 & 2012 permit FSCTL_SET_SPARSE if any of the
865 * following access flags are granted.
867 if ((fsp->access_mask & (FILE_WRITE_DATA
868 | FILE_WRITE_ATTRIBUTES
869 | SEC_FILE_APPEND_DATA)) == 0) {
870 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
871 "access_mask[0x%08X] - access denied\n",
872 smb_fname_str_dbg(fsp->fsp_name),
873 sparse,
874 fsp->access_mask));
875 return NT_STATUS_ACCESS_DENIED;
878 if (fsp->is_directory) {
879 DEBUG(9, ("invalid attempt to %s sparse flag on dir %s\n",
880 (sparse ? "set" : "clear"),
881 smb_fname_str_dbg(fsp->fsp_name)));
882 return NT_STATUS_INVALID_PARAMETER;
885 if (IS_IPC(conn) || IS_PRINT(conn)) {
886 DEBUG(9, ("attempt to %s sparse flag over invalid conn\n",
887 (sparse ? "set" : "clear")));
888 return NT_STATUS_INVALID_PARAMETER;
891 DEBUG(10,("file_set_sparse: setting sparse bit %u on file %s\n",
892 sparse, smb_fname_str_dbg(fsp->fsp_name)));
894 if (!lp_store_dos_attributes(SNUM(conn))) {
895 return NT_STATUS_INVALID_DEVICE_REQUEST;
898 status = vfs_stat_fsp(fsp);
899 if (!NT_STATUS_IS_OK(status)) {
900 return status;
903 old_dosmode = dos_mode(conn, fsp->fsp_name);
905 if (sparse && !(old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
906 new_dosmode = old_dosmode | FILE_ATTRIBUTE_SPARSE;
907 } else if (!sparse && (old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
908 new_dosmode = old_dosmode & ~FILE_ATTRIBUTE_SPARSE;
909 } else {
910 return NT_STATUS_OK;
913 /* Store the DOS attributes in an EA. */
914 if (!set_ea_dos_attribute(conn, fsp->fsp_name,
915 new_dosmode)) {
916 if (errno == 0) {
917 errno = EIO;
919 return map_nt_error_from_unix(errno);
922 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
923 FILE_NOTIFY_CHANGE_ATTRIBUTES,
924 fsp->fsp_name->base_name);
926 fsp->is_sparse = sparse;
928 return NT_STATUS_OK;
931 /*******************************************************************
932 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
933 than POSIX.
934 *******************************************************************/
936 int file_ntimes(connection_struct *conn, const struct smb_filename *smb_fname,
937 struct smb_file_time *ft)
939 int ret = -1;
941 errno = 0;
943 DEBUG(6, ("file_ntime: actime: %s",
944 time_to_asc(convert_timespec_to_time_t(ft->atime))));
945 DEBUG(6, ("file_ntime: modtime: %s",
946 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
947 DEBUG(6, ("file_ntime: ctime: %s",
948 time_to_asc(convert_timespec_to_time_t(ft->ctime))));
949 DEBUG(6, ("file_ntime: createtime: %s",
950 time_to_asc(convert_timespec_to_time_t(ft->create_time))));
952 /* Don't update the time on read-only shares */
953 /* We need this as set_filetime (which can be called on
954 close and other paths) can end up calling this function
955 without the NEED_WRITE protection. Found by :
956 Leo Weppelman <leo@wau.mis.ah.nl>
959 if (!CAN_WRITE(conn)) {
960 return 0;
963 if(SMB_VFS_NTIMES(conn, smb_fname, ft) == 0) {
964 return 0;
967 if((errno != EPERM) && (errno != EACCES)) {
968 return -1;
971 if(!lp_dos_filetimes(SNUM(conn))) {
972 return -1;
975 /* We have permission (given by the Samba admin) to
976 break POSIX semantics and allow a user to change
977 the time on a file they don't own but can write to
978 (as DOS does).
981 /* Check if we have write access. */
982 if (can_write_to_file(conn, smb_fname)) {
983 /* We are allowed to become root and change the filetime. */
984 become_root();
985 ret = SMB_VFS_NTIMES(conn, smb_fname, ft);
986 unbecome_root();
989 return ret;
992 /******************************************************************
993 Force a "sticky" write time on a pathname. This will always be
994 returned on all future write time queries and set on close.
995 ******************************************************************/
997 bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime)
999 if (null_timespec(mtime)) {
1000 return true;
1003 if (!set_sticky_write_time(fileid, mtime)) {
1004 return false;
1007 return true;
1010 /******************************************************************
1011 Force a "sticky" write time on an fsp. This will always be
1012 returned on all future write time queries and set on close.
1013 ******************************************************************/
1015 bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime)
1017 if (null_timespec(mtime)) {
1018 return true;
1021 fsp->write_time_forced = true;
1022 TALLOC_FREE(fsp->update_write_time_event);
1024 return set_sticky_write_time_path(fsp->file_id, mtime);
1027 /******************************************************************
1028 Set a create time EA.
1029 ******************************************************************/
1031 NTSTATUS set_create_timespec_ea(connection_struct *conn,
1032 const struct smb_filename *psmb_fname,
1033 struct timespec create_time)
1035 struct smb_filename *smb_fname;
1036 uint32_t dosmode;
1037 int ret;
1039 if (!lp_store_dos_attributes(SNUM(conn))) {
1040 return NT_STATUS_OK;
1043 smb_fname = synthetic_smb_fname(talloc_tos(), psmb_fname->base_name,
1044 NULL, &psmb_fname->st);
1046 if (smb_fname == NULL) {
1047 return NT_STATUS_NO_MEMORY;
1050 dosmode = dos_mode(conn, smb_fname);
1052 smb_fname->st.st_ex_btime = create_time;
1054 ret = file_set_dosmode(conn, smb_fname, dosmode, NULL, false);
1055 if (ret == -1) {
1056 map_nt_error_from_unix(errno);
1059 DEBUG(10,("set_create_timespec_ea: wrote create time EA for file %s\n",
1060 smb_fname_str_dbg(smb_fname)));
1062 return NT_STATUS_OK;
1065 /******************************************************************
1066 Return a create time.
1067 ******************************************************************/
1069 struct timespec get_create_timespec(connection_struct *conn,
1070 struct files_struct *fsp,
1071 const struct smb_filename *smb_fname)
1073 return smb_fname->st.st_ex_btime;
1076 /******************************************************************
1077 Return a change time (may look at EA in future).
1078 ******************************************************************/
1080 struct timespec get_change_timespec(connection_struct *conn,
1081 struct files_struct *fsp,
1082 const struct smb_filename *smb_fname)
1084 return smb_fname->st.st_ex_mtime;
1087 /****************************************************************************
1088 Get a real open file handle we can do meta-data operations on. As it's
1089 going to be used under root access only on meta-data we should look for
1090 any existing open file handle first, and use that in preference (also to
1091 avoid kernel self-oplock breaks). If not use an INTERNAL_OPEN_ONLY handle.
1092 ****************************************************************************/
1094 static NTSTATUS get_file_handle_for_metadata(connection_struct *conn,
1095 struct smb_filename *smb_fname,
1096 files_struct **ret_fsp,
1097 bool *need_close)
1099 NTSTATUS status;
1100 files_struct *fsp;
1101 struct file_id file_id;
1103 *need_close = false;
1105 if (!VALID_STAT(smb_fname->st)) {
1106 return NT_STATUS_INVALID_PARAMETER;
1109 file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1111 for(fsp = file_find_di_first(conn->sconn, file_id);
1112 fsp;
1113 fsp = file_find_di_next(fsp)) {
1114 if (fsp->fh->fd != -1) {
1115 *ret_fsp = fsp;
1116 return NT_STATUS_OK;
1120 /* Opens an INTERNAL_OPEN_ONLY write handle. */
1121 status = SMB_VFS_CREATE_FILE(
1122 conn, /* conn */
1123 NULL, /* req */
1124 0, /* root_dir_fid */
1125 smb_fname, /* fname */
1126 FILE_WRITE_DATA, /* access_mask */
1127 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
1128 FILE_SHARE_DELETE),
1129 FILE_OPEN, /* create_disposition*/
1130 0, /* create_options */
1131 0, /* file_attributes */
1132 INTERNAL_OPEN_ONLY, /* oplock_request */
1133 NULL, /* lease */
1134 0, /* allocation_size */
1135 0, /* private_flags */
1136 NULL, /* sd */
1137 NULL, /* ea_list */
1138 ret_fsp, /* result */
1139 NULL, /* pinfo */
1140 NULL, NULL); /* create context */
1142 if (NT_STATUS_IS_OK(status)) {
1143 *need_close = true;
1145 return status;