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"
30 #include "lib/util/string_wrappers.h"
31 #include "fake_file.h"
33 static void dos_mode_debug_print(const char *func, uint32_t mode)
37 if (DEBUGLEVEL < DBGLVL_INFO) {
43 if (mode & FILE_ATTRIBUTE_HIDDEN) {
44 fstrcat(modestr, "h");
46 if (mode & FILE_ATTRIBUTE_READONLY) {
47 fstrcat(modestr, "r");
49 if (mode & FILE_ATTRIBUTE_SYSTEM) {
50 fstrcat(modestr, "s");
52 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
53 fstrcat(modestr, "d");
55 if (mode & FILE_ATTRIBUTE_ARCHIVE) {
56 fstrcat(modestr, "a");
58 if (mode & FILE_ATTRIBUTE_SPARSE) {
59 fstrcat(modestr, "[sparse]");
61 if (mode & FILE_ATTRIBUTE_OFFLINE) {
62 fstrcat(modestr, "[offline]");
64 if (mode & FILE_ATTRIBUTE_COMPRESSED) {
65 fstrcat(modestr, "[compressed]");
68 DBG_INFO("%s returning (0x%x): \"%s\"\n", func, (unsigned)mode,
72 static uint32_t filter_mode_by_protocol(uint32_t mode)
74 if (get_Protocol() <= PROTOCOL_LANMAN2) {
75 DEBUG(10,("filter_mode_by_protocol: "
76 "filtering result 0x%x to 0x%x\n",
78 (unsigned int)(mode & 0x3f) ));
84 /****************************************************************************
85 Change a dos mode to a unix mode.
86 Base permission for files:
87 if creating file and inheriting (i.e. parent_dir != NULL)
88 apply read/write bits from parent directory.
90 everybody gets read bit set
91 dos readonly is represented in unix by removing everyone's write bit
92 dos archive is represented in unix by the user's execute bit
93 dos system is represented in unix by the group's execute bit
94 dos hidden is represented in unix by the other's execute bit
96 Then apply create mask,
99 Base permission for directories:
100 dos directory is represented in unix by unix's dir bit and the exec bit
102 Then apply create mask,
105 ****************************************************************************/
107 mode_t unix_mode(connection_struct *conn, int dosmode,
108 const struct smb_filename *smb_fname,
109 struct files_struct *parent_dirfsp)
111 mode_t result = (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
112 mode_t dir_mode = 0; /* Mode of the inherit_from directory if
115 if ((dosmode & FILE_ATTRIBUTE_READONLY) &&
116 !lp_store_dos_attributes(SNUM(conn))) {
117 result &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
120 if ((parent_dirfsp != NULL) && lp_inherit_permissions(SNUM(conn))) {
121 struct stat_ex sbuf = { .st_ex_nlink = 0, };
124 DBG_DEBUG("[%s] inheriting from [%s]\n",
125 smb_fname_str_dbg(smb_fname),
126 smb_fname_str_dbg(parent_dirfsp->fsp_name));
128 ret = SMB_VFS_FSTAT(parent_dirfsp, &sbuf);
130 DBG_ERR("fstat failed [%s]: %s\n",
131 smb_fname_str_dbg(parent_dirfsp->fsp_name),
133 return(0); /* *** shouldn't happen! *** */
136 /* Save for later - but explicitly remove setuid bit for safety. */
137 dir_mode = sbuf.st_ex_mode & ~S_ISUID;
138 DEBUG(2,("unix_mode(%s) inherit mode %o\n",
139 smb_fname_str_dbg(smb_fname), (int)dir_mode));
144 if (dosmode & FILE_ATTRIBUTE_DIRECTORY) {
145 /* We never make directories read only for the owner as under DOS a user
146 can always create a file in a read-only directory. */
147 result |= (S_IFDIR | S_IWUSR);
150 /* Inherit mode of parent directory. */
153 /* Provisionally add all 'x' bits */
154 result |= (S_IXUSR | S_IXGRP | S_IXOTH);
156 /* Apply directory mask */
157 result &= lp_directory_mask(SNUM(conn));
158 /* Add in force bits */
159 result |= lp_force_directory_mode(SNUM(conn));
162 if ((dosmode & FILE_ATTRIBUTE_ARCHIVE) &&
163 lp_map_archive(SNUM(conn))) {
167 if ((dosmode & FILE_ATTRIBUTE_SYSTEM) &&
168 lp_map_system(SNUM(conn))) {
172 if ((dosmode & FILE_ATTRIBUTE_HIDDEN) &&
173 lp_map_hidden(SNUM(conn))) {
178 /* Inherit 666 component of parent directory mode */
179 result |= dir_mode & (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
181 /* Apply mode mask */
182 result &= lp_create_mask(SNUM(conn));
183 /* Add in force bits */
184 result |= lp_force_create_mode(SNUM(conn));
188 DBG_INFO("unix_mode(%s) returning 0%o\n",
189 smb_fname_str_dbg(smb_fname), (int)result);
194 /****************************************************************************
195 Change a unix mode to a dos mode.
196 ****************************************************************************/
198 static uint32_t dos_mode_from_sbuf(connection_struct *conn,
199 const struct stat_ex *st,
200 struct files_struct *fsp)
203 enum mapreadonly_options ro_opts =
204 (enum mapreadonly_options)lp_map_readonly(SNUM(conn));
206 #if defined(UF_IMMUTABLE) && defined(SF_IMMUTABLE)
207 /* if we can find out if a file is immutable we should report it r/o */
208 if (st->st_ex_flags & (UF_IMMUTABLE | SF_IMMUTABLE)) {
209 result |= FILE_ATTRIBUTE_READONLY;
212 if (ro_opts == MAP_READONLY_YES) {
213 /* Original Samba method - map inverse of user "w" bit. */
214 if ((st->st_ex_mode & S_IWUSR) == 0) {
215 result |= FILE_ATTRIBUTE_READONLY;
217 } else if (ro_opts == MAP_READONLY_PERMISSIONS) {
218 /* smb_fname->fsp can be NULL for an MS-DFS link. */
219 /* Check actual permissions for read-only. */
220 if ((fsp != NULL) && !can_write_to_fsp(fsp)) {
221 result |= FILE_ATTRIBUTE_READONLY;
223 } /* Else never set the readonly bit. */
225 if (MAP_ARCHIVE(conn) && ((st->st_ex_mode & S_IXUSR) != 0)) {
226 result |= FILE_ATTRIBUTE_ARCHIVE;
229 if (MAP_SYSTEM(conn) && ((st->st_ex_mode & S_IXGRP) != 0)) {
230 result |= FILE_ATTRIBUTE_SYSTEM;
233 if (MAP_HIDDEN(conn) && ((st->st_ex_mode & S_IXOTH) != 0)) {
234 result |= FILE_ATTRIBUTE_HIDDEN;
237 if (S_ISDIR(st->st_ex_mode)) {
238 result = FILE_ATTRIBUTE_DIRECTORY |
239 (result & FILE_ATTRIBUTE_READONLY);
242 dos_mode_debug_print(__func__, result);
247 /****************************************************************************
248 Get DOS attributes from an EA.
249 This can also pull the create time into the stat struct inside smb_fname.
250 ****************************************************************************/
252 NTSTATUS parse_dos_attribute_blob(struct smb_filename *smb_fname,
256 struct xattr_DOSATTRIB dosattrib;
257 enum ndr_err_code ndr_err;
260 ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &dosattrib,
261 (ndr_pull_flags_fn_t)ndr_pull_xattr_DOSATTRIB);
263 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
264 DBG_WARNING("bad ndr decode "
265 "from EA on file %s: Error = %s\n",
266 smb_fname_str_dbg(smb_fname),
267 ndr_errstr(ndr_err));
268 return ndr_map_error2ntstatus(ndr_err);
271 DBG_DEBUG("%s attr = %s\n",
272 smb_fname_str_dbg(smb_fname), dosattrib.attrib_hex);
274 switch (dosattrib.version) {
276 dosattr = dosattrib.info.compatinfoFFFF.attrib;
279 dosattr = dosattrib.info.info1.attrib;
280 if (!null_nttime(dosattrib.info.info1.create_time)) {
281 struct timespec create_time =
282 nt_time_to_unix_timespec(
283 dosattrib.info.info1.create_time);
285 update_stat_ex_create_time(&smb_fname->st,
288 DBG_DEBUG("file %s case 1 set btime %s",
289 smb_fname_str_dbg(smb_fname),
290 time_to_asc(convert_timespec_to_time_t(
295 dosattr = dosattrib.info.oldinfo2.attrib;
296 /* Don't know what flags to check for this case. */
299 dosattr = dosattrib.info.info3.attrib;
300 if ((dosattrib.info.info3.valid_flags & XATTR_DOSINFO_CREATE_TIME) &&
301 !null_nttime(dosattrib.info.info3.create_time)) {
302 struct timespec create_time =
303 nt_time_to_full_timespec(
304 dosattrib.info.info3.create_time);
306 update_stat_ex_create_time(&smb_fname->st,
309 DBG_DEBUG("file %s case 3 set btime %s",
310 smb_fname_str_dbg(smb_fname),
311 time_to_asc(convert_timespec_to_time_t(
318 uint32_t info_valid_flags;
319 NTTIME info_create_time;
321 if (dosattrib.version == 4) {
322 info_valid_flags = dosattrib.info.info4.valid_flags;
323 info_create_time = dosattrib.info.info4.create_time;
324 dosattr = dosattrib.info.info4.attrib;
326 info_valid_flags = dosattrib.info.info5.valid_flags;
327 info_create_time = dosattrib.info.info5.create_time;
328 dosattr = dosattrib.info.info5.attrib;
331 if ((info_valid_flags & XATTR_DOSINFO_CREATE_TIME) &&
332 !null_nttime(info_create_time))
334 struct timespec creat_time;
336 creat_time = nt_time_to_full_timespec(info_create_time);
337 update_stat_ex_create_time(&smb_fname->st, creat_time);
339 DBG_DEBUG("file [%s] creation time [%s]\n",
340 smb_fname_str_dbg(smb_fname),
341 nt_time_string(talloc_tos(), info_create_time));
347 DBG_WARNING("Badly formed DOSATTRIB on file %s - %s\n",
348 smb_fname_str_dbg(smb_fname), blob.data);
349 /* Should this be INTERNAL_ERROR? */
350 return NT_STATUS_INVALID_PARAMETER;
353 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
354 dosattr |= FILE_ATTRIBUTE_DIRECTORY;
357 /* FILE_ATTRIBUTE_SPARSE is valid on get but not on set. */
358 *pattr |= (uint32_t)(dosattr & (SAMBA_ATTRIBUTES_MASK|FILE_ATTRIBUTE_SPARSE));
360 dos_mode_debug_print(__func__, *pattr);
365 NTSTATUS fget_ea_dos_attribute(struct files_struct *fsp,
373 if (!lp_store_dos_attributes(SNUM(fsp->conn))) {
374 return NT_STATUS_NOT_IMPLEMENTED;
377 /* Don't reset pattr to zero as we may already have filename-based attributes we
380 sizeret = SMB_VFS_FGETXATTR(fsp,
381 SAMBA_XATTR_DOS_ATTRIB,
384 if (sizeret == -1 && ( errno == EPERM || errno == EACCES )) {
385 /* we may also retrieve dos attribs for unreadable files, this
386 is why we'll retry as root. We don't use root in the first
387 run because in cases like NFS, root might have even less
388 rights than the real user
390 set_effective_capability(DAC_OVERRIDE_CAPABILITY);
391 sizeret = SMB_VFS_FGETXATTR(fsp,
392 SAMBA_XATTR_DOS_ATTRIB,
395 drop_effective_capability(DAC_OVERRIDE_CAPABILITY);
398 DBG_INFO("Cannot get attribute "
399 "from EA on file %s: Error = %s\n",
400 fsp_str_dbg(fsp), strerror(errno));
401 return map_nt_error_from_unix(errno);
404 blob.data = (uint8_t *)attrstr;
405 blob.length = sizeret;
407 status = parse_dos_attribute_blob(fsp->fsp_name, blob, pattr);
408 if (!NT_STATUS_IS_OK(status)) {
415 /****************************************************************************
416 Set DOS attributes in an EA.
417 Also sets the create time.
418 ****************************************************************************/
420 NTSTATUS set_ea_dos_attribute(connection_struct *conn,
421 struct smb_filename *smb_fname,
424 struct xattr_DOSATTRIB dosattrib = { .version = 0, };
425 enum ndr_err_code ndr_err;
426 DATA_BLOB blob = { .data = NULL, };
427 struct timespec btime;
430 if (!lp_store_dos_attributes(SNUM(conn))) {
431 return NT_STATUS_NOT_IMPLEMENTED;
434 if (smb_fname->fsp == NULL) {
436 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
439 * Don't store FILE_ATTRIBUTE_OFFLINE, it's dealt with in
440 * vfs_default via DMAPI if that is enabled.
442 dosmode &= ~FILE_ATTRIBUTE_OFFLINE;
444 dosattrib.version = 5;
445 dosattrib.info.info5.valid_flags = XATTR_DOSINFO_ATTRIB |
446 XATTR_DOSINFO_CREATE_TIME;
447 dosattrib.info.info5.attrib = dosmode;
448 dosattrib.info.info5.create_time = full_timespec_to_nt_time(
449 &smb_fname->st.st_ex_btime);
451 DEBUG(10,("set_ea_dos_attributes: set attribute 0x%x, btime = %s on file %s\n",
452 (unsigned int)dosmode,
453 time_to_asc(convert_timespec_to_time_t(smb_fname->st.st_ex_btime)),
454 smb_fname_str_dbg(smb_fname) ));
456 ndr_err = ndr_push_struct_blob(
457 &blob, talloc_tos(), &dosattrib,
458 (ndr_push_flags_fn_t)ndr_push_xattr_DOSATTRIB);
460 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
461 DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n",
462 ndr_errstr(ndr_err)));
463 return ndr_map_error2ntstatus(ndr_err);
466 if (blob.data == NULL || blob.length == 0) {
467 /* Should this be INTERNAL_ERROR? */
468 return NT_STATUS_INVALID_PARAMETER;
471 ret = SMB_VFS_FSETXATTR(smb_fname->fsp,
472 SAMBA_XATTR_DOS_ATTRIB,
473 blob.data, blob.length, 0);
475 NTSTATUS status = NT_STATUS_OK;
476 bool set_dosmode_ok = false;
478 if ((errno != EPERM) && (errno != EACCES)) {
479 DBG_INFO("Cannot set "
480 "attribute EA on file %s: Error = %s\n",
481 smb_fname_str_dbg(smb_fname), strerror(errno));
482 return map_nt_error_from_unix(errno);
485 /* We want DOS semantics, ie allow non owner with write permission to change the
486 bits on a file. Just like file_ntimes below.
489 /* Check if we have write access. */
490 if (!CAN_WRITE(conn)) {
491 return NT_STATUS_ACCESS_DENIED;
494 status = smbd_check_access_rights_fsp(conn->cwd_fsp,
497 FILE_WRITE_ATTRIBUTES);
498 if (NT_STATUS_IS_OK(status)) {
499 set_dosmode_ok = true;
502 if (!set_dosmode_ok && lp_dos_filemode(SNUM(conn))) {
503 set_dosmode_ok = can_write_to_fsp(smb_fname->fsp);
506 if (!set_dosmode_ok) {
507 return NT_STATUS_ACCESS_DENIED;
510 set_effective_capability(DAC_OVERRIDE_CAPABILITY);
511 ret = SMB_VFS_FSETXATTR(smb_fname->fsp,
512 SAMBA_XATTR_DOS_ATTRIB,
513 blob.data, blob.length, 0);
514 drop_effective_capability(DAC_OVERRIDE_CAPABILITY);
516 status = NT_STATUS_OK;
518 if (!NT_STATUS_IS_OK(status)) {
524 * We correctly stored the create time.
525 * We *always* set XATTR_DOSINFO_CREATE_TIME,
526 * so now it can no longer be considered
527 * calculated. Make sure to use the value rounded
528 * to NTTIME granularity we've stored in the xattr.
530 btime = nt_time_to_full_timespec(dosattrib.info.info5.create_time);
531 update_stat_ex_create_time(&smb_fname->st, btime);
533 DEBUG(10,("set_ea_dos_attribute: set EA 0x%x on file %s\n",
534 (unsigned int)dosmode,
535 smb_fname_str_dbg(smb_fname)));
540 dos_mode_from_name(connection_struct *conn, const char *name, uint32_t dosmode)
542 const char *p = NULL;
543 uint32_t result = dosmode;
545 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
546 lp_hide_dot_files(SNUM(conn)))
548 p = strrchr_m(name, '/');
555 /* Only . and .. are not hidden. */
556 if ((p[0] == '.') && !(ISDOT(p) || ISDOTDOT(p))) {
557 result |= FILE_ATTRIBUTE_HIDDEN;
561 if (!(result & FILE_ATTRIBUTE_HIDDEN) && IS_HIDDEN_PATH(conn, name)) {
562 result |= FILE_ATTRIBUTE_HIDDEN;
568 /****************************************************************************
569 Change a unix mode to a dos mode for an ms dfs link.
570 ****************************************************************************/
572 uint32_t dos_mode_msdfs(connection_struct *conn,
574 const struct stat_ex *st)
578 DEBUG(8, ("dos_mode_msdfs: %s\n", name));
580 if (!VALID_STAT(*st)) {
584 result = dos_mode_from_name(conn, name, result);
585 result |= dos_mode_from_sbuf(conn, st, NULL);
588 result = FILE_ATTRIBUTE_NORMAL;
591 result = filter_mode_by_protocol(result);
594 * Add in that it is a reparse point
596 result |= FILE_ATTRIBUTE_REPARSE_POINT;
598 dos_mode_debug_print(__func__, result);
604 * check whether a file or directory is flagged as compressed.
606 static NTSTATUS dos_mode_check_compressed(struct files_struct *fsp,
610 uint16_t compression_fmt;
612 status = SMB_VFS_FGET_COMPRESSION(
613 fsp->conn, talloc_tos(), fsp, &compression_fmt);
614 if (!NT_STATUS_IS_OK(status)) {
618 if (compression_fmt == COMPRESSION_FORMAT_LZNT1) {
619 *is_compressed = true;
621 *is_compressed = false;
626 static uint32_t dos_mode_post(uint32_t dosmode,
627 struct files_struct *fsp,
630 struct smb_filename *smb_fname = NULL;
634 smb_fname = fsp->fsp_name;
636 SMB_ASSERT(smb_fname != NULL);
639 * According to MS-FSA a stream name does not have
640 * separate DOS attribute metadata, so we must return
641 * the DOS attribute from the base filename. With one caveat,
642 * a non-default stream name can never be a directory.
644 * As this is common to all streams data stores, we handle
645 * it here instead of inside all stream VFS modules.
647 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13380
650 if (is_named_stream(smb_fname)) {
651 /* is_ntfs_stream_smb_fname() returns false for a POSIX path. */
652 dosmode &= ~(FILE_ATTRIBUTE_DIRECTORY);
655 if (fsp->conn->fs_capabilities & FILE_FILE_COMPRESSION) {
656 bool compressed = false;
658 status = dos_mode_check_compressed(fsp, &compressed);
659 if (NT_STATUS_IS_OK(status) && compressed) {
660 dosmode |= FILE_ATTRIBUTE_COMPRESSED;
664 dosmode |= dos_mode_from_name(fsp->conn, smb_fname->base_name, dosmode);
666 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
667 dosmode |= FILE_ATTRIBUTE_DIRECTORY;
668 } else if (dosmode == 0) {
669 dosmode = FILE_ATTRIBUTE_NORMAL;
672 dosmode = filter_mode_by_protocol(dosmode);
674 dos_mode_debug_print(func, dosmode);
678 /****************************************************************************
679 Change a unix mode to a dos mode.
680 May also read the create timespec into the stat struct in smb_fname
681 if "store dos attributes" is true.
682 ****************************************************************************/
684 uint32_t fdos_mode(struct files_struct *fsp)
687 NTSTATUS status = NT_STATUS_OK;
689 DBG_DEBUG("%s\n", fsp_str_dbg(fsp));
691 if (fsp->fake_file_handle != NULL) {
692 return dosmode_from_fake_filehandle(fsp->fake_file_handle);
695 if (!VALID_STAT(fsp->fsp_name->st)) {
699 if (S_ISLNK(fsp->fsp_name->st.st_ex_mode)) {
700 return FILE_ATTRIBUTE_NORMAL;
703 if (fsp->fsp_name->st.cached_dos_attributes != FILE_ATTRIBUTE_INVALID) {
704 return fsp->fsp_name->st.cached_dos_attributes;
707 /* Get the DOS attributes via the VFS if we can */
708 status = SMB_VFS_FGET_DOS_ATTRIBUTES(fsp->conn,
711 if (!NT_STATUS_IS_OK(status)) {
713 * Only fall back to using UNIX modes if we get NOT_IMPLEMENTED.
715 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
716 result |= dos_mode_from_sbuf(fsp->conn,
722 fsp->fsp_name->st.cached_dos_attributes = dos_mode_post(result, fsp, __func__);
723 return fsp->fsp_name->st.cached_dos_attributes;
726 struct dos_mode_at_state {
727 files_struct *dir_fsp;
728 struct smb_filename *smb_fname;
732 static void dos_mode_at_vfs_get_dosmode_done(struct tevent_req *subreq);
734 struct tevent_req *dos_mode_at_send(TALLOC_CTX *mem_ctx,
735 struct tevent_context *ev,
736 files_struct *dir_fsp,
737 struct smb_filename *smb_fname)
739 struct tevent_req *req = NULL;
740 struct dos_mode_at_state *state = NULL;
741 struct tevent_req *subreq = NULL;
743 DBG_DEBUG("%s\n", smb_fname_str_dbg(smb_fname));
745 req = tevent_req_create(mem_ctx, &state,
746 struct dos_mode_at_state);
751 *state = (struct dos_mode_at_state) {
753 .smb_fname = smb_fname,
756 if (!VALID_STAT(smb_fname->st)) {
757 tevent_req_done(req);
758 return tevent_req_post(req, ev);
761 if (smb_fname->fsp == NULL) {
762 if (ISDOTDOT(smb_fname->base_name)) {
764 * smb_fname->fsp is explicitly closed
765 * for ".." to prevent meta-data leakage.
767 state->dosmode = FILE_ATTRIBUTE_DIRECTORY;
770 * This is a symlink in POSIX context.
771 * FIXME ? Should we move to returning
772 * FILE_ATTRIBUTE_REPARSE_POINT here ?
774 state->dosmode = FILE_ATTRIBUTE_NORMAL;
776 tevent_req_done(req);
777 return tevent_req_post(req, ev);
780 subreq = SMB_VFS_GET_DOS_ATTRIBUTES_SEND(state,
784 if (tevent_req_nomem(subreq, req)) {
785 return tevent_req_post(req, ev);
787 tevent_req_set_callback(subreq, dos_mode_at_vfs_get_dosmode_done, req);
792 static void dos_mode_at_vfs_get_dosmode_done(struct tevent_req *subreq)
794 struct tevent_req *req =
795 tevent_req_callback_data(subreq,
797 struct dos_mode_at_state *state =
799 struct dos_mode_at_state);
800 struct vfs_aio_state aio_state;
805 * Make sure we run as the user again
807 ok = change_to_user_and_service_by_fsp(state->dir_fsp);
810 status = SMB_VFS_GET_DOS_ATTRIBUTES_RECV(subreq,
814 if (!NT_STATUS_IS_OK(status)) {
816 * Both the sync dos_mode() as well as the async
817 * dos_mode_at_[send|recv] have no real error return, the only
818 * unhandled error is when the stat info in smb_fname is not
819 * valid (cf the checks in dos_mode() and dos_mode_at_send().
821 * If SMB_VFS_GET_DOS_ATTRIBUTES[_SEND|_RECV] fails we must call
822 * dos_mode_post() which also does the mapping of a last resort
823 * from S_IFMT(st_mode).
825 * Only if we get NT_STATUS_NOT_IMPLEMENTED or
826 * NT_STATUS_NOT_SUPPORTED from a stacked VFS module we must
827 * fallback to sync processing.
829 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED) &&
830 !NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED))
833 * state->dosmode should still be 0, but reset
837 status = NT_STATUS_OK;
840 if (NT_STATUS_IS_OK(status)) {
841 state->dosmode = dos_mode_post(state->dosmode,
842 state->smb_fname->fsp,
844 tevent_req_done(req);
849 * Fall back to sync dos_mode() if we got NOT_IMPLEMENTED.
852 state->dosmode = fdos_mode(state->smb_fname->fsp);
853 tevent_req_done(req);
857 NTSTATUS dos_mode_at_recv(struct tevent_req *req, uint32_t *dosmode)
859 struct dos_mode_at_state *state =
861 struct dos_mode_at_state);
864 if (tevent_req_is_nterror(req, &status)) {
865 tevent_req_received(req);
869 *dosmode = state->dosmode;
870 tevent_req_received(req);
874 /*******************************************************************
875 chmod a file - but preserve some bits.
876 If "store dos attributes" is also set it will store the create time
877 from the stat struct in smb_fname (in NTTIME format) in the EA
879 ********************************************************************/
881 int file_set_dosmode(connection_struct *conn,
882 struct smb_filename *smb_fname,
884 struct smb_filename *parent_dir,
893 if (!CAN_WRITE(conn)) {
898 if (S_ISLNK(smb_fname->st.st_ex_mode)) {
899 /* A symlink in POSIX context, ignore */
903 if ((S_ISDIR(smb_fname->st.st_ex_mode)) &&
904 (dosmode & FILE_ATTRIBUTE_TEMPORARY))
910 dosmode &= SAMBA_ATTRIBUTES_MASK;
912 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
913 dosmode, smb_fname_str_dbg(smb_fname)));
915 if (smb_fname->fsp == NULL) {
920 if (smb_fname->fsp->posix_flags & FSP_POSIX_FLAGS_OPEN &&
921 !lp_store_dos_attributes(SNUM(conn)))
926 unixmode = smb_fname->st.st_ex_mode;
928 get_acl_group_bits(conn, smb_fname->fsp, &smb_fname->st.st_ex_mode);
930 if (S_ISDIR(smb_fname->st.st_ex_mode))
931 dosmode |= FILE_ATTRIBUTE_DIRECTORY;
933 dosmode &= ~FILE_ATTRIBUTE_DIRECTORY;
935 /* Store the DOS attributes in an EA by preference. */
936 status = SMB_VFS_FSET_DOS_ATTRIBUTES(conn,
937 metadata_fsp(smb_fname->fsp),
939 if (NT_STATUS_IS_OK(status)) {
940 smb_fname->st.cached_dos_attributes = dosmode;
946 * Only fall back to using UNIX modes if
947 * we get NOT_IMPLEMENTED.
949 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
950 errno = map_errno_from_nt_status(status);
954 /* Fall back to UNIX modes. */
955 unixmode = unix_mode(
959 parent_dir != NULL ? parent_dir->fsp : NULL);
961 /* preserve the file type bits */
964 /* preserve the s bits */
965 mask |= (S_ISUID | S_ISGID);
967 /* preserve the t bit */
972 /* possibly preserve the x bits */
973 if (!MAP_ARCHIVE(conn))
975 if (!MAP_SYSTEM(conn))
977 if (!MAP_HIDDEN(conn))
980 unixmode |= (smb_fname->st.st_ex_mode & mask);
982 /* if we previously had any r bits set then leave them alone */
983 if ((tmp = smb_fname->st.st_ex_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
984 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
988 /* if we previously had any w bits set then leave them alone
989 whilst adding in the new w bits, if the new mode is not rdonly */
990 if (!(dosmode & FILE_ATTRIBUTE_READONLY)) {
991 unixmode |= (smb_fname->st.st_ex_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
995 * From the chmod 2 man page:
997 * "If the calling process is not privileged, and the group of the file
998 * does not match the effective group ID of the process or one of its
999 * supplementary group IDs, the S_ISGID bit will be turned off, but
1000 * this will not cause an error to be returned."
1002 * Simply refuse to do the chmod in this case.
1005 if (S_ISDIR(smb_fname->st.st_ex_mode) &&
1006 (unixmode & S_ISGID) &&
1007 geteuid() != sec_initial_uid() &&
1008 !current_user_in_group(conn, smb_fname->st.st_ex_gid))
1010 DEBUG(3,("file_set_dosmode: setgid bit cannot be "
1011 "set for directory %s\n",
1012 smb_fname_str_dbg(smb_fname)));
1017 ret = SMB_VFS_FCHMOD(smb_fname->fsp, unixmode);
1022 if((errno != EPERM) && (errno != EACCES))
1025 if(!lp_dos_filemode(SNUM(conn)))
1028 /* We want DOS semantics, ie allow non owner with write permission to change the
1029 bits on a file. Just like file_ntimes below.
1032 if (!can_write_to_fsp(smb_fname->fsp))
1039 ret = SMB_VFS_FCHMOD(smb_fname->fsp, unixmode);
1044 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
1045 FILE_NOTIFY_CHANGE_ATTRIBUTES,
1046 smb_fname->base_name);
1049 smb_fname->st.st_ex_mode = unixmode;
1056 NTSTATUS file_set_sparse(connection_struct *conn,
1060 const struct loadparm_substitution *lp_sub =
1061 loadparm_s3_global_substitution();
1062 uint32_t old_dosmode;
1063 uint32_t new_dosmode;
1066 if (!CAN_WRITE(conn)) {
1067 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
1068 "on readonly share[%s]\n",
1069 smb_fname_str_dbg(fsp->fsp_name),
1071 lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
1072 return NT_STATUS_MEDIA_WRITE_PROTECTED;
1076 * Windows Server 2008 & 2012 permit FSCTL_SET_SPARSE if any of the
1077 * following access flags are granted.
1079 if ((fsp->access_mask & (FILE_WRITE_DATA
1080 | FILE_WRITE_ATTRIBUTES
1081 | SEC_FILE_APPEND_DATA)) == 0) {
1082 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
1083 "access_mask[0x%08X] - access denied\n",
1084 smb_fname_str_dbg(fsp->fsp_name),
1087 return NT_STATUS_ACCESS_DENIED;
1090 if (fsp->fsp_flags.is_directory) {
1091 DEBUG(9, ("invalid attempt to %s sparse flag on dir %s\n",
1092 (sparse ? "set" : "clear"),
1093 smb_fname_str_dbg(fsp->fsp_name)));
1094 return NT_STATUS_INVALID_PARAMETER;
1097 if (IS_IPC(conn) || IS_PRINT(conn)) {
1098 DEBUG(9, ("attempt to %s sparse flag over invalid conn\n",
1099 (sparse ? "set" : "clear")));
1100 return NT_STATUS_INVALID_PARAMETER;
1103 if (fsp_is_alternate_stream(fsp)) {
1105 * MS-FSA 2.1.1.5 IsSparse
1107 * This is a per stream attribute, but our backends don't
1108 * support it a consistent way, therefore just pretend
1109 * success and ignore the request.
1111 DBG_DEBUG("Ignoring request to set FILE_ATTRIBUTE_SPARSE on "
1112 "[%s]\n", fsp_str_dbg(fsp));
1113 return NT_STATUS_OK;
1116 DEBUG(10,("file_set_sparse: setting sparse bit %u on file %s\n",
1117 sparse, smb_fname_str_dbg(fsp->fsp_name)));
1119 if (!lp_store_dos_attributes(SNUM(conn))) {
1120 return NT_STATUS_INVALID_DEVICE_REQUEST;
1123 status = vfs_stat_fsp(fsp);
1124 if (!NT_STATUS_IS_OK(status)) {
1128 old_dosmode = fdos_mode(fsp);
1130 if (sparse && !(old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
1131 new_dosmode = old_dosmode | FILE_ATTRIBUTE_SPARSE;
1132 } else if (!sparse && (old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
1133 new_dosmode = old_dosmode & ~FILE_ATTRIBUTE_SPARSE;
1135 return NT_STATUS_OK;
1138 /* Store the DOS attributes in an EA. */
1139 status = SMB_VFS_FSET_DOS_ATTRIBUTES(conn, fsp, new_dosmode);
1140 if (!NT_STATUS_IS_OK(status)) {
1144 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
1145 FILE_NOTIFY_CHANGE_ATTRIBUTES,
1146 fsp->fsp_name->base_name);
1148 fsp->fsp_name->st.cached_dos_attributes = new_dosmode;
1149 fsp->fsp_flags.is_sparse = sparse;
1151 return NT_STATUS_OK;
1154 /*******************************************************************
1155 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
1157 *******************************************************************/
1159 int file_ntimes(connection_struct *conn,
1161 struct smb_file_time *ft)
1167 DBG_INFO("actime: %s",
1168 time_to_asc(convert_timespec_to_time_t(ft->atime)));
1169 DBG_INFO("modtime: %s",
1170 time_to_asc(convert_timespec_to_time_t(ft->mtime)));
1171 DBG_INFO("ctime: %s",
1172 time_to_asc(convert_timespec_to_time_t(ft->ctime)));
1173 DBG_INFO("createtime: %s",
1174 time_to_asc(convert_timespec_to_time_t(ft->create_time)));
1176 /* Don't update the time on read-only shares */
1177 /* We need this as set_filetime (which can be called on
1178 close and other paths) can end up calling this function
1179 without the NEED_WRITE protection. Found by :
1180 Leo Weppelman <leo@wau.mis.ah.nl>
1183 if (!CAN_WRITE(conn)) {
1187 if (SMB_VFS_FNTIMES(fsp, ft) == 0) {
1191 if((errno != EPERM) && (errno != EACCES)) {
1195 if(!lp_dos_filetimes(SNUM(conn))) {
1199 /* We have permission (given by the Samba admin) to
1200 break POSIX semantics and allow a user to change
1201 the time on a file they don't own but can write to
1205 /* Check if we have write access. */
1206 if (can_write_to_fsp(fsp)) {
1207 /* We are allowed to become root and change the filetime. */
1209 ret = SMB_VFS_FNTIMES(fsp, ft);
1216 /******************************************************************
1217 Force a "sticky" write time on a pathname. This will always be
1218 returned on all future write time queries and set on close.
1219 ******************************************************************/
1221 bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime)
1223 if (is_omit_timespec(&mtime)) {
1227 if (!set_sticky_write_time(fileid, mtime)) {
1234 /******************************************************************
1235 Force a "sticky" write time on an fsp. This will always be
1236 returned on all future write time queries and set on close.
1237 ******************************************************************/
1239 bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime)
1241 if (is_omit_timespec(&mtime)) {
1245 fsp->fsp_flags.write_time_forced = true;
1246 TALLOC_FREE(fsp->update_write_time_event);
1248 return set_sticky_write_time_path(fsp->file_id, mtime);
1251 /******************************************************************
1252 Set a create time EA.
1253 ******************************************************************/
1255 NTSTATUS set_create_timespec_ea(struct files_struct *fsp,
1256 struct timespec create_time)
1261 if (!lp_store_dos_attributes(SNUM(fsp->conn))) {
1262 return NT_STATUS_OK;
1265 dosmode = fdos_mode(fsp);
1267 fsp->fsp_name->st.st_ex_btime = create_time;
1268 ret = file_set_dosmode(fsp->conn, fsp->fsp_name, dosmode, NULL, false);
1270 return map_nt_error_from_unix(errno);
1273 DBG_DEBUG("wrote create time EA for file %s\n",
1274 smb_fname_str_dbg(fsp->fsp_name));
1276 return NT_STATUS_OK;
1279 /******************************************************************
1280 Return a create time.
1281 ******************************************************************/
1283 struct timespec get_create_timespec(connection_struct *conn,
1284 struct files_struct *fsp,
1285 const struct smb_filename *smb_fname)
1288 struct files_struct *meta_fsp = metadata_fsp(fsp);
1289 return meta_fsp->fsp_name->st.st_ex_btime;
1291 return smb_fname->st.st_ex_btime;
1294 /******************************************************************
1295 Return a change time (may look at EA in future).
1296 ******************************************************************/
1298 struct timespec get_change_timespec(connection_struct *conn,
1299 struct files_struct *fsp,
1300 const struct smb_filename *smb_fname)
1302 return smb_fname->st.st_ex_mtime;