113237Sgraichen/* 213237Sgraichen * by Manuel Bouyer (bouyer@ensta.fr) 3184638Sdes * 413237Sgraichen * There is no copyright, you can use it as you want. 513237Sgraichen */ 613237Sgraichen 7184638Sdes#include <sys/cdefs.h> 8184638Sdes__FBSDID("$FreeBSD$"); 931420Scharnier 1013237Sgraichen#include <sys/param.h> 1113237Sgraichen#include <sys/mount.h> 1213237Sgraichen#include <sys/file.h> 1313237Sgraichen#include <sys/stat.h> 1413237Sgraichen#include <sys/socket.h> 1513237Sgraichen 16184638Sdes#include <ufs/ufs/quota.h> 17184638Sdes#include <rpc/rpc.h> 18184638Sdes#include <rpcsvc/rquota.h> 19184638Sdes#include <arpa/inet.h> 20184638Sdes#include <netdb.h> 21184638Sdes 2231420Scharnier#include <ctype.h> 2331420Scharnier#include <errno.h> 2431420Scharnier#include <fstab.h> 2531420Scharnier#include <grp.h> 26207736Smckusick#include <libutil.h> 2731420Scharnier#include <pwd.h> 28184638Sdes#include <signal.h> 2913237Sgraichen#include <stdio.h> 3013237Sgraichen#include <stdlib.h> 3131420Scharnier#include <string.h> 32184638Sdes#include <syslog.h> 3313237Sgraichen#include <unistd.h> 3413237Sgraichen 35197531Sdesstatic void rquota_service(struct svc_req *request, SVCXPRT *transp); 36197531Sdesstatic void sendquota(struct svc_req *request, SVCXPRT *transp); 37197531Sdesstatic void initfs(void); 38197531Sdesstatic int getfsquota(long id, char *path, struct dqblk *dqblk); 3913237Sgraichen 40207736Smckusickstatic struct quotafile **qfa; /* array of qfs */ 41207736Smckusickstatic int nqf, szqf; /* number of qfs and size of array */ 42197531Sdesstatic int from_inetd = 1; 4313237Sgraichen 44184638Sdesstatic void 4590336Simpcleanup(int sig) 4613237Sgraichen{ 47184638Sdes 48197506Sdes (void)sig; 49197506Sdes (void)rpcb_unset(RQUOTAPROG, RQUOTAVERS, NULL); 5013237Sgraichen exit(0); 5113237Sgraichen} 5213237Sgraichen 5313237Sgraichenint 54184638Sdesmain(void) 5513237Sgraichen{ 5613237Sgraichen SVCXPRT *transp; 57100120Salfred int ok; 58100120Salfred struct sockaddr_storage from; 59141918Sstefanf socklen_t fromlen; 6013237Sgraichen 6113237Sgraichen fromlen = sizeof(from); 62197506Sdes if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0) 6313237Sgraichen from_inetd = 0; 6413237Sgraichen 6513237Sgraichen if (!from_inetd) { 6613237Sgraichen daemon(0, 0); 67197506Sdes (void)rpcb_unset(RQUOTAPROG, RQUOTAVERS, NULL); 68197506Sdes (void)signal(SIGINT, cleanup); 69197506Sdes (void)signal(SIGTERM, cleanup); 70197506Sdes (void)signal(SIGHUP, cleanup); 7113237Sgraichen } 7213237Sgraichen 7313237Sgraichen openlog("rpc.rquotad", LOG_CONS|LOG_PID, LOG_DAEMON); 7413237Sgraichen 7513237Sgraichen /* create and register the service */ 76100120Salfred if (from_inetd) { 77100120Salfred transp = svc_tli_create(0, NULL, NULL, 0, 0); 78100120Salfred if (transp == NULL) { 79100120Salfred syslog(LOG_ERR, "couldn't create udp service."); 80100120Salfred exit(1); 81100120Salfred } 82100120Salfred ok = svc_reg(transp, RQUOTAPROG, RQUOTAVERS, 83197506Sdes rquota_service, NULL); 84197506Sdes } else { 85100120Salfred ok = svc_create(rquota_service, 86197506Sdes RQUOTAPROG, RQUOTAVERS, "udp"); 87197506Sdes } 88100120Salfred if (!ok) { 89184638Sdes syslog(LOG_ERR, 90184638Sdes "unable to register (RQUOTAPROG, RQUOTAVERS, %s)", 91184638Sdes from_inetd ? "(inetd)" : "udp"); 9213237Sgraichen exit(1); 9313237Sgraichen } 9413237Sgraichen 95184638Sdes initfs(); 9613237Sgraichen svc_run(); 9713237Sgraichen syslog(LOG_ERR, "svc_run returned"); 9813237Sgraichen exit(1); 9913237Sgraichen} 10013237Sgraichen 101197531Sdesstatic void 10290336Simprquota_service(struct svc_req *request, SVCXPRT *transp) 10313237Sgraichen{ 104184638Sdes 10513237Sgraichen switch (request->rq_proc) { 10613237Sgraichen case NULLPROC: 10795658Sdes (void)svc_sendreply(transp, (xdrproc_t)xdr_void, (char *)NULL); 10813237Sgraichen break; 10913237Sgraichen case RQUOTAPROC_GETQUOTA: 11013237Sgraichen case RQUOTAPROC_GETACTIVEQUOTA: 11113237Sgraichen sendquota(request, transp); 11213237Sgraichen break; 11313237Sgraichen default: 11413237Sgraichen svcerr_noproc(transp); 11513237Sgraichen break; 11613237Sgraichen } 11713237Sgraichen if (from_inetd) 11813237Sgraichen exit(0); 11913237Sgraichen} 12013237Sgraichen 12113237Sgraichen/* read quota for the specified id, and send it */ 122197531Sdesstatic void 12390336Simpsendquota(struct svc_req *request, SVCXPRT *transp) 12413237Sgraichen{ 12513237Sgraichen struct getquota_args getq_args; 12613237Sgraichen struct getquota_rslt getq_rslt; 12713237Sgraichen struct dqblk dqblk; 12813237Sgraichen struct timeval timev; 129207736Smckusick int scale; 13013237Sgraichen 131197506Sdes bzero(&getq_args, sizeof(getq_args)); 13295658Sdes if (!svc_getargs(transp, (xdrproc_t)xdr_getquota_args, &getq_args)) { 13313237Sgraichen svcerr_decode(transp); 13413237Sgraichen return; 13513237Sgraichen } 13613237Sgraichen if (request->rq_cred.oa_flavor != AUTH_UNIX) { 13713237Sgraichen /* bad auth */ 13813237Sgraichen getq_rslt.status = Q_EPERM; 13913237Sgraichen } else if (!getfsquota(getq_args.gqa_uid, getq_args.gqa_pathp, &dqblk)) { 14013237Sgraichen /* failed, return noquota */ 14113237Sgraichen getq_rslt.status = Q_NOQUOTA; 14213237Sgraichen } else { 14313237Sgraichen gettimeofday(&timev, NULL); 14413237Sgraichen getq_rslt.status = Q_OK; 14513237Sgraichen getq_rslt.getquota_rslt_u.gqr_rquota.rq_active = TRUE; 146207736Smckusick scale = 1 << flsll(dqblk.dqb_bhardlimit >> 32); 147207736Smckusick getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize = 148207736Smckusick DEV_BSIZE * scale; 14913237Sgraichen getq_rslt.getquota_rslt_u.gqr_rquota.rq_bhardlimit = 150207736Smckusick dqblk.dqb_bhardlimit / scale; 15113237Sgraichen getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsoftlimit = 152207736Smckusick dqblk.dqb_bsoftlimit / scale; 15313237Sgraichen getq_rslt.getquota_rslt_u.gqr_rquota.rq_curblocks = 154207736Smckusick dqblk.dqb_curblocks / scale; 15513237Sgraichen getq_rslt.getquota_rslt_u.gqr_rquota.rq_fhardlimit = 15613237Sgraichen dqblk.dqb_ihardlimit; 15713237Sgraichen getq_rslt.getquota_rslt_u.gqr_rquota.rq_fsoftlimit = 15813237Sgraichen dqblk.dqb_isoftlimit; 15913237Sgraichen getq_rslt.getquota_rslt_u.gqr_rquota.rq_curfiles = 16013237Sgraichen dqblk.dqb_curinodes; 16113237Sgraichen getq_rslt.getquota_rslt_u.gqr_rquota.rq_btimeleft = 16213237Sgraichen dqblk.dqb_btime - timev.tv_sec; 16313237Sgraichen getq_rslt.getquota_rslt_u.gqr_rquota.rq_ftimeleft = 16413237Sgraichen dqblk.dqb_itime - timev.tv_sec; 16513237Sgraichen } 166197508Sdes if (!svc_sendreply(transp, (xdrproc_t)xdr_getquota_rslt, &getq_rslt)) 16713237Sgraichen svcerr_systemerr(transp); 16895658Sdes if (!svc_freeargs(transp, (xdrproc_t)xdr_getquota_args, &getq_args)) { 16913237Sgraichen syslog(LOG_ERR, "unable to free arguments"); 17013237Sgraichen exit(1); 17113237Sgraichen } 17213237Sgraichen} 17313237Sgraichen 174197531Sdesstatic void 17590336Simpinitfs(void) 17613237Sgraichen{ 17713237Sgraichen struct fstab *fs; 17813237Sgraichen 17913237Sgraichen setfsent(); 180207736Smckusick szqf = 8; 181207736Smckusick if ((qfa = malloc(szqf * sizeof *qfa)) == NULL) 182207736Smckusick goto enomem; 18313237Sgraichen while ((fs = getfsent())) { 18413237Sgraichen if (strcmp(fs->fs_vfstype, "ufs")) 18513237Sgraichen continue; 186207736Smckusick if (nqf >= szqf) { 187207736Smckusick szqf *= 2; 188207736Smckusick if ((qfa = reallocf(qfa, szqf * sizeof *qfa)) == NULL) 189207736Smckusick goto enomem; 190207736Smckusick } 191207736Smckusick if ((qfa[nqf] = quota_open(fs, USRQUOTA, O_RDONLY)) == NULL) { 192207736Smckusick if (errno != EOPNOTSUPP) 193207736Smckusick goto fserr; 19413237Sgraichen continue; 195207736Smckusick } 196207736Smckusick ++nqf; 197207736Smckusick /* XXX */ 19813237Sgraichen } 19913237Sgraichen endfsent(); 200207736Smckusick return; 201207736Smckusickenomem: 202207736Smckusick syslog(LOG_ERR, "out of memory"); 203207736Smckusick exit(1); 204207736Smckusickfserr: 205207736Smckusick syslog(LOG_ERR, "%s: %s", fs->fs_file, strerror(errno)); 206207736Smckusick exit(1); 20713237Sgraichen} 20813237Sgraichen 20913237Sgraichen/* 21013237Sgraichen * gets the quotas for id, filesystem path. 21113237Sgraichen * Return 0 if fail, 1 otherwise 21213237Sgraichen */ 213197531Sdesstatic int 214184638Sdesgetfsquota(long id, char *path, struct dqblk *dqblk) 21513237Sgraichen{ 216207736Smckusick int i; 21713237Sgraichen 218207736Smckusick for (i = 0; i < nqf; ++i) 219207736Smckusick if (quota_check_path(qfa[i], path) == 1) 220207736Smckusick return (quota_read(qfa[i], dqblk, id) == 0); 221207736Smckusick return (0); 22213237Sgraichen} 223