Home | History | Annotate | Line # | Download | only in rpc.rquotad
rquotad.c revision 1.32
      1  1.32  dholland /*	$NetBSD: rquotad.c,v 1.32 2012/01/09 15:37:34 dholland Exp $	*/
      2   1.7   thorpej 
      3   1.1   deraadt /*
      4  1.19    bouyer  * by Manuel Bouyer (bouyer (at) ensta.fr). Public domain.
      5   1.1   deraadt  */
      6   1.1   deraadt 
      7   1.9       mrg #include <sys/cdefs.h>
      8   1.9       mrg #ifndef lint
      9  1.32  dholland __RCSID("$NetBSD: rquotad.c,v 1.32 2012/01/09 15:37:34 dholland Exp $");
     10   1.9       mrg #endif
     11   1.9       mrg 
     12   1.1   deraadt #include <sys/param.h>
     13   1.1   deraadt #include <sys/types.h>
     14   1.1   deraadt #include <sys/mount.h>
     15   1.1   deraadt #include <sys/file.h>
     16   1.1   deraadt #include <sys/stat.h>
     17   1.9       mrg #include <sys/socket.h>
     18   1.5       jtc #include <signal.h>
     19   1.1   deraadt 
     20   1.1   deraadt #include <stdio.h>
     21   1.1   deraadt #include <fstab.h>
     22   1.1   deraadt #include <ctype.h>
     23   1.1   deraadt #include <stdlib.h>
     24   1.1   deraadt #include <string.h>
     25   1.1   deraadt #include <pwd.h>
     26   1.1   deraadt #include <grp.h>
     27   1.1   deraadt #include <errno.h>
     28   1.9       mrg #include <unistd.h>
     29   1.1   deraadt #include <syslog.h>
     30   1.1   deraadt 
     31   1.1   deraadt #include <rpc/rpc.h>
     32   1.1   deraadt #include <rpcsvc/rquota.h>
     33   1.2       cgd #include <arpa/inet.h>
     34   1.1   deraadt 
     35  1.32  dholland #include <quota.h>
     36  1.32  dholland 
     37  1.28     joerg static void rquota_service(struct svc_req *request, SVCXPRT *transp);
     38  1.28     joerg static void ext_rquota_service(struct svc_req *request, SVCXPRT *transp);
     39  1.28     joerg static void sendquota(struct svc_req *request, int vers, SVCXPRT *transp);
     40  1.28     joerg __dead static void cleanup(int);
     41   1.1   deraadt 
     42  1.28     joerg static int from_inetd = 1;
     43   1.4   mycroft 
     44  1.28     joerg static void
     45  1.15      fvdl cleanup(int dummy)
     46   1.4   mycroft {
     47  1.11       mrg 
     48  1.15      fvdl 	(void)rpcb_unset(RQUOTAPROG, RQUOTAVERS, NULL);
     49  1.20    bouyer 	(void)rpcb_unset(RQUOTAPROG, EXT_RQUOTAVERS, NULL);
     50   1.4   mycroft 	exit(0);
     51   1.4   mycroft }
     52   1.4   mycroft 
     53   1.1   deraadt int
     54  1.15      fvdl main(int argc, char *argv[])
     55   1.1   deraadt {
     56   1.4   mycroft 	SVCXPRT *transp;
     57  1.15      fvdl 	struct sockaddr_storage from;
     58  1.23       mrg 	socklen_t fromlen;
     59   1.1   deraadt 
     60   1.3   mycroft 	fromlen = sizeof(from);
     61  1.15      fvdl 	if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0)
     62   1.1   deraadt 		from_inetd = 0;
     63   1.3   mycroft 
     64   1.1   deraadt 	if (!from_inetd) {
     65   1.1   deraadt 		daemon(0, 0);
     66   1.3   mycroft 
     67  1.16      fvdl 		(void) rpcb_unset(RQUOTAPROG, RQUOTAVERS, NULL);
     68  1.20    bouyer 		(void) rpcb_unset(RQUOTAPROG, EXT_RQUOTAVERS, NULL);
     69   1.4   mycroft 		(void) signal(SIGINT, cleanup);
     70   1.4   mycroft 		(void) signal(SIGTERM, cleanup);
     71   1.4   mycroft 		(void) signal(SIGHUP, cleanup);
     72   1.1   deraadt 	}
     73   1.3   mycroft 
     74  1.13       mrg 	openlog("rpc.rquotad", LOG_PID, LOG_DAEMON);
     75   1.1   deraadt 
     76   1.1   deraadt 	/* create and register the service */
     77  1.15      fvdl 	if (from_inetd) {
     78  1.15      fvdl 		transp = svc_dg_create(0, 0, 0);
     79  1.15      fvdl 		if (transp == NULL) {
     80  1.15      fvdl 			syslog(LOG_ERR, "couldn't create udp service.");
     81  1.15      fvdl 			exit(1);
     82  1.15      fvdl 		}
     83  1.15      fvdl 		if (!svc_reg(transp, RQUOTAPROG, RQUOTAVERS, rquota_service,
     84  1.15      fvdl 		    NULL)) {
     85  1.15      fvdl 			syslog(LOG_ERR,
     86  1.15      fvdl 			    "unable to register (RQUOTAPROG, RQUOTAVERS).");
     87  1.15      fvdl 			exit(1);
     88  1.15      fvdl 		}
     89  1.20    bouyer 		if (!svc_reg(transp, RQUOTAPROG, EXT_RQUOTAVERS,
     90  1.20    bouyer 		    ext_rquota_service, NULL)) {
     91  1.20    bouyer 			syslog(LOG_ERR,
     92  1.20    bouyer 			    "unable to register (RQUOTAPROG, EXT_RQUOTAVERS).");
     93  1.20    bouyer 			exit(1);
     94  1.20    bouyer 		}
     95  1.15      fvdl 	} else {
     96  1.15      fvdl 		if (!svc_create(rquota_service, RQUOTAPROG, RQUOTAVERS, "udp")){
     97  1.15      fvdl 			syslog(LOG_ERR,
     98  1.15      fvdl 			    "unable to create (RQUOTAPROG, RQUOTAVERS).");
     99  1.15      fvdl 			exit(1);
    100  1.15      fvdl 		}
    101  1.20    bouyer 		if (!svc_create(ext_rquota_service, RQUOTAPROG,
    102  1.20    bouyer 		    EXT_RQUOTAVERS, "udp")){
    103  1.20    bouyer 			syslog(LOG_ERR,
    104  1.20    bouyer 			    "unable to create (RQUOTAPROG, EXT_RQUOTAVERS).");
    105  1.20    bouyer 			exit(1);
    106  1.20    bouyer 		}
    107   1.1   deraadt 	}
    108   1.4   mycroft 
    109   1.1   deraadt 	svc_run();
    110   1.4   mycroft 	syslog(LOG_ERR, "svc_run returned");
    111   1.4   mycroft 	exit(1);
    112   1.1   deraadt }
    113   1.1   deraadt 
    114  1.28     joerg static void
    115  1.15      fvdl rquota_service(struct svc_req *request, SVCXPRT *transp)
    116   1.1   deraadt {
    117   1.1   deraadt 	switch (request->rq_proc) {
    118   1.1   deraadt 	case NULLPROC:
    119  1.30    plunky 		(void)svc_sendreply(transp, (xdrproc_t)xdr_void, NULL);
    120   1.1   deraadt 		break;
    121   1.4   mycroft 
    122   1.1   deraadt 	case RQUOTAPROC_GETQUOTA:
    123   1.1   deraadt 	case RQUOTAPROC_GETACTIVEQUOTA:
    124  1.20    bouyer 		sendquota(request, RQUOTAVERS, transp);
    125  1.20    bouyer 		break;
    126  1.20    bouyer 
    127  1.20    bouyer 	default:
    128  1.20    bouyer 		svcerr_noproc(transp);
    129  1.20    bouyer 		break;
    130  1.20    bouyer 	}
    131  1.20    bouyer 	if (from_inetd)
    132  1.20    bouyer 		exit(0);
    133  1.20    bouyer }
    134  1.20    bouyer 
    135  1.28     joerg static void
    136  1.20    bouyer ext_rquota_service(struct svc_req *request, SVCXPRT *transp)
    137  1.20    bouyer {
    138  1.20    bouyer 	switch (request->rq_proc) {
    139  1.20    bouyer 	case NULLPROC:
    140  1.30    plunky 		(void)svc_sendreply(transp, (xdrproc_t)xdr_void, NULL);
    141  1.20    bouyer 		break;
    142  1.20    bouyer 
    143  1.20    bouyer 	case RQUOTAPROC_GETQUOTA:
    144  1.20    bouyer 	case RQUOTAPROC_GETACTIVEQUOTA:
    145  1.20    bouyer 		sendquota(request, EXT_RQUOTAVERS, transp);
    146   1.1   deraadt 		break;
    147   1.4   mycroft 
    148   1.1   deraadt 	default:
    149   1.4   mycroft 		svcerr_noproc(transp);
    150   1.1   deraadt 		break;
    151   1.1   deraadt 	}
    152   1.4   mycroft 	if (from_inetd)
    153   1.4   mycroft 		exit(0);
    154   1.1   deraadt }
    155   1.1   deraadt 
    156  1.32  dholland /*
    157  1.32  dholland  * Convert a limit to rquota representation (where 0 == unlimited).
    158  1.32  dholland  * Clamp the result into a uint32_t.
    159  1.32  dholland  */
    160  1.32  dholland static uint32_t
    161  1.32  dholland limit_to_rquota(uint64_t lim)
    162  1.32  dholland {
    163  1.32  dholland 	if (lim == QUOTA_NOLIMIT || lim > 0xfffffffeUL)
    164  1.32  dholland 		return 0;
    165  1.32  dholland 	else
    166  1.32  dholland 		return (lim + 1);
    167  1.32  dholland }
    168  1.32  dholland 
    169  1.32  dholland /*
    170  1.32  dholland  * Convert a time to rquota representation.
    171  1.32  dholland  */
    172  1.32  dholland static uint32_t
    173  1.32  dholland time_to_rquota(time_t when, time_t now)
    174  1.32  dholland {
    175  1.32  dholland 	if (when == QUOTA_NOTIME) {
    176  1.32  dholland 		return 0;
    177  1.32  dholland 	} else {
    178  1.32  dholland 		return when - now;
    179  1.32  dholland 	}
    180  1.32  dholland }
    181  1.32  dholland 
    182  1.32  dholland /*
    183  1.32  dholland  * Convert to rquota representation.
    184  1.32  dholland  */
    185  1.32  dholland static void
    186  1.32  dholland quotavals_to_rquota(const struct quotaval *blocks,
    187  1.32  dholland 		    const struct quotaval *files,
    188  1.32  dholland 		    struct rquota *rq)
    189  1.32  dholland {
    190  1.32  dholland 	struct timeval now;
    191  1.32  dholland 
    192  1.32  dholland 	gettimeofday(&now, NULL);
    193  1.32  dholland 
    194  1.32  dholland 	rq->rq_active = TRUE;
    195  1.32  dholland 	rq->rq_bsize = DEV_BSIZE;
    196  1.32  dholland 
    197  1.32  dholland 	rq->rq_bhardlimit = limit_to_rquota(blocks->qv_hardlimit);
    198  1.32  dholland 	rq->rq_bsoftlimit = limit_to_rquota(blocks->qv_softlimit);
    199  1.32  dholland 	rq->rq_curblocks = blocks->qv_usage;
    200  1.32  dholland 	rq->rq_btimeleft = time_to_rquota(blocks->qv_expiretime, now.tv_sec);
    201  1.32  dholland 
    202  1.32  dholland 	rq->rq_fhardlimit = limit_to_rquota(files->qv_hardlimit);
    203  1.32  dholland 	rq->rq_fsoftlimit = limit_to_rquota(files->qv_softlimit);
    204  1.32  dholland 	rq->rq_curfiles = files->qv_usage;
    205  1.32  dholland 	rq->rq_ftimeleft = time_to_rquota(files->qv_expiretime, now.tv_sec);
    206  1.32  dholland }
    207  1.32  dholland 
    208   1.1   deraadt /* read quota for the specified id, and send it */
    209  1.28     joerg static void
    210  1.20    bouyer sendquota(struct svc_req *request, int vers, SVCXPRT *transp)
    211   1.1   deraadt {
    212   1.1   deraadt 	struct getquota_args getq_args;
    213  1.20    bouyer 	struct ext_getquota_args ext_getq_args;
    214   1.1   deraadt 	struct getquota_rslt getq_rslt;
    215  1.32  dholland 	struct quotahandle *qh;
    216  1.32  dholland 	struct quotakey qk;
    217  1.32  dholland 	struct quotaval blocks, files;
    218  1.32  dholland 	int idtype;
    219   1.1   deraadt 
    220  1.12     perry 	memset((char *)&getq_args, 0, sizeof(getq_args));
    221  1.21    bouyer 	memset((char *)&ext_getq_args, 0, sizeof(ext_getq_args));
    222  1.20    bouyer 	switch (vers) {
    223  1.20    bouyer 	case RQUOTAVERS:
    224  1.20    bouyer 		if (!svc_getargs(transp, xdr_getquota_args,
    225  1.20    bouyer 		    (caddr_t)&getq_args)) {
    226  1.20    bouyer 			svcerr_decode(transp);
    227  1.20    bouyer 			return;
    228  1.20    bouyer 		}
    229  1.20    bouyer 		ext_getq_args.gqa_pathp = getq_args.gqa_pathp;
    230  1.20    bouyer 		ext_getq_args.gqa_id = getq_args.gqa_uid;
    231  1.20    bouyer 		ext_getq_args.gqa_type = RQUOTA_USRQUOTA;
    232  1.20    bouyer 		break;
    233  1.20    bouyer 	case EXT_RQUOTAVERS:
    234  1.20    bouyer 		if (!svc_getargs(transp, xdr_ext_getquota_args,
    235  1.20    bouyer 		    (caddr_t)&ext_getq_args)) {
    236  1.20    bouyer 			svcerr_decode(transp);
    237  1.20    bouyer 			return;
    238  1.20    bouyer 		}
    239  1.20    bouyer 		break;
    240   1.1   deraadt 	}
    241  1.25    bouyer 	switch (ext_getq_args.gqa_type) {
    242  1.25    bouyer 	case RQUOTA_USRQUOTA:
    243  1.32  dholland 		idtype = QUOTA_IDTYPE_USER;
    244  1.25    bouyer 		break;
    245  1.25    bouyer 	case RQUOTA_GRPQUOTA:
    246  1.32  dholland 		idtype = QUOTA_IDTYPE_GROUP;
    247  1.25    bouyer 		break;
    248  1.25    bouyer 	default:
    249  1.25    bouyer 		getq_rslt.status = Q_NOQUOTA;
    250  1.25    bouyer 		goto out;
    251  1.25    bouyer 	}
    252   1.1   deraadt 	if (request->rq_cred.oa_flavor != AUTH_UNIX) {
    253   1.1   deraadt 		/* bad auth */
    254   1.1   deraadt 		getq_rslt.status = Q_EPERM;
    255  1.32  dholland 		goto out;
    256  1.32  dholland 	}
    257  1.32  dholland 
    258  1.32  dholland 	/*
    259  1.32  dholland 	 * XXX validate the path...
    260  1.32  dholland 	 */
    261  1.32  dholland 
    262  1.32  dholland 	qh = quota_open(ext_getq_args.gqa_pathp);
    263  1.32  dholland 	if (qh == NULL) {
    264  1.32  dholland 		/*
    265  1.32  dholland 		 * There are only three possible responses: success,
    266  1.32  dholland 		 * permission denied, and "no quota", so we return
    267  1.32  dholland 		 * the last for essentially all errors.
    268  1.32  dholland 		 */
    269  1.32  dholland 		if (errno == EPERM || errno == EACCES) {
    270  1.32  dholland 			getq_rslt.status = Q_EPERM;
    271  1.32  dholland 			goto out;
    272  1.32  dholland 		}
    273  1.32  dholland 		getq_rslt.status = Q_NOQUOTA;
    274  1.32  dholland 		goto out;
    275  1.32  dholland 	}
    276  1.32  dholland 
    277  1.32  dholland 	qk.qk_id = ext_getq_args.gqa_id;
    278  1.32  dholland 	qk.qk_idtype = idtype;
    279  1.32  dholland 	qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS;
    280  1.32  dholland 	if (quota_get(qh, &qk, &blocks) < 0) {
    281   1.4   mycroft 		/* failed, return noquota */
    282  1.32  dholland 		quota_close(qh);
    283   1.4   mycroft 		getq_rslt.status = Q_NOQUOTA;
    284  1.32  dholland 		goto out;
    285  1.32  dholland 	}
    286  1.32  dholland 
    287  1.32  dholland 	qk.qk_objtype = QUOTA_OBJTYPE_FILES;
    288  1.32  dholland 	if (quota_get(qh, &qk, &files) < 0) {
    289  1.32  dholland 		/* failed, return noquota */
    290  1.32  dholland 		quota_close(qh);
    291  1.32  dholland 		getq_rslt.status = Q_NOQUOTA;
    292  1.32  dholland 		goto out;
    293   1.1   deraadt 	}
    294  1.32  dholland 
    295  1.32  dholland 	quota_close(qh);
    296  1.32  dholland 
    297  1.32  dholland 	quotavals_to_rquota(&blocks, &files,
    298  1.32  dholland 			    &getq_rslt.getquota_rslt_u.gqr_rquota);
    299  1.32  dholland 	getq_rslt.status = Q_OK;
    300  1.32  dholland 
    301  1.25    bouyer out:
    302  1.29    plunky 	if (!svc_sendreply(transp, (xdrproc_t)xdr_getquota_rslt, (char *)&getq_rslt))
    303   1.4   mycroft 		svcerr_systemerr(transp);
    304   1.4   mycroft 	if (!svc_freeargs(transp, xdr_getquota_args, (caddr_t)&getq_args)) {
    305   1.4   mycroft 		syslog(LOG_ERR, "unable to free arguments");
    306   1.4   mycroft 		exit(1);
    307   1.4   mycroft 	}
    308   1.1   deraadt }
    309