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/>.
23 #include "system/filesys.h"
24 #include "librpc/gen_ndr/ndr_xattr.h"
25 #include "librpc/gen_ndr/ioctl.h"
26 #include "../libcli/security/security.h"
27 #include "smbd/smbd.h"
28 #include "lib/param/loadparm.h"
29 #include "lib/util/tevent_ntstatus.h"
31 static NTSTATUS get_file_handle_for_metadata(connection_struct *conn,
32 const struct smb_filename *smb_fname,
33 files_struct **ret_fsp,
36 static void dos_mode_debug_print(const char *func, uint32_t mode)
40 if (DEBUGLEVEL < DBGLVL_INFO) {
46 if (mode & FILE_ATTRIBUTE_HIDDEN) {
47 fstrcat(modestr, "h");
49 if (mode & FILE_ATTRIBUTE_READONLY) {
50 fstrcat(modestr, "r");
52 if (mode & FILE_ATTRIBUTE_SYSTEM) {
53 fstrcat(modestr, "s");
55 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
56 fstrcat(modestr, "d");
58 if (mode & FILE_ATTRIBUTE_ARCHIVE) {
59 fstrcat(modestr, "a");
61 if (mode & FILE_ATTRIBUTE_SPARSE) {
62 fstrcat(modestr, "[sparse]");
64 if (mode & FILE_ATTRIBUTE_OFFLINE) {
65 fstrcat(modestr, "[offline]");
67 if (mode & FILE_ATTRIBUTE_COMPRESSED) {
68 fstrcat(modestr, "[compressed]");
71 DBG_INFO("%s returning (0x%x): \"%s\"\n", func, (unsigned)mode,
75 static uint32_t filter_mode_by_protocol(uint32_t mode)
77 if (get_Protocol() <= PROTOCOL_LANMAN2) {
78 DEBUG(10,("filter_mode_by_protocol: "
79 "filtering result 0x%x to 0x%x\n",
81 (unsigned int)(mode & 0x3f) ));
87 static int set_link_read_only_flag(const SMB_STRUCT_STAT *const sbuf)
91 if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
92 return FILE_ATTRIBUTE_READONLY;
98 /****************************************************************************
99 Change a dos mode to a unix mode.
100 Base permission for files:
101 if creating file and inheriting (i.e. parent_dir != NULL)
102 apply read/write bits from parent directory.
104 everybody gets read bit set
105 dos readonly is represented in unix by removing everyone's write bit
106 dos archive is represented in unix by the user's execute bit
107 dos system is represented in unix by the group's execute bit
108 dos hidden is represented in unix by the other's execute bit
110 Then apply create mask,
113 Base permission for directories:
114 dos directory is represented in unix by unix's dir bit and the exec bit
116 Then apply create mask,
119 ****************************************************************************/
121 mode_t unix_mode(connection_struct *conn, int dosmode,
122 const struct smb_filename *smb_fname,
123 const char *inherit_from_dir)
125 mode_t result = (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
126 mode_t dir_mode = 0; /* Mode of the inherit_from directory if
129 if (!lp_store_dos_attributes(SNUM(conn)) && IS_DOS_READONLY(dosmode)) {
130 result &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
133 if ((inherit_from_dir != NULL) && lp_inherit_permissions(SNUM(conn))) {
134 struct smb_filename *smb_fname_parent;
136 DEBUG(2, ("unix_mode(%s) inheriting from %s\n",
137 smb_fname_str_dbg(smb_fname),
140 smb_fname_parent = synthetic_smb_fname(talloc_tos(),
145 if (smb_fname_parent == NULL) {
146 DEBUG(1,("unix_mode(%s) failed, [dir %s]: No memory\n",
147 smb_fname_str_dbg(smb_fname),
152 if (SMB_VFS_STAT(conn, smb_fname_parent) != 0) {
153 DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n",
154 smb_fname_str_dbg(smb_fname),
155 inherit_from_dir, strerror(errno)));
156 TALLOC_FREE(smb_fname_parent);
157 return(0); /* *** shouldn't happen! *** */
160 /* Save for later - but explicitly remove setuid bit for safety. */
161 dir_mode = smb_fname_parent->st.st_ex_mode & ~S_ISUID;
162 DEBUG(2,("unix_mode(%s) inherit mode %o\n",
163 smb_fname_str_dbg(smb_fname), (int)dir_mode));
166 TALLOC_FREE(smb_fname_parent);
169 if (IS_DOS_DIR(dosmode)) {
170 /* We never make directories read only for the owner as under DOS a user
171 can always create a file in a read-only directory. */
172 result |= (S_IFDIR | S_IWUSR);
175 /* Inherit mode of parent directory. */
178 /* Provisionally add all 'x' bits */
179 result |= (S_IXUSR | S_IXGRP | S_IXOTH);
181 /* Apply directory mask */
182 result &= lp_directory_mask(SNUM(conn));
183 /* Add in force bits */
184 result |= lp_force_directory_mode(SNUM(conn));
187 if (lp_map_archive(SNUM(conn)) && IS_DOS_ARCHIVE(dosmode))
190 if (lp_map_system(SNUM(conn)) && IS_DOS_SYSTEM(dosmode))
193 if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode))
197 /* Inherit 666 component of parent directory mode */
198 result |= dir_mode & (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
200 /* Apply mode mask */
201 result &= lp_create_mask(SNUM(conn));
202 /* Add in force bits */
203 result |= lp_force_create_mode(SNUM(conn));
207 DBG_INFO("unix_mode(%s) returning 0%o\n",
208 smb_fname_str_dbg(smb_fname), (int)result);
213 /****************************************************************************
214 Change a unix mode to a dos mode.
215 ****************************************************************************/
217 static uint32_t dos_mode_from_sbuf(connection_struct *conn,
218 const struct smb_filename *smb_fname)
221 enum mapreadonly_options ro_opts = (enum mapreadonly_options)lp_map_readonly(SNUM(conn));
223 #if defined(UF_IMMUTABLE) && defined(SF_IMMUTABLE)
224 /* if we can find out if a file is immutable we should report it r/o */
225 if (smb_fname->st.st_ex_flags & (UF_IMMUTABLE | SF_IMMUTABLE)) {
226 result |= FILE_ATTRIBUTE_READONLY;
229 if (ro_opts == MAP_READONLY_YES) {
230 /* Original Samba method - map inverse of user "w" bit. */
231 if ((smb_fname->st.st_ex_mode & S_IWUSR) == 0) {
232 result |= FILE_ATTRIBUTE_READONLY;
234 } else if (ro_opts == MAP_READONLY_PERMISSIONS) {
235 /* Check actual permissions for read-only. */
236 if (!can_write_to_file(conn, smb_fname)) {
237 result |= FILE_ATTRIBUTE_READONLY;
239 } /* Else never set the readonly bit. */
241 if (MAP_ARCHIVE(conn) && ((smb_fname->st.st_ex_mode & S_IXUSR) != 0))
242 result |= FILE_ATTRIBUTE_ARCHIVE;
244 if (MAP_SYSTEM(conn) && ((smb_fname->st.st_ex_mode & S_IXGRP) != 0))
245 result |= FILE_ATTRIBUTE_SYSTEM;
247 if (MAP_HIDDEN(conn) && ((smb_fname->st.st_ex_mode & S_IXOTH) != 0))
248 result |= FILE_ATTRIBUTE_HIDDEN;
250 if (S_ISDIR(smb_fname->st.st_ex_mode))
251 result = FILE_ATTRIBUTE_DIRECTORY | (result & FILE_ATTRIBUTE_READONLY);
253 result |= set_link_read_only_flag(&smb_fname->st);
255 dos_mode_debug_print(__func__, result);
260 /****************************************************************************
261 Get DOS attributes from an EA.
262 This can also pull the create time into the stat struct inside smb_fname.
263 ****************************************************************************/
265 NTSTATUS parse_dos_attribute_blob(struct smb_filename *smb_fname,
269 struct xattr_DOSATTRIB dosattrib;
270 enum ndr_err_code ndr_err;
273 ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &dosattrib,
274 (ndr_pull_flags_fn_t)ndr_pull_xattr_DOSATTRIB);
276 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
277 DBG_WARNING("bad ndr decode "
278 "from EA on file %s: Error = %s\n",
279 smb_fname_str_dbg(smb_fname),
280 ndr_errstr(ndr_err));
281 return ndr_map_error2ntstatus(ndr_err);
284 DBG_DEBUG("%s attr = %s\n",
285 smb_fname_str_dbg(smb_fname), dosattrib.attrib_hex);
287 switch (dosattrib.version) {
289 dosattr = dosattrib.info.compatinfoFFFF.attrib;
292 dosattr = dosattrib.info.info1.attrib;
293 if (!null_nttime(dosattrib.info.info1.create_time)) {
294 struct timespec create_time =
295 nt_time_to_unix_timespec(
296 dosattrib.info.info1.create_time);
298 update_stat_ex_create_time(&smb_fname->st,
301 DBG_DEBUG("file %s case 1 set btime %s\n",
302 smb_fname_str_dbg(smb_fname),
303 time_to_asc(convert_timespec_to_time_t(
308 dosattr = dosattrib.info.oldinfo2.attrib;
309 /* Don't know what flags to check for this case. */
312 dosattr = dosattrib.info.info3.attrib;
313 if ((dosattrib.info.info3.valid_flags & XATTR_DOSINFO_CREATE_TIME) &&
314 !null_nttime(dosattrib.info.info3.create_time)) {
315 struct timespec create_time =
316 nt_time_to_full_timespec(
317 dosattrib.info.info3.create_time);
319 update_stat_ex_create_time(&smb_fname->st,
322 DBG_DEBUG("file %s case 3 set btime %s\n",
323 smb_fname_str_dbg(smb_fname),
324 time_to_asc(convert_timespec_to_time_t(
330 struct xattr_DosInfo4 *info = &dosattrib.info.info4;
332 dosattr = info->attrib;
334 if ((info->valid_flags & XATTR_DOSINFO_CREATE_TIME) &&
335 !null_nttime(info->create_time))
337 struct timespec creat_time;
339 creat_time = nt_time_to_full_timespec(info->create_time);
340 update_stat_ex_create_time(&smb_fname->st, creat_time);
342 DBG_DEBUG("file [%s] creation time [%s]\n",
343 smb_fname_str_dbg(smb_fname),
344 nt_time_string(talloc_tos(), info->create_time));
347 if (info->valid_flags & XATTR_DOSINFO_ITIME) {
348 struct timespec itime;
351 itime = nt_time_to_unix_timespec(info->itime);
352 if (smb_fname->st.st_ex_iflags &
353 ST_EX_IFLAG_CALCULATED_ITIME)
355 update_stat_ex_itime(&smb_fname->st, itime);
358 file_id = make_file_id_from_itime(&smb_fname->st);
359 if (smb_fname->st.st_ex_iflags &
360 ST_EX_IFLAG_CALCULATED_FILE_ID)
362 update_stat_ex_file_id(&smb_fname->st, file_id);
365 DBG_DEBUG("file [%s] itime [%s] fileid [%"PRIx64"]\n",
366 smb_fname_str_dbg(smb_fname),
367 nt_time_string(talloc_tos(), info->itime),
373 DBG_WARNING("Badly formed DOSATTRIB on file %s - %s\n",
374 smb_fname_str_dbg(smb_fname), blob.data);
375 /* Should this be INTERNAL_ERROR? */
376 return NT_STATUS_INVALID_PARAMETER;
379 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
380 dosattr |= FILE_ATTRIBUTE_DIRECTORY;
383 /* FILE_ATTRIBUTE_SPARSE is valid on get but not on set. */
384 *pattr |= (uint32_t)(dosattr & (SAMBA_ATTRIBUTES_MASK|FILE_ATTRIBUTE_SPARSE));
386 dos_mode_debug_print(__func__, *pattr);
391 NTSTATUS get_ea_dos_attribute(connection_struct *conn,
392 struct smb_filename *smb_fname,
400 if (!lp_store_dos_attributes(SNUM(conn))) {
401 return NT_STATUS_NOT_IMPLEMENTED;
404 /* Don't reset pattr to zero as we may already have filename-based attributes we
407 sizeret = SMB_VFS_GETXATTR(conn, smb_fname,
408 SAMBA_XATTR_DOS_ATTRIB, attrstr,
410 if (sizeret == -1 && errno == EACCES) {
414 * According to MS-FSA 2.1.5.1.2.1 "Algorithm to Check Access to
415 * an Existing File" FILE_LIST_DIRECTORY on a directory implies
416 * FILE_READ_ATTRIBUTES for directory entries. Being able to
417 * stat() a file implies FILE_LIST_DIRECTORY for the directory
418 * containing the file.
421 if (!VALID_STAT(smb_fname->st)) {
423 * Safety net: dos_mode() already checks this, but as we
424 * become root based on this, add an additional layer of
427 DBG_ERR("Rejecting root override, invalid stat [%s]\n",
428 smb_fname_str_dbg(smb_fname));
429 return NT_STATUS_ACCESS_DENIED;
433 sizeret = SMB_VFS_GETXATTR(conn, smb_fname,
434 SAMBA_XATTR_DOS_ATTRIB,
442 if (saved_errno != 0) {
447 DBG_INFO("Cannot get attribute "
448 "from EA on file %s: Error = %s\n",
449 smb_fname_str_dbg(smb_fname), strerror(errno));
450 return map_nt_error_from_unix(errno);
453 blob.data = (uint8_t *)attrstr;
454 blob.length = sizeret;
456 status = parse_dos_attribute_blob(smb_fname, blob, pattr);
457 if (!NT_STATUS_IS_OK(status)) {
464 /****************************************************************************
465 Set DOS attributes in an EA.
466 Also sets the create time.
467 ****************************************************************************/
469 NTSTATUS set_ea_dos_attribute(connection_struct *conn,
470 const struct smb_filename *smb_fname,
473 struct xattr_DOSATTRIB dosattrib;
474 enum ndr_err_code ndr_err;
478 if (!lp_store_dos_attributes(SNUM(conn))) {
479 return NT_STATUS_NOT_IMPLEMENTED;
483 * Don't store FILE_ATTRIBUTE_OFFLINE, it's dealt with in
484 * vfs_default via DMAPI if that is enabled.
486 dosmode &= ~FILE_ATTRIBUTE_OFFLINE;
488 ZERO_STRUCT(dosattrib);
491 dosattrib.version = 4;
492 dosattrib.info.info4.valid_flags = XATTR_DOSINFO_ATTRIB |
493 XATTR_DOSINFO_CREATE_TIME;
494 dosattrib.info.info4.attrib = dosmode;
495 dosattrib.info.info4.create_time = full_timespec_to_nt_time(
496 &smb_fname->st.st_ex_btime);
498 if (!(smb_fname->st.st_ex_iflags & ST_EX_IFLAG_CALCULATED_ITIME)) {
499 dosattrib.info.info4.valid_flags |= XATTR_DOSINFO_ITIME;
500 dosattrib.info.info4.itime = full_timespec_to_nt_time(
501 &smb_fname->st.st_ex_itime);
504 DEBUG(10,("set_ea_dos_attributes: set attribute 0x%x, btime = %s on file %s\n",
505 (unsigned int)dosmode,
506 time_to_asc(convert_timespec_to_time_t(smb_fname->st.st_ex_btime)),
507 smb_fname_str_dbg(smb_fname) ));
509 ndr_err = ndr_push_struct_blob(
510 &blob, talloc_tos(), &dosattrib,
511 (ndr_push_flags_fn_t)ndr_push_xattr_DOSATTRIB);
513 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
514 DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n",
515 ndr_errstr(ndr_err)));
516 return ndr_map_error2ntstatus(ndr_err);
519 if (blob.data == NULL || blob.length == 0) {
520 /* Should this be INTERNAL_ERROR? */
521 return NT_STATUS_INVALID_PARAMETER;
524 ret = SMB_VFS_SETXATTR(conn, smb_fname,
525 SAMBA_XATTR_DOS_ATTRIB,
526 blob.data, blob.length, 0);
528 NTSTATUS status = NT_STATUS_OK;
529 bool need_close = false;
530 files_struct *fsp = NULL;
531 bool set_dosmode_ok = false;
533 if ((errno != EPERM) && (errno != EACCES)) {
534 DBG_INFO("Cannot set "
535 "attribute EA on file %s: Error = %s\n",
536 smb_fname_str_dbg(smb_fname), strerror(errno));
537 return map_nt_error_from_unix(errno);
540 /* We want DOS semantics, ie allow non owner with write permission to change the
541 bits on a file. Just like file_ntimes below.
544 /* Check if we have write access. */
545 if (!CAN_WRITE(conn)) {
546 return NT_STATUS_ACCESS_DENIED;
549 status = smbd_check_access_rights(conn, smb_fname, false,
550 FILE_WRITE_ATTRIBUTES);
551 if (NT_STATUS_IS_OK(status)) {
552 set_dosmode_ok = true;
555 if (!set_dosmode_ok && lp_dos_filemode(SNUM(conn))) {
556 set_dosmode_ok = can_write_to_file(conn, smb_fname);
559 if (!set_dosmode_ok) {
560 return NT_STATUS_ACCESS_DENIED;
564 * We need to get an open file handle to do the
565 * metadata operation under root.
568 status = get_file_handle_for_metadata(conn,
572 if (!NT_STATUS_IS_OK(status)) {
577 ret = SMB_VFS_FSETXATTR(fsp,
578 SAMBA_XATTR_DOS_ATTRIB,
579 blob.data, blob.length, 0);
581 status = NT_STATUS_OK;
585 close_file(NULL, fsp, NORMAL_CLOSE);
589 DEBUG(10,("set_ea_dos_attribute: set EA 0x%x on file %s\n",
590 (unsigned int)dosmode,
591 smb_fname_str_dbg(smb_fname)));
595 /****************************************************************************
596 Change a unix mode to a dos mode for an ms dfs link.
597 ****************************************************************************/
599 uint32_t dos_mode_msdfs(connection_struct *conn,
600 const struct smb_filename *smb_fname)
604 DEBUG(8,("dos_mode_msdfs: %s\n", smb_fname_str_dbg(smb_fname)));
606 if (!VALID_STAT(smb_fname->st)) {
610 /* First do any modifications that depend on the path name. */
611 /* hide files with a name starting with a . */
612 if (lp_hide_dot_files(SNUM(conn))) {
613 const char *p = strrchr_m(smb_fname->base_name, '/');
617 p = smb_fname->base_name;
620 /* Only . and .. are not hidden. */
621 if (p[0] == '.' && !((p[1] == '\0') ||
622 (p[1] == '.' && p[2] == '\0'))) {
623 result |= FILE_ATTRIBUTE_HIDDEN;
627 result |= dos_mode_from_sbuf(conn, smb_fname);
629 /* Optimization : Only call is_hidden_path if it's not already
631 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
632 IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
633 result |= FILE_ATTRIBUTE_HIDDEN;
637 result = FILE_ATTRIBUTE_NORMAL;
640 result = filter_mode_by_protocol(result);
643 * Add in that it is a reparse point
645 result |= FILE_ATTRIBUTE_REPARSE_POINT;
647 dos_mode_debug_print(__func__, result);
653 * check whether a file or directory is flagged as compressed.
655 static NTSTATUS dos_mode_check_compressed(connection_struct *conn,
656 struct smb_filename *smb_fname,
660 uint16_t compression_fmt;
661 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
662 if (tmp_ctx == NULL) {
663 status = NT_STATUS_NO_MEMORY;
667 status = SMB_VFS_GET_COMPRESSION(conn, tmp_ctx, NULL, smb_fname,
669 if (!NT_STATUS_IS_OK(status)) {
673 if (compression_fmt == COMPRESSION_FORMAT_LZNT1) {
674 *is_compressed = true;
676 *is_compressed = false;
678 status = NT_STATUS_OK;
681 talloc_free(tmp_ctx);
686 static uint32_t dos_mode_from_name(connection_struct *conn,
687 const struct smb_filename *smb_fname,
690 const char *p = NULL;
691 uint32_t result = dosmode;
693 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
694 lp_hide_dot_files(SNUM(conn)))
696 p = strrchr_m(smb_fname->base_name, '/');
700 p = smb_fname->base_name;
703 /* Only . and .. are not hidden. */
705 !((p[1] == '\0') || (p[1] == '.' && p[2] == '\0')))
707 result |= FILE_ATTRIBUTE_HIDDEN;
711 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
712 IS_HIDDEN_PATH(conn, smb_fname->base_name))
714 result |= FILE_ATTRIBUTE_HIDDEN;
720 static uint32_t dos_mode_post(uint32_t dosmode,
721 connection_struct *conn,
722 struct smb_filename *smb_fname,
728 * According to MS-FSA a stream name does not have
729 * separate DOS attribute metadata, so we must return
730 * the DOS attribute from the base filename. With one caveat,
731 * a non-default stream name can never be a directory.
733 * As this is common to all streams data stores, we handle
734 * it here instead of inside all stream VFS modules.
736 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13380
739 if (is_named_stream(smb_fname)) {
740 /* is_ntfs_stream_smb_fname() returns false for a POSIX path. */
741 dosmode &= ~(FILE_ATTRIBUTE_DIRECTORY);
744 if (conn->fs_capabilities & FILE_FILE_COMPRESSION) {
745 bool compressed = false;
747 status = dos_mode_check_compressed(conn, smb_fname,
749 if (NT_STATUS_IS_OK(status) && compressed) {
750 dosmode |= FILE_ATTRIBUTE_COMPRESSED;
754 dosmode |= dos_mode_from_name(conn, smb_fname, dosmode);
756 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
757 dosmode |= FILE_ATTRIBUTE_DIRECTORY;
758 } else if (dosmode == 0) {
759 dosmode = FILE_ATTRIBUTE_NORMAL;
762 dosmode = filter_mode_by_protocol(dosmode);
764 dos_mode_debug_print(func, dosmode);
768 /****************************************************************************
769 Change a unix mode to a dos mode.
770 May also read the create timespec into the stat struct in smb_fname
771 if "store dos attributes" is true.
772 ****************************************************************************/
774 uint32_t dos_mode(connection_struct *conn, struct smb_filename *smb_fname)
777 NTSTATUS status = NT_STATUS_OK;
779 DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname)));
781 if (!VALID_STAT(smb_fname->st)) {
785 /* Get the DOS attributes via the VFS if we can */
786 status = SMB_VFS_GET_DOS_ATTRIBUTES(conn, smb_fname, &result);
787 if (!NT_STATUS_IS_OK(status)) {
789 * Only fall back to using UNIX modes if we get NOT_IMPLEMENTED.
791 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
792 result |= dos_mode_from_sbuf(conn, smb_fname);
796 result = dos_mode_post(result, conn, smb_fname, __func__);
800 struct dos_mode_at_state {
801 files_struct *dir_fsp;
802 struct smb_filename *smb_fname;
806 static void dos_mode_at_vfs_get_dosmode_done(struct tevent_req *subreq);
808 struct tevent_req *dos_mode_at_send(TALLOC_CTX *mem_ctx,
809 struct tevent_context *ev,
810 files_struct *dir_fsp,
811 struct smb_filename *smb_fname)
813 struct tevent_req *req = NULL;
814 struct dos_mode_at_state *state = NULL;
815 struct tevent_req *subreq = NULL;
817 DBG_DEBUG("%s\n", smb_fname_str_dbg(smb_fname));
819 req = tevent_req_create(mem_ctx, &state,
820 struct dos_mode_at_state);
825 *state = (struct dos_mode_at_state) {
827 .smb_fname = smb_fname,
830 if (!VALID_STAT(smb_fname->st)) {
831 tevent_req_done(req);
832 return tevent_req_post(req, ev);
835 subreq = SMB_VFS_GET_DOS_ATTRIBUTES_SEND(state,
839 if (tevent_req_nomem(subreq, req)) {
840 return tevent_req_post(req, ev);
842 tevent_req_set_callback(subreq, dos_mode_at_vfs_get_dosmode_done, req);
847 static void dos_mode_at_vfs_get_dosmode_done(struct tevent_req *subreq)
849 struct tevent_req *req =
850 tevent_req_callback_data(subreq,
852 struct dos_mode_at_state *state =
854 struct dos_mode_at_state);
856 struct smb_filename *smb_path = NULL;
857 struct vfs_aio_state aio_state;
862 * Make sure we run as the user again
864 ok = change_to_user_and_service_by_fsp(state->dir_fsp);
867 status = SMB_VFS_GET_DOS_ATTRIBUTES_RECV(subreq,
871 if (!NT_STATUS_IS_OK(status)) {
873 * Both the sync dos_mode() as well as the async
874 * dos_mode_at_[send|recv] have no real error return, the only
875 * unhandled error is when the stat info in smb_fname is not
876 * valid (cf the checks in dos_mode() and dos_mode_at_send().
878 * If SMB_VFS_GET_DOS_ATTRIBUTES[_SEND|_RECV] fails we must call
879 * dos_mode_post() which also does the mapping of a last ressort
880 * from S_IFMT(st_mode).
882 * Only if we get NT_STATUS_NOT_IMPLEMENTED from a stacked VFS
883 * module we must fallback to sync processing.
885 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
887 * state->dosmode should still be 0, but reset
891 status = NT_STATUS_OK;
894 if (NT_STATUS_IS_OK(status)) {
895 state->dosmode = dos_mode_post(state->dosmode,
896 state->dir_fsp->conn,
899 tevent_req_done(req);
904 * Fall back to sync dos_mode() if we got NOT_IMPLEMENTED.
907 path = talloc_asprintf(state,
909 state->dir_fsp->fsp_name->base_name,
910 state->smb_fname->base_name);
911 if (tevent_req_nomem(path, req)) {
915 smb_path = synthetic_smb_fname(state,
918 &state->smb_fname->st,
920 if (tevent_req_nomem(smb_path, req)) {
924 state->dosmode = dos_mode(state->dir_fsp->conn, smb_path);
925 tevent_req_done(req);
929 NTSTATUS dos_mode_at_recv(struct tevent_req *req, uint32_t *dosmode)
931 struct dos_mode_at_state *state =
933 struct dos_mode_at_state);
936 if (tevent_req_is_nterror(req, &status)) {
937 tevent_req_received(req);
941 *dosmode = state->dosmode;
942 tevent_req_received(req);
946 /*******************************************************************
947 chmod a file - but preserve some bits.
948 If "store dos attributes" is also set it will store the create time
949 from the stat struct in smb_fname (in NTTIME format) in the EA
951 ********************************************************************/
953 int file_set_dosmode(connection_struct *conn,
954 struct smb_filename *smb_fname,
956 struct smb_filename *parent_dir,
962 int ret = -1, lret = -1;
963 files_struct *fsp = NULL;
964 bool need_close = false;
967 if (!CAN_WRITE(conn)) {
972 dosmode &= SAMBA_ATTRIBUTES_MASK;
974 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
975 dosmode, smb_fname_str_dbg(smb_fname)));
977 unixmode = smb_fname->st.st_ex_mode;
979 get_acl_group_bits(conn, smb_fname,
980 &smb_fname->st.st_ex_mode);
982 if (S_ISDIR(smb_fname->st.st_ex_mode))
983 dosmode |= FILE_ATTRIBUTE_DIRECTORY;
985 dosmode &= ~FILE_ATTRIBUTE_DIRECTORY;
987 /* Store the DOS attributes in an EA by preference. */
988 status = SMB_VFS_SET_DOS_ATTRIBUTES(conn, smb_fname, dosmode);
989 if (NT_STATUS_IS_OK(status)) {
991 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
992 FILE_NOTIFY_CHANGE_ATTRIBUTES,
993 smb_fname->base_name);
995 smb_fname->st.st_ex_mode = unixmode;
999 * Only fall back to using UNIX modes if
1000 * we get NOT_IMPLEMENTED.
1002 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
1003 errno = map_errno_from_nt_status(status);
1008 /* Fall back to UNIX modes. */
1009 unixmode = unix_mode(conn, dosmode, smb_fname, parent_dir->base_name);
1011 /* preserve the file type bits */
1014 /* preserve the s bits */
1015 mask |= (S_ISUID | S_ISGID);
1017 /* preserve the t bit */
1022 /* possibly preserve the x bits */
1023 if (!MAP_ARCHIVE(conn))
1025 if (!MAP_SYSTEM(conn))
1027 if (!MAP_HIDDEN(conn))
1030 unixmode |= (smb_fname->st.st_ex_mode & mask);
1032 /* if we previously had any r bits set then leave them alone */
1033 if ((tmp = smb_fname->st.st_ex_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
1034 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
1038 /* if we previously had any w bits set then leave them alone
1039 whilst adding in the new w bits, if the new mode is not rdonly */
1040 if (!IS_DOS_READONLY(dosmode)) {
1041 unixmode |= (smb_fname->st.st_ex_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
1045 * From the chmod 2 man page:
1047 * "If the calling process is not privileged, and the group of the file
1048 * does not match the effective group ID of the process or one of its
1049 * supplementary group IDs, the S_ISGID bit will be turned off, but
1050 * this will not cause an error to be returned."
1052 * Simply refuse to do the chmod in this case.
1055 if (S_ISDIR(smb_fname->st.st_ex_mode) && (unixmode & S_ISGID) &&
1056 geteuid() != sec_initial_uid() &&
1057 !current_user_in_group(conn, smb_fname->st.st_ex_gid)) {
1058 DEBUG(3,("file_set_dosmode: setgid bit cannot be "
1059 "set for directory %s\n",
1060 smb_fname_str_dbg(smb_fname)));
1065 ret = SMB_VFS_CHMOD(conn, smb_fname, unixmode);
1067 if(!newfile || (lret != -1)) {
1068 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
1069 FILE_NOTIFY_CHANGE_ATTRIBUTES,
1070 smb_fname->base_name);
1072 smb_fname->st.st_ex_mode = unixmode;
1076 if((errno != EPERM) && (errno != EACCES))
1079 if(!lp_dos_filemode(SNUM(conn)))
1082 /* We want DOS semantics, ie allow non owner with write permission to change the
1083 bits on a file. Just like file_ntimes below.
1086 if (!can_write_to_file(conn, smb_fname)) {
1092 * We need to get an open file handle to do the
1093 * metadata operation under root.
1096 status = get_file_handle_for_metadata(conn,
1100 if (!NT_STATUS_IS_OK(status)) {
1101 errno = map_errno_from_nt_status(status);
1106 ret = SMB_VFS_FCHMOD(fsp, unixmode);
1109 close_file(NULL, fsp, NORMAL_CLOSE);
1112 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
1113 FILE_NOTIFY_CHANGE_ATTRIBUTES,
1114 smb_fname->base_name);
1117 smb_fname->st.st_ex_mode = unixmode;
1124 NTSTATUS file_set_sparse(connection_struct *conn,
1128 const struct loadparm_substitution *lp_sub =
1129 loadparm_s3_global_substitution();
1130 uint32_t old_dosmode;
1131 uint32_t new_dosmode;
1134 if (!CAN_WRITE(conn)) {
1135 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
1136 "on readonly share[%s]\n",
1137 smb_fname_str_dbg(fsp->fsp_name),
1139 lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
1140 return NT_STATUS_MEDIA_WRITE_PROTECTED;
1144 * Windows Server 2008 & 2012 permit FSCTL_SET_SPARSE if any of the
1145 * following access flags are granted.
1147 if ((fsp->access_mask & (FILE_WRITE_DATA
1148 | FILE_WRITE_ATTRIBUTES
1149 | SEC_FILE_APPEND_DATA)) == 0) {
1150 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
1151 "access_mask[0x%08X] - access denied\n",
1152 smb_fname_str_dbg(fsp->fsp_name),
1155 return NT_STATUS_ACCESS_DENIED;
1158 if (fsp->fsp_flags.is_directory) {
1159 DEBUG(9, ("invalid attempt to %s sparse flag on dir %s\n",
1160 (sparse ? "set" : "clear"),
1161 smb_fname_str_dbg(fsp->fsp_name)));
1162 return NT_STATUS_INVALID_PARAMETER;
1165 if (IS_IPC(conn) || IS_PRINT(conn)) {
1166 DEBUG(9, ("attempt to %s sparse flag over invalid conn\n",
1167 (sparse ? "set" : "clear")));
1168 return NT_STATUS_INVALID_PARAMETER;
1171 DEBUG(10,("file_set_sparse: setting sparse bit %u on file %s\n",
1172 sparse, smb_fname_str_dbg(fsp->fsp_name)));
1174 if (!lp_store_dos_attributes(SNUM(conn))) {
1175 return NT_STATUS_INVALID_DEVICE_REQUEST;
1178 status = vfs_stat_fsp(fsp);
1179 if (!NT_STATUS_IS_OK(status)) {
1183 old_dosmode = dos_mode(conn, fsp->fsp_name);
1185 if (sparse && !(old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
1186 new_dosmode = old_dosmode | FILE_ATTRIBUTE_SPARSE;
1187 } else if (!sparse && (old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
1188 new_dosmode = old_dosmode & ~FILE_ATTRIBUTE_SPARSE;
1190 return NT_STATUS_OK;
1193 /* Store the DOS attributes in an EA. */
1194 status = SMB_VFS_FSET_DOS_ATTRIBUTES(conn, fsp, new_dosmode);
1195 if (!NT_STATUS_IS_OK(status)) {
1199 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
1200 FILE_NOTIFY_CHANGE_ATTRIBUTES,
1201 fsp->fsp_name->base_name);
1203 fsp->fsp_flags.is_sparse = sparse;
1205 return NT_STATUS_OK;
1208 /*******************************************************************
1209 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
1211 *******************************************************************/
1213 int file_ntimes(connection_struct *conn, const struct smb_filename *smb_fname,
1214 struct smb_file_time *ft)
1220 DEBUG(6, ("file_ntime: actime: %s",
1221 time_to_asc(convert_timespec_to_time_t(ft->atime))));
1222 DEBUG(6, ("file_ntime: modtime: %s",
1223 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
1224 DEBUG(6, ("file_ntime: ctime: %s",
1225 time_to_asc(convert_timespec_to_time_t(ft->ctime))));
1226 DEBUG(6, ("file_ntime: createtime: %s",
1227 time_to_asc(convert_timespec_to_time_t(ft->create_time))));
1229 /* Don't update the time on read-only shares */
1230 /* We need this as set_filetime (which can be called on
1231 close and other paths) can end up calling this function
1232 without the NEED_WRITE protection. Found by :
1233 Leo Weppelman <leo@wau.mis.ah.nl>
1236 if (!CAN_WRITE(conn)) {
1240 if(SMB_VFS_NTIMES(conn, smb_fname, ft) == 0) {
1244 if((errno != EPERM) && (errno != EACCES)) {
1248 if(!lp_dos_filetimes(SNUM(conn))) {
1252 /* We have permission (given by the Samba admin) to
1253 break POSIX semantics and allow a user to change
1254 the time on a file they don't own but can write to
1258 /* Check if we have write access. */
1259 if (can_write_to_file(conn, smb_fname)) {
1260 /* We are allowed to become root and change the filetime. */
1262 ret = SMB_VFS_NTIMES(conn, smb_fname, ft);
1269 /******************************************************************
1270 Force a "sticky" write time on a pathname. This will always be
1271 returned on all future write time queries and set on close.
1272 ******************************************************************/
1274 bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime)
1276 if (is_omit_timespec(&mtime)) {
1280 if (!set_sticky_write_time(fileid, mtime)) {
1287 /******************************************************************
1288 Force a "sticky" write time on an fsp. This will always be
1289 returned on all future write time queries and set on close.
1290 ******************************************************************/
1292 bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime)
1294 if (is_omit_timespec(&mtime)) {
1298 fsp->fsp_flags.write_time_forced = true;
1299 TALLOC_FREE(fsp->update_write_time_event);
1301 return set_sticky_write_time_path(fsp->file_id, mtime);
1304 /******************************************************************
1305 Set a create time EA.
1306 ******************************************************************/
1308 NTSTATUS set_create_timespec_ea(connection_struct *conn,
1309 const struct smb_filename *psmb_fname,
1310 struct timespec create_time)
1312 struct smb_filename *smb_fname;
1316 if (!lp_store_dos_attributes(SNUM(conn))) {
1317 return NT_STATUS_OK;
1320 smb_fname = synthetic_smb_fname(talloc_tos(),
1321 psmb_fname->base_name,
1326 if (smb_fname == NULL) {
1327 return NT_STATUS_NO_MEMORY;
1330 dosmode = dos_mode(conn, smb_fname);
1332 smb_fname->st.st_ex_btime = create_time;
1334 ret = file_set_dosmode(conn, smb_fname, dosmode, NULL, false);
1336 return map_nt_error_from_unix(errno);
1339 DEBUG(10,("set_create_timespec_ea: wrote create time EA for file %s\n",
1340 smb_fname_str_dbg(smb_fname)));
1342 return NT_STATUS_OK;
1345 /******************************************************************
1346 Return a create time.
1347 ******************************************************************/
1349 struct timespec get_create_timespec(connection_struct *conn,
1350 struct files_struct *fsp,
1351 const struct smb_filename *smb_fname)
1353 return smb_fname->st.st_ex_btime;
1356 /******************************************************************
1357 Return a change time (may look at EA in future).
1358 ******************************************************************/
1360 struct timespec get_change_timespec(connection_struct *conn,
1361 struct files_struct *fsp,
1362 const struct smb_filename *smb_fname)
1364 return smb_fname->st.st_ex_mtime;
1367 /****************************************************************************
1368 Get a real open file handle we can do meta-data operations on. As it's
1369 going to be used under root access only on meta-data we should look for
1370 any existing open file handle first, and use that in preference (also to
1371 avoid kernel self-oplock breaks). If not use an INTERNAL_OPEN_ONLY handle.
1372 ****************************************************************************/
1374 static NTSTATUS get_file_handle_for_metadata(connection_struct *conn,
1375 const struct smb_filename *smb_fname,
1376 files_struct **ret_fsp,
1381 struct file_id file_id;
1382 struct smb_filename *smb_fname_cp = NULL;
1384 *need_close = false;
1386 if (!VALID_STAT(smb_fname->st)) {
1387 return NT_STATUS_INVALID_PARAMETER;
1390 file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1392 for(fsp = file_find_di_first(conn->sconn, file_id);
1394 fsp = file_find_di_next(fsp)) {
1395 if (fsp->fh->fd != -1) {
1397 return NT_STATUS_OK;
1401 smb_fname_cp = cp_smb_filename(talloc_tos(),
1403 if (smb_fname_cp == NULL) {
1404 return NT_STATUS_NO_MEMORY;
1407 /* Opens an INTERNAL_OPEN_ONLY write handle. */
1408 status = SMB_VFS_CREATE_FILE(
1411 0, /* root_dir_fid */
1412 smb_fname_cp, /* fname */
1413 FILE_WRITE_ATTRIBUTES, /* access_mask */
1414 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
1416 FILE_OPEN, /* create_disposition*/
1417 0, /* create_options */
1418 0, /* file_attributes */
1419 INTERNAL_OPEN_ONLY, /* oplock_request */
1421 0, /* allocation_size */
1422 0, /* private_flags */
1425 ret_fsp, /* result */
1427 NULL, NULL); /* create context */
1429 TALLOC_FREE(smb_fname_cp);
1431 if (NT_STATUS_IS_OK(status)) {