diff options
-rw-r--r-- | source3/smbd/quotas.c | 391 |
1 files changed, 279 insertions, 112 deletions
diff --git a/source3/smbd/quotas.c b/source3/smbd/quotas.c index 7808d269f9..57d7e36f10 100644 --- a/source3/smbd/quotas.c +++ b/source3/smbd/quotas.c @@ -250,6 +250,166 @@ BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_U #include <mntent.h> #endif +#if defined(SUNOS5) + +/**************************************************************************** + Allows querying of remote hosts for quotas on NFS mounted shares. + Supports normal NFS and AMD mounts. + Alan Romeril <a.romeril@ic.ac.uk> July 2K. +****************************************************************************/ + +#include <rpc/rpc.h> +#include <rpc/types.h> +#include <rpcsvc/rquota.h> +#include <rpc/nettype.h> +#include <rpc/xdr.h> + +static int quotastat; + +static int xdr_getquota_args(XDR *xdrsp, struct getquota_args *args) +{ + if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN )) + return(0); + if (!xdr_int(xdrsp, &args->gqa_uid)) + return(0); + return (1); +} + +static int xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr) +{ + gqr_status status; + union { + rquota gqr_rquota; + } getquota_rslt_u; + + if (!xdr_int(xdrsp, "astat)) { + DEBUG(6,("nfs_quotas: Status bad or zero\n")); + return 0; + } + if (!xdr_int32_t(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_uint32_t(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) { + DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n")); + return 0; + } + if (!xdr_uint32_t(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) { + DEBUG(6,("nfs_quotas: Softlimit bad or zero\n")); + return 0; + } + if (!xdr_uint32_t(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) { + DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n")); + return 0; + } + return (1); +} + +/* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */ +static BOOL nfs_quotas(char *nfspath, uid_t euser_id, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize) +{ + uid_t uid = euser_id; + struct dqblk 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; + + len=strcspn(mnttype, ":"); + pathname=strstr(mnttype, ":"); + cutstr = (char *) malloc(sizeof(char) * len ); + if (!cutstr) + return False; + + 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(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) { + clnt->cl_auth = authunix_create_default(); + DEBUG(9,("nfs_quotas: auth_success\n")); + + clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, xdr_getquota_args, (caddr_t)&args, + xdr_getquota_rslt, (caddr_t)&gqr, timeout); + if (clnt_stat == RPC_SUCCESS) + DEBUG(9,("nfs_quotas: rpccall_success\n")); + }; + + + /* + * quotastat 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. + */ + + if (quotastat == 1) { + DEBUG(9,("nfs_quotas: Good quota data\n")); + D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit; + D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit; + D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks; + } + + if (quotastat == 0 || quotastat == 3) { + D.dqb_bsoftlimit = 1; + D.dqb_curblocks = 1; + DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", quotastat )); + } + + if (quotastat == 2) { + DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", quotastat )); + auth_destroy(clnt->cl_auth); + clnt_destroy(clnt); + free(cutstr); + return(False); + } + + 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", + quotastat, + 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)); + + *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize; + *dsize = D.dqb_bsoftlimit; + + if (D.dqb_curblocks == D.dqb_curblocks == 1) + *bsize = 512; + + if (D.dqb_curblocks > D.dqb_bsoftlimit) { + *dfree = 0; + *dsize = D.dqb_curblocks; + } else + *dfree = D.dqb_bsoftlimit - D.dqb_curblocks; + + 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)); + + free(cutstr); + DEBUG(10,("nfs_quotas: End of nfs_quotas\n" )); + return(True); +} +#endif + /**************************************************************************** try to get the disk space from disk quotas (SunOS & Solaris2 version) Quota code by Peter Urbanec (amiga@cse.unsw.edu.au). @@ -257,147 +417,154 @@ Quota code by Peter Urbanec (amiga@cse.unsw.edu.au). BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize) { - uid_t euser_id; - int ret; - struct dqblk D; + uid_t euser_id; + int ret; + struct dqblk D; #if defined(SUNOS5) - struct quotctl command; - int file; - static struct mnttab mnt; - static pstring name; - pstring devopt; + struct quotctl command; + int file; + static struct mnttab mnt; + static pstring name; + pstring devopt; #else /* SunOS4 */ - struct mntent *mnt; - static pstring name; + struct mntent *mnt; + static pstring name; #endif - FILE *fd; - SMB_STRUCT_STAT sbuf; - SMB_DEV_T devno ; - static SMB_DEV_T devno_cached = 0 ; - static int found ; + FILE *fd; + SMB_STRUCT_STAT sbuf; + SMB_DEV_T devno ; + static SMB_DEV_T devno_cached = 0 ; + static int found ; - euser_id = geteuid(); + euser_id = geteuid(); - if ( sys_stat(path,&sbuf) == -1 ) - return(False) ; + if ( sys_stat(path,&sbuf) == -1 ) + return(False) ; - devno = sbuf.st_dev ; - DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n", path,devno)); - if ( devno != devno_cached ) { - devno_cached = devno ; + devno = sbuf.st_dev ; + DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n", path,devno)); + if ( devno != devno_cached ) { + devno_cached = devno ; #if defined(SUNOS5) - if ((fd = sys_fopen(MNTTAB, "r")) == NULL) - return(False) ; + if ((fd = sys_fopen(MNTTAB, "r")) == NULL) + return(False) ; - found = False ; - slprintf(devopt, sizeof(devopt) - 1, "dev=%x", devno); - while (getmntent(fd, &mnt) == 0) { - if( !hasmntopt(&mnt, devopt) ) - continue; - - DEBUG(5,("disk_quotas: testing \"%s\" %s\n", mnt.mnt_mountp,devopt)); - - /* quotas are only on vxfs, UFS or NFS, but nfs is not supported here */ - if ( strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 || - strcmp( mnt.mnt_fstype, "vxfs" ) == 0 ) - { - found = True ; - break ; - } - } + found = False ; + slprintf(devopt, sizeof(devopt) - 1, "dev=%x", devno); + while (getmntent(fd, &mnt) == 0) { + if( !hasmntopt(&mnt, devopt) ) + continue; + + DEBUG(5,("disk_quotas: testing \"%s\" %s\n", mnt.mnt_mountp,devopt)); + + /* quotas are only on vxfs, UFS or NFS */ + if ( strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 || + strcmp( mnt.mnt_fstype, "nfs" ) == 0 ) || + strcmp( mnt.mnt_fstype, "vxfs" ) == 0 ) { + found = True ; + break; + } + } - pstrcpy(name,mnt.mnt_mountp) ; - pstrcat(name,"/quotas") ; - fclose(fd) ; + pstrcpy(name,mnt.mnt_mountp) ; + pstrcat(name,"/quotas") ; + fclose(fd) ; #else /* SunOS4 */ - if ((fd = setmntent(MOUNTED, "r")) == NULL) - return(False) ; + if ((fd = setmntent(MOUNTED, "r")) == NULL) + return(False) ; - found = False ; - while ((mnt = getmntent(fd)) != NULL) { - if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 ) - continue ; - DEBUG(5,("disk_quotas: testing \"%s\" devno=%o\n", - mnt->mnt_dir,sbuf.st_dev)); - if (sbuf.st_dev == devno) { - found = True ; - break ; - } - } + found = False ; + while ((mnt = getmntent(fd)) != NULL) { + if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 ) + continue ; + DEBUG(5,("disk_quotas: testing \"%s\" devno=%o\n", mnt->mnt_dir,sbuf.st_dev)); + if (sbuf.st_dev == devno) { + found = True ; + break; + } + } - pstrcpy(name,mnt->mnt_fsname) ; - endmntent(fd) ; + pstrcpy(name,mnt->mnt_fsname) ; + endmntent(fd) ; #endif - - } + } - if ( ! found ) - return(False) ; + if ( ! found ) + return(False) ; - save_re_uid(); - set_effective_uid(0); + save_re_uid(); + set_effective_uid(0); #if defined(SUNOS5) - DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name)); - if((file=sys_open(name, O_RDONLY,0))<0) { - restore_re_uid(); - return(False); - } - command.op = Q_GETQUOTA; - command.uid = euser_id; - command.addr = (caddr_t) &D; - ret = ioctl(file, Q_QUOTACTL, &command); - close(file); + if ( strcmp( mnt.mnt_fstype, "nfs" ) == 0) { + BOOL retval; + DEBUG(5,("disk_quotas: looking for mountpath (NFS) \"%s\"\n", mnt.mnt_special)); + retval = nfs_quotas(mnt.mnt_special, euser_id, bsize, dfree, dsize); + restore_re_uid(); + return retval; + } + + DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name)); + if((file=sys_open(name, O_RDONLY,0))<0) { + restore_re_uid(); + return(False); + } + command.op = Q_GETQUOTA; + command.uid = euser_id; + command.addr = (caddr_t) &D; + ret = ioctl(file, Q_QUOTACTL, &command); + close(file); #else - DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name)); - ret = quotactl(Q_GETQUOTA, name, euser_id, &D); + DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name)); + ret = quotactl(Q_GETQUOTA, name, euser_id, &D); #endif - restore_re_uid(); + restore_re_uid(); - if (ret < 0) { - DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n", strerror(errno) )); + if (ret < 0) { + DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n", strerror(errno) )); #if defined(SUNOS5) && defined(VXFS_QUOTA) - /* If normal quotactl() fails, try vxfs private calls */ - set_effective_uid(euser_id); - DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt.mnt_fstype)); - if ( 0 == strcmp ( mnt.mnt_fstype, "vxfs" )) { - ret = disk_quotas_vxfs(name, path, bsize, dfree, dsize); - return(ret); - } + /* If normal quotactl() fails, try vxfs private calls */ + set_effective_uid(euser_id); + DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt.mnt_fstype)); + if ( 0 == strcmp ( mnt.mnt_fstype, "vxfs" )) { + BOOL retval; + retval = disk_quotas_vxfs(name, path, bsize, dfree, dsize); + return(retval); + } #else - return(False); + return(False); #endif - } + } - /* If softlimit is zero, set it equal to hardlimit. - */ + /* If softlimit is zero, set it equal to hardlimit. + */ - if (D.dqb_bsoftlimit==0) - D.dqb_bsoftlimit = D.dqb_bhardlimit; - - /* Use softlimit to determine disk space. A user exceeding the quota is told - * that there's no space left. Writes might actually work for a bit if the - * hardlimit is set higher than softlimit. Effectively the disk becomes - * made of rubber latex and begins to expand to accommodate the user :-) - */ - - if (D.dqb_bsoftlimit==0) - return(False); - *bsize = DEV_BSIZE; - *dsize = D.dqb_bsoftlimit; - - if (D.dqb_curblocks > D.dqb_bsoftlimit) { - *dfree = 0; - *dsize = D.dqb_curblocks; - } else - *dfree = D.dqb_bsoftlimit - D.dqb_curblocks; + if (D.dqb_bsoftlimit==0) + D.dqb_bsoftlimit = D.dqb_bhardlimit; + + /* Use softlimit to determine disk space. A user exceeding the quota is told + * that there's no space left. Writes might actually work for a bit if the + * hardlimit is set higher than softlimit. Effectively the disk becomes + * made of rubber latex and begins to expand to accommodate the user :-) + */ + + if (D.dqb_bsoftlimit==0) + return(False); + *bsize = DEV_BSIZE; + *dsize = D.dqb_bsoftlimit; + + if (D.dqb_curblocks > D.dqb_bsoftlimit) { + *dfree = 0; + *dsize = D.dqb_curblocks; + } else + *dfree = D.dqb_bsoftlimit - D.dqb_curblocks; - DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n", - path,(double)*bsize,(double)*dfree,(double)*dsize)); + DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n", + path,(double)*bsize,(double)*dfree,(double)*dsize)); - return(True); + return(True); } |