diff options
Diffstat (limited to 'source3')
-rw-r--r-- | source3/smbd/quotas.c | 439 |
1 files changed, 1 insertions, 438 deletions
diff --git a/source3/smbd/quotas.c b/source3/smbd/quotas.c index 10b05562af..0179e928d7 100644 --- a/source3/smbd/quotas.c +++ b/source3/smbd/quotas.c @@ -52,444 +52,7 @@ bool disk_quotas_vxfs(const char *name, char *path, uint64_t *bsize, uint64_t *d #endif /* VXFS_QUOTA */ -#ifdef LINUX - -#include <sys/types.h> -#include <mntent.h> - -/* - * This shouldn't be neccessary - it should be /usr/include/sys/quota.h - * So we include all the files has *should* be in the system into a large, - * grungy samba_linux_quoatas.h Sometimes I *hate* Linux :-). JRA. - */ - -#include "samba_linux_quota.h" - -typedef struct _LINUX_SMB_DISK_QUOTA { - uint64_t bsize; - uint64_t hardlimit; /* In bsize units. */ - uint64_t softlimit; /* In bsize units. */ - uint64_t curblocks; /* In bsize units. */ - uint64_t ihardlimit; /* inode hard limit. */ - uint64_t isoftlimit; /* inode soft limit. */ - uint64_t curinodes; /* Current used inodes. */ -} LINUX_SMB_DISK_QUOTA; - - -/* - * nfs quota support - * (essentially taken from FreeBSD / SUNOS5 section) - */ -#include <rpc/rpc.h> -#include <rpc/types.h> -#include <rpcsvc/rquota.h> -#ifdef HAVE_RPC_NETTYPE_H -#include <rpc/nettype.h> -#endif -#include <rpc/xdr.h> - -static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr) -{ - int quotastat; - - if (!xdr_int(xdrsp, "astat)) { - DEBUG(6,("nfs_quotas: Status bad or zero\n")); - return 0; - } - gqr->status = quotastat; - - if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) { - DEBUG(6,("nfs_quotas: Block size bad or zero\n")); - return 0; - } - if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) { - DEBUG(6,("nfs_quotas: Active bad or zero\n")); - return 0; - } - if (!xdr_int(xdrsp, (int *)&gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) { - DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n")); - return 0; - } - if (!xdr_int(xdrsp, (int *)&gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) { - DEBUG(6,("nfs_quotas: Softlimit bad or zero\n")); - return 0; - } - if (!xdr_int(xdrsp, (int *)&gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) { - DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n")); - return 0; - } - return 1; -} - -static bool nfs_quotas(char *nfspath, uid_t euser_id, uint64_t *bsize, - uint64_t *dfree, uint64_t *dsize) -{ - uid_t uid = euser_id; - LINUX_SMB_DISK_QUOTA D; - char *mnttype = nfspath; - CLIENT *clnt; - struct getquota_rslt gqr; - struct getquota_args args; - char *cutstr, *pathname, *host, *testpath; - int len; - static struct timeval timeout = {2,0}; - enum clnt_stat clnt_stat; - bool ret = True; - - *bsize = *dfree = *dsize = (uint64_t)0; - - len=strcspn(mnttype, ":"); - pathname=strstr(mnttype, ":"); - cutstr = (char *) SMB_MALLOC(len+1); - if (!cutstr) - return False; - - memset(cutstr, '\0', len+1); - host = strncat(cutstr,mnttype, sizeof(char) * len ); - DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr)); - DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype)); - testpath=strchr_m(mnttype, ':'); - args.gqa_pathp = testpath+1; - args.gqa_uid = uid; - - DEBUG(5, ("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers " - "\"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, - "udp")); - - if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) { - ret = False; - goto out; - } - - clnt->cl_auth = authunix_create_default(); - DEBUG(9,("nfs_quotas: auth_success\n")); - - clnt_stat=clnt_call(clnt, - RQUOTAPROC_GETQUOTA, - (const xdrproc_t)my_xdr_getquota_args, - (caddr_t)&args, - (const xdrproc_t)my_xdr_getquota_rslt, - (caddr_t)&gqr, timeout); - - if (clnt_stat != RPC_SUCCESS) { - DEBUG(9,("nfs_quotas: clnt_call fail\n")); - ret = False; - goto out; - } - - /* - * gqr.status returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is - * no quota set, and 3 if no permission to get the quota. If 0 or 3 return - * something sensible. - */ - - switch (gqr.status) { - case 0: - DEBUG(9, ("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", - gqr.status)); - ret = False; - goto out; - - case 1: - DEBUG(9,("nfs_quotas: Good quota data\n")); - D.softlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit; - D.hardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit; - D.curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks; - break; - - case 2: - case 3: - D.softlimit = 1; - D.curblocks = 1; - DEBUG(9, ("nfs_quotas: Remote Quotas returned \"%i\" \n", - gqr.status)); - break; - - default: - DEBUG(9, ("nfs_quotas: Remote Quotas Questionable! " - "Error \"%i\" \n", gqr.status)); - break; - } - - DEBUG(10, ("nfs_quotas: Let`s look at D a bit closer... " - "status \"%i\" bsize \"%i\" active? \"%i\" bhard " - "\"%i\" bsoft \"%i\" curb \"%i\" \n", - gqr.status, - gqr.getquota_rslt_u.gqr_rquota.rq_bsize, - gqr.getquota_rslt_u.gqr_rquota.rq_active, - gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit, - gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit, - gqr.getquota_rslt_u.gqr_rquota.rq_curblocks)); - - if (D.softlimit == 0) - D.softlimit = D.hardlimit; - if (D.softlimit == 0) - return False; - - *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize; - *dsize = D.softlimit; - - if (D.curblocks == 1) - *bsize = DEV_BSIZE; - - if (D.curblocks > D.softlimit) { - *dfree = 0; - *dsize = D.curblocks; - } else - *dfree = D.softlimit - D.curblocks; - - out: - - if (clnt) { - if (clnt->cl_auth) - auth_destroy(clnt->cl_auth); - clnt_destroy(clnt); - } - - DEBUG(5, ("nfs_quotas: For path \"%s\" returning " - "bsize %.0f, dfree %.0f, dsize %.0f\n", - args.gqa_pathp, (double)*bsize, (double)*dfree, - (double)*dsize)); - - SAFE_FREE(cutstr); - DEBUG(10,("nfs_quotas: End of nfs_quotas\n" )); - return ret; -} - -/* end of nfs quota section */ - -#ifdef HAVE_LINUX_DQBLK_XFS_H -#include <linux/dqblk_xfs.h> - -/**************************************************************************** - Abstract out the XFS Quota Manager quota get call. -****************************************************************************/ - -static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp) -{ - struct fs_disk_quota D; - int ret; - - ZERO_STRUCT(D); - - ret = quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D); - - if (ret) - ret = quotactl(QCMD(Q_XGETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D); - - if (ret) - return ret; - - dp->bsize = (uint64_t)512; - dp->softlimit = (uint64_t)D.d_blk_softlimit; - dp->hardlimit = (uint64_t)D.d_blk_hardlimit; - dp->ihardlimit = (uint64_t)D.d_ino_hardlimit; - dp->isoftlimit = (uint64_t)D.d_ino_softlimit; - dp->curinodes = (uint64_t)D.d_icount; - dp->curblocks = (uint64_t)D.d_bcount; - - return ret; -} -#else -static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp) -{ - DEBUG(0,("XFS quota support not available\n")); - errno = ENOSYS; - return -1; -} -#endif - - -/**************************************************************************** - Abstract out the old and new Linux quota get calls. -****************************************************************************/ - -static int get_smb_linux_v1_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp) -{ - struct v1_kern_dqblk D; - int ret; - - ZERO_STRUCT(D); - - ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D); - - if (ret && errno != EDQUOT) - ret = quotactl(QCMD(Q_V1_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D); - - if (ret && errno != EDQUOT) - return ret; - - dp->bsize = (uint64_t)QUOTABLOCK_SIZE; - dp->softlimit = (uint64_t)D.dqb_bsoftlimit; - dp->hardlimit = (uint64_t)D.dqb_bhardlimit; - dp->ihardlimit = (uint64_t)D.dqb_ihardlimit; - dp->isoftlimit = (uint64_t)D.dqb_isoftlimit; - dp->curinodes = (uint64_t)D.dqb_curinodes; - dp->curblocks = (uint64_t)D.dqb_curblocks; - - return ret; -} - -static int get_smb_linux_v2_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp) -{ - struct v2_kern_dqblk D; - int ret; - - ZERO_STRUCT(D); - - ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D); - - if (ret && errno != EDQUOT) - ret = quotactl(QCMD(Q_V2_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D); - - if (ret && errno != EDQUOT) - return ret; - - dp->bsize = (uint64_t)QUOTABLOCK_SIZE; - dp->softlimit = (uint64_t)D.dqb_bsoftlimit; - dp->hardlimit = (uint64_t)D.dqb_bhardlimit; - dp->ihardlimit = (uint64_t)D.dqb_ihardlimit; - dp->isoftlimit = (uint64_t)D.dqb_isoftlimit; - dp->curinodes = (uint64_t)D.dqb_curinodes; - dp->curblocks = ((uint64_t)D.dqb_curspace) / dp->bsize; - - return ret; -} - -/**************************************************************************** - Brand-new generic quota interface. -****************************************************************************/ - -static int get_smb_linux_gen_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp) -{ - struct if_dqblk D; - int ret; - - ZERO_STRUCT(D); - - ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D); - - if (ret && errno != EDQUOT) - ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D); - - if (ret && errno != EDQUOT) - return ret; - - dp->bsize = (uint64_t)QUOTABLOCK_SIZE; - dp->softlimit = (uint64_t)D.dqb_bsoftlimit; - dp->hardlimit = (uint64_t)D.dqb_bhardlimit; - dp->ihardlimit = (uint64_t)D.dqb_ihardlimit; - dp->isoftlimit = (uint64_t)D.dqb_isoftlimit; - dp->curinodes = (uint64_t)D.dqb_curinodes; - dp->curblocks = ((uint64_t)D.dqb_curspace) / dp->bsize; - - return ret; -} - -/**************************************************************************** - Try to get the disk space from disk quotas (LINUX version). -****************************************************************************/ - -bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize) -{ - int r; - SMB_STRUCT_STAT S; - FILE *fp; - LINUX_SMB_DISK_QUOTA D; - struct mntent *mnt; - SMB_DEV_T devno; - int found; - uid_t euser_id; - gid_t egrp_id; - - ZERO_STRUCT(D); - - euser_id = geteuid(); - egrp_id = getegid(); - - /* find the block device file */ - - if (sys_stat(path, &S, false) == -1 ) - return(False) ; - - devno = S.st_ex_dev ; - - if ((fp = setmntent(MOUNTED,"r")) == NULL) - return(False) ; - - found = False ; - - while ((mnt = getmntent(fp))) { - if (sys_stat(mnt->mnt_dir, &S, false) == -1) - continue ; - - if (S.st_ex_dev == devno) { - found = True ; - break; - } - } - - endmntent(fp) ; - - if (!found) - return(False); - - become_root(); - - if (strcmp(mnt->mnt_type, "nfs") == 0) { - bool retval; - retval = nfs_quotas(mnt->mnt_fsname , euser_id, bsize, dfree, dsize); - unbecome_root(); - return retval; - } - - if (strcmp(mnt->mnt_type, "xfs")==0) { - r=get_smb_linux_xfs_quota(mnt->mnt_fsname, euser_id, egrp_id, &D); - } else { - r=get_smb_linux_gen_quota(mnt->mnt_fsname, euser_id, egrp_id, &D); - if (r == -1 && errno != EDQUOT) { - r=get_smb_linux_v2_quota(mnt->mnt_fsname, euser_id, egrp_id, &D); - if (r == -1 && errno != EDQUOT) - r=get_smb_linux_v1_quota(mnt->mnt_fsname, euser_id, egrp_id, &D); - } - } - - unbecome_root(); - - /* 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); -} - -#elif defined(SUNOS5) || defined(SUNOS4) +#if defined(SUNOS5) || defined(SUNOS4) #include <fcntl.h> #include <sys/param.h> |