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, smb_fname)) {
223 result |= FILE_ATTRIBUTE_READONLY;
225 } /* Else never set the readonly bit. */
227 if (MAP_ARCHIVE(conn) && ((smb_fname->st.st_ex_mode & S_IXUSR) != 0))
228 result |= FILE_ATTRIBUTE_ARCHIVE;
230 if (MAP_SYSTEM(conn) && ((smb_fname->st.st_ex_mode & S_IXGRP) != 0))
231 result |= FILE_ATTRIBUTE_SYSTEM;
233 if (MAP_HIDDEN(conn) && ((smb_fname->st.st_ex_mode & S_IXOTH) != 0))
234 result |= FILE_ATTRIBUTE_HIDDEN;
236 if (S_ISDIR(smb_fname->st.st_ex_mode))
237 result = FILE_ATTRIBUTE_DIRECTORY | (result & FILE_ATTRIBUTE_READONLY);
239 result |= set_link_read_only_flag(&smb_fname->st);
241 dos_mode_debug_print(__func__, result);
246 /****************************************************************************
247 Get DOS attributes from an EA.
248 This can also pull the create time into the stat struct inside smb_fname.
249 ****************************************************************************/
251 NTSTATUS parse_dos_attribute_blob(struct smb_filename *smb_fname,
255 struct xattr_DOSATTRIB dosattrib;
256 enum ndr_err_code ndr_err;
259 ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &dosattrib,
260 (ndr_pull_flags_fn_t)ndr_pull_xattr_DOSATTRIB);
262 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
263 DBG_WARNING("bad ndr decode "
264 "from EA on file %s: Error = %s\n",
265 smb_fname_str_dbg(smb_fname),
266 ndr_errstr(ndr_err));
267 return ndr_map_error2ntstatus(ndr_err);
270 DBG_DEBUG("%s attr = %s\n",
271 smb_fname_str_dbg(smb_fname), dosattrib.attrib_hex);
273 switch (dosattrib.version) {
275 dosattr = dosattrib.info.compatinfoFFFF.attrib;
278 dosattr = dosattrib.info.info1.attrib;
279 if (!null_nttime(dosattrib.info.info1.create_time)) {
280 struct timespec create_time =
281 nt_time_to_unix_timespec(
282 dosattrib.info.info1.create_time);
284 update_stat_ex_create_time(&smb_fname->st,
287 DBG_DEBUG("file %s case 1 set btime %s\n",
288 smb_fname_str_dbg(smb_fname),
289 time_to_asc(convert_timespec_to_time_t(
294 dosattr = dosattrib.info.oldinfo2.attrib;
295 /* Don't know what flags to check for this case. */
298 dosattr = dosattrib.info.info3.attrib;
299 if ((dosattrib.info.info3.valid_flags & XATTR_DOSINFO_CREATE_TIME) &&
300 !null_nttime(dosattrib.info.info3.create_time)) {
301 struct timespec create_time =
302 nt_time_to_full_timespec(
303 dosattrib.info.info3.create_time);
305 update_stat_ex_create_time(&smb_fname->st,
308 DBG_DEBUG("file %s case 3 set btime %s\n",
309 smb_fname_str_dbg(smb_fname),
310 time_to_asc(convert_timespec_to_time_t(
316 struct xattr_DosInfo4 *info = &dosattrib.info.info4;
318 dosattr = info->attrib;
320 if ((info->valid_flags & XATTR_DOSINFO_CREATE_TIME) &&
321 !null_nttime(info->create_time))
323 struct timespec creat_time;
325 creat_time = nt_time_to_full_timespec(info->create_time);
326 update_stat_ex_create_time(&smb_fname->st, creat_time);
328 DBG_DEBUG("file [%s] creation time [%s]\n",
329 smb_fname_str_dbg(smb_fname),
330 nt_time_string(talloc_tos(), info->create_time));
333 if (info->valid_flags & XATTR_DOSINFO_ITIME) {
334 struct timespec itime;
337 itime = nt_time_to_unix_timespec(info->itime);
338 if (smb_fname->st.st_ex_iflags &
339 ST_EX_IFLAG_CALCULATED_ITIME)
341 update_stat_ex_itime(&smb_fname->st, itime);
344 file_id = make_file_id_from_itime(&smb_fname->st);
345 if (smb_fname->st.st_ex_iflags &
346 ST_EX_IFLAG_CALCULATED_FILE_ID)
348 update_stat_ex_file_id(&smb_fname->st, file_id);
351 DBG_DEBUG("file [%s] itime [%s] fileid [%"PRIx64"]\n",
352 smb_fname_str_dbg(smb_fname),
353 nt_time_string(talloc_tos(), info->itime),
359 DBG_WARNING("Badly formed DOSATTRIB on file %s - %s\n",
360 smb_fname_str_dbg(smb_fname), blob.data);
361 /* Should this be INTERNAL_ERROR? */
362 return NT_STATUS_INVALID_PARAMETER;
365 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
366 dosattr |= FILE_ATTRIBUTE_DIRECTORY;
369 /* FILE_ATTRIBUTE_SPARSE is valid on get but not on set. */
370 *pattr |= (uint32_t)(dosattr & (SAMBA_ATTRIBUTES_MASK|FILE_ATTRIBUTE_SPARSE));
372 dos_mode_debug_print(__func__, *pattr);
377 NTSTATUS get_ea_dos_attribute(connection_struct *conn,
378 struct smb_filename *smb_fname,
386 if (!lp_store_dos_attributes(SNUM(conn))) {
387 return NT_STATUS_NOT_IMPLEMENTED;
390 /* Don't reset pattr to zero as we may already have filename-based attributes we
393 sizeret = SMB_VFS_GETXATTR(conn, smb_fname,
394 SAMBA_XATTR_DOS_ATTRIB, attrstr,
396 if (sizeret == -1 && errno == EACCES) {
400 * According to MS-FSA 2.1.5.1.2.1 "Algorithm to Check Access to
401 * an Existing File" FILE_LIST_DIRECTORY on a directory implies
402 * FILE_READ_ATTRIBUTES for directory entries. Being able to
403 * stat() a file implies FILE_LIST_DIRECTORY for the directory
404 * containing the file.
407 if (!VALID_STAT(smb_fname->st)) {
409 * Safety net: dos_mode() already checks this, but as we
410 * become root based on this, add an additional layer of
413 DBG_ERR("Rejecting root override, invalid stat [%s]\n",
414 smb_fname_str_dbg(smb_fname));
415 return NT_STATUS_ACCESS_DENIED;
419 sizeret = SMB_VFS_GETXATTR(conn, smb_fname,
420 SAMBA_XATTR_DOS_ATTRIB,
428 if (saved_errno != 0) {
433 DBG_INFO("Cannot get attribute "
434 "from EA on file %s: Error = %s\n",
435 smb_fname_str_dbg(smb_fname), strerror(errno));
436 return map_nt_error_from_unix(errno);
439 blob.data = (uint8_t *)attrstr;
440 blob.length = sizeret;
442 status = parse_dos_attribute_blob(smb_fname, blob, pattr);
443 if (!NT_STATUS_IS_OK(status)) {
450 /****************************************************************************
451 Set DOS attributes in an EA.
452 Also sets the create time.
453 ****************************************************************************/
455 NTSTATUS set_ea_dos_attribute(connection_struct *conn,
456 const struct smb_filename *smb_fname,
459 struct xattr_DOSATTRIB dosattrib;
460 enum ndr_err_code ndr_err;
464 if (!lp_store_dos_attributes(SNUM(conn))) {
465 return NT_STATUS_NOT_IMPLEMENTED;
469 * Don't store FILE_ATTRIBUTE_OFFLINE, it's dealt with in
470 * vfs_default via DMAPI if that is enabled.
472 dosmode &= ~FILE_ATTRIBUTE_OFFLINE;
474 ZERO_STRUCT(dosattrib);
477 dosattrib.version = 4;
478 dosattrib.info.info4.valid_flags = XATTR_DOSINFO_ATTRIB |
479 XATTR_DOSINFO_CREATE_TIME;
480 dosattrib.info.info4.attrib = dosmode;
481 dosattrib.info.info4.create_time = full_timespec_to_nt_time(
482 &smb_fname->st.st_ex_btime);
484 if (!(smb_fname->st.st_ex_iflags & ST_EX_IFLAG_CALCULATED_ITIME)) {
485 dosattrib.info.info4.valid_flags |= XATTR_DOSINFO_ITIME;
486 dosattrib.info.info4.itime = full_timespec_to_nt_time(
487 &smb_fname->st.st_ex_itime);
490 DEBUG(10,("set_ea_dos_attributes: set attribute 0x%x, btime = %s on file %s\n",
491 (unsigned int)dosmode,
492 time_to_asc(convert_timespec_to_time_t(smb_fname->st.st_ex_btime)),
493 smb_fname_str_dbg(smb_fname) ));
495 ndr_err = ndr_push_struct_blob(
496 &blob, talloc_tos(), &dosattrib,
497 (ndr_push_flags_fn_t)ndr_push_xattr_DOSATTRIB);
499 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
500 DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n",
501 ndr_errstr(ndr_err)));
502 return ndr_map_error2ntstatus(ndr_err);
505 if (blob.data == NULL || blob.length == 0) {
506 /* Should this be INTERNAL_ERROR? */
507 return NT_STATUS_INVALID_PARAMETER;
510 ret = SMB_VFS_SETXATTR(conn, smb_fname,
511 SAMBA_XATTR_DOS_ATTRIB,
512 blob.data, blob.length, 0);
514 NTSTATUS status = NT_STATUS_OK;
515 bool need_close = false;
516 files_struct *fsp = NULL;
517 bool set_dosmode_ok = false;
519 if ((errno != EPERM) && (errno != EACCES)) {
520 DBG_INFO("Cannot set "
521 "attribute EA on file %s: Error = %s\n",
522 smb_fname_str_dbg(smb_fname), strerror(errno));
523 return map_nt_error_from_unix(errno);
526 /* We want DOS semantics, ie allow non owner with write permission to change the
527 bits on a file. Just like file_ntimes below.
530 /* Check if we have write access. */
531 if (!CAN_WRITE(conn)) {
532 return NT_STATUS_ACCESS_DENIED;
535 status = smbd_check_access_rights(conn, smb_fname, false,
536 FILE_WRITE_ATTRIBUTES);
537 if (NT_STATUS_IS_OK(status)) {
538 set_dosmode_ok = true;
541 if (!set_dosmode_ok && lp_dos_filemode(SNUM(conn))) {
542 set_dosmode_ok = can_write_to_file(conn, smb_fname);
545 if (!set_dosmode_ok) {
546 return NT_STATUS_ACCESS_DENIED;
550 * We need to get an open file handle to do the
551 * metadata operation under root.
554 status = get_file_handle_for_metadata(conn,
558 if (!NT_STATUS_IS_OK(status)) {
563 ret = SMB_VFS_FSETXATTR(fsp,
564 SAMBA_XATTR_DOS_ATTRIB,
565 blob.data, blob.length, 0);
567 status = NT_STATUS_OK;
571 close_file(NULL, fsp, NORMAL_CLOSE);
575 DEBUG(10,("set_ea_dos_attribute: set EA 0x%x on file %s\n",
576 (unsigned int)dosmode,
577 smb_fname_str_dbg(smb_fname)));
581 /****************************************************************************
582 Change a unix mode to a dos mode for an ms dfs link.
583 ****************************************************************************/
585 uint32_t dos_mode_msdfs(connection_struct *conn,
586 const struct smb_filename *smb_fname)
590 DEBUG(8,("dos_mode_msdfs: %s\n", smb_fname_str_dbg(smb_fname)));
592 if (!VALID_STAT(smb_fname->st)) {
596 /* First do any modifications that depend on the path name. */
597 /* hide files with a name starting with a . */
598 if (lp_hide_dot_files(SNUM(conn))) {
599 const char *p = strrchr_m(smb_fname->base_name, '/');
603 p = smb_fname->base_name;
606 /* Only . and .. are not hidden. */
607 if (p[0] == '.' && !((p[1] == '\0') ||
608 (p[1] == '.' && p[2] == '\0'))) {
609 result |= FILE_ATTRIBUTE_HIDDEN;
613 result |= dos_mode_from_sbuf(conn, smb_fname);
615 /* Optimization : Only call is_hidden_path if it's not already
617 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
618 IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
619 result |= FILE_ATTRIBUTE_HIDDEN;
623 result = FILE_ATTRIBUTE_NORMAL;
626 result = filter_mode_by_protocol(result);
629 * Add in that it is a reparse point
631 result |= FILE_ATTRIBUTE_REPARSE_POINT;
633 dos_mode_debug_print(__func__, result);
639 * check whether a file or directory is flagged as compressed.
641 static NTSTATUS dos_mode_check_compressed(connection_struct *conn,
642 struct smb_filename *smb_fname,
646 uint16_t compression_fmt;
647 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
648 if (tmp_ctx == NULL) {
649 status = NT_STATUS_NO_MEMORY;
653 status = SMB_VFS_GET_COMPRESSION(conn, tmp_ctx, NULL, smb_fname,
655 if (!NT_STATUS_IS_OK(status)) {
659 if (compression_fmt == COMPRESSION_FORMAT_LZNT1) {
660 *is_compressed = true;
662 *is_compressed = false;
664 status = NT_STATUS_OK;
667 talloc_free(tmp_ctx);
672 static uint32_t dos_mode_from_name(connection_struct *conn,
673 const struct smb_filename *smb_fname,
676 const char *p = NULL;
677 uint32_t result = dosmode;
679 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
680 lp_hide_dot_files(SNUM(conn)))
682 p = strrchr_m(smb_fname->base_name, '/');
686 p = smb_fname->base_name;
689 /* Only . and .. are not hidden. */
691 !((p[1] == '\0') || (p[1] == '.' && p[2] == '\0')))
693 result |= FILE_ATTRIBUTE_HIDDEN;
697 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
698 IS_HIDDEN_PATH(conn, smb_fname->base_name))
700 result |= FILE_ATTRIBUTE_HIDDEN;
706 static uint32_t dos_mode_post(uint32_t dosmode,
707 connection_struct *conn,
708 struct smb_filename *smb_fname,
714 * According to MS-FSA a stream name does not have
715 * separate DOS attribute metadata, so we must return
716 * the DOS attribute from the base filename. With one caveat,
717 * a non-default stream name can never be a directory.
719 * As this is common to all streams data stores, we handle
720 * it here instead of inside all stream VFS modules.
722 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13380
725 if (is_named_stream(smb_fname)) {
726 /* is_ntfs_stream_smb_fname() returns false for a POSIX path. */
727 dosmode &= ~(FILE_ATTRIBUTE_DIRECTORY);
730 if (conn->fs_capabilities & FILE_FILE_COMPRESSION) {
731 bool compressed = false;
733 status = dos_mode_check_compressed(conn, smb_fname,
735 if (NT_STATUS_IS_OK(status) && compressed) {
736 dosmode |= FILE_ATTRIBUTE_COMPRESSED;
740 dosmode |= dos_mode_from_name(conn, smb_fname, dosmode);
742 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
743 dosmode |= FILE_ATTRIBUTE_DIRECTORY;
744 } else if (dosmode == 0) {
745 dosmode = FILE_ATTRIBUTE_NORMAL;
748 dosmode = filter_mode_by_protocol(dosmode);
750 dos_mode_debug_print(func, dosmode);
754 /****************************************************************************
755 Change a unix mode to a dos mode.
756 May also read the create timespec into the stat struct in smb_fname
757 if "store dos attributes" is true.
758 ****************************************************************************/
760 uint32_t dos_mode(connection_struct *conn, struct smb_filename *smb_fname)
763 NTSTATUS status = NT_STATUS_OK;
765 DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname)));
767 if (!VALID_STAT(smb_fname->st)) {
771 /* Get the DOS attributes via the VFS if we can */
772 status = SMB_VFS_GET_DOS_ATTRIBUTES(conn, smb_fname, &result);
773 if (!NT_STATUS_IS_OK(status)) {
775 * Only fall back to using UNIX modes if we get NOT_IMPLEMENTED.
777 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
778 result |= dos_mode_from_sbuf(conn, smb_fname);
782 result = dos_mode_post(result, conn, smb_fname, __func__);
786 struct dos_mode_at_state {
787 files_struct *dir_fsp;
788 struct smb_filename *smb_fname;
792 static void dos_mode_at_vfs_get_dosmode_done(struct tevent_req *subreq);
794 struct tevent_req *dos_mode_at_send(TALLOC_CTX *mem_ctx,
795 struct tevent_context *ev,
796 files_struct *dir_fsp,
797 struct smb_filename *smb_fname)
799 struct tevent_req *req = NULL;
800 struct dos_mode_at_state *state = NULL;
801 struct tevent_req *subreq = NULL;
803 DBG_DEBUG("%s\n", smb_fname_str_dbg(smb_fname));
805 req = tevent_req_create(mem_ctx, &state,
806 struct dos_mode_at_state);
811 *state = (struct dos_mode_at_state) {
813 .smb_fname = smb_fname,
816 if (!VALID_STAT(smb_fname->st)) {
817 tevent_req_done(req);
818 return tevent_req_post(req, ev);
821 subreq = SMB_VFS_GET_DOS_ATTRIBUTES_SEND(state,
825 if (tevent_req_nomem(subreq, req)) {
826 return tevent_req_post(req, ev);
828 tevent_req_set_callback(subreq, dos_mode_at_vfs_get_dosmode_done, req);
833 static void dos_mode_at_vfs_get_dosmode_done(struct tevent_req *subreq)
835 struct tevent_req *req =
836 tevent_req_callback_data(subreq,
838 struct dos_mode_at_state *state =
840 struct dos_mode_at_state);
842 struct smb_filename *smb_path = NULL;
843 struct vfs_aio_state aio_state;
848 * Make sure we run as the user again
850 ok = change_to_user_and_service_by_fsp(state->dir_fsp);
853 status = SMB_VFS_GET_DOS_ATTRIBUTES_RECV(subreq,
857 if (!NT_STATUS_IS_OK(status)) {
859 * Both the sync dos_mode() as well as the async
860 * dos_mode_at_[send|recv] have no real error return, the only
861 * unhandled error is when the stat info in smb_fname is not
862 * valid (cf the checks in dos_mode() and dos_mode_at_send().
864 * If SMB_VFS_GET_DOS_ATTRIBUTES[_SEND|_RECV] fails we must call
865 * dos_mode_post() which also does the mapping of a last ressort
866 * from S_IFMT(st_mode).
868 * Only if we get NT_STATUS_NOT_IMPLEMENTED from a stacked VFS
869 * module we must fallback to sync processing.
871 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
873 * state->dosmode should still be 0, but reset
877 status = NT_STATUS_OK;
880 if (NT_STATUS_IS_OK(status)) {
881 state->dosmode = dos_mode_post(state->dosmode,
882 state->dir_fsp->conn,
885 tevent_req_done(req);
890 * Fall back to sync dos_mode() if we got NOT_IMPLEMENTED.
893 path = talloc_asprintf(state,
895 state->dir_fsp->fsp_name->base_name,
896 state->smb_fname->base_name);
897 if (tevent_req_nomem(path, req)) {
901 smb_path = synthetic_smb_fname(state,
904 &state->smb_fname->st,
906 if (tevent_req_nomem(smb_path, req)) {
910 state->dosmode = dos_mode(state->dir_fsp->conn, smb_path);
911 tevent_req_done(req);
915 NTSTATUS dos_mode_at_recv(struct tevent_req *req, uint32_t *dosmode)
917 struct dos_mode_at_state *state =
919 struct dos_mode_at_state);
922 if (tevent_req_is_nterror(req, &status)) {
923 tevent_req_received(req);
927 *dosmode = state->dosmode;
928 tevent_req_received(req);
932 /*******************************************************************
933 chmod a file - but preserve some bits.
934 If "store dos attributes" is also set it will store the create time
935 from the stat struct in smb_fname (in NTTIME format) in the EA
937 ********************************************************************/
939 int file_set_dosmode(connection_struct *conn,
940 struct smb_filename *smb_fname,
942 struct smb_filename *parent_dir,
948 int ret = -1, lret = -1;
949 files_struct *fsp = NULL;
950 bool need_close = false;
953 if (!CAN_WRITE(conn)) {
958 dosmode &= SAMBA_ATTRIBUTES_MASK;
960 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
961 dosmode, smb_fname_str_dbg(smb_fname)));
963 unixmode = smb_fname->st.st_ex_mode;
965 get_acl_group_bits(conn, smb_fname,
966 &smb_fname->st.st_ex_mode);
968 if (S_ISDIR(smb_fname->st.st_ex_mode))
969 dosmode |= FILE_ATTRIBUTE_DIRECTORY;
971 dosmode &= ~FILE_ATTRIBUTE_DIRECTORY;
973 /* Store the DOS attributes in an EA by preference. */
974 status = SMB_VFS_SET_DOS_ATTRIBUTES(conn, smb_fname, dosmode);
975 if (NT_STATUS_IS_OK(status)) {
977 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
978 FILE_NOTIFY_CHANGE_ATTRIBUTES,
979 smb_fname->base_name);
981 smb_fname->st.st_ex_mode = unixmode;
985 * Only fall back to using UNIX modes if
986 * we get NOT_IMPLEMENTED.
988 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
989 errno = map_errno_from_nt_status(status);
994 /* Fall back to UNIX modes. */
995 unixmode = unix_mode(conn, dosmode, smb_fname, parent_dir);
997 /* preserve the file type bits */
1000 /* preserve the s bits */
1001 mask |= (S_ISUID | S_ISGID);
1003 /* preserve the t bit */
1008 /* possibly preserve the x bits */
1009 if (!MAP_ARCHIVE(conn))
1011 if (!MAP_SYSTEM(conn))
1013 if (!MAP_HIDDEN(conn))
1016 unixmode |= (smb_fname->st.st_ex_mode & mask);
1018 /* if we previously had any r bits set then leave them alone */
1019 if ((tmp = smb_fname->st.st_ex_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
1020 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
1024 /* if we previously had any w bits set then leave them alone
1025 whilst adding in the new w bits, if the new mode is not rdonly */
1026 if (!IS_DOS_READONLY(dosmode)) {
1027 unixmode |= (smb_fname->st.st_ex_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
1031 * From the chmod 2 man page:
1033 * "If the calling process is not privileged, and the group of the file
1034 * does not match the effective group ID of the process or one of its
1035 * supplementary group IDs, the S_ISGID bit will be turned off, but
1036 * this will not cause an error to be returned."
1038 * Simply refuse to do the chmod in this case.
1041 if (S_ISDIR(smb_fname->st.st_ex_mode) && (unixmode & S_ISGID) &&
1042 geteuid() != sec_initial_uid() &&
1043 !current_user_in_group(conn, smb_fname->st.st_ex_gid)) {
1044 DEBUG(3,("file_set_dosmode: setgid bit cannot be "
1045 "set for directory %s\n",
1046 smb_fname_str_dbg(smb_fname)));
1051 ret = SMB_VFS_CHMOD(conn, smb_fname, unixmode);
1053 if(!newfile || (lret != -1)) {
1054 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
1055 FILE_NOTIFY_CHANGE_ATTRIBUTES,
1056 smb_fname->base_name);
1058 smb_fname->st.st_ex_mode = unixmode;
1062 if((errno != EPERM) && (errno != EACCES))
1065 if(!lp_dos_filemode(SNUM(conn)))
1068 /* We want DOS semantics, ie allow non owner with write permission to change the
1069 bits on a file. Just like file_ntimes below.
1072 if (!can_write_to_file(conn, smb_fname)) {
1078 * We need to get an open file handle to do the
1079 * metadata operation under root.
1082 status = get_file_handle_for_metadata(conn,
1086 if (!NT_STATUS_IS_OK(status)) {
1087 errno = map_errno_from_nt_status(status);
1092 ret = SMB_VFS_FCHMOD(fsp, unixmode);
1095 close_file(NULL, fsp, NORMAL_CLOSE);
1098 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
1099 FILE_NOTIFY_CHANGE_ATTRIBUTES,
1100 smb_fname->base_name);
1103 smb_fname->st.st_ex_mode = unixmode;
1110 NTSTATUS file_set_sparse(connection_struct *conn,
1114 const struct loadparm_substitution *lp_sub =
1115 loadparm_s3_global_substitution();
1116 uint32_t old_dosmode;
1117 uint32_t new_dosmode;
1120 if (!CAN_WRITE(conn)) {
1121 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
1122 "on readonly share[%s]\n",
1123 smb_fname_str_dbg(fsp->fsp_name),
1125 lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
1126 return NT_STATUS_MEDIA_WRITE_PROTECTED;
1130 * Windows Server 2008 & 2012 permit FSCTL_SET_SPARSE if any of the
1131 * following access flags are granted.
1133 if ((fsp->access_mask & (FILE_WRITE_DATA
1134 | FILE_WRITE_ATTRIBUTES
1135 | SEC_FILE_APPEND_DATA)) == 0) {
1136 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
1137 "access_mask[0x%08X] - access denied\n",
1138 smb_fname_str_dbg(fsp->fsp_name),
1141 return NT_STATUS_ACCESS_DENIED;
1144 if (fsp->fsp_flags.is_directory) {
1145 DEBUG(9, ("invalid attempt to %s sparse flag on dir %s\n",
1146 (sparse ? "set" : "clear"),
1147 smb_fname_str_dbg(fsp->fsp_name)));
1148 return NT_STATUS_INVALID_PARAMETER;
1151 if (IS_IPC(conn) || IS_PRINT(conn)) {
1152 DEBUG(9, ("attempt to %s sparse flag over invalid conn\n",
1153 (sparse ? "set" : "clear")));
1154 return NT_STATUS_INVALID_PARAMETER;
1157 DEBUG(10,("file_set_sparse: setting sparse bit %u on file %s\n",
1158 sparse, smb_fname_str_dbg(fsp->fsp_name)));
1160 if (!lp_store_dos_attributes(SNUM(conn))) {
1161 return NT_STATUS_INVALID_DEVICE_REQUEST;
1164 status = vfs_stat_fsp(fsp);
1165 if (!NT_STATUS_IS_OK(status)) {
1169 old_dosmode = dos_mode(conn, fsp->fsp_name);
1171 if (sparse && !(old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
1172 new_dosmode = old_dosmode | FILE_ATTRIBUTE_SPARSE;
1173 } else if (!sparse && (old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
1174 new_dosmode = old_dosmode & ~FILE_ATTRIBUTE_SPARSE;
1176 return NT_STATUS_OK;
1179 /* Store the DOS attributes in an EA. */
1180 status = SMB_VFS_FSET_DOS_ATTRIBUTES(conn, fsp, new_dosmode);
1181 if (!NT_STATUS_IS_OK(status)) {
1185 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
1186 FILE_NOTIFY_CHANGE_ATTRIBUTES,
1187 fsp->fsp_name->base_name);
1189 fsp->fsp_flags.is_sparse = sparse;
1191 return NT_STATUS_OK;
1194 /*******************************************************************
1195 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
1197 *******************************************************************/
1199 int file_ntimes(connection_struct *conn, const struct smb_filename *smb_fname,
1200 struct smb_file_time *ft)
1206 DEBUG(6, ("file_ntime: actime: %s",
1207 time_to_asc(convert_timespec_to_time_t(ft->atime))));
1208 DEBUG(6, ("file_ntime: modtime: %s",
1209 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
1210 DEBUG(6, ("file_ntime: ctime: %s",
1211 time_to_asc(convert_timespec_to_time_t(ft->ctime))));
1212 DEBUG(6, ("file_ntime: createtime: %s",
1213 time_to_asc(convert_timespec_to_time_t(ft->create_time))));
1215 /* Don't update the time on read-only shares */
1216 /* We need this as set_filetime (which can be called on
1217 close and other paths) can end up calling this function
1218 without the NEED_WRITE protection. Found by :
1219 Leo Weppelman <leo@wau.mis.ah.nl>
1222 if (!CAN_WRITE(conn)) {
1226 if(SMB_VFS_NTIMES(conn, smb_fname, ft) == 0) {
1230 if((errno != EPERM) && (errno != EACCES)) {
1234 if(!lp_dos_filetimes(SNUM(conn))) {
1238 /* We have permission (given by the Samba admin) to
1239 break POSIX semantics and allow a user to change
1240 the time on a file they don't own but can write to
1244 /* Check if we have write access. */
1245 if (can_write_to_file(conn, smb_fname)) {
1246 /* We are allowed to become root and change the filetime. */
1248 ret = SMB_VFS_NTIMES(conn, smb_fname, ft);
1255 /******************************************************************
1256 Force a "sticky" write time on a pathname. This will always be
1257 returned on all future write time queries and set on close.
1258 ******************************************************************/
1260 bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime)
1262 if (is_omit_timespec(&mtime)) {
1266 if (!set_sticky_write_time(fileid, mtime)) {
1273 /******************************************************************
1274 Force a "sticky" write time on an fsp. This will always be
1275 returned on all future write time queries and set on close.
1276 ******************************************************************/
1278 bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime)
1280 if (is_omit_timespec(&mtime)) {
1284 fsp->fsp_flags.write_time_forced = true;
1285 TALLOC_FREE(fsp->update_write_time_event);
1287 return set_sticky_write_time_path(fsp->file_id, mtime);
1290 /******************************************************************
1291 Set a create time EA.
1292 ******************************************************************/
1294 NTSTATUS set_create_timespec_ea(connection_struct *conn,
1295 const struct smb_filename *psmb_fname,
1296 struct timespec create_time)
1298 struct smb_filename *smb_fname;
1302 if (!lp_store_dos_attributes(SNUM(conn))) {
1303 return NT_STATUS_OK;
1306 smb_fname = synthetic_smb_fname(talloc_tos(),
1307 psmb_fname->base_name,
1312 if (smb_fname == NULL) {
1313 return NT_STATUS_NO_MEMORY;
1316 dosmode = dos_mode(conn, smb_fname);
1318 smb_fname->st.st_ex_btime = create_time;
1320 ret = file_set_dosmode(conn, smb_fname, dosmode, NULL, false);
1322 return map_nt_error_from_unix(errno);
1325 DEBUG(10,("set_create_timespec_ea: wrote create time EA for file %s\n",
1326 smb_fname_str_dbg(smb_fname)));
1328 return NT_STATUS_OK;
1331 /******************************************************************
1332 Return a create time.
1333 ******************************************************************/
1335 struct timespec get_create_timespec(connection_struct *conn,
1336 struct files_struct *fsp,
1337 const struct smb_filename *smb_fname)
1339 return smb_fname->st.st_ex_btime;
1342 /******************************************************************
1343 Return a change time (may look at EA in future).
1344 ******************************************************************/
1346 struct timespec get_change_timespec(connection_struct *conn,
1347 struct files_struct *fsp,
1348 const struct smb_filename *smb_fname)
1350 return smb_fname->st.st_ex_mtime;
1353 /****************************************************************************
1354 Get a real open file handle we can do meta-data operations on. As it's
1355 going to be used under root access only on meta-data we should look for
1356 any existing open file handle first, and use that in preference (also to
1357 avoid kernel self-oplock breaks). If not use an INTERNAL_OPEN_ONLY handle.
1358 ****************************************************************************/
1360 static NTSTATUS get_file_handle_for_metadata(connection_struct *conn,
1361 const struct smb_filename *smb_fname,
1362 files_struct **ret_fsp,
1367 struct file_id file_id;
1368 struct smb_filename *smb_fname_cp = NULL;
1370 *need_close = false;
1372 if (!VALID_STAT(smb_fname->st)) {
1373 return NT_STATUS_INVALID_PARAMETER;
1376 file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1378 for(fsp = file_find_di_first(conn->sconn, file_id);
1380 fsp = file_find_di_next(fsp)) {
1381 if (fsp->fh->fd != -1) {
1383 return NT_STATUS_OK;
1387 smb_fname_cp = cp_smb_filename(talloc_tos(),
1389 if (smb_fname_cp == NULL) {
1390 return NT_STATUS_NO_MEMORY;
1393 /* Opens an INTERNAL_OPEN_ONLY write handle. */
1394 status = SMB_VFS_CREATE_FILE(
1397 0, /* root_dir_fid */
1398 smb_fname_cp, /* fname */
1399 FILE_WRITE_ATTRIBUTES, /* access_mask */
1400 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
1402 FILE_OPEN, /* create_disposition*/
1403 0, /* create_options */
1404 0, /* file_attributes */
1405 INTERNAL_OPEN_ONLY, /* oplock_request */
1407 0, /* allocation_size */
1408 0, /* private_flags */
1411 ret_fsp, /* result */
1413 NULL, NULL); /* create context */
1415 TALLOC_FREE(smb_fname_cp);
1417 if (NT_STATUS_IS_OK(status)) {