smb2_server: call smbXsrv_connection_disconnect_transport() early on network errors
[gd/samba-autobuild/.git] / source3 / smbd / quotas.c
index 9d3b9061e9b1eb840132696b51f83c391389a62f..604631f81d6d283680b5506aa88ce3bdc69f036f 100644 (file)
@@ -216,8 +216,8 @@ try to get the disk space from disk quotas (SunOS & Solaris2 version)
 Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
 ****************************************************************************/
 
-bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
-                uint64_t *dfree, uint64_t *dsize)
+bool disk_quotas(connection_struct *conn, struct smb_filename *fname,
+                uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
 {
        uid_t euser_id;
        int ret;
@@ -230,14 +230,11 @@ bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
        SMB_STRUCT_STAT sbuf;
        SMB_DEV_T devno;
        bool found = false;
+       const char *path = fname->base_name;
 
        euser_id = geteuid();
 
-       if (sys_stat(path, &sbuf, false) == -1) {
-               return false;
-       }
-
-       devno = sbuf.st_ex_dev ;
+       devno = fname->st.st_ex_dev;
        DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n",
                path, (unsigned int)devno));
        if ((fd = fopen(MNTTAB, "r")) == NULL) {
@@ -338,133 +335,12 @@ bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
        return true;
 }
 
-
-#else /* not Solaris */
-
-#if           AIX
-/* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
-#include <jfs/quota.h>
-/* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
-#define dqb_curfiles dqb_curinodes
-#define dqb_fhardlimit dqb_ihardlimit
-#define dqb_fsoftlimit dqb_isoftlimit
-#ifdef _AIXVERSION_530 
-#include <sys/statfs.h>
-#include <sys/vmount.h>
-#endif /* AIX 5.3 */
-#else /* !AIX */
-#include <sys/quota.h>
-#include <devnm.h>
-#endif
-
-
-/****************************************************************************
-try to get the disk space from disk quotas - default version
-****************************************************************************/
-
-bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
-                uint64_t *dfree, uint64_t *dsize)
-{
-  int r;
-  struct dqblk D;
-  uid_t euser_id;
-#if !defined(AIX)
-  char dev_disk[256];
-  SMB_STRUCT_STAT S;
-
-  /* find the block device file */
-
-  if ((sys_stat(path, &S, false)<0)
-      || (devnm(S_IFBLK, S.st_ex_dev, dev_disk, 256, 0)<0))
-       return (False);
-
-#endif /* !defined(AIX) */
-
-  euser_id = geteuid();
-
-#if   defined(AIX)
-  /* AIX has both USER and GROUP quotas: 
-     Get the USER quota (ohnielse@fysik.dtu.dk) */
-#ifdef _AIXVERSION_530
-  {
-    struct statfs statbuf;
-    quota64_t user_quota;
-    if (statfs(path,&statbuf) != 0)
-      return False;
-    if(statbuf.f_vfstype == MNT_J2)
-    {
-    /* For some reason we need to be root for jfs2 */
-      become_root();
-      r = quotactl(path,QCMD(Q_J2GETQUOTA,USRQUOTA),euser_id,(char *) &user_quota);
-      unbecome_root();
-    /* Copy results to old struct to let the following code work as before */
-      D.dqb_curblocks  = user_quota.bused;
-      D.dqb_bsoftlimit = user_quota.bsoft;
-      D.dqb_bhardlimit = user_quota.bhard;
-      D.dqb_curfiles   = user_quota.iused;
-      D.dqb_fsoftlimit = user_quota.isoft;
-      D.dqb_fhardlimit = user_quota.ihard;
-    }
-    else if(statbuf.f_vfstype == MNT_JFS)
-    {
-#endif /* AIX 5.3 */
-  save_re_uid();
-  if (set_re_uid() != 0) 
-    return False;
-  r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
-  restore_re_uid();
-#ifdef _AIXVERSION_530
-    }
-    else
-      r = 1; /* Fail for other FS-types */
-  }
-#endif /* AIX 5.3 */
-#else /* !AIX */
-  r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
-#endif /* !AIX */
-
-  /* Use softlimit to determine disk space, except when it has been exceeded */
-  *bsize = 1024;
-
-  if (r)
-    {
-      if (errno == EDQUOT) 
-       {
-         *dfree =0;
-         *dsize =D.dqb_curblocks;
-         return (True);
-       }
-      else return(False);
-    }
-
-  /* If softlimit is zero, set it equal to hardlimit.
-   */
-
-  if (D.dqb_bsoftlimit==0)
-    D.dqb_bsoftlimit = D.dqb_bhardlimit;
-
-  if (D.dqb_bsoftlimit==0)
-    return(False);
-  /* Use softlimit to determine disk space, except when it has been exceeded */
-  if ((D.dqb_curblocks>D.dqb_bsoftlimit)
-||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
-    ) {
-      *dfree = 0;
-      *dsize = D.dqb_curblocks;
-    }
-  else {
-    *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
-    *dsize = D.dqb_bsoftlimit;
-  }
-  return (True);
-}
-
 #endif /* Solaris */
 
 #else /* WITH_QUOTAS */
 
-bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
-                uint64_t *dfree, uint64_t *dsize)
+bool disk_quotas(connection_struct *conn, struct smb_filename *fname,
+                uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
 {
        (*bsize) = 512; /* This value should be ignored */
 
@@ -482,8 +358,8 @@ bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
 /* wrapper to the new sys_quota interface
    this file should be removed later
    */
-bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
-                uint64_t *dfree, uint64_t *dsize)
+bool disk_quotas(connection_struct *conn, struct smb_filename *fname,
+                uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
 {
        int r;
        SMB_DISK_QUOTA D;
@@ -496,7 +372,8 @@ bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
         */
        ZERO_STRUCT(D);
        id.uid = -1;
-       r = SMB_VFS_GET_QUOTA(conn, path, SMB_USER_FS_QUOTA_TYPE, id, &D);
+       r = SMB_VFS_GET_QUOTA(conn, fname, SMB_USER_FS_QUOTA_TYPE,
+                             id, &D);
        if (r == -1 && errno != ENOSYS) {
                goto try_group_quota;
        }
@@ -507,7 +384,25 @@ bool disk_quotas(connection_struct *conn, const char *path, uint64_t *bsize,
        ZERO_STRUCT(D);
        id.uid = geteuid();
 
-       r = SMB_VFS_GET_QUOTA(conn, path, SMB_USER_QUOTA_TYPE, id, &D);
+       /* if new files created under this folder get this
+        * folder's UID, then available space is governed by
+        * the quota of the folder's UID, not the creating user.
+        */
+       if (lp_inherit_owner(SNUM(conn)) != INHERIT_OWNER_NO &&
+           id.uid != fname->st.st_ex_uid && id.uid != sec_initial_uid()) {
+               int save_errno;
+
+               id.uid = fname->st.st_ex_uid;
+               become_root();
+               r = SMB_VFS_GET_QUOTA(conn, fname,
+                                     SMB_USER_QUOTA_TYPE, id, &D);
+               save_errno = errno;
+               unbecome_root();
+               errno = save_errno;
+       } else {
+               r = SMB_VFS_GET_QUOTA(conn, fname,
+                                     SMB_USER_QUOTA_TYPE, id, &D);
+       }
 
        if (r == -1) {
                goto try_group_quota;
@@ -543,7 +438,8 @@ try_group_quota:
         */
        ZERO_STRUCT(D);
        id.gid = -1;
-       r = SMB_VFS_GET_QUOTA(conn, path, SMB_GROUP_FS_QUOTA_TYPE, id, &D);
+       r = SMB_VFS_GET_QUOTA(conn, fname, SMB_GROUP_FS_QUOTA_TYPE,
+                             id, &D);
        if (r == -1 && errno != ENOSYS) {
                return false;
        }
@@ -551,10 +447,26 @@ try_group_quota:
                return false;
        }
 
-       id.gid = getegid();
-
        ZERO_STRUCT(D);
-       r = SMB_VFS_GET_QUOTA(conn, path, SMB_GROUP_QUOTA_TYPE, id, &D);
+
+       /*
+        * If new files created under this folder get this folder's
+        * GID, then available space is governed by the quota of the
+        * folder's GID, not the primary group of the creating user.
+        */
+       if (VALID_STAT(fname->st) &&
+           S_ISDIR(fname->st.st_ex_mode) &&
+           fname->st.st_ex_mode & S_ISGID) {
+               id.gid = fname->st.st_ex_gid;
+               become_root();
+               r = SMB_VFS_GET_QUOTA(conn, fname, SMB_GROUP_QUOTA_TYPE, id,
+                                     &D);
+               unbecome_root();
+       } else {
+               id.gid = getegid();
+               r = SMB_VFS_GET_QUOTA(conn, fname, SMB_GROUP_QUOTA_TYPE, id,
+                                     &D);
+       }
 
        if (r == -1) {
                return False;