s3:utils: let smbstatus report anonymous signing/encryption explicitly
[samba.git] / source3 / modules / vfs_fake_dfq.c
index b375a95b2a225cbdca8ebe09ee079424fa36e28b..47c0b0714cc7aed23c47dca13dcdf810fa505e23 100644 (file)
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_VFS
 
-static int dfq_get_quota_do(struct vfs_handle_struct *handle, const char *path,
-                           enum SMB_QUOTA_TYPE qtype, unid_t id,
-                           SMB_DISK_QUOTA *qt);
+static int dfq_get_quota(struct vfs_handle_struct *handle,
+                       const struct smb_filename *smb_fname,
+                       enum SMB_QUOTA_TYPE qtype,
+                       unid_t id,
+                       SMB_DISK_QUOTA *qt);
 
 static uint64_t dfq_load_param(int snum, const char *path, const char *section,
                               const char *param, uint64_t def_val)
@@ -50,126 +52,36 @@ static uint64_t dfq_load_param(int snum, const char *path, const char *section,
        return ret;
 }
 
-static bool dfq_disk_quotas(vfs_handle_struct *handle, const char *path,
-                           uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
-{
-       int r;
-       SMB_DISK_QUOTA D;
-       unid_t id;
-
-       id.uid = geteuid();
-
-       ZERO_STRUCT(D);
-       r = dfq_get_quota_do(handle, path, SMB_USER_QUOTA_TYPE, id, &D);
-
-       /* Use softlimit to determine disk space, except when it has been
-        * exceeded */
-       *bsize = D.bsize;
-       if (r == -1) {
-               if (errno == EDQUOT) {
-                       *dfree = 0;
-                       *dsize = D.curblocks;
-                       return (true);
-               } else {
-                       goto try_group_quota;
-               }
-       }
-
-       /* Use softlimit to determine disk space, except when it has been
-        * exceeded */
-       if ((D.softlimit && D.curblocks >= D.softlimit) ||
-           (D.hardlimit && D.curblocks >= D.hardlimit) ||
-           (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
-           (D.ihardlimit && D.curinodes >= D.ihardlimit)) {
-               *dfree = 0;
-               *dsize = D.curblocks;
-       } else if (D.softlimit == 0 && D.hardlimit == 0) {
-               goto try_group_quota;
-       } else {
-               if (D.softlimit == 0) {
-                       D.softlimit = D.hardlimit;
-               }
-               *dfree = D.softlimit - D.curblocks;
-               *dsize = D.softlimit;
-       }
-
-       return true;
-
-try_group_quota:
-       id.gid = getegid();
-
-       ZERO_STRUCT(D);
-       r = dfq_get_quota_do(handle, path, SMB_GROUP_QUOTA_TYPE, id, &D);
-
-       /* Use softlimit to determine disk space, except when it has been
-        * exceeded */
-       *bsize = D.bsize;
-       if (r == -1) {
-               if (errno == EDQUOT) {
-                       *dfree = 0;
-                       *dsize = D.curblocks;
-                       return (true);
-               } else {
-                       return false;
-               }
-       }
-
-       /* Use softlimit to determine disk space, except when it has been
-        * exceeded */
-       if ((D.softlimit && D.curblocks >= D.softlimit) ||
-           (D.hardlimit && D.curblocks >= D.hardlimit) ||
-           (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
-           (D.ihardlimit && D.curinodes >= D.ihardlimit)) {
-               *dfree = 0;
-               *dsize = D.curblocks;
-       } else if (D.softlimit == 0 && D.hardlimit == 0) {
-               return false;
-       } else {
-               if (D.softlimit == 0) {
-                       D.softlimit = D.hardlimit;
-               }
-               *dfree = D.softlimit - D.curblocks;
-               *dsize = D.softlimit;
-       }
-
-       return (true);
-}
-
-static uint64_t dfq_disk_free(vfs_handle_struct *handle, const char *path,
-                             uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
+static uint64_t dfq_disk_free(vfs_handle_struct *handle,
+                               const struct smb_filename *smb_fname,
+                               uint64_t *bsize,
+                               uint64_t *dfree,
+                               uint64_t *dsize)
 {
        uint64_t free_1k;
-       uint64_t dfree_q = 0;
-       uint64_t bsize_q = 0;
-       uint64_t dsize_q = 0;
        int snum = SNUM(handle->conn);
        uint64_t dfq_bsize = 0;
-       char *rpath = NULL;
+       struct smb_filename *rpath_fname = NULL;
 
        /* look up the params based on real path to be resilient
         * to refactoring of path<->realpath
         */
-       rpath = SMB_VFS_NEXT_REALPATH(handle, path);
-       if (rpath != NULL) {
-               dfq_bsize = dfq_load_param(snum, rpath, "df", "block size", 0);
+       rpath_fname = SMB_VFS_NEXT_REALPATH(handle, talloc_tos(), smb_fname);
+       if (rpath_fname != NULL) {
+               dfq_bsize = dfq_load_param(snum, rpath_fname->base_name,
+                               "df", "block size", 0);
        }
        if (dfq_bsize == 0) {
-               SAFE_FREE(rpath);
-               return SMB_VFS_NEXT_DISK_FREE(handle, path, bsize, dfree,
+               TALLOC_FREE(rpath_fname);
+               return SMB_VFS_NEXT_DISK_FREE(handle, smb_fname, bsize, dfree,
                                              dsize);
        }
 
        *bsize = dfq_bsize;
-       *dfree = dfq_load_param(snum, rpath, "df", "disk free", 0);
-       *dsize = dfq_load_param(snum, rpath, "df", "disk size", 0);
-
-       if (dfq_disk_quotas(handle, path, &bsize_q, &dfree_q, &dsize_q)) {
-               (*bsize) = bsize_q;
-               (*dfree) = MIN(*dfree, dfree_q);
-               (*dsize) = MIN(*dsize, dsize_q);
-       }
-
-       disk_norm(bsize, dfree, dsize);
+       *dfree = dfq_load_param(snum, rpath_fname->base_name,
+                               "df", "disk free", 0);
+       *dsize = dfq_load_param(snum, rpath_fname->base_name,
+                               "df", "disk size", 0);
 
        if ((*bsize) < 1024) {
                free_1k = (*dfree) / (1024 / (*bsize));
@@ -177,23 +89,25 @@ static uint64_t dfq_disk_free(vfs_handle_struct *handle, const char *path,
                free_1k = ((*bsize) / 1024) * (*dfree);
        }
 
-       SAFE_FREE(rpath);
+       TALLOC_FREE(rpath_fname);
        return free_1k;
 }
 
-static int dfq_get_quota_do(struct vfs_handle_struct *handle, const char *path,
-                           enum SMB_QUOTA_TYPE qtype, unid_t id,
-                           SMB_DISK_QUOTA *qt)
+static int dfq_get_quota(struct vfs_handle_struct *handle,
+                       const struct smb_filename *smb_fname,
+                       enum SMB_QUOTA_TYPE qtype,
+                       unid_t id,
+                       SMB_DISK_QUOTA *qt)
 {
        int rc = 0;
        int save_errno;
        char *section = NULL;
        int snum = SNUM(handle->conn);
        uint64_t bsize = 0;
-       char *rpath = NULL;
+       struct smb_filename *rpath_fname = NULL;
 
-       rpath = SMB_VFS_NEXT_REALPATH(handle, path);
-       if (rpath == NULL) {
+       rpath_fname = SMB_VFS_NEXT_REALPATH(handle, talloc_tos(), smb_fname);
+       if (rpath_fname == NULL) {
                goto dflt;
        }
 
@@ -206,6 +120,12 @@ static int dfq_get_quota_do(struct vfs_handle_struct *handle, const char *path,
                section = talloc_asprintf(talloc_tos(), "g%llu",
                                          (unsigned long long)id.gid);
                break;
+       case SMB_USER_FS_QUOTA_TYPE:
+               section = talloc_strdup(talloc_tos(), "udflt");
+               break;
+       case SMB_GROUP_FS_QUOTA_TYPE:
+               section = talloc_strdup(talloc_tos(), "gdflt");
+               break;
        default:
                break;
        }
@@ -214,53 +134,132 @@ static int dfq_get_quota_do(struct vfs_handle_struct *handle, const char *path,
                goto dflt;
        }
 
-       bsize = dfq_load_param(snum, rpath, section, "block size", 0);
+       bsize = dfq_load_param(snum, rpath_fname->base_name,
+                               section, "block size", 4096);
        if (bsize == 0) {
                goto dflt;
        }
 
-       if (dfq_load_param(snum, rpath, section, "err", 0) != 0) {
+       if (dfq_load_param(snum, rpath_fname->base_name,
+                               section, "err", 0) != 0) {
                errno = ENOTSUP;
                rc = -1;
                goto out;
        }
 
+       if (dfq_load_param(snum, rpath_fname->base_name,
+                               section, "nosys", 0) != 0) {
+               errno = ENOSYS;
+               rc = -1;
+               goto out;
+       }
+
        ZERO_STRUCTP(qt);
 
        qt->bsize = bsize;
-       qt->hardlimit = dfq_load_param(snum, rpath, section, "hard limit", 0);
-       qt->softlimit = dfq_load_param(snum, rpath, section, "soft limit", 0);
-       qt->curblocks = dfq_load_param(snum, rpath, section, "cur blocks", 0);
+       qt->hardlimit = dfq_load_param(snum, rpath_fname->base_name,
+                               section, "hard limit", 0);
+       qt->softlimit = dfq_load_param(snum, rpath_fname->base_name,
+                               section, "soft limit", 0);
+       qt->curblocks = dfq_load_param(snum, rpath_fname->base_name,
+                               section, "cur blocks", 0);
        qt->ihardlimit =
-           dfq_load_param(snum, rpath, section, "inode hard limit", 0);
+           dfq_load_param(snum, rpath_fname->base_name,
+                               section, "inode hard limit", 0);
        qt->isoftlimit =
-           dfq_load_param(snum, rpath, section, "inode soft limit", 0);
-       qt->curinodes = dfq_load_param(snum, rpath, section, "cur inodes", 0);
-
-       if (dfq_load_param(snum, rpath, section, "edquot", 0) != 0) {
-               errno = EDQUOT;
-               rc = -1;
-       }
+           dfq_load_param(snum, rpath_fname->base_name,
+                               section, "inode soft limit", 0);
+       qt->curinodes = dfq_load_param(snum, rpath_fname->base_name,
+                               section, "cur inodes", 0);
+       qt->qflags = dfq_load_param(snum, rpath_fname->base_name,
+                               section, "qflags", QUOTAS_DENY_DISK);
 
        goto out;
 
 dflt:
-       rc = SMB_VFS_NEXT_GET_QUOTA(handle, qtype, id, qt);
+       rc = SMB_VFS_NEXT_GET_QUOTA(handle, smb_fname, qtype, id, qt);
 
 out:
        save_errno = errno;
        TALLOC_FREE(section);
-       SAFE_FREE(rpath);
+       TALLOC_FREE(rpath_fname);
        errno = save_errno;
        return rc;
 }
 
-static int dfq_get_quota(struct vfs_handle_struct *handle,
-                        enum SMB_QUOTA_TYPE qtype, unid_t id,
-                        SMB_DISK_QUOTA *qt)
+static void dfq_fake_stat(struct vfs_handle_struct *handle,
+                         struct smb_filename *smb_fname,
+                         SMB_STRUCT_STAT *sbuf)
 {
-       return dfq_get_quota_do(handle, handle->conn->connectpath, qtype, id,
-                               qt);
+       int snum = SNUM(handle->conn);
+       char *full_path = NULL;
+       char *to_free = NULL;
+       char path[PATH_MAX + 1];
+       int len;
+       gid_t gid;
+
+       len = full_path_tos(handle->conn->cwd_fsp->fsp_name->base_name,
+                           smb_fname->base_name,
+                           path, sizeof(path),
+                           &full_path, &to_free);
+       if (len == -1) {
+               DBG_ERR("Could not allocate memory in full_path_tos.\n");
+               return;
+       }
+
+       gid = dfq_load_param(snum, full_path, "stat", "sgid", 0);
+       if (gid != 0) {
+               sbuf->st_ex_gid = gid;
+               sbuf->st_ex_mode |= S_ISGID;
+       }
+
+       TALLOC_FREE(to_free);
+}
+
+static int dfq_stat(vfs_handle_struct *handle,
+                   struct smb_filename *smb_fname)
+{
+       int ret;
+
+       ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
+       if (ret == -1) {
+               return ret;
+       }
+
+       dfq_fake_stat(handle, smb_fname, &smb_fname->st);
+
+       return 0;
+}
+
+static int dfq_fstat(vfs_handle_struct *handle,
+                    files_struct *fsp,
+                    SMB_STRUCT_STAT *sbuf)
+{
+       int ret;
+
+       ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
+       if (ret == -1) {
+               return ret;
+       }
+
+       dfq_fake_stat(handle, fsp->fsp_name, sbuf);
+
+       return 0;
+}
+
+static int dfq_lstat(vfs_handle_struct *handle,
+                    struct smb_filename *smb_fname)
+{
+       int ret;
+
+       ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
+       if (ret == -1) {
+               return ret;
+       }
+
+       dfq_fake_stat(handle, smb_fname, &smb_fname->st);
+
+       return 0;
 }
 
 struct vfs_fn_pointers vfs_fake_dfq_fns = {
@@ -268,10 +267,14 @@ struct vfs_fn_pointers vfs_fake_dfq_fns = {
 
     .disk_free_fn = dfq_disk_free,
     .get_quota_fn = dfq_get_quota,
+
+    .stat_fn = dfq_stat,
+    .fstat_fn = dfq_fstat,
+    .lstat_fn = dfq_lstat,
 };
 
 static_decl_vfs;
-NTSTATUS vfs_fake_dfq_init(void)
+NTSTATUS vfs_fake_dfq_init(TALLOC_CTX *ctx)
 {
        return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "fake_dfq",
                                &vfs_fake_dfq_fns);