2 Unix SMB/CIFS implementation.
3 dos mode handling functions
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) James Peach 2006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "system/filesys.h"
24 #include "librpc/gen_ndr/ndr_xattr.h"
25 #include "librpc/gen_ndr/ioctl.h"
26 #include "../libcli/security/security.h"
27 #include "smbd/smbd.h"
28 #include "lib/param/loadparm.h"
29 #include "lib/util/tevent_ntstatus.h"
31 static NTSTATUS get_file_handle_for_metadata(connection_struct *conn,
32 const struct smb_filename *smb_fname,
33 files_struct **ret_fsp,
36 static void dos_mode_debug_print(const char *func, uint32_t mode)
40 if (DEBUGLEVEL < DBGLVL_INFO) {
46 if (mode & FILE_ATTRIBUTE_HIDDEN) {
47 fstrcat(modestr, "h");
49 if (mode & FILE_ATTRIBUTE_READONLY) {
50 fstrcat(modestr, "r");
52 if (mode & FILE_ATTRIBUTE_SYSTEM) {
53 fstrcat(modestr, "s");
55 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
56 fstrcat(modestr, "d");
58 if (mode & FILE_ATTRIBUTE_ARCHIVE) {
59 fstrcat(modestr, "a");
61 if (mode & FILE_ATTRIBUTE_SPARSE) {
62 fstrcat(modestr, "[sparse]");
64 if (mode & FILE_ATTRIBUTE_OFFLINE) {
65 fstrcat(modestr, "[offline]");
67 if (mode & FILE_ATTRIBUTE_COMPRESSED) {
68 fstrcat(modestr, "[compressed]");
71 DBG_INFO("%s returning (0x%x): \"%s\"\n", func, (unsigned)mode,
75 static uint32_t filter_mode_by_protocol(uint32_t mode)
77 if (get_Protocol() <= PROTOCOL_LANMAN2) {
78 DEBUG(10,("filter_mode_by_protocol: "
79 "filtering result 0x%x to 0x%x\n",
81 (unsigned int)(mode & 0x3f) ));
87 static int set_link_read_only_flag(const SMB_STRUCT_STAT *const sbuf)
91 if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
92 return FILE_ATTRIBUTE_READONLY;
98 /****************************************************************************
99 Change a dos mode to a unix mode.
100 Base permission for files:
101 if creating file and inheriting (i.e. parent_dir != NULL)
102 apply read/write bits from parent directory.
104 everybody gets read bit set
105 dos readonly is represented in unix by removing everyone's write bit
106 dos archive is represented in unix by the user's execute bit
107 dos system is represented in unix by the group's execute bit
108 dos hidden is represented in unix by the other's execute bit
110 Then apply create mask,
113 Base permission for directories:
114 dos directory is represented in unix by unix's dir bit and the exec bit
116 Then apply create mask,
119 ****************************************************************************/
121 mode_t unix_mode(connection_struct *conn, int dosmode,
122 const struct smb_filename *smb_fname,
123 const char *inherit_from_dir)
125 mode_t result = (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
126 mode_t dir_mode = 0; /* Mode of the inherit_from directory if
129 if (!lp_store_dos_attributes(SNUM(conn)) && IS_DOS_READONLY(dosmode)) {
130 result &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
133 if ((inherit_from_dir != NULL) && lp_inherit_permissions(SNUM(conn))) {
134 struct smb_filename *smb_fname_parent;
136 DEBUG(2, ("unix_mode(%s) inheriting from %s\n",
137 smb_fname_str_dbg(smb_fname),
140 smb_fname_parent = synthetic_smb_fname(talloc_tos(),
145 if (smb_fname_parent == NULL) {
146 DEBUG(1,("unix_mode(%s) failed, [dir %s]: No memory\n",
147 smb_fname_str_dbg(smb_fname),
152 if (SMB_VFS_STAT(conn, smb_fname_parent) != 0) {
153 DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n",
154 smb_fname_str_dbg(smb_fname),
155 inherit_from_dir, strerror(errno)));
156 TALLOC_FREE(smb_fname_parent);
157 return(0); /* *** shouldn't happen! *** */
160 /* Save for later - but explicitly remove setuid bit for safety. */
161 dir_mode = smb_fname_parent->st.st_ex_mode & ~S_ISUID;
162 DEBUG(2,("unix_mode(%s) inherit mode %o\n",
163 smb_fname_str_dbg(smb_fname), (int)dir_mode));
166 TALLOC_FREE(smb_fname_parent);
169 if (IS_DOS_DIR(dosmode)) {
170 /* We never make directories read only for the owner as under DOS a user
171 can always create a file in a read-only directory. */
172 result |= (S_IFDIR | S_IWUSR);
175 /* Inherit mode of parent directory. */
178 /* Provisionally add all 'x' bits */
179 result |= (S_IXUSR | S_IXGRP | S_IXOTH);
181 /* Apply directory mask */
182 result &= lp_directory_mask(SNUM(conn));
183 /* Add in force bits */
184 result |= lp_force_directory_mode(SNUM(conn));
187 if (lp_map_archive(SNUM(conn)) && IS_DOS_ARCHIVE(dosmode))
190 if (lp_map_system(SNUM(conn)) && IS_DOS_SYSTEM(dosmode))
193 if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode))
197 /* Inherit 666 component of parent directory mode */
198 result |= dir_mode & (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
200 /* Apply mode mask */
201 result &= lp_create_mask(SNUM(conn));
202 /* Add in force bits */
203 result |= lp_force_create_mode(SNUM(conn));
207 DBG_INFO("unix_mode(%s) returning 0%o\n",
208 smb_fname_str_dbg(smb_fname), (int)result);
213 /****************************************************************************
214 Change a unix mode to a dos mode.
215 ****************************************************************************/
217 static uint32_t dos_mode_from_sbuf(connection_struct *conn,
218 const struct smb_filename *smb_fname)
221 enum mapreadonly_options ro_opts = (enum mapreadonly_options)lp_map_readonly(SNUM(conn));
223 #if defined(UF_IMMUTABLE) && defined(SF_IMMUTABLE)
224 /* if we can find out if a file is immutable we should report it r/o */
225 if (smb_fname->st.st_ex_flags & (UF_IMMUTABLE | SF_IMMUTABLE)) {
226 result |= FILE_ATTRIBUTE_READONLY;
229 if (ro_opts == MAP_READONLY_YES) {
230 /* Original Samba method - map inverse of user "w" bit. */
231 if ((smb_fname->st.st_ex_mode & S_IWUSR) == 0) {
232 result |= FILE_ATTRIBUTE_READONLY;
234 } else if (ro_opts == MAP_READONLY_PERMISSIONS) {
235 /* Check actual permissions for read-only. */
236 if (!can_write_to_file(conn, smb_fname)) {
237 result |= FILE_ATTRIBUTE_READONLY;
239 } /* Else never set the readonly bit. */
241 if (MAP_ARCHIVE(conn) && ((smb_fname->st.st_ex_mode & S_IXUSR) != 0))
242 result |= FILE_ATTRIBUTE_ARCHIVE;
244 if (MAP_SYSTEM(conn) && ((smb_fname->st.st_ex_mode & S_IXGRP) != 0))
245 result |= FILE_ATTRIBUTE_SYSTEM;
247 if (MAP_HIDDEN(conn) && ((smb_fname->st.st_ex_mode & S_IXOTH) != 0))
248 result |= FILE_ATTRIBUTE_HIDDEN;
250 if (S_ISDIR(smb_fname->st.st_ex_mode))
251 result = FILE_ATTRIBUTE_DIRECTORY | (result & FILE_ATTRIBUTE_READONLY);
253 result |= set_link_read_only_flag(&smb_fname->st);
255 dos_mode_debug_print(__func__, result);
260 /****************************************************************************
261 Get DOS attributes from an EA.
262 This can also pull the create time into the stat struct inside smb_fname.
263 ****************************************************************************/
265 NTSTATUS parse_dos_attribute_blob(struct smb_filename *smb_fname,
269 struct xattr_DOSATTRIB dosattrib;
270 enum ndr_err_code ndr_err;
273 ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &dosattrib,
274 (ndr_pull_flags_fn_t)ndr_pull_xattr_DOSATTRIB);
276 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
277 DBG_WARNING("bad ndr decode "
278 "from EA on file %s: Error = %s\n",
279 smb_fname_str_dbg(smb_fname),
280 ndr_errstr(ndr_err));
281 return ndr_map_error2ntstatus(ndr_err);
284 DBG_DEBUG("%s attr = %s\n",
285 smb_fname_str_dbg(smb_fname), dosattrib.attrib_hex);
287 switch (dosattrib.version) {
289 dosattr = dosattrib.info.compatinfoFFFF.attrib;
292 dosattr = dosattrib.info.info1.attrib;
293 if (!null_nttime(dosattrib.info.info1.create_time)) {
294 struct timespec create_time =
295 nt_time_to_unix_timespec(
296 dosattrib.info.info1.create_time);
298 update_stat_ex_create_time(&smb_fname->st,
301 DBG_DEBUG("file %s case 1 set btime %s\n",
302 smb_fname_str_dbg(smb_fname),
303 time_to_asc(convert_timespec_to_time_t(
308 dosattr = dosattrib.info.oldinfo2.attrib;
309 /* Don't know what flags to check for this case. */
312 dosattr = dosattrib.info.info3.attrib;
313 if ((dosattrib.info.info3.valid_flags & XATTR_DOSINFO_CREATE_TIME) &&
314 !null_nttime(dosattrib.info.info3.create_time)) {
315 struct timespec create_time =
316 nt_time_to_unix_timespec(
317 dosattrib.info.info3.create_time);
319 update_stat_ex_create_time(&smb_fname->st,
322 DBG_DEBUG("file %s case 3 set btime %s\n",
323 smb_fname_str_dbg(smb_fname),
324 time_to_asc(convert_timespec_to_time_t(
329 DBG_WARNING("Badly formed DOSATTRIB on file %s - %s\n",
330 smb_fname_str_dbg(smb_fname), blob.data);
331 /* Should this be INTERNAL_ERROR? */
332 return NT_STATUS_INVALID_PARAMETER;
335 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
336 dosattr |= FILE_ATTRIBUTE_DIRECTORY;
339 /* FILE_ATTRIBUTE_SPARSE is valid on get but not on set. */
340 *pattr |= (uint32_t)(dosattr & (SAMBA_ATTRIBUTES_MASK|FILE_ATTRIBUTE_SPARSE));
342 dos_mode_debug_print(__func__, *pattr);
347 NTSTATUS get_ea_dos_attribute(connection_struct *conn,
348 struct smb_filename *smb_fname,
356 if (!lp_store_dos_attributes(SNUM(conn))) {
357 return NT_STATUS_NOT_IMPLEMENTED;
360 /* Don't reset pattr to zero as we may already have filename-based attributes we
363 sizeret = SMB_VFS_GETXATTR(conn, smb_fname,
364 SAMBA_XATTR_DOS_ATTRIB, attrstr,
366 if (sizeret == -1 && errno == EACCES) {
370 * According to MS-FSA 2.1.5.1.2.1 "Algorithm to Check Access to
371 * an Existing File" FILE_LIST_DIRECTORY on a directory implies
372 * FILE_READ_ATTRIBUTES for directory entries. Being able to
373 * stat() a file implies FILE_LIST_DIRECTORY for the directory
374 * containing the file.
377 if (!VALID_STAT(smb_fname->st)) {
379 * Safety net: dos_mode() already checks this, but as we
380 * become root based on this, add an additional layer of
383 DBG_ERR("Rejecting root override, invalid stat [%s]\n",
384 smb_fname_str_dbg(smb_fname));
385 return NT_STATUS_ACCESS_DENIED;
389 sizeret = SMB_VFS_GETXATTR(conn, smb_fname,
390 SAMBA_XATTR_DOS_ATTRIB,
398 if (saved_errno != 0) {
403 DBG_INFO("Cannot get attribute "
404 "from EA on file %s: Error = %s\n",
405 smb_fname_str_dbg(smb_fname), strerror(errno));
406 return map_nt_error_from_unix(errno);
409 blob.data = (uint8_t *)attrstr;
410 blob.length = sizeret;
412 status = parse_dos_attribute_blob(smb_fname, blob, pattr);
413 if (!NT_STATUS_IS_OK(status)) {
420 /****************************************************************************
421 Set DOS attributes in an EA.
422 Also sets the create time.
423 ****************************************************************************/
425 NTSTATUS set_ea_dos_attribute(connection_struct *conn,
426 const struct smb_filename *smb_fname,
429 struct xattr_DOSATTRIB dosattrib;
430 enum ndr_err_code ndr_err;
434 if (!lp_store_dos_attributes(SNUM(conn))) {
435 return NT_STATUS_NOT_IMPLEMENTED;
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 ZERO_STRUCT(dosattrib);
447 dosattrib.version = 3;
448 dosattrib.info.info3.valid_flags = XATTR_DOSINFO_ATTRIB|
449 XATTR_DOSINFO_CREATE_TIME;
450 dosattrib.info.info3.attrib = dosmode;
451 dosattrib.info.info3.create_time = unix_timespec_to_nt_time(
452 smb_fname->st.st_ex_btime);
454 DEBUG(10,("set_ea_dos_attributes: set attribute 0x%x, btime = %s on file %s\n",
455 (unsigned int)dosmode,
456 time_to_asc(convert_timespec_to_time_t(smb_fname->st.st_ex_btime)),
457 smb_fname_str_dbg(smb_fname) ));
459 ndr_err = ndr_push_struct_blob(
460 &blob, talloc_tos(), &dosattrib,
461 (ndr_push_flags_fn_t)ndr_push_xattr_DOSATTRIB);
463 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
464 DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n",
465 ndr_errstr(ndr_err)));
466 return ndr_map_error2ntstatus(ndr_err);
469 if (blob.data == NULL || blob.length == 0) {
470 /* Should this be INTERNAL_ERROR? */
471 return NT_STATUS_INVALID_PARAMETER;
474 ret = SMB_VFS_SETXATTR(conn, smb_fname,
475 SAMBA_XATTR_DOS_ATTRIB,
476 blob.data, blob.length, 0);
478 NTSTATUS status = NT_STATUS_OK;
479 bool need_close = false;
480 files_struct *fsp = NULL;
481 bool set_dosmode_ok = false;
483 if ((errno != EPERM) && (errno != EACCES)) {
484 DBG_INFO("Cannot set "
485 "attribute EA on file %s: Error = %s\n",
486 smb_fname_str_dbg(smb_fname), strerror(errno));
487 return map_nt_error_from_unix(errno);
490 /* We want DOS semantics, ie allow non owner with write permission to change the
491 bits on a file. Just like file_ntimes below.
494 /* Check if we have write access. */
495 if (!CAN_WRITE(conn)) {
496 return NT_STATUS_ACCESS_DENIED;
499 status = smbd_check_access_rights(conn, smb_fname, false,
500 FILE_WRITE_ATTRIBUTES);
501 if (NT_STATUS_IS_OK(status)) {
502 set_dosmode_ok = true;
505 if (!set_dosmode_ok && lp_dos_filemode(SNUM(conn))) {
506 set_dosmode_ok = can_write_to_file(conn, smb_fname);
509 if (!set_dosmode_ok) {
510 return NT_STATUS_ACCESS_DENIED;
514 * We need to get an open file handle to do the
515 * metadata operation under root.
518 status = get_file_handle_for_metadata(conn,
522 if (!NT_STATUS_IS_OK(status)) {
527 ret = SMB_VFS_FSETXATTR(fsp,
528 SAMBA_XATTR_DOS_ATTRIB,
529 blob.data, blob.length, 0);
531 status = NT_STATUS_OK;
535 close_file(NULL, fsp, NORMAL_CLOSE);
539 DEBUG(10,("set_ea_dos_attribute: set EA 0x%x on file %s\n",
540 (unsigned int)dosmode,
541 smb_fname_str_dbg(smb_fname)));
545 /****************************************************************************
546 Change a unix mode to a dos mode for an ms dfs link.
547 ****************************************************************************/
549 uint32_t dos_mode_msdfs(connection_struct *conn,
550 const struct smb_filename *smb_fname)
554 DEBUG(8,("dos_mode_msdfs: %s\n", smb_fname_str_dbg(smb_fname)));
556 if (!VALID_STAT(smb_fname->st)) {
560 /* First do any modifications that depend on the path name. */
561 /* hide files with a name starting with a . */
562 if (lp_hide_dot_files(SNUM(conn))) {
563 const char *p = strrchr_m(smb_fname->base_name, '/');
567 p = smb_fname->base_name;
570 /* Only . and .. are not hidden. */
571 if (p[0] == '.' && !((p[1] == '\0') ||
572 (p[1] == '.' && p[2] == '\0'))) {
573 result |= FILE_ATTRIBUTE_HIDDEN;
577 result |= dos_mode_from_sbuf(conn, smb_fname);
579 /* Optimization : Only call is_hidden_path if it's not already
581 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
582 IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
583 result |= FILE_ATTRIBUTE_HIDDEN;
587 result = FILE_ATTRIBUTE_NORMAL;
590 result = filter_mode_by_protocol(result);
593 * Add in that it is a reparse point
595 result |= FILE_ATTRIBUTE_REPARSE_POINT;
597 dos_mode_debug_print(__func__, result);
603 * check whether a file or directory is flagged as compressed.
605 static NTSTATUS dos_mode_check_compressed(connection_struct *conn,
606 struct smb_filename *smb_fname,
610 uint16_t compression_fmt;
611 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
612 if (tmp_ctx == NULL) {
613 status = NT_STATUS_NO_MEMORY;
617 status = SMB_VFS_GET_COMPRESSION(conn, tmp_ctx, NULL, smb_fname,
619 if (!NT_STATUS_IS_OK(status)) {
623 if (compression_fmt == COMPRESSION_FORMAT_LZNT1) {
624 *is_compressed = true;
626 *is_compressed = false;
628 status = NT_STATUS_OK;
631 talloc_free(tmp_ctx);
636 static uint32_t dos_mode_from_name(connection_struct *conn,
637 const struct smb_filename *smb_fname,
640 const char *p = NULL;
641 uint32_t result = dosmode;
643 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
644 lp_hide_dot_files(SNUM(conn)))
646 p = strrchr_m(smb_fname->base_name, '/');
650 p = smb_fname->base_name;
653 /* Only . and .. are not hidden. */
655 !((p[1] == '\0') || (p[1] == '.' && p[2] == '\0')))
657 result |= FILE_ATTRIBUTE_HIDDEN;
661 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
662 IS_HIDDEN_PATH(conn, smb_fname->base_name))
664 result |= FILE_ATTRIBUTE_HIDDEN;
670 static uint32_t dos_mode_post(uint32_t dosmode,
671 connection_struct *conn,
672 struct smb_filename *smb_fname,
678 * According to MS-FSA a stream name does not have
679 * separate DOS attribute metadata, so we must return
680 * the DOS attribute from the base filename. With one caveat,
681 * a non-default stream name can never be a directory.
683 * As this is common to all streams data stores, we handle
684 * it here instead of inside all stream VFS modules.
686 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13380
689 if (is_ntfs_stream_smb_fname(smb_fname)) {
690 /* is_ntfs_stream_smb_fname() returns false for a POSIX path. */
691 if (!is_ntfs_default_stream_smb_fname(smb_fname)) {
693 * Non-default stream name, not a posix path.
695 dosmode &= ~(FILE_ATTRIBUTE_DIRECTORY);
699 if (conn->fs_capabilities & FILE_FILE_COMPRESSION) {
700 bool compressed = false;
702 status = dos_mode_check_compressed(conn, smb_fname,
704 if (NT_STATUS_IS_OK(status) && compressed) {
705 dosmode |= FILE_ATTRIBUTE_COMPRESSED;
709 dosmode |= dos_mode_from_name(conn, smb_fname, dosmode);
711 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
712 dosmode |= FILE_ATTRIBUTE_DIRECTORY;
713 } else if (dosmode == 0) {
714 dosmode = FILE_ATTRIBUTE_NORMAL;
717 dosmode = filter_mode_by_protocol(dosmode);
719 dos_mode_debug_print(func, dosmode);
723 /****************************************************************************
724 Change a unix mode to a dos mode.
725 May also read the create timespec into the stat struct in smb_fname
726 if "store dos attributes" is true.
727 ****************************************************************************/
729 uint32_t dos_mode(connection_struct *conn, struct smb_filename *smb_fname)
732 NTSTATUS status = NT_STATUS_OK;
734 DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname)));
736 if (!VALID_STAT(smb_fname->st)) {
740 /* Get the DOS attributes via the VFS if we can */
741 status = SMB_VFS_GET_DOS_ATTRIBUTES(conn, smb_fname, &result);
742 if (!NT_STATUS_IS_OK(status)) {
744 * Only fall back to using UNIX modes if we get NOT_IMPLEMENTED.
746 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
747 result |= dos_mode_from_sbuf(conn, smb_fname);
751 result = dos_mode_post(result, conn, smb_fname, __func__);
755 struct dos_mode_at_state {
756 files_struct *dir_fsp;
757 struct smb_filename *smb_fname;
761 static void dos_mode_at_vfs_get_dosmode_done(struct tevent_req *subreq);
763 struct tevent_req *dos_mode_at_send(TALLOC_CTX *mem_ctx,
764 struct tevent_context *ev,
765 files_struct *dir_fsp,
766 struct smb_filename *smb_fname)
768 struct tevent_req *req = NULL;
769 struct dos_mode_at_state *state = NULL;
770 struct tevent_req *subreq = NULL;
772 DBG_DEBUG("%s\n", smb_fname_str_dbg(smb_fname));
774 req = tevent_req_create(mem_ctx, &state,
775 struct dos_mode_at_state);
780 *state = (struct dos_mode_at_state) {
782 .smb_fname = smb_fname,
785 if (!VALID_STAT(smb_fname->st)) {
786 tevent_req_done(req);
787 return tevent_req_post(req, ev);
790 subreq = SMB_VFS_GET_DOS_ATTRIBUTES_SEND(state,
794 if (tevent_req_nomem(subreq, req)) {
795 return tevent_req_post(req, ev);
797 tevent_req_set_callback(subreq, dos_mode_at_vfs_get_dosmode_done, req);
802 static void dos_mode_at_vfs_get_dosmode_done(struct tevent_req *subreq)
804 struct tevent_req *req =
805 tevent_req_callback_data(subreq,
807 struct dos_mode_at_state *state =
809 struct dos_mode_at_state);
811 struct smb_filename *smb_path = NULL;
812 struct vfs_aio_state aio_state;
817 * Make sure we run as the user again
819 ok = change_to_user_by_fsp(state->dir_fsp);
822 status = SMB_VFS_GET_DOS_ATTRIBUTES_RECV(subreq,
826 if (!NT_STATUS_IS_OK(status)) {
828 * Both the sync dos_mode() as well as the async
829 * dos_mode_at_[send|recv] have no real error return, the only
830 * unhandled error is when the stat info in smb_fname is not
831 * valid (cf the checks in dos_mode() and dos_mode_at_send().
833 * If SMB_VFS_GET_DOS_ATTRIBUTES[_SEND|_RECV] fails we must call
834 * dos_mode_post() which also does the mapping of a last ressort
835 * from S_IFMT(st_mode).
837 * Only if we get NT_STATUS_NOT_IMPLEMENTED from a stacked VFS
838 * module we must fallback to sync processing.
840 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
842 * state->dosmode should still be 0, but reset
846 status = NT_STATUS_OK;
849 if (NT_STATUS_IS_OK(status)) {
850 state->dosmode = dos_mode_post(state->dosmode,
851 state->dir_fsp->conn,
854 tevent_req_done(req);
859 * Fall back to sync dos_mode() if we got NOT_IMPLEMENTED.
862 path = talloc_asprintf(state,
864 state->dir_fsp->fsp_name->base_name,
865 state->smb_fname->base_name);
866 if (tevent_req_nomem(path, req)) {
870 smb_path = synthetic_smb_fname(state, path, NULL, NULL, 0);
871 if (tevent_req_nomem(path, req)) {
875 state->dosmode = dos_mode(state->dir_fsp->conn, smb_path);
876 tevent_req_done(req);
880 NTSTATUS dos_mode_at_recv(struct tevent_req *req, uint32_t *dosmode)
882 struct dos_mode_at_state *state =
884 struct dos_mode_at_state);
887 if (tevent_req_is_nterror(req, &status)) {
888 tevent_req_received(req);
892 *dosmode = state->dosmode;
893 tevent_req_received(req);
897 /*******************************************************************
898 chmod a file - but preserve some bits.
899 If "store dos attributes" is also set it will store the create time
900 from the stat struct in smb_fname (in NTTIME format) in the EA
902 ********************************************************************/
904 int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname,
905 uint32_t dosmode, const char *parent_dir, bool newfile)
910 int ret = -1, lret = -1;
911 files_struct *fsp = NULL;
912 bool need_close = false;
915 if (!CAN_WRITE(conn)) {
920 dosmode &= SAMBA_ATTRIBUTES_MASK;
922 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
923 dosmode, smb_fname_str_dbg(smb_fname)));
925 unixmode = smb_fname->st.st_ex_mode;
927 get_acl_group_bits(conn, smb_fname,
928 &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_SET_DOS_ATTRIBUTES(conn, smb_fname, dosmode);
937 if (NT_STATUS_IS_OK(status)) {
939 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
940 FILE_NOTIFY_CHANGE_ATTRIBUTES,
941 smb_fname->base_name);
943 smb_fname->st.st_ex_mode = unixmode;
947 * Only fall back to using UNIX modes if
948 * we get NOT_IMPLEMENTED.
950 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
951 errno = map_errno_from_nt_status(status);
956 /* Fall back to UNIX modes. */
957 unixmode = unix_mode(conn, dosmode, smb_fname, parent_dir);
959 /* preserve the file type bits */
962 /* preserve the s bits */
963 mask |= (S_ISUID | S_ISGID);
965 /* preserve the t bit */
970 /* possibly preserve the x bits */
971 if (!MAP_ARCHIVE(conn))
973 if (!MAP_SYSTEM(conn))
975 if (!MAP_HIDDEN(conn))
978 unixmode |= (smb_fname->st.st_ex_mode & mask);
980 /* if we previously had any r bits set then leave them alone */
981 if ((tmp = smb_fname->st.st_ex_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
982 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
986 /* if we previously had any w bits set then leave them alone
987 whilst adding in the new w bits, if the new mode is not rdonly */
988 if (!IS_DOS_READONLY(dosmode)) {
989 unixmode |= (smb_fname->st.st_ex_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
993 * From the chmod 2 man page:
995 * "If the calling process is not privileged, and the group of the file
996 * does not match the effective group ID of the process or one of its
997 * supplementary group IDs, the S_ISGID bit will be turned off, but
998 * this will not cause an error to be returned."
1000 * Simply refuse to do the chmod in this case.
1003 if (S_ISDIR(smb_fname->st.st_ex_mode) && (unixmode & S_ISGID) &&
1004 geteuid() != sec_initial_uid() &&
1005 !current_user_in_group(conn, smb_fname->st.st_ex_gid)) {
1006 DEBUG(3,("file_set_dosmode: setgid bit cannot be "
1007 "set for directory %s\n",
1008 smb_fname_str_dbg(smb_fname)));
1013 ret = SMB_VFS_CHMOD(conn, smb_fname, unixmode);
1015 if(!newfile || (lret != -1)) {
1016 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
1017 FILE_NOTIFY_CHANGE_ATTRIBUTES,
1018 smb_fname->base_name);
1020 smb_fname->st.st_ex_mode = unixmode;
1024 if((errno != EPERM) && (errno != EACCES))
1027 if(!lp_dos_filemode(SNUM(conn)))
1030 /* We want DOS semantics, ie allow non owner with write permission to change the
1031 bits on a file. Just like file_ntimes below.
1034 if (!can_write_to_file(conn, smb_fname)) {
1040 * We need to get an open file handle to do the
1041 * metadata operation under root.
1044 status = get_file_handle_for_metadata(conn,
1048 if (!NT_STATUS_IS_OK(status)) {
1049 errno = map_errno_from_nt_status(status);
1054 ret = SMB_VFS_FCHMOD(fsp, unixmode);
1057 close_file(NULL, fsp, NORMAL_CLOSE);
1060 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
1061 FILE_NOTIFY_CHANGE_ATTRIBUTES,
1062 smb_fname->base_name);
1065 smb_fname->st.st_ex_mode = unixmode;
1072 NTSTATUS file_set_sparse(connection_struct *conn,
1076 uint32_t old_dosmode;
1077 uint32_t new_dosmode;
1080 if (!CAN_WRITE(conn)) {
1081 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
1082 "on readonly share[%s]\n",
1083 smb_fname_str_dbg(fsp->fsp_name),
1085 lp_servicename(talloc_tos(), SNUM(conn))));
1086 return NT_STATUS_MEDIA_WRITE_PROTECTED;
1090 * Windows Server 2008 & 2012 permit FSCTL_SET_SPARSE if any of the
1091 * following access flags are granted.
1093 if ((fsp->access_mask & (FILE_WRITE_DATA
1094 | FILE_WRITE_ATTRIBUTES
1095 | SEC_FILE_APPEND_DATA)) == 0) {
1096 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
1097 "access_mask[0x%08X] - access denied\n",
1098 smb_fname_str_dbg(fsp->fsp_name),
1101 return NT_STATUS_ACCESS_DENIED;
1104 if (fsp->is_directory) {
1105 DEBUG(9, ("invalid attempt to %s sparse flag on dir %s\n",
1106 (sparse ? "set" : "clear"),
1107 smb_fname_str_dbg(fsp->fsp_name)));
1108 return NT_STATUS_INVALID_PARAMETER;
1111 if (IS_IPC(conn) || IS_PRINT(conn)) {
1112 DEBUG(9, ("attempt to %s sparse flag over invalid conn\n",
1113 (sparse ? "set" : "clear")));
1114 return NT_STATUS_INVALID_PARAMETER;
1117 DEBUG(10,("file_set_sparse: setting sparse bit %u on file %s\n",
1118 sparse, smb_fname_str_dbg(fsp->fsp_name)));
1120 if (!lp_store_dos_attributes(SNUM(conn))) {
1121 return NT_STATUS_INVALID_DEVICE_REQUEST;
1124 status = vfs_stat_fsp(fsp);
1125 if (!NT_STATUS_IS_OK(status)) {
1129 old_dosmode = dos_mode(conn, fsp->fsp_name);
1131 if (sparse && !(old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
1132 new_dosmode = old_dosmode | FILE_ATTRIBUTE_SPARSE;
1133 } else if (!sparse && (old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
1134 new_dosmode = old_dosmode & ~FILE_ATTRIBUTE_SPARSE;
1136 return NT_STATUS_OK;
1139 /* Store the DOS attributes in an EA. */
1140 status = SMB_VFS_FSET_DOS_ATTRIBUTES(conn, fsp, new_dosmode);
1141 if (!NT_STATUS_IS_OK(status)) {
1145 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
1146 FILE_NOTIFY_CHANGE_ATTRIBUTES,
1147 fsp->fsp_name->base_name);
1149 fsp->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, const struct smb_filename *smb_fname,
1160 struct smb_file_time *ft)
1166 DEBUG(6, ("file_ntime: actime: %s",
1167 time_to_asc(convert_timespec_to_time_t(ft->atime))));
1168 DEBUG(6, ("file_ntime: modtime: %s",
1169 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
1170 DEBUG(6, ("file_ntime: ctime: %s",
1171 time_to_asc(convert_timespec_to_time_t(ft->ctime))));
1172 DEBUG(6, ("file_ntime: createtime: %s",
1173 time_to_asc(convert_timespec_to_time_t(ft->create_time))));
1175 /* Don't update the time on read-only shares */
1176 /* We need this as set_filetime (which can be called on
1177 close and other paths) can end up calling this function
1178 without the NEED_WRITE protection. Found by :
1179 Leo Weppelman <leo@wau.mis.ah.nl>
1182 if (!CAN_WRITE(conn)) {
1186 if(SMB_VFS_NTIMES(conn, smb_fname, ft) == 0) {
1190 if((errno != EPERM) && (errno != EACCES)) {
1194 if(!lp_dos_filetimes(SNUM(conn))) {
1198 /* We have permission (given by the Samba admin) to
1199 break POSIX semantics and allow a user to change
1200 the time on a file they don't own but can write to
1204 /* Check if we have write access. */
1205 if (can_write_to_file(conn, smb_fname)) {
1206 /* We are allowed to become root and change the filetime. */
1208 ret = SMB_VFS_NTIMES(conn, smb_fname, ft);
1215 /******************************************************************
1216 Force a "sticky" write time on a pathname. This will always be
1217 returned on all future write time queries and set on close.
1218 ******************************************************************/
1220 bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime)
1222 if (null_timespec(mtime)) {
1226 if (!set_sticky_write_time(fileid, mtime)) {
1233 /******************************************************************
1234 Force a "sticky" write time on an fsp. This will always be
1235 returned on all future write time queries and set on close.
1236 ******************************************************************/
1238 bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime)
1240 if (null_timespec(mtime)) {
1244 fsp->write_time_forced = true;
1245 TALLOC_FREE(fsp->update_write_time_event);
1247 return set_sticky_write_time_path(fsp->file_id, mtime);
1250 /******************************************************************
1251 Set a create time EA.
1252 ******************************************************************/
1254 NTSTATUS set_create_timespec_ea(connection_struct *conn,
1255 const struct smb_filename *psmb_fname,
1256 struct timespec create_time)
1258 struct smb_filename *smb_fname;
1262 if (!lp_store_dos_attributes(SNUM(conn))) {
1263 return NT_STATUS_OK;
1266 smb_fname = synthetic_smb_fname(talloc_tos(),
1267 psmb_fname->base_name,
1272 if (smb_fname == NULL) {
1273 return NT_STATUS_NO_MEMORY;
1276 dosmode = dos_mode(conn, smb_fname);
1278 smb_fname->st.st_ex_btime = create_time;
1280 ret = file_set_dosmode(conn, smb_fname, dosmode, NULL, false);
1282 return map_nt_error_from_unix(errno);
1285 DEBUG(10,("set_create_timespec_ea: wrote create time EA for file %s\n",
1286 smb_fname_str_dbg(smb_fname)));
1288 return NT_STATUS_OK;
1291 /******************************************************************
1292 Return a create time.
1293 ******************************************************************/
1295 struct timespec get_create_timespec(connection_struct *conn,
1296 struct files_struct *fsp,
1297 const struct smb_filename *smb_fname)
1299 return smb_fname->st.st_ex_btime;
1302 /******************************************************************
1303 Return a change time (may look at EA in future).
1304 ******************************************************************/
1306 struct timespec get_change_timespec(connection_struct *conn,
1307 struct files_struct *fsp,
1308 const struct smb_filename *smb_fname)
1310 return smb_fname->st.st_ex_mtime;
1313 /****************************************************************************
1314 Get a real open file handle we can do meta-data operations on. As it's
1315 going to be used under root access only on meta-data we should look for
1316 any existing open file handle first, and use that in preference (also to
1317 avoid kernel self-oplock breaks). If not use an INTERNAL_OPEN_ONLY handle.
1318 ****************************************************************************/
1320 static NTSTATUS get_file_handle_for_metadata(connection_struct *conn,
1321 const struct smb_filename *smb_fname,
1322 files_struct **ret_fsp,
1327 struct file_id file_id;
1328 struct smb_filename *smb_fname_cp = NULL;
1330 *need_close = false;
1332 if (!VALID_STAT(smb_fname->st)) {
1333 return NT_STATUS_INVALID_PARAMETER;
1336 file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1338 for(fsp = file_find_di_first(conn->sconn, file_id);
1340 fsp = file_find_di_next(fsp)) {
1341 if (fsp->fh->fd != -1) {
1343 return NT_STATUS_OK;
1347 smb_fname_cp = cp_smb_filename(talloc_tos(),
1349 if (smb_fname_cp == NULL) {
1350 return NT_STATUS_NO_MEMORY;
1353 /* Opens an INTERNAL_OPEN_ONLY write handle. */
1354 status = SMB_VFS_CREATE_FILE(
1357 0, /* root_dir_fid */
1358 smb_fname_cp, /* fname */
1359 FILE_WRITE_ATTRIBUTES, /* access_mask */
1360 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
1362 FILE_OPEN, /* create_disposition*/
1363 0, /* create_options */
1364 0, /* file_attributes */
1365 INTERNAL_OPEN_ONLY, /* oplock_request */
1367 0, /* allocation_size */
1368 0, /* private_flags */
1371 ret_fsp, /* result */
1373 NULL, NULL); /* create context */
1375 TALLOC_FREE(smb_fname_cp);
1377 if (NT_STATUS_IS_OK(status)) {