diff options
Diffstat (limited to 'source3')
-rw-r--r-- | source3/smbd/quotas.c | 330 |
1 files changed, 330 insertions, 0 deletions
diff --git a/source3/smbd/quotas.c b/source3/smbd/quotas.c new file mode 100644 index 0000000000..32c9fc35d3 --- /dev/null +++ b/source3/smbd/quotas.c @@ -0,0 +1,330 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + support for quotas + Copyright (C) Andrew Tridgell 1992-1995 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + + +#ifdef QUOTAS + +#ifdef LINUX +/**************************************************************************** +try to get the disk space from disk quotas (LINUX version) +****************************************************************************/ +/* +If you didn't make the symlink to the quota package, too bad :( +*/ +#include "quota/quotactl.c" +#include "quota/hasquota.c" +static BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize) +{ + uid_t euser_id; + struct dqblk D; + struct stat S; + dev_t devno ; + struct mntent *mnt; + FILE *fp; + int found ; + int qcmd, fd ; + char *qfpathname; + + /* find the block device file */ + + if ( stat(path, &S) == -1 ) + return(False) ; + + devno = S.st_dev ; + + fp = setmntent(MOUNTED,"r"); + found = False ; + + while ((mnt = getmntent(fp)) != (struct mntent *) 0) { + if ( stat(mnt->mnt_dir,&S) == -1 ) + continue ; + if (S.st_dev == devno) { + found = True ; + break ; + } + } + endmntent(fp) ; + + if ( ! found ) + return(False) ; + + qcmd = QCMD(Q_GETQUOTA, USRQUOTA); + + if (hasmntopt(mnt, MNTOPT_NOAUTO) || hasmntopt(mnt, MNTOPT_NOQUOTA)) + return(False) ; + + if (!hasquota(mnt, USRQUOTA, &qfpathname)) + return(False) ; + + euser_id = geteuid(); + seteuid(0); + + if (quotactl(qcmd, mnt->mnt_fsname, euser_id, (caddr_t)&D) != 0) { + if ((fd = open(qfpathname, O_RDONLY)) < 0) { + seteuid(euser_id); + return(False); + } + lseek(fd, (long) dqoff(euser_id), L_SET); + switch (read(fd, &D, sizeof(struct dqblk))) { + case 0:/* EOF */ + memset((caddr_t)&D, 0, sizeof(struct dqblk)); + break; + case sizeof(struct dqblk): /* OK */ + break; + default: /* ERROR */ + close(fd); + seteuid(euser_id); + return(False); + } + } + seteuid(euser_id); + *bsize=1024; + + if (D.dqb_bsoftlimit==0) + return(False); + if ((D.dqb_curblocks>D.dqb_bsoftlimit)||(D.dqb_curinodes>D.dqb_isoftlimit)) + { + *dfree = 0; + *dsize = D.dqb_curblocks; + } + else { + *dfree = D.dqb_bsoftlimit - D.dqb_curblocks; + *dsize = D.dqb_bsoftlimit; + } + return (True); +} + +#elif defined(CRAY) +/**************************************************************************** +try to get the disk space from disk quotas (CRAY VERSION) +****************************************************************************/ +static BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize) +{ + struct mntent *mnt; + FILE *fd; + struct stat sbuf; + dev_t devno ; + static dev_t devno_cached = 0 ; + static char name[MNTMAXSTR] ; + struct q_request request ; + struct qf_header header ; + static int quota_default = 0 ; + int found ; + + if ( stat(path,&sbuf) == -1 ) + return(False) ; + + devno = sbuf.st_dev ; + + if ( devno != devno_cached ) { + + devno_cached = devno ; + + if ((fd = setmntent(KMTAB)) == NULL) + return(False) ; + + found = False ; + + while ((mnt = getmntent(fd)) != NULL) { + + if ( stat(mnt->mnt_dir,&sbuf) == -1 ) + continue ; + + if (sbuf.st_dev == devno) { + + found = True ; + break ; + + } + + } + + strcpy(name,mnt->mnt_dir) ; + endmntent(fd) ; + + if ( ! found ) + return(False) ; + } + + request.qf_magic = QF_MAGIC ; + request.qf_entry.id = geteuid() ; + + if (quotactl(name, Q_GETQUOTA, &request) == -1) + return(False) ; + + if ( ! request.user ) + return(False) ; + + if ( request.qf_entry.user_q.f_quota == QFV_DEFAULT ) { + + if ( ! quota_default ) { + + if ( quotactl(name, Q_GETHEADER, &header) == -1 ) + return(False) ; + else + quota_default = header.user_h.def_fq ; + } + + *dfree = quota_default ; + + }else if ( request.qf_entry.user_q.f_quota == QFV_PREVENT ) { + + *dfree = 0 ; + + }else{ + + *dfree = request.qf_entry.user_q.f_quota ; + + } + + *dsize = request.qf_entry.user_q.f_use ; + + if ( *dfree ) + *dfree -= *dsize ; + + if ( *dfree < 0 ) + *dfree = 0 ; + + *bsize = 4096 ; /* Cray blocksize */ + + return(True) ; + +} + + +#elif defined(SUNOS5) + +#include <fcntl.h> +#include <sys/fs/ufs_quota.h> + +/**************************************************************************** +try to get the disk space from disk quotas (solaris 2 version) +****************************************************************************/ +/* Quota code by Peter Urbanec (amiga@cse.unsw.edu.au) */ +static BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize) +{ + uid_t user_id, euser_id; + int r; + struct dqblk D; + struct quotctl command; + int file; + + if((file=open(path, O_RDONLY))<0) return(False); + + euser_id = geteuid(); + user_id = getuid(); + + setuid(0); /* Solaris seems to want to give info only to super-user */ + seteuid(0); + + command.op = Q_GETQUOTA; + command.uid = euser_id; + command.addr = (caddr_t) &D; + + if(ioctl(file, Q_QUOTACTL, &command)<0) + { + close(file); + DEBUG(2,("disk_quotas ioctl (Solaris) failed\n")); + return(False); + } + close(file); + + setuid(user_id); /* Restore the original UID status */ + seteuid(euser_id); + + /* 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 :-) + */ + + *bsize = 512; + *dfree = D.dqb_bsoftlimit - D.dqb_curblocks; + *dsize = D.dqb_bsoftlimit; + if(*dfree < 0) + { + *dfree = 0; + *dsize = D.dqb_curblocks; + } + +DEBUG(5,("disk_quotas for path \"%s\" returning bsize %d, dfree %d, dsize %d\n", + path,*bsize,*dfree,*dsize)); + + return(True); +} + +#else + +/**************************************************************************** +try to get the disk space from disk quotas - default version +****************************************************************************/ +static BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize) +{ + uid_t user_id, euser_id; + int r; + char dev_disk[256]; + struct dqblk D; + struct stat S; + /* find the block device file */ + if ((stat(path, &S)<0) || + (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0)) return (False); + + euser_id = geteuid(); + +#ifdef USE_SETRES + /* for HPUX, real uid must be same as euid to execute quotactl for euid */ + user_id = getuid(); + setresuid(euser_id,-1,-1); +#endif + r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D); + #ifdef USE_SETRES + if (setresuid(user_id,-1,-1)) + DEBUG(5,("Unable to reset uid to %d\n", user_id)); + #endif + /* 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); + } + /* 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)) + { + *dfree = 0; + *dsize = D.dqb_curblocks; + } + else { + *dfree = D.dqb_bsoftlimit - D.dqb_curblocks; + *dsize = D.dqb_bsoftlimit; + } + return (True); +} + +#endif +#endif |