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 struct smb_filename *smb_fname_parent)
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 ((smb_fname_parent != NULL) && lp_inherit_permissions(SNUM(conn))) {
134 DBG_DEBUG("[%s] inheriting from [%s]\n",
135 smb_fname_str_dbg(smb_fname),
136 smb_fname_str_dbg(smb_fname_parent));
138 if (SMB_VFS_STAT(conn, smb_fname_parent) != 0) {
139 DBG_ERR("stat failed [%s]: %s\n",
140 smb_fname_str_dbg(smb_fname_parent),
142 TALLOC_FREE(smb_fname_parent);
143 return(0); /* *** shouldn't happen! *** */
146 /* Save for later - but explicitly remove setuid bit for safety. */
147 dir_mode = smb_fname_parent->st.st_ex_mode & ~S_ISUID;
148 DEBUG(2,("unix_mode(%s) inherit mode %o\n",
149 smb_fname_str_dbg(smb_fname), (int)dir_mode));
152 TALLOC_FREE(smb_fname_parent);
155 if (IS_DOS_DIR(dosmode)) {
156 /* We never make directories read only for the owner as under DOS a user
157 can always create a file in a read-only directory. */
158 result |= (S_IFDIR | S_IWUSR);
161 /* Inherit mode of parent directory. */
164 /* Provisionally add all 'x' bits */
165 result |= (S_IXUSR | S_IXGRP | S_IXOTH);
167 /* Apply directory mask */
168 result &= lp_directory_mask(SNUM(conn));
169 /* Add in force bits */
170 result |= lp_force_directory_mode(SNUM(conn));
173 if (lp_map_archive(SNUM(conn)) && IS_DOS_ARCHIVE(dosmode))
176 if (lp_map_system(SNUM(conn)) && IS_DOS_SYSTEM(dosmode))
179 if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode))
183 /* Inherit 666 component of parent directory mode */
184 result |= dir_mode & (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
186 /* Apply mode mask */
187 result &= lp_create_mask(SNUM(conn));
188 /* Add in force bits */
189 result |= lp_force_create_mode(SNUM(conn));
193 DBG_INFO("unix_mode(%s) returning 0%o\n",
194 smb_fname_str_dbg(smb_fname), (int)result);
199 /****************************************************************************
200 Change a unix mode to a dos mode.
201 ****************************************************************************/
203 static uint32_t dos_mode_from_sbuf(connection_struct *conn,
204 const struct smb_filename *smb_fname)
207 enum mapreadonly_options ro_opts = (enum mapreadonly_options)lp_map_readonly(SNUM(conn));
209 #if defined(UF_IMMUTABLE) && defined(SF_IMMUTABLE)
210 /* if we can find out if a file is immutable we should report it r/o */
211 if (smb_fname->st.st_ex_flags & (UF_IMMUTABLE | SF_IMMUTABLE)) {
212 result |= FILE_ATTRIBUTE_READONLY;
215 if (ro_opts == MAP_READONLY_YES) {
216 /* Original Samba method - map inverse of user "w" bit. */
217 if ((smb_fname->st.st_ex_mode & S_IWUSR) == 0) {
218 result |= FILE_ATTRIBUTE_READONLY;
220 } else if (ro_opts == MAP_READONLY_PERMISSIONS) {
221 /* Check actual permissions for read-only. */
222 if (!can_write_to_file(conn,
226 result |= FILE_ATTRIBUTE_READONLY;
228 } /* Else never set the readonly bit. */
230 if (MAP_ARCHIVE(conn) && ((smb_fname->st.st_ex_mode & S_IXUSR) != 0))
231 result |= FILE_ATTRIBUTE_ARCHIVE;
233 if (MAP_SYSTEM(conn) && ((smb_fname->st.st_ex_mode & S_IXGRP) != 0))
234 result |= FILE_ATTRIBUTE_SYSTEM;
236 if (MAP_HIDDEN(conn) && ((smb_fname->st.st_ex_mode & S_IXOTH) != 0))
237 result |= FILE_ATTRIBUTE_HIDDEN;
239 if (S_ISDIR(smb_fname->st.st_ex_mode))
240 result = FILE_ATTRIBUTE_DIRECTORY | (result & FILE_ATTRIBUTE_READONLY);
242 result |= set_link_read_only_flag(&smb_fname->st);
244 dos_mode_debug_print(__func__, result);
249 /****************************************************************************
250 Get DOS attributes from an EA.
251 This can also pull the create time into the stat struct inside smb_fname.
252 ****************************************************************************/
254 NTSTATUS parse_dos_attribute_blob(struct smb_filename *smb_fname,
258 struct xattr_DOSATTRIB dosattrib;
259 enum ndr_err_code ndr_err;
262 ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &dosattrib,
263 (ndr_pull_flags_fn_t)ndr_pull_xattr_DOSATTRIB);
265 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
266 DBG_WARNING("bad ndr decode "
267 "from EA on file %s: Error = %s\n",
268 smb_fname_str_dbg(smb_fname),
269 ndr_errstr(ndr_err));
270 return ndr_map_error2ntstatus(ndr_err);
273 DBG_DEBUG("%s attr = %s\n",
274 smb_fname_str_dbg(smb_fname), dosattrib.attrib_hex);
276 switch (dosattrib.version) {
278 dosattr = dosattrib.info.compatinfoFFFF.attrib;
281 dosattr = dosattrib.info.info1.attrib;
282 if (!null_nttime(dosattrib.info.info1.create_time)) {
283 struct timespec create_time =
284 nt_time_to_unix_timespec(
285 dosattrib.info.info1.create_time);
287 update_stat_ex_create_time(&smb_fname->st,
290 DBG_DEBUG("file %s case 1 set btime %s\n",
291 smb_fname_str_dbg(smb_fname),
292 time_to_asc(convert_timespec_to_time_t(
297 dosattr = dosattrib.info.oldinfo2.attrib;
298 /* Don't know what flags to check for this case. */
301 dosattr = dosattrib.info.info3.attrib;
302 if ((dosattrib.info.info3.valid_flags & XATTR_DOSINFO_CREATE_TIME) &&
303 !null_nttime(dosattrib.info.info3.create_time)) {
304 struct timespec create_time =
305 nt_time_to_full_timespec(
306 dosattrib.info.info3.create_time);
308 update_stat_ex_create_time(&smb_fname->st,
311 DBG_DEBUG("file %s case 3 set btime %s\n",
312 smb_fname_str_dbg(smb_fname),
313 time_to_asc(convert_timespec_to_time_t(
319 struct xattr_DosInfo4 *info = &dosattrib.info.info4;
321 dosattr = info->attrib;
323 if ((info->valid_flags & XATTR_DOSINFO_CREATE_TIME) &&
324 !null_nttime(info->create_time))
326 struct timespec creat_time;
328 creat_time = nt_time_to_full_timespec(info->create_time);
329 update_stat_ex_create_time(&smb_fname->st, creat_time);
331 DBG_DEBUG("file [%s] creation time [%s]\n",
332 smb_fname_str_dbg(smb_fname),
333 nt_time_string(talloc_tos(), info->create_time));
336 if (info->valid_flags & XATTR_DOSINFO_ITIME) {
337 struct timespec itime;
340 itime = nt_time_to_unix_timespec(info->itime);
341 if (smb_fname->st.st_ex_iflags &
342 ST_EX_IFLAG_CALCULATED_ITIME)
344 update_stat_ex_itime(&smb_fname->st, itime);
347 file_id = make_file_id_from_itime(&smb_fname->st);
348 if (smb_fname->st.st_ex_iflags &
349 ST_EX_IFLAG_CALCULATED_FILE_ID)
351 update_stat_ex_file_id(&smb_fname->st, file_id);
354 DBG_DEBUG("file [%s] itime [%s] fileid [%"PRIx64"]\n",
355 smb_fname_str_dbg(smb_fname),
356 nt_time_string(talloc_tos(), info->itime),
362 DBG_WARNING("Badly formed DOSATTRIB on file %s - %s\n",
363 smb_fname_str_dbg(smb_fname), blob.data);
364 /* Should this be INTERNAL_ERROR? */
365 return NT_STATUS_INVALID_PARAMETER;
368 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
369 dosattr |= FILE_ATTRIBUTE_DIRECTORY;
372 /* FILE_ATTRIBUTE_SPARSE is valid on get but not on set. */
373 *pattr |= (uint32_t)(dosattr & (SAMBA_ATTRIBUTES_MASK|FILE_ATTRIBUTE_SPARSE));
375 dos_mode_debug_print(__func__, *pattr);
380 NTSTATUS get_ea_dos_attribute(connection_struct *conn,
381 struct smb_filename *smb_fname,
389 if (!lp_store_dos_attributes(SNUM(conn))) {
390 return NT_STATUS_NOT_IMPLEMENTED;
393 /* Don't reset pattr to zero as we may already have filename-based attributes we
396 sizeret = SMB_VFS_GETXATTR(conn, smb_fname,
397 SAMBA_XATTR_DOS_ATTRIB, attrstr,
399 if (sizeret == -1 && errno == EACCES) {
403 * According to MS-FSA 2.1.5.1.2.1 "Algorithm to Check Access to
404 * an Existing File" FILE_LIST_DIRECTORY on a directory implies
405 * FILE_READ_ATTRIBUTES for directory entries. Being able to
406 * stat() a file implies FILE_LIST_DIRECTORY for the directory
407 * containing the file.
410 if (!VALID_STAT(smb_fname->st)) {
412 * Safety net: dos_mode() already checks this, but as we
413 * become root based on this, add an additional layer of
416 DBG_ERR("Rejecting root override, invalid stat [%s]\n",
417 smb_fname_str_dbg(smb_fname));
418 return NT_STATUS_ACCESS_DENIED;
422 sizeret = SMB_VFS_GETXATTR(conn, smb_fname,
423 SAMBA_XATTR_DOS_ATTRIB,
431 if (saved_errno != 0) {
436 DBG_INFO("Cannot get attribute "
437 "from EA on file %s: Error = %s\n",
438 smb_fname_str_dbg(smb_fname), strerror(errno));
439 return map_nt_error_from_unix(errno);
442 blob.data = (uint8_t *)attrstr;
443 blob.length = sizeret;
445 status = parse_dos_attribute_blob(smb_fname, blob, pattr);
446 if (!NT_STATUS_IS_OK(status)) {
453 /****************************************************************************
454 Set DOS attributes in an EA.
455 Also sets the create time.
456 ****************************************************************************/
458 NTSTATUS set_ea_dos_attribute(connection_struct *conn,
459 const struct smb_filename *smb_fname,
462 struct xattr_DOSATTRIB dosattrib;
463 enum ndr_err_code ndr_err;
467 if (!lp_store_dos_attributes(SNUM(conn))) {
468 return NT_STATUS_NOT_IMPLEMENTED;
472 * Don't store FILE_ATTRIBUTE_OFFLINE, it's dealt with in
473 * vfs_default via DMAPI if that is enabled.
475 dosmode &= ~FILE_ATTRIBUTE_OFFLINE;
477 ZERO_STRUCT(dosattrib);
480 dosattrib.version = 4;
481 dosattrib.info.info4.valid_flags = XATTR_DOSINFO_ATTRIB |
482 XATTR_DOSINFO_CREATE_TIME;
483 dosattrib.info.info4.attrib = dosmode;
484 dosattrib.info.info4.create_time = full_timespec_to_nt_time(
485 &smb_fname->st.st_ex_btime);
487 if (!(smb_fname->st.st_ex_iflags & ST_EX_IFLAG_CALCULATED_ITIME)) {
488 dosattrib.info.info4.valid_flags |= XATTR_DOSINFO_ITIME;
489 dosattrib.info.info4.itime = full_timespec_to_nt_time(
490 &smb_fname->st.st_ex_itime);
493 DEBUG(10,("set_ea_dos_attributes: set attribute 0x%x, btime = %s on file %s\n",
494 (unsigned int)dosmode,
495 time_to_asc(convert_timespec_to_time_t(smb_fname->st.st_ex_btime)),
496 smb_fname_str_dbg(smb_fname) ));
498 ndr_err = ndr_push_struct_blob(
499 &blob, talloc_tos(), &dosattrib,
500 (ndr_push_flags_fn_t)ndr_push_xattr_DOSATTRIB);
502 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
503 DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n",
504 ndr_errstr(ndr_err)));
505 return ndr_map_error2ntstatus(ndr_err);
508 if (blob.data == NULL || blob.length == 0) {
509 /* Should this be INTERNAL_ERROR? */
510 return NT_STATUS_INVALID_PARAMETER;
513 ret = SMB_VFS_SETXATTR(conn, smb_fname,
514 SAMBA_XATTR_DOS_ATTRIB,
515 blob.data, blob.length, 0);
517 NTSTATUS status = NT_STATUS_OK;
518 bool need_close = false;
519 files_struct *fsp = NULL;
520 bool set_dosmode_ok = false;
522 if ((errno != EPERM) && (errno != EACCES)) {
523 DBG_INFO("Cannot set "
524 "attribute EA on file %s: Error = %s\n",
525 smb_fname_str_dbg(smb_fname), strerror(errno));
526 return map_nt_error_from_unix(errno);
529 /* We want DOS semantics, ie allow non owner with write permission to change the
530 bits on a file. Just like file_ntimes below.
533 /* Check if we have write access. */
534 if (!CAN_WRITE(conn)) {
535 return NT_STATUS_ACCESS_DENIED;
538 status = smbd_check_access_rights(conn,
542 FILE_WRITE_ATTRIBUTES);
543 if (NT_STATUS_IS_OK(status)) {
544 set_dosmode_ok = true;
547 if (!set_dosmode_ok && lp_dos_filemode(SNUM(conn))) {
548 set_dosmode_ok = can_write_to_file(conn,
553 if (!set_dosmode_ok) {
554 return NT_STATUS_ACCESS_DENIED;
558 * We need to get an open file handle to do the
559 * metadata operation under root.
562 status = get_file_handle_for_metadata(conn,
566 if (!NT_STATUS_IS_OK(status)) {
571 ret = SMB_VFS_FSETXATTR(fsp,
572 SAMBA_XATTR_DOS_ATTRIB,
573 blob.data, blob.length, 0);
575 status = NT_STATUS_OK;
579 close_file(NULL, fsp, NORMAL_CLOSE);
583 DEBUG(10,("set_ea_dos_attribute: set EA 0x%x on file %s\n",
584 (unsigned int)dosmode,
585 smb_fname_str_dbg(smb_fname)));
589 /****************************************************************************
590 Change a unix mode to a dos mode for an ms dfs link.
591 ****************************************************************************/
593 uint32_t dos_mode_msdfs(connection_struct *conn,
594 const struct smb_filename *smb_fname)
598 DEBUG(8,("dos_mode_msdfs: %s\n", smb_fname_str_dbg(smb_fname)));
600 if (!VALID_STAT(smb_fname->st)) {
604 /* First do any modifications that depend on the path name. */
605 /* hide files with a name starting with a . */
606 if (lp_hide_dot_files(SNUM(conn))) {
607 const char *p = strrchr_m(smb_fname->base_name, '/');
611 p = smb_fname->base_name;
614 /* Only . and .. are not hidden. */
615 if (p[0] == '.' && !((p[1] == '\0') ||
616 (p[1] == '.' && p[2] == '\0'))) {
617 result |= FILE_ATTRIBUTE_HIDDEN;
621 result |= dos_mode_from_sbuf(conn, smb_fname);
623 /* Optimization : Only call is_hidden_path if it's not already
625 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
626 IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
627 result |= FILE_ATTRIBUTE_HIDDEN;
631 result = FILE_ATTRIBUTE_NORMAL;
634 result = filter_mode_by_protocol(result);
637 * Add in that it is a reparse point
639 result |= FILE_ATTRIBUTE_REPARSE_POINT;
641 dos_mode_debug_print(__func__, result);
647 * check whether a file or directory is flagged as compressed.
649 static NTSTATUS dos_mode_check_compressed(connection_struct *conn,
650 struct smb_filename *smb_fname,
654 uint16_t compression_fmt;
655 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
656 if (tmp_ctx == NULL) {
657 status = NT_STATUS_NO_MEMORY;
661 status = SMB_VFS_GET_COMPRESSION(conn, tmp_ctx, NULL, smb_fname,
663 if (!NT_STATUS_IS_OK(status)) {
667 if (compression_fmt == COMPRESSION_FORMAT_LZNT1) {
668 *is_compressed = true;
670 *is_compressed = false;
672 status = NT_STATUS_OK;
675 talloc_free(tmp_ctx);
680 static uint32_t dos_mode_from_name(connection_struct *conn,
681 const struct smb_filename *smb_fname,
684 const char *p = NULL;
685 uint32_t result = dosmode;
687 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
688 lp_hide_dot_files(SNUM(conn)))
690 p = strrchr_m(smb_fname->base_name, '/');
694 p = smb_fname->base_name;
697 /* Only . and .. are not hidden. */
699 !((p[1] == '\0') || (p[1] == '.' && p[2] == '\0')))
701 result |= FILE_ATTRIBUTE_HIDDEN;
705 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
706 IS_HIDDEN_PATH(conn, smb_fname->base_name))
708 result |= FILE_ATTRIBUTE_HIDDEN;
714 static uint32_t dos_mode_post(uint32_t dosmode,
715 connection_struct *conn,
716 struct smb_filename *smb_fname,
722 * According to MS-FSA a stream name does not have
723 * separate DOS attribute metadata, so we must return
724 * the DOS attribute from the base filename. With one caveat,
725 * a non-default stream name can never be a directory.
727 * As this is common to all streams data stores, we handle
728 * it here instead of inside all stream VFS modules.
730 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13380
733 if (is_named_stream(smb_fname)) {
734 /* is_ntfs_stream_smb_fname() returns false for a POSIX path. */
735 dosmode &= ~(FILE_ATTRIBUTE_DIRECTORY);
738 if (conn->fs_capabilities & FILE_FILE_COMPRESSION) {
739 bool compressed = false;
741 status = dos_mode_check_compressed(conn, smb_fname,
743 if (NT_STATUS_IS_OK(status) && compressed) {
744 dosmode |= FILE_ATTRIBUTE_COMPRESSED;
748 dosmode |= dos_mode_from_name(conn, smb_fname, dosmode);
750 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
751 dosmode |= FILE_ATTRIBUTE_DIRECTORY;
752 } else if (dosmode == 0) {
753 dosmode = FILE_ATTRIBUTE_NORMAL;
756 dosmode = filter_mode_by_protocol(dosmode);
758 dos_mode_debug_print(func, dosmode);
762 /****************************************************************************
763 Change a unix mode to a dos mode.
764 May also read the create timespec into the stat struct in smb_fname
765 if "store dos attributes" is true.
766 ****************************************************************************/
768 uint32_t dos_mode(connection_struct *conn, struct smb_filename *smb_fname)
771 NTSTATUS status = NT_STATUS_OK;
773 DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname)));
775 if (!VALID_STAT(smb_fname->st)) {
779 /* Get the DOS attributes via the VFS if we can */
780 status = SMB_VFS_GET_DOS_ATTRIBUTES(conn, smb_fname, &result);
781 if (!NT_STATUS_IS_OK(status)) {
783 * Only fall back to using UNIX modes if we get NOT_IMPLEMENTED.
785 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
786 result |= dos_mode_from_sbuf(conn, smb_fname);
790 result = dos_mode_post(result, conn, smb_fname, __func__);
794 struct dos_mode_at_state {
795 files_struct *dir_fsp;
796 struct smb_filename *smb_fname;
800 static void dos_mode_at_vfs_get_dosmode_done(struct tevent_req *subreq);
802 struct tevent_req *dos_mode_at_send(TALLOC_CTX *mem_ctx,
803 struct tevent_context *ev,
804 files_struct *dir_fsp,
805 struct smb_filename *smb_fname)
807 struct tevent_req *req = NULL;
808 struct dos_mode_at_state *state = NULL;
809 struct tevent_req *subreq = NULL;
811 DBG_DEBUG("%s\n", smb_fname_str_dbg(smb_fname));
813 req = tevent_req_create(mem_ctx, &state,
814 struct dos_mode_at_state);
819 *state = (struct dos_mode_at_state) {
821 .smb_fname = smb_fname,
824 if (!VALID_STAT(smb_fname->st)) {
825 tevent_req_done(req);
826 return tevent_req_post(req, ev);
829 subreq = SMB_VFS_GET_DOS_ATTRIBUTES_SEND(state,
833 if (tevent_req_nomem(subreq, req)) {
834 return tevent_req_post(req, ev);
836 tevent_req_set_callback(subreq, dos_mode_at_vfs_get_dosmode_done, req);
841 static void dos_mode_at_vfs_get_dosmode_done(struct tevent_req *subreq)
843 struct tevent_req *req =
844 tevent_req_callback_data(subreq,
846 struct dos_mode_at_state *state =
848 struct dos_mode_at_state);
850 struct smb_filename *smb_path = NULL;
851 struct vfs_aio_state aio_state;
856 * Make sure we run as the user again
858 ok = change_to_user_and_service_by_fsp(state->dir_fsp);
861 status = SMB_VFS_GET_DOS_ATTRIBUTES_RECV(subreq,
865 if (!NT_STATUS_IS_OK(status)) {
867 * Both the sync dos_mode() as well as the async
868 * dos_mode_at_[send|recv] have no real error return, the only
869 * unhandled error is when the stat info in smb_fname is not
870 * valid (cf the checks in dos_mode() and dos_mode_at_send().
872 * If SMB_VFS_GET_DOS_ATTRIBUTES[_SEND|_RECV] fails we must call
873 * dos_mode_post() which also does the mapping of a last ressort
874 * from S_IFMT(st_mode).
876 * Only if we get NT_STATUS_NOT_IMPLEMENTED from a stacked VFS
877 * module we must fallback to sync processing.
879 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
881 * state->dosmode should still be 0, but reset
885 status = NT_STATUS_OK;
888 if (NT_STATUS_IS_OK(status)) {
889 state->dosmode = dos_mode_post(state->dosmode,
890 state->dir_fsp->conn,
893 tevent_req_done(req);
898 * Fall back to sync dos_mode() if we got NOT_IMPLEMENTED.
901 path = talloc_asprintf(state,
903 state->dir_fsp->fsp_name->base_name,
904 state->smb_fname->base_name);
905 if (tevent_req_nomem(path, req)) {
909 smb_path = synthetic_smb_fname(state,
912 &state->smb_fname->st,
913 state->smb_fname->twrp,
915 if (tevent_req_nomem(smb_path, req)) {
919 state->dosmode = dos_mode(state->dir_fsp->conn, smb_path);
920 tevent_req_done(req);
924 NTSTATUS dos_mode_at_recv(struct tevent_req *req, uint32_t *dosmode)
926 struct dos_mode_at_state *state =
928 struct dos_mode_at_state);
931 if (tevent_req_is_nterror(req, &status)) {
932 tevent_req_received(req);
936 *dosmode = state->dosmode;
937 tevent_req_received(req);
941 /*******************************************************************
942 chmod a file - but preserve some bits.
943 If "store dos attributes" is also set it will store the create time
944 from the stat struct in smb_fname (in NTTIME format) in the EA
946 ********************************************************************/
948 int file_set_dosmode(connection_struct *conn,
949 struct smb_filename *smb_fname,
951 struct smb_filename *parent_dir,
957 int ret = -1, lret = -1;
958 files_struct *fsp = NULL;
959 bool need_close = false;
962 if (!CAN_WRITE(conn)) {
967 dosmode &= SAMBA_ATTRIBUTES_MASK;
969 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
970 dosmode, smb_fname_str_dbg(smb_fname)));
972 unixmode = smb_fname->st.st_ex_mode;
974 get_acl_group_bits(conn, smb_fname,
975 &smb_fname->st.st_ex_mode);
977 if (S_ISDIR(smb_fname->st.st_ex_mode))
978 dosmode |= FILE_ATTRIBUTE_DIRECTORY;
980 dosmode &= ~FILE_ATTRIBUTE_DIRECTORY;
982 /* Store the DOS attributes in an EA by preference. */
983 status = SMB_VFS_SET_DOS_ATTRIBUTES(conn, smb_fname, dosmode);
984 if (NT_STATUS_IS_OK(status)) {
986 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
987 FILE_NOTIFY_CHANGE_ATTRIBUTES,
988 smb_fname->base_name);
990 smb_fname->st.st_ex_mode = unixmode;
994 * Only fall back to using UNIX modes if
995 * we get NOT_IMPLEMENTED.
997 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
998 errno = map_errno_from_nt_status(status);
1003 /* Fall back to UNIX modes. */
1004 unixmode = unix_mode(conn, dosmode, smb_fname, parent_dir);
1006 /* preserve the file type bits */
1009 /* preserve the s bits */
1010 mask |= (S_ISUID | S_ISGID);
1012 /* preserve the t bit */
1017 /* possibly preserve the x bits */
1018 if (!MAP_ARCHIVE(conn))
1020 if (!MAP_SYSTEM(conn))
1022 if (!MAP_HIDDEN(conn))
1025 unixmode |= (smb_fname->st.st_ex_mode & mask);
1027 /* if we previously had any r bits set then leave them alone */
1028 if ((tmp = smb_fname->st.st_ex_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
1029 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
1033 /* if we previously had any w bits set then leave them alone
1034 whilst adding in the new w bits, if the new mode is not rdonly */
1035 if (!IS_DOS_READONLY(dosmode)) {
1036 unixmode |= (smb_fname->st.st_ex_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
1040 * From the chmod 2 man page:
1042 * "If the calling process is not privileged, and the group of the file
1043 * does not match the effective group ID of the process or one of its
1044 * supplementary group IDs, the S_ISGID bit will be turned off, but
1045 * this will not cause an error to be returned."
1047 * Simply refuse to do the chmod in this case.
1050 if (S_ISDIR(smb_fname->st.st_ex_mode) && (unixmode & S_ISGID) &&
1051 geteuid() != sec_initial_uid() &&
1052 !current_user_in_group(conn, smb_fname->st.st_ex_gid)) {
1053 DEBUG(3,("file_set_dosmode: setgid bit cannot be "
1054 "set for directory %s\n",
1055 smb_fname_str_dbg(smb_fname)));
1060 ret = SMB_VFS_CHMOD(conn, smb_fname, unixmode);
1062 if(!newfile || (lret != -1)) {
1063 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
1064 FILE_NOTIFY_CHANGE_ATTRIBUTES,
1065 smb_fname->base_name);
1067 smb_fname->st.st_ex_mode = unixmode;
1071 if((errno != EPERM) && (errno != EACCES))
1074 if(!lp_dos_filemode(SNUM(conn)))
1077 /* We want DOS semantics, ie allow non owner with write permission to change the
1078 bits on a file. Just like file_ntimes below.
1081 if (!can_write_to_file(conn,
1090 * We need to get an open file handle to do the
1091 * metadata operation under root.
1094 status = get_file_handle_for_metadata(conn,
1098 if (!NT_STATUS_IS_OK(status)) {
1099 errno = map_errno_from_nt_status(status);
1104 ret = SMB_VFS_FCHMOD(fsp, unixmode);
1107 close_file(NULL, fsp, NORMAL_CLOSE);
1110 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
1111 FILE_NOTIFY_CHANGE_ATTRIBUTES,
1112 smb_fname->base_name);
1115 smb_fname->st.st_ex_mode = unixmode;
1122 NTSTATUS file_set_sparse(connection_struct *conn,
1126 const struct loadparm_substitution *lp_sub =
1127 loadparm_s3_global_substitution();
1128 uint32_t old_dosmode;
1129 uint32_t new_dosmode;
1132 if (!CAN_WRITE(conn)) {
1133 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
1134 "on readonly share[%s]\n",
1135 smb_fname_str_dbg(fsp->fsp_name),
1137 lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
1138 return NT_STATUS_MEDIA_WRITE_PROTECTED;
1142 * Windows Server 2008 & 2012 permit FSCTL_SET_SPARSE if any of the
1143 * following access flags are granted.
1145 if ((fsp->access_mask & (FILE_WRITE_DATA
1146 | FILE_WRITE_ATTRIBUTES
1147 | SEC_FILE_APPEND_DATA)) == 0) {
1148 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
1149 "access_mask[0x%08X] - access denied\n",
1150 smb_fname_str_dbg(fsp->fsp_name),
1153 return NT_STATUS_ACCESS_DENIED;
1156 if (fsp->fsp_flags.is_directory) {
1157 DEBUG(9, ("invalid attempt to %s sparse flag on dir %s\n",
1158 (sparse ? "set" : "clear"),
1159 smb_fname_str_dbg(fsp->fsp_name)));
1160 return NT_STATUS_INVALID_PARAMETER;
1163 if (IS_IPC(conn) || IS_PRINT(conn)) {
1164 DEBUG(9, ("attempt to %s sparse flag over invalid conn\n",
1165 (sparse ? "set" : "clear")));
1166 return NT_STATUS_INVALID_PARAMETER;
1169 DEBUG(10,("file_set_sparse: setting sparse bit %u on file %s\n",
1170 sparse, smb_fname_str_dbg(fsp->fsp_name)));
1172 if (!lp_store_dos_attributes(SNUM(conn))) {
1173 return NT_STATUS_INVALID_DEVICE_REQUEST;
1176 status = vfs_stat_fsp(fsp);
1177 if (!NT_STATUS_IS_OK(status)) {
1181 old_dosmode = dos_mode(conn, fsp->fsp_name);
1183 if (sparse && !(old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
1184 new_dosmode = old_dosmode | FILE_ATTRIBUTE_SPARSE;
1185 } else if (!sparse && (old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
1186 new_dosmode = old_dosmode & ~FILE_ATTRIBUTE_SPARSE;
1188 return NT_STATUS_OK;
1191 /* Store the DOS attributes in an EA. */
1192 status = SMB_VFS_FSET_DOS_ATTRIBUTES(conn, fsp, new_dosmode);
1193 if (!NT_STATUS_IS_OK(status)) {
1197 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
1198 FILE_NOTIFY_CHANGE_ATTRIBUTES,
1199 fsp->fsp_name->base_name);
1201 fsp->fsp_flags.is_sparse = sparse;
1203 return NT_STATUS_OK;
1206 /*******************************************************************
1207 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
1209 *******************************************************************/
1211 int file_ntimes(connection_struct *conn, const struct smb_filename *smb_fname,
1212 struct smb_file_time *ft)
1218 DEBUG(6, ("file_ntime: actime: %s",
1219 time_to_asc(convert_timespec_to_time_t(ft->atime))));
1220 DEBUG(6, ("file_ntime: modtime: %s",
1221 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
1222 DEBUG(6, ("file_ntime: ctime: %s",
1223 time_to_asc(convert_timespec_to_time_t(ft->ctime))));
1224 DEBUG(6, ("file_ntime: createtime: %s",
1225 time_to_asc(convert_timespec_to_time_t(ft->create_time))));
1227 /* Don't update the time on read-only shares */
1228 /* We need this as set_filetime (which can be called on
1229 close and other paths) can end up calling this function
1230 without the NEED_WRITE protection. Found by :
1231 Leo Weppelman <leo@wau.mis.ah.nl>
1234 if (!CAN_WRITE(conn)) {
1238 if(SMB_VFS_NTIMES(conn, smb_fname, ft) == 0) {
1242 if((errno != EPERM) && (errno != EACCES)) {
1246 if(!lp_dos_filetimes(SNUM(conn))) {
1250 /* We have permission (given by the Samba admin) to
1251 break POSIX semantics and allow a user to change
1252 the time on a file they don't own but can write to
1256 /* Check if we have write access. */
1257 if (can_write_to_file(conn,
1261 /* We are allowed to become root and change the filetime. */
1263 ret = SMB_VFS_NTIMES(conn, smb_fname, ft);
1270 /******************************************************************
1271 Force a "sticky" write time on a pathname. This will always be
1272 returned on all future write time queries and set on close.
1273 ******************************************************************/
1275 bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime)
1277 if (is_omit_timespec(&mtime)) {
1281 if (!set_sticky_write_time(fileid, mtime)) {
1288 /******************************************************************
1289 Force a "sticky" write time on an fsp. This will always be
1290 returned on all future write time queries and set on close.
1291 ******************************************************************/
1293 bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime)
1295 if (is_omit_timespec(&mtime)) {
1299 fsp->fsp_flags.write_time_forced = true;
1300 TALLOC_FREE(fsp->update_write_time_event);
1302 return set_sticky_write_time_path(fsp->file_id, mtime);
1305 /******************************************************************
1306 Set a create time EA.
1307 ******************************************************************/
1309 NTSTATUS set_create_timespec_ea(connection_struct *conn,
1310 const struct smb_filename *psmb_fname,
1311 struct timespec create_time)
1313 struct smb_filename *smb_fname;
1317 if (!lp_store_dos_attributes(SNUM(conn))) {
1318 return NT_STATUS_OK;
1321 smb_fname = synthetic_smb_fname(talloc_tos(),
1322 psmb_fname->base_name,
1328 if (smb_fname == NULL) {
1329 return NT_STATUS_NO_MEMORY;
1332 dosmode = dos_mode(conn, smb_fname);
1334 smb_fname->st.st_ex_btime = create_time;
1336 ret = file_set_dosmode(conn, smb_fname, dosmode, NULL, false);
1338 return map_nt_error_from_unix(errno);
1341 DEBUG(10,("set_create_timespec_ea: wrote create time EA for file %s\n",
1342 smb_fname_str_dbg(smb_fname)));
1344 return NT_STATUS_OK;
1347 /******************************************************************
1348 Return a create time.
1349 ******************************************************************/
1351 struct timespec get_create_timespec(connection_struct *conn,
1352 struct files_struct *fsp,
1353 const struct smb_filename *smb_fname)
1355 return smb_fname->st.st_ex_btime;
1358 /******************************************************************
1359 Return a change time (may look at EA in future).
1360 ******************************************************************/
1362 struct timespec get_change_timespec(connection_struct *conn,
1363 struct files_struct *fsp,
1364 const struct smb_filename *smb_fname)
1366 return smb_fname->st.st_ex_mtime;
1369 /****************************************************************************
1370 Get a real open file handle we can do meta-data operations on. As it's
1371 going to be used under root access only on meta-data we should look for
1372 any existing open file handle first, and use that in preference (also to
1373 avoid kernel self-oplock breaks). If not use an INTERNAL_OPEN_ONLY handle.
1374 ****************************************************************************/
1376 static NTSTATUS get_file_handle_for_metadata(connection_struct *conn,
1377 const struct smb_filename *smb_fname,
1378 files_struct **ret_fsp,
1383 struct file_id file_id;
1384 struct smb_filename *smb_fname_cp = NULL;
1386 *need_close = false;
1388 if (!VALID_STAT(smb_fname->st)) {
1389 return NT_STATUS_INVALID_PARAMETER;
1392 file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1394 for(fsp = file_find_di_first(conn->sconn, file_id);
1396 fsp = file_find_di_next(fsp)) {
1397 if (fsp->fh->fd != -1) {
1399 return NT_STATUS_OK;
1403 smb_fname_cp = cp_smb_filename(talloc_tos(),
1405 if (smb_fname_cp == NULL) {
1406 return NT_STATUS_NO_MEMORY;
1409 /* Opens an INTERNAL_OPEN_ONLY write handle. */
1410 status = SMB_VFS_CREATE_FILE(
1413 &conn->cwd_fsp, /* dirfsp */
1414 smb_fname_cp, /* fname */
1415 FILE_WRITE_ATTRIBUTES, /* access_mask */
1416 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
1418 FILE_OPEN, /* create_disposition*/
1419 0, /* create_options */
1420 0, /* file_attributes */
1421 INTERNAL_OPEN_ONLY, /* oplock_request */
1423 0, /* allocation_size */
1424 0, /* private_flags */
1427 ret_fsp, /* result */
1429 NULL, NULL); /* create context */
1431 TALLOC_FREE(smb_fname_cp);
1433 if (NT_STATUS_IS_OK(status)) {