smbd: add twrp arg to synthetic_smb_fname()
[amitay/samba.git] / source3 / smbd / dosmode.c
index 177fe68c89480dfe16edc9280dd652de9b613e02..9bb8d1c1941659b52a52dfc9641fe0e02745ae2e 100644 (file)
@@ -120,7 +120,7 @@ static int set_link_read_only_flag(const SMB_STRUCT_STAT *const sbuf)
 
 mode_t unix_mode(connection_struct *conn, int dosmode,
                 const struct smb_filename *smb_fname,
-                const char *inherit_from_dir)
+                struct smb_filename *smb_fname_parent)
 {
        mode_t result = (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
        mode_t dir_mode = 0; /* Mode of the inherit_from directory if
@@ -130,29 +130,15 @@ mode_t unix_mode(connection_struct *conn, int dosmode,
                result &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
        }
 
-       if ((inherit_from_dir != NULL) && lp_inherit_permissions(SNUM(conn))) {
-               struct smb_filename *smb_fname_parent;
-
-               DEBUG(2, ("unix_mode(%s) inheriting from %s\n",
+       if ((smb_fname_parent != NULL) && lp_inherit_permissions(SNUM(conn))) {
+               DBG_DEBUG("[%s] inheriting from [%s]\n",
                          smb_fname_str_dbg(smb_fname),
-                         inherit_from_dir));
-
-               smb_fname_parent = synthetic_smb_fname(talloc_tos(),
-                                       inherit_from_dir,
-                                       NULL,
-                                       NULL,
-                                       smb_fname->flags);
-               if (smb_fname_parent == NULL) {
-                       DEBUG(1,("unix_mode(%s) failed, [dir %s]: No memory\n",
-                                smb_fname_str_dbg(smb_fname),
-                                inherit_from_dir));
-                       return(0);
-               }
+                         smb_fname_str_dbg(smb_fname_parent));
 
                if (SMB_VFS_STAT(conn, smb_fname_parent) != 0) {
-                       DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n",
-                                smb_fname_str_dbg(smb_fname),
-                                inherit_from_dir, strerror(errno)));
+                       DBG_ERR("stat failed [%s]: %s\n",
+                               smb_fname_str_dbg(smb_fname_parent),
+                               strerror(errno));
                        TALLOC_FREE(smb_fname_parent);
                        return(0);      /* *** shouldn't happen! *** */
                }
@@ -233,7 +219,10 @@ static uint32_t dos_mode_from_sbuf(connection_struct *conn,
                }
        } else if (ro_opts == MAP_READONLY_PERMISSIONS) {
                /* Check actual permissions for read-only. */
-               if (!can_write_to_file(conn, smb_fname)) {
+               if (!can_write_to_file(conn,
+                               conn->cwd_fsp,
+                               smb_fname))
+               {
                        result |= FILE_ATTRIBUTE_READONLY;
                }
        } /* Else never set the readonly bit. */
@@ -313,7 +302,7 @@ NTSTATUS parse_dos_attribute_blob(struct smb_filename *smb_fname,
                if ((dosattrib.info.info3.valid_flags & XATTR_DOSINFO_CREATE_TIME) &&
                    !null_nttime(dosattrib.info.info3.create_time)) {
                        struct timespec create_time =
-                               nt_time_to_unix_timespec(
+                               nt_time_to_full_timespec(
                                        dosattrib.info.info3.create_time);
 
                        update_stat_ex_create_time(&smb_fname->st,
@@ -325,6 +314,50 @@ NTSTATUS parse_dos_attribute_blob(struct smb_filename *smb_fname,
                                                      create_time)));
                }
                break;
+       case 4:
+       {
+               struct xattr_DosInfo4 *info = &dosattrib.info.info4;
+
+               dosattr = info->attrib;
+
+               if ((info->valid_flags & XATTR_DOSINFO_CREATE_TIME) &&
+                   !null_nttime(info->create_time))
+               {
+                       struct timespec creat_time;
+
+                       creat_time = nt_time_to_full_timespec(info->create_time);
+                       update_stat_ex_create_time(&smb_fname->st, creat_time);
+
+                       DBG_DEBUG("file [%s] creation time [%s]\n",
+                               smb_fname_str_dbg(smb_fname),
+                               nt_time_string(talloc_tos(), info->create_time));
+               }
+
+               if (info->valid_flags & XATTR_DOSINFO_ITIME) {
+                       struct timespec itime;
+                       uint64_t file_id;
+
+                       itime = nt_time_to_unix_timespec(info->itime);
+                       if (smb_fname->st.st_ex_iflags &
+                           ST_EX_IFLAG_CALCULATED_ITIME)
+                       {
+                               update_stat_ex_itime(&smb_fname->st, itime);
+                       }
+
+                       file_id = make_file_id_from_itime(&smb_fname->st);
+                       if (smb_fname->st.st_ex_iflags &
+                           ST_EX_IFLAG_CALCULATED_FILE_ID)
+                       {
+                               update_stat_ex_file_id(&smb_fname->st, file_id);
+                       }
+
+                       DBG_DEBUG("file [%s] itime [%s] fileid [%"PRIx64"]\n",
+                               smb_fname_str_dbg(smb_fname),
+                               nt_time_string(talloc_tos(), info->itime),
+                               file_id);
+               }
+               break;
+       }
        default:
                DBG_WARNING("Badly formed DOSATTRIB on file %s - %s\n",
                            smb_fname_str_dbg(smb_fname), blob.data);
@@ -444,12 +477,18 @@ NTSTATUS set_ea_dos_attribute(connection_struct *conn,
        ZERO_STRUCT(dosattrib);
        ZERO_STRUCT(blob);
 
-       dosattrib.version = 3;
-       dosattrib.info.info3.valid_flags = XATTR_DOSINFO_ATTRIB|
+       dosattrib.version = 4;
+       dosattrib.info.info4.valid_flags = XATTR_DOSINFO_ATTRIB |
                                        XATTR_DOSINFO_CREATE_TIME;
-       dosattrib.info.info3.attrib = dosmode;
-       dosattrib.info.info3.create_time = unix_timespec_to_nt_time(
-                               smb_fname->st.st_ex_btime);
+       dosattrib.info.info4.attrib = dosmode;
+       dosattrib.info.info4.create_time = full_timespec_to_nt_time(
+               &smb_fname->st.st_ex_btime);
+
+       if (!(smb_fname->st.st_ex_iflags & ST_EX_IFLAG_CALCULATED_ITIME)) {
+               dosattrib.info.info4.valid_flags |= XATTR_DOSINFO_ITIME;
+               dosattrib.info.info4.itime = full_timespec_to_nt_time(
+                       &smb_fname->st.st_ex_itime);
+       }
 
        DEBUG(10,("set_ea_dos_attributes: set attribute 0x%x, btime = %s on file %s\n",
                (unsigned int)dosmode,
@@ -496,14 +535,19 @@ NTSTATUS set_ea_dos_attribute(connection_struct *conn,
                        return NT_STATUS_ACCESS_DENIED;
                }
 
-               status = smbd_check_access_rights(conn, smb_fname, false,
-                                                 FILE_WRITE_ATTRIBUTES);
+               status = smbd_check_access_rights(conn,
+                                       conn->cwd_fsp,
+                                       smb_fname,
+                                       false,
+                                       FILE_WRITE_ATTRIBUTES);
                if (NT_STATUS_IS_OK(status)) {
                        set_dosmode_ok = true;
                }
 
                if (!set_dosmode_ok && lp_dos_filemode(SNUM(conn))) {
-                       set_dosmode_ok = can_write_to_file(conn, smb_fname);
+                       set_dosmode_ok = can_write_to_file(conn,
+                                               conn->cwd_fsp,
+                                               smb_fname);
                }
 
                if (!set_dosmode_ok) {
@@ -686,14 +730,9 @@ static uint32_t dos_mode_post(uint32_t dosmode,
         * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13380
         */
 
-       if (is_ntfs_stream_smb_fname(smb_fname)) {
+       if (is_named_stream(smb_fname)) {
                /* is_ntfs_stream_smb_fname() returns false for a POSIX path. */
-               if (!is_ntfs_default_stream_smb_fname(smb_fname)) {
-                       /*
-                        * Non-default stream name, not a posix path.
-                        */
-                       dosmode &= ~(FILE_ATTRIBUTE_DIRECTORY);
-               }
+               dosmode &= ~(FILE_ATTRIBUTE_DIRECTORY);
        }
 
        if (conn->fs_capabilities & FILE_FILE_COMPRESSION) {
@@ -811,6 +850,13 @@ static void dos_mode_at_vfs_get_dosmode_done(struct tevent_req *subreq)
        struct smb_filename *smb_path = NULL;
        struct vfs_aio_state aio_state;
        NTSTATUS status;
+       bool ok;
+
+       /*
+        * Make sure we run as the user again
+        */
+       ok = change_to_user_and_service_by_fsp(state->dir_fsp);
+       SMB_ASSERT(ok);
 
        status = SMB_VFS_GET_DOS_ATTRIBUTES_RECV(subreq,
                                                 &aio_state,
@@ -860,8 +906,13 @@ static void dos_mode_at_vfs_get_dosmode_done(struct tevent_req *subreq)
                return;
        }
 
-       smb_path = synthetic_smb_fname(state, path, NULL, NULL, 0);
-       if (tevent_req_nomem(path, req)) {
+       smb_path = synthetic_smb_fname(state,
+                                      path,
+                                      NULL,
+                                      &state->smb_fname->st,
+                                      state->smb_fname->twrp,
+                                      0);
+       if (tevent_req_nomem(smb_path, req)) {
                return;
        }
 
@@ -894,8 +945,11 @@ NTSTATUS dos_mode_at_recv(struct tevent_req *req, uint32_t *dosmode)
  attribute also.
 ********************************************************************/
 
-int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname,
-                    uint32_t dosmode, const char *parent_dir, bool newfile)
+int file_set_dosmode(connection_struct *conn,
+                    struct smb_filename *smb_fname,
+                    uint32_t dosmode,
+                    struct smb_filename *parent_dir,
+                    bool newfile)
 {
        int mask=0;
        mode_t tmp;
@@ -1024,7 +1078,10 @@ int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname,
                bits on a file. Just like file_ntimes below.
        */
 
-       if (!can_write_to_file(conn, smb_fname)) {
+       if (!can_write_to_file(conn,
+                       conn->cwd_fsp,
+                       smb_fname))
+       {
                errno = EACCES;
                return -1;
        }
@@ -1066,6 +1123,8 @@ NTSTATUS file_set_sparse(connection_struct *conn,
                         files_struct *fsp,
                         bool sparse)
 {
+       const struct loadparm_substitution *lp_sub =
+               loadparm_s3_global_substitution();
        uint32_t old_dosmode;
        uint32_t new_dosmode;
        NTSTATUS status;
@@ -1075,7 +1134,7 @@ NTSTATUS file_set_sparse(connection_struct *conn,
                        "on readonly share[%s]\n",
                        smb_fname_str_dbg(fsp->fsp_name),
                        sparse,
-                       lp_servicename(talloc_tos(), SNUM(conn))));
+                       lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
                return NT_STATUS_MEDIA_WRITE_PROTECTED;
        }
 
@@ -1094,7 +1153,7 @@ NTSTATUS file_set_sparse(connection_struct *conn,
                return NT_STATUS_ACCESS_DENIED;
        }
 
-       if (fsp->is_directory) {
+       if (fsp->fsp_flags.is_directory) {
                DEBUG(9, ("invalid attempt to %s sparse flag on dir %s\n",
                          (sparse ? "set" : "clear"),
                          smb_fname_str_dbg(fsp->fsp_name)));
@@ -1139,7 +1198,7 @@ NTSTATUS file_set_sparse(connection_struct *conn,
                     FILE_NOTIFY_CHANGE_ATTRIBUTES,
                     fsp->fsp_name->base_name);
 
-       fsp->is_sparse = sparse;
+       fsp->fsp_flags.is_sparse = sparse;
 
        return NT_STATUS_OK;
 }
@@ -1195,7 +1254,10 @@ int file_ntimes(connection_struct *conn, const struct smb_filename *smb_fname,
         */
 
        /* Check if we have write access. */
-       if (can_write_to_file(conn, smb_fname)) {
+       if (can_write_to_file(conn,
+                       conn->cwd_fsp,
+                       smb_fname))
+       {
                /* We are allowed to become root and change the filetime. */
                become_root();
                ret = SMB_VFS_NTIMES(conn, smb_fname, ft);
@@ -1212,7 +1274,7 @@ int file_ntimes(connection_struct *conn, const struct smb_filename *smb_fname,
 
 bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime)
 {
-       if (null_timespec(mtime)) {
+       if (is_omit_timespec(&mtime)) {
                return true;
        }
 
@@ -1230,11 +1292,11 @@ bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime)
 
 bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime)
 {
-       if (null_timespec(mtime)) {
+       if (is_omit_timespec(&mtime)) {
                return true;
        }
 
-       fsp->write_time_forced = true;
+       fsp->fsp_flags.write_time_forced = true;
        TALLOC_FREE(fsp->update_write_time_event);
 
        return set_sticky_write_time_path(fsp->file_id, mtime);
@@ -1260,6 +1322,7 @@ NTSTATUS set_create_timespec_ea(connection_struct *conn,
                                        psmb_fname->base_name,
                                        NULL,
                                        &psmb_fname->st,
+                                       psmb_fname->twrp,
                                        psmb_fname->flags);
 
        if (smb_fname == NULL) {