selftest/Samba4: make use of get_cmd_env_vars() to setup all relevant env variables
[samba.git] / source3 / modules / nfs4_acls.c
index 1e18ae3b1cff986d93f9d51c1cc2ec16b612c0af..c80f8390170b92a3e87e76571f833e2a4a86b229 100644 (file)
@@ -116,6 +116,155 @@ int smbacl4_get_vfs_params(struct connection_struct *conn,
        return 0;
 }
 
+static int fstatat_with_cap_dac_override(int fd,
+                                        const char *pathname,
+                                        SMB_STRUCT_STAT *sbuf,
+                                        int flags,
+                                        bool fake_dir_create_times)
+{
+       int ret;
+
+       set_effective_capability(DAC_OVERRIDE_CAPABILITY);
+       ret = sys_fstatat(fd,
+                         pathname,
+                         sbuf,
+                         flags,
+                         fake_dir_create_times);
+       drop_effective_capability(DAC_OVERRIDE_CAPABILITY);
+
+       return ret;
+}
+
+static int stat_with_cap_dac_override(struct vfs_handle_struct *handle,
+                                     struct smb_filename *smb_fname, int flag)
+{
+       bool fake_dctime = lp_fake_directory_create_times(SNUM(handle->conn));
+       int fd = -1;
+       NTSTATUS status;
+       struct smb_filename *dir_name = NULL;
+       struct smb_filename *rel_name = NULL;
+       int ret = -1;
+#ifdef O_PATH
+       int open_flags = O_PATH;
+#else
+       int open_flags = O_RDONLY;
+#endif
+
+       status = SMB_VFS_PARENT_PATHNAME(handle->conn,
+                                        talloc_tos(),
+                                        smb_fname,
+                                        &dir_name,
+                                        &rel_name);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               return -1;
+       }
+
+       fd = open(dir_name->base_name, open_flags, 0);
+       if (fd == -1) {
+               TALLOC_FREE(dir_name);
+               return -1;
+       }
+
+       ret = fstatat_with_cap_dac_override(fd,
+                                           rel_name->base_name,
+                                           &smb_fname->st,
+                                           flag,
+                                           fake_dctime);
+
+       TALLOC_FREE(dir_name);
+       close(fd);
+
+       return ret;
+}
+
+int nfs4_acl_stat(struct vfs_handle_struct *handle,
+                 struct smb_filename *smb_fname)
+{
+       int ret;
+
+       ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
+       if (ret == -1 && errno == EACCES) {
+               DEBUG(10, ("Trying stat with capability for %s\n",
+                          smb_fname->base_name));
+               ret = stat_with_cap_dac_override(handle, smb_fname, 0);
+       }
+       return ret;
+}
+
+static int fstat_with_cap_dac_override(int fd, SMB_STRUCT_STAT *sbuf,
+                                      bool fake_dir_create_times)
+{
+       int ret;
+
+       set_effective_capability(DAC_OVERRIDE_CAPABILITY);
+       ret = sys_fstat(fd, sbuf, fake_dir_create_times);
+       drop_effective_capability(DAC_OVERRIDE_CAPABILITY);
+
+       return ret;
+}
+
+int nfs4_acl_fstat(struct vfs_handle_struct *handle,
+                  struct files_struct *fsp,
+                  SMB_STRUCT_STAT *sbuf)
+{
+       int ret;
+
+       ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
+       if (ret == -1 && errno == EACCES) {
+               bool fake_dctime =
+                       lp_fake_directory_create_times(SNUM(handle->conn));
+
+               DBG_DEBUG("fstat for %s failed with EACCES. Trying with "
+                         "CAP_DAC_OVERRIDE.\n", fsp->fsp_name->base_name);
+               ret = fstat_with_cap_dac_override(fsp_get_pathref_fd(fsp),
+                                                 sbuf,
+                                                 fake_dctime);
+       }
+
+       return ret;
+}
+
+int nfs4_acl_lstat(struct vfs_handle_struct *handle,
+                  struct smb_filename *smb_fname)
+{
+       int ret;
+
+       ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
+       if (ret == -1 && errno == EACCES) {
+               DEBUG(10, ("Trying lstat with capability for %s\n",
+                          smb_fname->base_name));
+               ret = stat_with_cap_dac_override(handle, smb_fname,
+                                                AT_SYMLINK_NOFOLLOW);
+       }
+       return ret;
+}
+
+int nfs4_acl_fstatat(struct vfs_handle_struct *handle,
+                    const struct files_struct *dirfsp,
+                    const struct smb_filename *smb_fname,
+                    SMB_STRUCT_STAT *sbuf,
+                    int flags)
+{
+       int ret;
+
+       ret = SMB_VFS_NEXT_FSTATAT(handle, dirfsp, smb_fname, sbuf, flags);
+       if (ret == -1 && errno == EACCES) {
+               bool fake_dctime =
+                       lp_fake_directory_create_times(SNUM(handle->conn));
+
+               DBG_DEBUG("fstatat for %s failed with EACCES. Trying with "
+                         "CAP_DAC_OVERRIDE.\n", dirfsp->fsp_name->base_name);
+               ret = fstatat_with_cap_dac_override(fsp_get_pathref_fd(dirfsp),
+                                                   smb_fname->base_name,
+                                                   sbuf,
+                                                   flags,
+                                                   fake_dctime);
+       }
+
+       return ret;
+}
+
 /************************************************
  Split the ACE flag mapping between nfs4 and Windows
  into two separate functions rather than trying to do
@@ -399,7 +548,7 @@ static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx,
                    (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
                                      SEC_ACE_FLAG_CONTAINER_INHERIT))) {
                        /*
-                        * GPFS sets inherits dir_inhert and file_inherit flags
+                        * GPFS sets inherits dir_inherit and file_inherit flags
                         * to files, too, which confuses windows, and seems to
                         * be wrong anyways. ==> Map these bits away for files.
                         */