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,
225 result |= FILE_ATTRIBUTE_READONLY;
227 } /* Else never set the readonly bit. */
229 if (MAP_ARCHIVE(conn) && ((smb_fname->st.st_ex_mode & S_IXUSR) != 0))
230 result |= FILE_ATTRIBUTE_ARCHIVE;
232 if (MAP_SYSTEM(conn) && ((smb_fname->st.st_ex_mode & S_IXGRP) != 0))
233 result |= FILE_ATTRIBUTE_SYSTEM;
235 if (MAP_HIDDEN(conn) && ((smb_fname->st.st_ex_mode & S_IXOTH) != 0))
236 result |= FILE_ATTRIBUTE_HIDDEN;
238 if (S_ISDIR(smb_fname->st.st_ex_mode))
239 result = FILE_ATTRIBUTE_DIRECTORY | (result & FILE_ATTRIBUTE_READONLY);
241 result |= set_link_read_only_flag(&smb_fname->st);
243 dos_mode_debug_print(__func__, result);
248 /****************************************************************************
249 Get DOS attributes from an EA.
250 This can also pull the create time into the stat struct inside smb_fname.
251 ****************************************************************************/
253 NTSTATUS parse_dos_attribute_blob(struct smb_filename *smb_fname,
257 struct xattr_DOSATTRIB dosattrib;
258 enum ndr_err_code ndr_err;
261 ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &dosattrib,
262 (ndr_pull_flags_fn_t)ndr_pull_xattr_DOSATTRIB);
264 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
265 DBG_WARNING("bad ndr decode "
266 "from EA on file %s: Error = %s\n",
267 smb_fname_str_dbg(smb_fname),
268 ndr_errstr(ndr_err));
269 return ndr_map_error2ntstatus(ndr_err);
272 DBG_DEBUG("%s attr = %s\n",
273 smb_fname_str_dbg(smb_fname), dosattrib.attrib_hex);
275 switch (dosattrib.version) {
277 dosattr = dosattrib.info.compatinfoFFFF.attrib;
280 dosattr = dosattrib.info.info1.attrib;
281 if (!null_nttime(dosattrib.info.info1.create_time)) {
282 struct timespec create_time =
283 nt_time_to_unix_timespec(
284 dosattrib.info.info1.create_time);
286 update_stat_ex_create_time(&smb_fname->st,
289 DBG_DEBUG("file %s case 1 set btime %s\n",
290 smb_fname_str_dbg(smb_fname),
291 time_to_asc(convert_timespec_to_time_t(
296 dosattr = dosattrib.info.oldinfo2.attrib;
297 /* Don't know what flags to check for this case. */
300 dosattr = dosattrib.info.info3.attrib;
301 if ((dosattrib.info.info3.valid_flags & XATTR_DOSINFO_CREATE_TIME) &&
302 !null_nttime(dosattrib.info.info3.create_time)) {
303 struct timespec create_time =
304 nt_time_to_full_timespec(
305 dosattrib.info.info3.create_time);
307 update_stat_ex_create_time(&smb_fname->st,
310 DBG_DEBUG("file %s case 3 set btime %s\n",
311 smb_fname_str_dbg(smb_fname),
312 time_to_asc(convert_timespec_to_time_t(
318 struct xattr_DosInfo4 *info = &dosattrib.info.info4;
320 dosattr = info->attrib;
322 if ((info->valid_flags & XATTR_DOSINFO_CREATE_TIME) &&
323 !null_nttime(info->create_time))
325 struct timespec creat_time;
327 creat_time = nt_time_to_full_timespec(info->create_time);
328 update_stat_ex_create_time(&smb_fname->st, creat_time);
330 DBG_DEBUG("file [%s] creation time [%s]\n",
331 smb_fname_str_dbg(smb_fname),
332 nt_time_string(talloc_tos(), info->create_time));
335 if (info->valid_flags & XATTR_DOSINFO_ITIME) {
336 struct timespec itime;
339 itime = nt_time_to_unix_timespec(info->itime);
340 if (smb_fname->st.st_ex_iflags &
341 ST_EX_IFLAG_CALCULATED_ITIME)
343 update_stat_ex_itime(&smb_fname->st, itime);
346 file_id = make_file_id_from_itime(&smb_fname->st);
347 if (smb_fname->st.st_ex_iflags &
348 ST_EX_IFLAG_CALCULATED_FILE_ID)
350 update_stat_ex_file_id(&smb_fname->st, file_id);
353 DBG_DEBUG("file [%s] itime [%s] fileid [%"PRIx64"]\n",
354 smb_fname_str_dbg(smb_fname),
355 nt_time_string(talloc_tos(), info->itime),
361 DBG_WARNING("Badly formed DOSATTRIB on file %s - %s\n",
362 smb_fname_str_dbg(smb_fname), blob.data);
363 /* Should this be INTERNAL_ERROR? */
364 return NT_STATUS_INVALID_PARAMETER;
367 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
368 dosattr |= FILE_ATTRIBUTE_DIRECTORY;
371 /* FILE_ATTRIBUTE_SPARSE is valid on get but not on set. */
372 *pattr |= (uint32_t)(dosattr & (SAMBA_ATTRIBUTES_MASK|FILE_ATTRIBUTE_SPARSE));
374 dos_mode_debug_print(__func__, *pattr);
379 NTSTATUS get_ea_dos_attribute(connection_struct *conn,
380 struct smb_filename *smb_fname,
388 if (!lp_store_dos_attributes(SNUM(conn))) {
389 return NT_STATUS_NOT_IMPLEMENTED;
392 /* Don't reset pattr to zero as we may already have filename-based attributes we
395 sizeret = SMB_VFS_GETXATTR(conn, smb_fname,
396 SAMBA_XATTR_DOS_ATTRIB, attrstr,
398 if (sizeret == -1 && errno == EACCES) {
402 * According to MS-FSA 2.1.5.1.2.1 "Algorithm to Check Access to
403 * an Existing File" FILE_LIST_DIRECTORY on a directory implies
404 * FILE_READ_ATTRIBUTES for directory entries. Being able to
405 * stat() a file implies FILE_LIST_DIRECTORY for the directory
406 * containing the file.
409 if (!VALID_STAT(smb_fname->st)) {
411 * Safety net: dos_mode() already checks this, but as we
412 * become root based on this, add an additional layer of
415 DBG_ERR("Rejecting root override, invalid stat [%s]\n",
416 smb_fname_str_dbg(smb_fname));
417 return NT_STATUS_ACCESS_DENIED;
421 sizeret = SMB_VFS_GETXATTR(conn, smb_fname,
422 SAMBA_XATTR_DOS_ATTRIB,
430 if (saved_errno != 0) {
435 DBG_INFO("Cannot get attribute "
436 "from EA on file %s: Error = %s\n",
437 smb_fname_str_dbg(smb_fname), strerror(errno));
438 return map_nt_error_from_unix(errno);
441 blob.data = (uint8_t *)attrstr;
442 blob.length = sizeret;
444 status = parse_dos_attribute_blob(smb_fname, blob, pattr);
445 if (!NT_STATUS_IS_OK(status)) {
452 /****************************************************************************
453 Set DOS attributes in an EA.
454 Also sets the create time.
455 ****************************************************************************/
457 NTSTATUS set_ea_dos_attribute(connection_struct *conn,
458 const struct smb_filename *smb_fname,
461 struct xattr_DOSATTRIB dosattrib;
462 enum ndr_err_code ndr_err;
466 if (!lp_store_dos_attributes(SNUM(conn))) {
467 return NT_STATUS_NOT_IMPLEMENTED;
471 * Don't store FILE_ATTRIBUTE_OFFLINE, it's dealt with in
472 * vfs_default via DMAPI if that is enabled.
474 dosmode &= ~FILE_ATTRIBUTE_OFFLINE;
476 ZERO_STRUCT(dosattrib);
479 dosattrib.version = 4;
480 dosattrib.info.info4.valid_flags = XATTR_DOSINFO_ATTRIB |
481 XATTR_DOSINFO_CREATE_TIME;
482 dosattrib.info.info4.attrib = dosmode;
483 dosattrib.info.info4.create_time = full_timespec_to_nt_time(
484 &smb_fname->st.st_ex_btime);
486 if (!(smb_fname->st.st_ex_iflags & ST_EX_IFLAG_CALCULATED_ITIME)) {
487 dosattrib.info.info4.valid_flags |= XATTR_DOSINFO_ITIME;
488 dosattrib.info.info4.itime = full_timespec_to_nt_time(
489 &smb_fname->st.st_ex_itime);
492 DEBUG(10,("set_ea_dos_attributes: set attribute 0x%x, btime = %s on file %s\n",
493 (unsigned int)dosmode,
494 time_to_asc(convert_timespec_to_time_t(smb_fname->st.st_ex_btime)),
495 smb_fname_str_dbg(smb_fname) ));
497 ndr_err = ndr_push_struct_blob(
498 &blob, talloc_tos(), &dosattrib,
499 (ndr_push_flags_fn_t)ndr_push_xattr_DOSATTRIB);
501 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
502 DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n",
503 ndr_errstr(ndr_err)));
504 return ndr_map_error2ntstatus(ndr_err);
507 if (blob.data == NULL || blob.length == 0) {
508 /* Should this be INTERNAL_ERROR? */
509 return NT_STATUS_INVALID_PARAMETER;
512 ret = SMB_VFS_SETXATTR(conn, smb_fname,
513 SAMBA_XATTR_DOS_ATTRIB,
514 blob.data, blob.length, 0);
516 NTSTATUS status = NT_STATUS_OK;
517 bool need_close = false;
518 files_struct *fsp = NULL;
519 bool set_dosmode_ok = false;
521 if ((errno != EPERM) && (errno != EACCES)) {
522 DBG_INFO("Cannot set "
523 "attribute EA on file %s: Error = %s\n",
524 smb_fname_str_dbg(smb_fname), strerror(errno));
525 return map_nt_error_from_unix(errno);
528 /* We want DOS semantics, ie allow non owner with write permission to change the
529 bits on a file. Just like file_ntimes below.
532 /* Check if we have write access. */
533 if (!CAN_WRITE(conn)) {
534 return NT_STATUS_ACCESS_DENIED;
537 status = smbd_check_access_rights(conn, smb_fname, false,
538 FILE_WRITE_ATTRIBUTES);
539 if (NT_STATUS_IS_OK(status)) {
540 set_dosmode_ok = true;
543 if (!set_dosmode_ok && lp_dos_filemode(SNUM(conn))) {
544 set_dosmode_ok = can_write_to_file(conn,
548 if (!set_dosmode_ok) {
549 return NT_STATUS_ACCESS_DENIED;
553 * We need to get an open file handle to do the
554 * metadata operation under root.
557 status = get_file_handle_for_metadata(conn,
561 if (!NT_STATUS_IS_OK(status)) {
566 ret = SMB_VFS_FSETXATTR(fsp,
567 SAMBA_XATTR_DOS_ATTRIB,
568 blob.data, blob.length, 0);
570 status = NT_STATUS_OK;
574 close_file(NULL, fsp, NORMAL_CLOSE);
578 DEBUG(10,("set_ea_dos_attribute: set EA 0x%x on file %s\n",
579 (unsigned int)dosmode,
580 smb_fname_str_dbg(smb_fname)));
584 /****************************************************************************
585 Change a unix mode to a dos mode for an ms dfs link.
586 ****************************************************************************/
588 uint32_t dos_mode_msdfs(connection_struct *conn,
589 const struct smb_filename *smb_fname)
593 DEBUG(8,("dos_mode_msdfs: %s\n", smb_fname_str_dbg(smb_fname)));
595 if (!VALID_STAT(smb_fname->st)) {
599 /* First do any modifications that depend on the path name. */
600 /* hide files with a name starting with a . */
601 if (lp_hide_dot_files(SNUM(conn))) {
602 const char *p = strrchr_m(smb_fname->base_name, '/');
606 p = smb_fname->base_name;
609 /* Only . and .. are not hidden. */
610 if (p[0] == '.' && !((p[1] == '\0') ||
611 (p[1] == '.' && p[2] == '\0'))) {
612 result |= FILE_ATTRIBUTE_HIDDEN;
616 result |= dos_mode_from_sbuf(conn, smb_fname);
618 /* Optimization : Only call is_hidden_path if it's not already
620 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
621 IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
622 result |= FILE_ATTRIBUTE_HIDDEN;
626 result = FILE_ATTRIBUTE_NORMAL;
629 result = filter_mode_by_protocol(result);
632 * Add in that it is a reparse point
634 result |= FILE_ATTRIBUTE_REPARSE_POINT;
636 dos_mode_debug_print(__func__, result);
642 * check whether a file or directory is flagged as compressed.
644 static NTSTATUS dos_mode_check_compressed(connection_struct *conn,
645 struct smb_filename *smb_fname,
649 uint16_t compression_fmt;
650 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
651 if (tmp_ctx == NULL) {
652 status = NT_STATUS_NO_MEMORY;
656 status = SMB_VFS_GET_COMPRESSION(conn, tmp_ctx, NULL, smb_fname,
658 if (!NT_STATUS_IS_OK(status)) {
662 if (compression_fmt == COMPRESSION_FORMAT_LZNT1) {
663 *is_compressed = true;
665 *is_compressed = false;
667 status = NT_STATUS_OK;
670 talloc_free(tmp_ctx);
675 static uint32_t dos_mode_from_name(connection_struct *conn,
676 const struct smb_filename *smb_fname,
679 const char *p = NULL;
680 uint32_t result = dosmode;
682 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
683 lp_hide_dot_files(SNUM(conn)))
685 p = strrchr_m(smb_fname->base_name, '/');
689 p = smb_fname->base_name;
692 /* Only . and .. are not hidden. */
694 !((p[1] == '\0') || (p[1] == '.' && p[2] == '\0')))
696 result |= FILE_ATTRIBUTE_HIDDEN;
700 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
701 IS_HIDDEN_PATH(conn, smb_fname->base_name))
703 result |= FILE_ATTRIBUTE_HIDDEN;
709 static uint32_t dos_mode_post(uint32_t dosmode,
710 connection_struct *conn,
711 struct smb_filename *smb_fname,
717 * According to MS-FSA a stream name does not have
718 * separate DOS attribute metadata, so we must return
719 * the DOS attribute from the base filename. With one caveat,
720 * a non-default stream name can never be a directory.
722 * As this is common to all streams data stores, we handle
723 * it here instead of inside all stream VFS modules.
725 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13380
728 if (is_named_stream(smb_fname)) {
729 /* is_ntfs_stream_smb_fname() returns false for a POSIX path. */
730 dosmode &= ~(FILE_ATTRIBUTE_DIRECTORY);
733 if (conn->fs_capabilities & FILE_FILE_COMPRESSION) {
734 bool compressed = false;
736 status = dos_mode_check_compressed(conn, smb_fname,
738 if (NT_STATUS_IS_OK(status) && compressed) {
739 dosmode |= FILE_ATTRIBUTE_COMPRESSED;
743 dosmode |= dos_mode_from_name(conn, smb_fname, dosmode);
745 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
746 dosmode |= FILE_ATTRIBUTE_DIRECTORY;
747 } else if (dosmode == 0) {
748 dosmode = FILE_ATTRIBUTE_NORMAL;
751 dosmode = filter_mode_by_protocol(dosmode);
753 dos_mode_debug_print(func, dosmode);
757 /****************************************************************************
758 Change a unix mode to a dos mode.
759 May also read the create timespec into the stat struct in smb_fname
760 if "store dos attributes" is true.
761 ****************************************************************************/
763 uint32_t dos_mode(connection_struct *conn, struct smb_filename *smb_fname)
766 NTSTATUS status = NT_STATUS_OK;
768 DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname)));
770 if (!VALID_STAT(smb_fname->st)) {
774 /* Get the DOS attributes via the VFS if we can */
775 status = SMB_VFS_GET_DOS_ATTRIBUTES(conn, smb_fname, &result);
776 if (!NT_STATUS_IS_OK(status)) {
778 * Only fall back to using UNIX modes if we get NOT_IMPLEMENTED.
780 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
781 result |= dos_mode_from_sbuf(conn, smb_fname);
785 result = dos_mode_post(result, conn, smb_fname, __func__);
789 struct dos_mode_at_state {
790 files_struct *dir_fsp;
791 struct smb_filename *smb_fname;
795 static void dos_mode_at_vfs_get_dosmode_done(struct tevent_req *subreq);
797 struct tevent_req *dos_mode_at_send(TALLOC_CTX *mem_ctx,
798 struct tevent_context *ev,
799 files_struct *dir_fsp,
800 struct smb_filename *smb_fname)
802 struct tevent_req *req = NULL;
803 struct dos_mode_at_state *state = NULL;
804 struct tevent_req *subreq = NULL;
806 DBG_DEBUG("%s\n", smb_fname_str_dbg(smb_fname));
808 req = tevent_req_create(mem_ctx, &state,
809 struct dos_mode_at_state);
814 *state = (struct dos_mode_at_state) {
816 .smb_fname = smb_fname,
819 if (!VALID_STAT(smb_fname->st)) {
820 tevent_req_done(req);
821 return tevent_req_post(req, ev);
824 subreq = SMB_VFS_GET_DOS_ATTRIBUTES_SEND(state,
828 if (tevent_req_nomem(subreq, req)) {
829 return tevent_req_post(req, ev);
831 tevent_req_set_callback(subreq, dos_mode_at_vfs_get_dosmode_done, req);
836 static void dos_mode_at_vfs_get_dosmode_done(struct tevent_req *subreq)
838 struct tevent_req *req =
839 tevent_req_callback_data(subreq,
841 struct dos_mode_at_state *state =
843 struct dos_mode_at_state);
845 struct smb_filename *smb_path = NULL;
846 struct vfs_aio_state aio_state;
851 * Make sure we run as the user again
853 ok = change_to_user_and_service_by_fsp(state->dir_fsp);
856 status = SMB_VFS_GET_DOS_ATTRIBUTES_RECV(subreq,
860 if (!NT_STATUS_IS_OK(status)) {
862 * Both the sync dos_mode() as well as the async
863 * dos_mode_at_[send|recv] have no real error return, the only
864 * unhandled error is when the stat info in smb_fname is not
865 * valid (cf the checks in dos_mode() and dos_mode_at_send().
867 * If SMB_VFS_GET_DOS_ATTRIBUTES[_SEND|_RECV] fails we must call
868 * dos_mode_post() which also does the mapping of a last ressort
869 * from S_IFMT(st_mode).
871 * Only if we get NT_STATUS_NOT_IMPLEMENTED from a stacked VFS
872 * module we must fallback to sync processing.
874 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
876 * state->dosmode should still be 0, but reset
880 status = NT_STATUS_OK;
883 if (NT_STATUS_IS_OK(status)) {
884 state->dosmode = dos_mode_post(state->dosmode,
885 state->dir_fsp->conn,
888 tevent_req_done(req);
893 * Fall back to sync dos_mode() if we got NOT_IMPLEMENTED.
896 path = talloc_asprintf(state,
898 state->dir_fsp->fsp_name->base_name,
899 state->smb_fname->base_name);
900 if (tevent_req_nomem(path, req)) {
904 smb_path = synthetic_smb_fname(state,
907 &state->smb_fname->st,
909 if (tevent_req_nomem(smb_path, req)) {
913 state->dosmode = dos_mode(state->dir_fsp->conn, smb_path);
914 tevent_req_done(req);
918 NTSTATUS dos_mode_at_recv(struct tevent_req *req, uint32_t *dosmode)
920 struct dos_mode_at_state *state =
922 struct dos_mode_at_state);
925 if (tevent_req_is_nterror(req, &status)) {
926 tevent_req_received(req);
930 *dosmode = state->dosmode;
931 tevent_req_received(req);
935 /*******************************************************************
936 chmod a file - but preserve some bits.
937 If "store dos attributes" is also set it will store the create time
938 from the stat struct in smb_fname (in NTTIME format) in the EA
940 ********************************************************************/
942 int file_set_dosmode(connection_struct *conn,
943 struct smb_filename *smb_fname,
945 struct smb_filename *parent_dir,
951 int ret = -1, lret = -1;
952 files_struct *fsp = NULL;
953 bool need_close = false;
956 if (!CAN_WRITE(conn)) {
961 dosmode &= SAMBA_ATTRIBUTES_MASK;
963 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
964 dosmode, smb_fname_str_dbg(smb_fname)));
966 unixmode = smb_fname->st.st_ex_mode;
968 get_acl_group_bits(conn, smb_fname,
969 &smb_fname->st.st_ex_mode);
971 if (S_ISDIR(smb_fname->st.st_ex_mode))
972 dosmode |= FILE_ATTRIBUTE_DIRECTORY;
974 dosmode &= ~FILE_ATTRIBUTE_DIRECTORY;
976 /* Store the DOS attributes in an EA by preference. */
977 status = SMB_VFS_SET_DOS_ATTRIBUTES(conn, smb_fname, dosmode);
978 if (NT_STATUS_IS_OK(status)) {
980 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
981 FILE_NOTIFY_CHANGE_ATTRIBUTES,
982 smb_fname->base_name);
984 smb_fname->st.st_ex_mode = unixmode;
988 * Only fall back to using UNIX modes if
989 * we get NOT_IMPLEMENTED.
991 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
992 errno = map_errno_from_nt_status(status);
997 /* Fall back to UNIX modes. */
998 unixmode = unix_mode(conn, dosmode, smb_fname, parent_dir);
1000 /* preserve the file type bits */
1003 /* preserve the s bits */
1004 mask |= (S_ISUID | S_ISGID);
1006 /* preserve the t bit */
1011 /* possibly preserve the x bits */
1012 if (!MAP_ARCHIVE(conn))
1014 if (!MAP_SYSTEM(conn))
1016 if (!MAP_HIDDEN(conn))
1019 unixmode |= (smb_fname->st.st_ex_mode & mask);
1021 /* if we previously had any r bits set then leave them alone */
1022 if ((tmp = smb_fname->st.st_ex_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
1023 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
1027 /* if we previously had any w bits set then leave them alone
1028 whilst adding in the new w bits, if the new mode is not rdonly */
1029 if (!IS_DOS_READONLY(dosmode)) {
1030 unixmode |= (smb_fname->st.st_ex_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
1034 * From the chmod 2 man page:
1036 * "If the calling process is not privileged, and the group of the file
1037 * does not match the effective group ID of the process or one of its
1038 * supplementary group IDs, the S_ISGID bit will be turned off, but
1039 * this will not cause an error to be returned."
1041 * Simply refuse to do the chmod in this case.
1044 if (S_ISDIR(smb_fname->st.st_ex_mode) && (unixmode & S_ISGID) &&
1045 geteuid() != sec_initial_uid() &&
1046 !current_user_in_group(conn, smb_fname->st.st_ex_gid)) {
1047 DEBUG(3,("file_set_dosmode: setgid bit cannot be "
1048 "set for directory %s\n",
1049 smb_fname_str_dbg(smb_fname)));
1054 ret = SMB_VFS_CHMOD(conn, smb_fname, unixmode);
1056 if(!newfile || (lret != -1)) {
1057 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
1058 FILE_NOTIFY_CHANGE_ATTRIBUTES,
1059 smb_fname->base_name);
1061 smb_fname->st.st_ex_mode = unixmode;
1065 if((errno != EPERM) && (errno != EACCES))
1068 if(!lp_dos_filemode(SNUM(conn)))
1071 /* We want DOS semantics, ie allow non owner with write permission to change the
1072 bits on a file. Just like file_ntimes below.
1075 if (!can_write_to_file(conn,
1083 * We need to get an open file handle to do the
1084 * metadata operation under root.
1087 status = get_file_handle_for_metadata(conn,
1091 if (!NT_STATUS_IS_OK(status)) {
1092 errno = map_errno_from_nt_status(status);
1097 ret = SMB_VFS_FCHMOD(fsp, unixmode);
1100 close_file(NULL, fsp, NORMAL_CLOSE);
1103 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
1104 FILE_NOTIFY_CHANGE_ATTRIBUTES,
1105 smb_fname->base_name);
1108 smb_fname->st.st_ex_mode = unixmode;
1115 NTSTATUS file_set_sparse(connection_struct *conn,
1119 const struct loadparm_substitution *lp_sub =
1120 loadparm_s3_global_substitution();
1121 uint32_t old_dosmode;
1122 uint32_t new_dosmode;
1125 if (!CAN_WRITE(conn)) {
1126 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
1127 "on readonly share[%s]\n",
1128 smb_fname_str_dbg(fsp->fsp_name),
1130 lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
1131 return NT_STATUS_MEDIA_WRITE_PROTECTED;
1135 * Windows Server 2008 & 2012 permit FSCTL_SET_SPARSE if any of the
1136 * following access flags are granted.
1138 if ((fsp->access_mask & (FILE_WRITE_DATA
1139 | FILE_WRITE_ATTRIBUTES
1140 | SEC_FILE_APPEND_DATA)) == 0) {
1141 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
1142 "access_mask[0x%08X] - access denied\n",
1143 smb_fname_str_dbg(fsp->fsp_name),
1146 return NT_STATUS_ACCESS_DENIED;
1149 if (fsp->fsp_flags.is_directory) {
1150 DEBUG(9, ("invalid attempt to %s sparse flag on dir %s\n",
1151 (sparse ? "set" : "clear"),
1152 smb_fname_str_dbg(fsp->fsp_name)));
1153 return NT_STATUS_INVALID_PARAMETER;
1156 if (IS_IPC(conn) || IS_PRINT(conn)) {
1157 DEBUG(9, ("attempt to %s sparse flag over invalid conn\n",
1158 (sparse ? "set" : "clear")));
1159 return NT_STATUS_INVALID_PARAMETER;
1162 DEBUG(10,("file_set_sparse: setting sparse bit %u on file %s\n",
1163 sparse, smb_fname_str_dbg(fsp->fsp_name)));
1165 if (!lp_store_dos_attributes(SNUM(conn))) {
1166 return NT_STATUS_INVALID_DEVICE_REQUEST;
1169 status = vfs_stat_fsp(fsp);
1170 if (!NT_STATUS_IS_OK(status)) {
1174 old_dosmode = dos_mode(conn, fsp->fsp_name);
1176 if (sparse && !(old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
1177 new_dosmode = old_dosmode | FILE_ATTRIBUTE_SPARSE;
1178 } else if (!sparse && (old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
1179 new_dosmode = old_dosmode & ~FILE_ATTRIBUTE_SPARSE;
1181 return NT_STATUS_OK;
1184 /* Store the DOS attributes in an EA. */
1185 status = SMB_VFS_FSET_DOS_ATTRIBUTES(conn, fsp, new_dosmode);
1186 if (!NT_STATUS_IS_OK(status)) {
1190 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
1191 FILE_NOTIFY_CHANGE_ATTRIBUTES,
1192 fsp->fsp_name->base_name);
1194 fsp->fsp_flags.is_sparse = sparse;
1196 return NT_STATUS_OK;
1199 /*******************************************************************
1200 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
1202 *******************************************************************/
1204 int file_ntimes(connection_struct *conn, const struct smb_filename *smb_fname,
1205 struct smb_file_time *ft)
1211 DEBUG(6, ("file_ntime: actime: %s",
1212 time_to_asc(convert_timespec_to_time_t(ft->atime))));
1213 DEBUG(6, ("file_ntime: modtime: %s",
1214 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
1215 DEBUG(6, ("file_ntime: ctime: %s",
1216 time_to_asc(convert_timespec_to_time_t(ft->ctime))));
1217 DEBUG(6, ("file_ntime: createtime: %s",
1218 time_to_asc(convert_timespec_to_time_t(ft->create_time))));
1220 /* Don't update the time on read-only shares */
1221 /* We need this as set_filetime (which can be called on
1222 close and other paths) can end up calling this function
1223 without the NEED_WRITE protection. Found by :
1224 Leo Weppelman <leo@wau.mis.ah.nl>
1227 if (!CAN_WRITE(conn)) {
1231 if(SMB_VFS_NTIMES(conn, smb_fname, ft) == 0) {
1235 if((errno != EPERM) && (errno != EACCES)) {
1239 if(!lp_dos_filetimes(SNUM(conn))) {
1243 /* We have permission (given by the Samba admin) to
1244 break POSIX semantics and allow a user to change
1245 the time on a file they don't own but can write to
1249 /* Check if we have write access. */
1250 if (can_write_to_file(conn,
1253 /* We are allowed to become root and change the filetime. */
1255 ret = SMB_VFS_NTIMES(conn, smb_fname, ft);
1262 /******************************************************************
1263 Force a "sticky" write time on a pathname. This will always be
1264 returned on all future write time queries and set on close.
1265 ******************************************************************/
1267 bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime)
1269 if (is_omit_timespec(&mtime)) {
1273 if (!set_sticky_write_time(fileid, mtime)) {
1280 /******************************************************************
1281 Force a "sticky" write time on an fsp. This will always be
1282 returned on all future write time queries and set on close.
1283 ******************************************************************/
1285 bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime)
1287 if (is_omit_timespec(&mtime)) {
1291 fsp->fsp_flags.write_time_forced = true;
1292 TALLOC_FREE(fsp->update_write_time_event);
1294 return set_sticky_write_time_path(fsp->file_id, mtime);
1297 /******************************************************************
1298 Set a create time EA.
1299 ******************************************************************/
1301 NTSTATUS set_create_timespec_ea(connection_struct *conn,
1302 const struct smb_filename *psmb_fname,
1303 struct timespec create_time)
1305 struct smb_filename *smb_fname;
1309 if (!lp_store_dos_attributes(SNUM(conn))) {
1310 return NT_STATUS_OK;
1313 smb_fname = synthetic_smb_fname(talloc_tos(),
1314 psmb_fname->base_name,
1319 if (smb_fname == NULL) {
1320 return NT_STATUS_NO_MEMORY;
1323 dosmode = dos_mode(conn, smb_fname);
1325 smb_fname->st.st_ex_btime = create_time;
1327 ret = file_set_dosmode(conn, smb_fname, dosmode, NULL, false);
1329 return map_nt_error_from_unix(errno);
1332 DEBUG(10,("set_create_timespec_ea: wrote create time EA for file %s\n",
1333 smb_fname_str_dbg(smb_fname)));
1335 return NT_STATUS_OK;
1338 /******************************************************************
1339 Return a create time.
1340 ******************************************************************/
1342 struct timespec get_create_timespec(connection_struct *conn,
1343 struct files_struct *fsp,
1344 const struct smb_filename *smb_fname)
1346 return smb_fname->st.st_ex_btime;
1349 /******************************************************************
1350 Return a change time (may look at EA in future).
1351 ******************************************************************/
1353 struct timespec get_change_timespec(connection_struct *conn,
1354 struct files_struct *fsp,
1355 const struct smb_filename *smb_fname)
1357 return smb_fname->st.st_ex_mtime;
1360 /****************************************************************************
1361 Get a real open file handle we can do meta-data operations on. As it's
1362 going to be used under root access only on meta-data we should look for
1363 any existing open file handle first, and use that in preference (also to
1364 avoid kernel self-oplock breaks). If not use an INTERNAL_OPEN_ONLY handle.
1365 ****************************************************************************/
1367 static NTSTATUS get_file_handle_for_metadata(connection_struct *conn,
1368 const struct smb_filename *smb_fname,
1369 files_struct **ret_fsp,
1374 struct file_id file_id;
1375 struct smb_filename *smb_fname_cp = NULL;
1377 *need_close = false;
1379 if (!VALID_STAT(smb_fname->st)) {
1380 return NT_STATUS_INVALID_PARAMETER;
1383 file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1385 for(fsp = file_find_di_first(conn->sconn, file_id);
1387 fsp = file_find_di_next(fsp)) {
1388 if (fsp->fh->fd != -1) {
1390 return NT_STATUS_OK;
1394 smb_fname_cp = cp_smb_filename(talloc_tos(),
1396 if (smb_fname_cp == NULL) {
1397 return NT_STATUS_NO_MEMORY;
1400 /* Opens an INTERNAL_OPEN_ONLY write handle. */
1401 status = SMB_VFS_CREATE_FILE(
1404 0, /* root_dir_fid */
1405 smb_fname_cp, /* fname */
1406 FILE_WRITE_ATTRIBUTES, /* access_mask */
1407 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
1409 FILE_OPEN, /* create_disposition*/
1410 0, /* create_options */
1411 0, /* file_attributes */
1412 INTERNAL_OPEN_ONLY, /* oplock_request */
1414 0, /* allocation_size */
1415 0, /* private_flags */
1418 ret_fsp, /* result */
1420 NULL, NULL); /* create context */
1422 TALLOC_FREE(smb_fname_cp);
1424 if (NT_STATUS_IS_OK(status)) {