Home | History | Annotate | Line # | Download | only in rpc.rquotad
      1  1.33      gson /*	$NetBSD: rquotad.c,v 1.33 2014/03/18 11:00:20 gson 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.33      gson __RCSID("$NetBSD: rquotad.c,v 1.33 2014/03/18 11:00:20 gson 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.16      fvdl 		(void) rpcb_unset(RQUOTAPROG, RQUOTAVERS, NULL);
     66  1.20    bouyer 		(void) rpcb_unset(RQUOTAPROG, EXT_RQUOTAVERS, NULL);
     67   1.1   deraadt 	}
     68   1.3   mycroft 
     69  1.13       mrg 	openlog("rpc.rquotad", LOG_PID, LOG_DAEMON);
     70   1.1   deraadt 
     71   1.1   deraadt 	/* create and register the service */
     72  1.15      fvdl 	if (from_inetd) {
     73  1.15      fvdl 		transp = svc_dg_create(0, 0, 0);
     74  1.15      fvdl 		if (transp == NULL) {
     75  1.15      fvdl 			syslog(LOG_ERR, "couldn't create udp service.");
     76  1.15      fvdl 			exit(1);
     77  1.15      fvdl 		}
     78  1.15      fvdl 		if (!svc_reg(transp, RQUOTAPROG, RQUOTAVERS, rquota_service,
     79  1.15      fvdl 		    NULL)) {
     80  1.15      fvdl 			syslog(LOG_ERR,
     81  1.15      fvdl 			    "unable to register (RQUOTAPROG, RQUOTAVERS).");
     82  1.15      fvdl 			exit(1);
     83  1.15      fvdl 		}
     84  1.20    bouyer 		if (!svc_reg(transp, RQUOTAPROG, EXT_RQUOTAVERS,
     85  1.20    bouyer 		    ext_rquota_service, NULL)) {
     86  1.20    bouyer 			syslog(LOG_ERR,
     87  1.20    bouyer 			    "unable to register (RQUOTAPROG, EXT_RQUOTAVERS).");
     88  1.20    bouyer 			exit(1);
     89  1.20    bouyer 		}
     90  1.15      fvdl 	} else {
     91  1.15      fvdl 		if (!svc_create(rquota_service, RQUOTAPROG, RQUOTAVERS, "udp")){
     92  1.15      fvdl 			syslog(LOG_ERR,
     93  1.15      fvdl 			    "unable to create (RQUOTAPROG, RQUOTAVERS).");
     94  1.15      fvdl 			exit(1);
     95  1.15      fvdl 		}
     96  1.20    bouyer 		if (!svc_create(ext_rquota_service, RQUOTAPROG,
     97  1.20    bouyer 		    EXT_RQUOTAVERS, "udp")){
     98  1.20    bouyer 			syslog(LOG_ERR,
     99  1.20    bouyer 			    "unable to create (RQUOTAPROG, EXT_RQUOTAVERS).");
    100  1.20    bouyer 			exit(1);
    101  1.20    bouyer 		}
    102   1.1   deraadt 	}
    103   1.4   mycroft 
    104  1.33      gson 	if (!from_inetd) {
    105  1.33      gson 		daemon(0, 0);
    106  1.33      gson 		(void) signal(SIGINT, cleanup);
    107  1.33      gson 		(void) signal(SIGTERM, cleanup);
    108  1.33      gson 		(void) signal(SIGHUP, cleanup);
    109  1.33      gson 	}
    110   1.1   deraadt 	svc_run();
    111   1.4   mycroft 	syslog(LOG_ERR, "svc_run returned");
    112   1.4   mycroft 	exit(1);
    113   1.1   deraadt }
    114   1.1   deraadt 
    115  1.28     joerg static void
    116  1.15      fvdl rquota_service(struct svc_req *request, SVCXPRT *transp)
    117   1.1   deraadt {
    118   1.1   deraadt 	switch (request->rq_proc) {
    119   1.1   deraadt 	case NULLPROC:
    120  1.30    plunky 		(void)svc_sendreply(transp, (xdrproc_t)xdr_void, NULL);
    121   1.1   deraadt 		break;
    122   1.4   mycroft 
    123   1.1   deraadt 	case RQUOTAPROC_GETQUOTA:
    124   1.1   deraadt 	case RQUOTAPROC_GETACTIVEQUOTA:
    125  1.20    bouyer 		sendquota(request, RQUOTAVERS, transp);
    126  1.20    bouyer 		break;
    127  1.20    bouyer 
    128  1.20    bouyer 	default:
    129  1.20    bouyer 		svcerr_noproc(transp);
    130  1.20    bouyer 		break;
    131  1.20    bouyer 	}
    132  1.20    bouyer 	if (from_inetd)
    133  1.20    bouyer 		exit(0);
    134  1.20    bouyer }
    135  1.20    bouyer 
    136  1.28     joerg static void
    137  1.20    bouyer ext_rquota_service(struct svc_req *request, SVCXPRT *transp)
    138  1.20    bouyer {
    139  1.20    bouyer 	switch (request->rq_proc) {
    140  1.20    bouyer 	case NULLPROC:
    141  1.30    plunky 		(void)svc_sendreply(transp, (xdrproc_t)xdr_void, NULL);
    142  1.20    bouyer 		break;
    143  1.20    bouyer 
    144  1.20    bouyer 	case RQUOTAPROC_GETQUOTA:
    145  1.20    bouyer 	case RQUOTAPROC_GETACTIVEQUOTA:
    146  1.20    bouyer 		sendquota(request, EXT_RQUOTAVERS, transp);
    147   1.1   deraadt 		break;
    148   1.4   mycroft 
    149   1.1   deraadt 	default:
    150   1.4   mycroft 		svcerr_noproc(transp);
    151   1.1   deraadt 		break;
    152   1.1   deraadt 	}
    153   1.4   mycroft 	if (from_inetd)
    154   1.4   mycroft 		exit(0);
    155   1.1   deraadt }
    156   1.1   deraadt 
    157  1.32  dholland /*
    158  1.32  dholland  * Convert a limit to rquota representation (where 0 == unlimited).
    159  1.32  dholland  * Clamp the result into a uint32_t.
    160  1.32  dholland  */
    161  1.32  dholland static uint32_t
    162  1.32  dholland limit_to_rquota(uint64_t lim)
    163  1.32  dholland {
    164  1.32  dholland 	if (lim == QUOTA_NOLIMIT || lim > 0xfffffffeUL)
    165  1.32  dholland 		return 0;
    166  1.32  dholland 	else
    167  1.32  dholland 		return (lim + 1);
    168  1.32  dholland }
    169  1.32  dholland 
    170  1.32  dholland /*
    171  1.32  dholland  * Convert a time to rquota representation.
    172  1.32  dholland  */
    173  1.32  dholland static uint32_t
    174  1.32  dholland time_to_rquota(time_t when, time_t now)
    175  1.32  dholland {
    176  1.32  dholland 	if (when == QUOTA_NOTIME) {
    177  1.32  dholland 		return 0;
    178  1.32  dholland 	} else {
    179  1.32  dholland 		return when - now;
    180  1.32  dholland 	}
    181  1.32  dholland }
    182  1.32  dholland 
    183  1.32  dholland /*
    184  1.32  dholland  * Convert to rquota representation.
    185  1.32  dholland  */
    186  1.32  dholland static void
    187  1.32  dholland quotavals_to_rquota(const struct quotaval *blocks,
    188  1.32  dholland 		    const struct quotaval *files,
    189  1.32  dholland 		    struct rquota *rq)
    190  1.32  dholland {
    191  1.32  dholland 	struct timeval now;
    192  1.32  dholland 
    193  1.32  dholland 	gettimeofday(&now, NULL);
    194  1.32  dholland 
    195  1.32  dholland 	rq->rq_active = TRUE;
    196  1.32  dholland 	rq->rq_bsize = DEV_BSIZE;
    197  1.32  dholland 
    198  1.32  dholland 	rq->rq_bhardlimit = limit_to_rquota(blocks->qv_hardlimit);
    199  1.32  dholland 	rq->rq_bsoftlimit = limit_to_rquota(blocks->qv_softlimit);
    200  1.32  dholland 	rq->rq_curblocks = blocks->qv_usage;
    201  1.32  dholland 	rq->rq_btimeleft = time_to_rquota(blocks->qv_expiretime, now.tv_sec);
    202  1.32  dholland 
    203  1.32  dholland 	rq->rq_fhardlimit = limit_to_rquota(files->qv_hardlimit);
    204  1.32  dholland 	rq->rq_fsoftlimit = limit_to_rquota(files->qv_softlimit);
    205  1.32  dholland 	rq->rq_curfiles = files->qv_usage;
    206  1.32  dholland 	rq->rq_ftimeleft = time_to_rquota(files->qv_expiretime, now.tv_sec);
    207  1.32  dholland }
    208  1.32  dholland 
    209   1.1   deraadt /* read quota for the specified id, and send it */
    210  1.28     joerg static void
    211  1.20    bouyer sendquota(struct svc_req *request, int vers, SVCXPRT *transp)
    212   1.1   deraadt {
    213   1.1   deraadt 	struct getquota_args getq_args;
    214  1.20    bouyer 	struct ext_getquota_args ext_getq_args;
    215   1.1   deraadt 	struct getquota_rslt getq_rslt;
    216  1.32  dholland 	struct quotahandle *qh;
    217  1.32  dholland 	struct quotakey qk;
    218  1.32  dholland 	struct quotaval blocks, files;
    219  1.32  dholland 	int idtype;
    220   1.1   deraadt 
    221  1.12     perry 	memset((char *)&getq_args, 0, sizeof(getq_args));
    222  1.21    bouyer 	memset((char *)&ext_getq_args, 0, sizeof(ext_getq_args));
    223  1.20    bouyer 	switch (vers) {
    224  1.20    bouyer 	case RQUOTAVERS:
    225  1.20    bouyer 		if (!svc_getargs(transp, xdr_getquota_args,
    226  1.20    bouyer 		    (caddr_t)&getq_args)) {
    227  1.20    bouyer 			svcerr_decode(transp);
    228  1.20    bouyer 			return;
    229  1.20    bouyer 		}
    230  1.20    bouyer 		ext_getq_args.gqa_pathp = getq_args.gqa_pathp;
    231  1.20    bouyer 		ext_getq_args.gqa_id = getq_args.gqa_uid;
    232  1.20    bouyer 		ext_getq_args.gqa_type = RQUOTA_USRQUOTA;
    233  1.20    bouyer 		break;
    234  1.20    bouyer 	case EXT_RQUOTAVERS:
    235  1.20    bouyer 		if (!svc_getargs(transp, xdr_ext_getquota_args,
    236  1.20    bouyer 		    (caddr_t)&ext_getq_args)) {
    237  1.20    bouyer 			svcerr_decode(transp);
    238  1.20    bouyer 			return;
    239  1.20    bouyer 		}
    240  1.20    bouyer 		break;
    241   1.1   deraadt 	}
    242  1.25    bouyer 	switch (ext_getq_args.gqa_type) {
    243  1.25    bouyer 	case RQUOTA_USRQUOTA:
    244  1.32  dholland 		idtype = QUOTA_IDTYPE_USER;
    245  1.25    bouyer 		break;
    246  1.25    bouyer 	case RQUOTA_GRPQUOTA:
    247  1.32  dholland 		idtype = QUOTA_IDTYPE_GROUP;
    248  1.25    bouyer 		break;
    249  1.25    bouyer 	default:
    250  1.25    bouyer 		getq_rslt.status = Q_NOQUOTA;
    251  1.25    bouyer 		goto out;
    252  1.25    bouyer 	}
    253   1.1   deraadt 	if (request->rq_cred.oa_flavor != AUTH_UNIX) {
    254   1.1   deraadt 		/* bad auth */
    255   1.1   deraadt 		getq_rslt.status = Q_EPERM;
    256  1.32  dholland 		goto out;
    257  1.32  dholland 	}
    258  1.32  dholland 
    259  1.32  dholland 	/*
    260  1.32  dholland 	 * XXX validate the path...
    261  1.32  dholland 	 */
    262  1.32  dholland 
    263  1.32  dholland 	qh = quota_open(ext_getq_args.gqa_pathp);
    264  1.32  dholland 	if (qh == NULL) {
    265  1.32  dholland 		/*
    266  1.32  dholland 		 * There are only three possible responses: success,
    267  1.32  dholland 		 * permission denied, and "no quota", so we return
    268  1.32  dholland 		 * the last for essentially all errors.
    269  1.32  dholland 		 */
    270  1.32  dholland 		if (errno == EPERM || errno == EACCES) {
    271  1.32  dholland 			getq_rslt.status = Q_EPERM;
    272  1.32  dholland 			goto out;
    273  1.32  dholland 		}
    274  1.32  dholland 		getq_rslt.status = Q_NOQUOTA;
    275  1.32  dholland 		goto out;
    276  1.32  dholland 	}
    277  1.32  dholland 
    278  1.32  dholland 	qk.qk_id = ext_getq_args.gqa_id;
    279  1.32  dholland 	qk.qk_idtype = idtype;
    280  1.32  dholland 	qk.qk_objtype = QUOTA_OBJTYPE_BLOCKS;
    281  1.32  dholland 	if (quota_get(qh, &qk, &blocks) < 0) {
    282   1.4   mycroft 		/* failed, return noquota */
    283  1.32  dholland 		quota_close(qh);
    284   1.4   mycroft 		getq_rslt.status = Q_NOQUOTA;
    285  1.32  dholland 		goto out;
    286  1.32  dholland 	}
    287  1.32  dholland 
    288  1.32  dholland 	qk.qk_objtype = QUOTA_OBJTYPE_FILES;
    289  1.32  dholland 	if (quota_get(qh, &qk, &files) < 0) {
    290  1.32  dholland 		/* failed, return noquota */
    291  1.32  dholland 		quota_close(qh);
    292  1.32  dholland 		getq_rslt.status = Q_NOQUOTA;
    293  1.32  dholland 		goto out;
    294   1.1   deraadt 	}
    295  1.32  dholland 
    296  1.32  dholland 	quota_close(qh);
    297  1.32  dholland 
    298  1.32  dholland 	quotavals_to_rquota(&blocks, &files,
    299  1.32  dholland 			    &getq_rslt.getquota_rslt_u.gqr_rquota);
    300  1.32  dholland 	getq_rslt.status = Q_OK;
    301  1.32  dholland 
    302  1.25    bouyer out:
    303  1.29    plunky 	if (!svc_sendreply(transp, (xdrproc_t)xdr_getquota_rslt, (char *)&getq_rslt))
    304   1.4   mycroft 		svcerr_systemerr(transp);
    305   1.4   mycroft 	if (!svc_freeargs(transp, xdr_getquota_args, (caddr_t)&getq_args)) {
    306   1.4   mycroft 		syslog(LOG_ERR, "unable to free arguments");
    307   1.4   mycroft 		exit(1);
    308   1.4   mycroft 	}
    309   1.1   deraadt }
    310