Home | History | Annotate | Line # | Download | only in rpc.rquotad
rquotad.c revision 1.30
      1 /*	$NetBSD: rquotad.c,v 1.30 2011/09/16 16:13:17 plunky Exp $	*/
      2 
      3 /*
      4  * by Manuel Bouyer (bouyer (at) ensta.fr). Public domain.
      5  */
      6 
      7 #include <sys/cdefs.h>
      8 #ifndef lint
      9 __RCSID("$NetBSD: rquotad.c,v 1.30 2011/09/16 16:13:17 plunky Exp $");
     10 #endif
     11 
     12 #include <sys/param.h>
     13 #include <sys/types.h>
     14 #include <sys/mount.h>
     15 #include <sys/file.h>
     16 #include <sys/stat.h>
     17 #include <sys/socket.h>
     18 #include <signal.h>
     19 
     20 #include <stdio.h>
     21 #include <fstab.h>
     22 #include <ctype.h>
     23 #include <stdlib.h>
     24 #include <string.h>
     25 #include <pwd.h>
     26 #include <grp.h>
     27 #include <errno.h>
     28 #include <unistd.h>
     29 
     30 #include <syslog.h>
     31 
     32 #include <quota/quotaprop.h>
     33 #include <quota/quota.h>
     34 #include <rpc/rpc.h>
     35 #include <rpcsvc/rquota.h>
     36 #include <arpa/inet.h>
     37 
     38 static void rquota_service(struct svc_req *request, SVCXPRT *transp);
     39 static void ext_rquota_service(struct svc_req *request, SVCXPRT *transp);
     40 static void sendquota(struct svc_req *request, int vers, SVCXPRT *transp);
     41 __dead static void cleanup(int);
     42 
     43 static int from_inetd = 1;
     44 
     45 static uint32_t
     46 qlim2rqlim(uint64_t lim)
     47 {
     48 	if (lim == UQUAD_MAX)
     49 		return 0;
     50 	else
     51 		return (lim + 1);
     52 }
     53 
     54 static void
     55 cleanup(int dummy)
     56 {
     57 
     58 	(void)rpcb_unset(RQUOTAPROG, RQUOTAVERS, NULL);
     59 	(void)rpcb_unset(RQUOTAPROG, EXT_RQUOTAVERS, NULL);
     60 	exit(0);
     61 }
     62 
     63 int
     64 main(int argc, char *argv[])
     65 {
     66 	SVCXPRT *transp;
     67 	struct sockaddr_storage from;
     68 	socklen_t fromlen;
     69 
     70 	fromlen = sizeof(from);
     71 	if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0)
     72 		from_inetd = 0;
     73 
     74 	if (!from_inetd) {
     75 		daemon(0, 0);
     76 
     77 		(void) rpcb_unset(RQUOTAPROG, RQUOTAVERS, NULL);
     78 		(void) rpcb_unset(RQUOTAPROG, EXT_RQUOTAVERS, NULL);
     79 		(void) signal(SIGINT, cleanup);
     80 		(void) signal(SIGTERM, cleanup);
     81 		(void) signal(SIGHUP, cleanup);
     82 	}
     83 
     84 	openlog("rpc.rquotad", LOG_PID, LOG_DAEMON);
     85 
     86 	/* create and register the service */
     87 	if (from_inetd) {
     88 		transp = svc_dg_create(0, 0, 0);
     89 		if (transp == NULL) {
     90 			syslog(LOG_ERR, "couldn't create udp service.");
     91 			exit(1);
     92 		}
     93 		if (!svc_reg(transp, RQUOTAPROG, RQUOTAVERS, rquota_service,
     94 		    NULL)) {
     95 			syslog(LOG_ERR,
     96 			    "unable to register (RQUOTAPROG, RQUOTAVERS).");
     97 			exit(1);
     98 		}
     99 		if (!svc_reg(transp, RQUOTAPROG, EXT_RQUOTAVERS,
    100 		    ext_rquota_service, NULL)) {
    101 			syslog(LOG_ERR,
    102 			    "unable to register (RQUOTAPROG, EXT_RQUOTAVERS).");
    103 			exit(1);
    104 		}
    105 	} else {
    106 		if (!svc_create(rquota_service, RQUOTAPROG, RQUOTAVERS, "udp")){
    107 			syslog(LOG_ERR,
    108 			    "unable to create (RQUOTAPROG, RQUOTAVERS).");
    109 			exit(1);
    110 		}
    111 		if (!svc_create(ext_rquota_service, RQUOTAPROG,
    112 		    EXT_RQUOTAVERS, "udp")){
    113 			syslog(LOG_ERR,
    114 			    "unable to create (RQUOTAPROG, EXT_RQUOTAVERS).");
    115 			exit(1);
    116 		}
    117 	}
    118 
    119 	svc_run();
    120 	syslog(LOG_ERR, "svc_run returned");
    121 	exit(1);
    122 }
    123 
    124 static void
    125 rquota_service(struct svc_req *request, SVCXPRT *transp)
    126 {
    127 	switch (request->rq_proc) {
    128 	case NULLPROC:
    129 		(void)svc_sendreply(transp, (xdrproc_t)xdr_void, NULL);
    130 		break;
    131 
    132 	case RQUOTAPROC_GETQUOTA:
    133 	case RQUOTAPROC_GETACTIVEQUOTA:
    134 		sendquota(request, RQUOTAVERS, transp);
    135 		break;
    136 
    137 	default:
    138 		svcerr_noproc(transp);
    139 		break;
    140 	}
    141 	if (from_inetd)
    142 		exit(0);
    143 }
    144 
    145 static void
    146 ext_rquota_service(struct svc_req *request, SVCXPRT *transp)
    147 {
    148 	switch (request->rq_proc) {
    149 	case NULLPROC:
    150 		(void)svc_sendreply(transp, (xdrproc_t)xdr_void, NULL);
    151 		break;
    152 
    153 	case RQUOTAPROC_GETQUOTA:
    154 	case RQUOTAPROC_GETACTIVEQUOTA:
    155 		sendquota(request, EXT_RQUOTAVERS, transp);
    156 		break;
    157 
    158 	default:
    159 		svcerr_noproc(transp);
    160 		break;
    161 	}
    162 	if (from_inetd)
    163 		exit(0);
    164 }
    165 
    166 /* read quota for the specified id, and send it */
    167 static void
    168 sendquota(struct svc_req *request, int vers, SVCXPRT *transp)
    169 {
    170 	struct getquota_args getq_args;
    171 	struct ext_getquota_args ext_getq_args;
    172 	struct getquota_rslt getq_rslt;
    173 	struct ufs_quota_entry qe[QUOTA_NLIMITS];
    174 	const char *class;
    175 	struct timeval timev;
    176 
    177 	memset((char *)&getq_args, 0, sizeof(getq_args));
    178 	memset((char *)&ext_getq_args, 0, sizeof(ext_getq_args));
    179 	switch (vers) {
    180 	case RQUOTAVERS:
    181 		if (!svc_getargs(transp, xdr_getquota_args,
    182 		    (caddr_t)&getq_args)) {
    183 			svcerr_decode(transp);
    184 			return;
    185 		}
    186 		ext_getq_args.gqa_pathp = getq_args.gqa_pathp;
    187 		ext_getq_args.gqa_id = getq_args.gqa_uid;
    188 		ext_getq_args.gqa_type = RQUOTA_USRQUOTA;
    189 		break;
    190 	case EXT_RQUOTAVERS:
    191 		if (!svc_getargs(transp, xdr_ext_getquota_args,
    192 		    (caddr_t)&ext_getq_args)) {
    193 			svcerr_decode(transp);
    194 			return;
    195 		}
    196 		break;
    197 	}
    198 	switch (ext_getq_args.gqa_type) {
    199 	case RQUOTA_USRQUOTA:
    200 		class = QUOTADICT_CLASS_USER;
    201 		break;
    202 	case RQUOTA_GRPQUOTA:
    203 		class = QUOTADICT_CLASS_GROUP;
    204 		break;
    205 	default:
    206 		getq_rslt.status = Q_NOQUOTA;
    207 		goto out;
    208 	}
    209 	if (request->rq_cred.oa_flavor != AUTH_UNIX) {
    210 		/* bad auth */
    211 		getq_rslt.status = Q_EPERM;
    212 	} else if (!getufsquota(ext_getq_args.gqa_pathp, qe,
    213 	    ext_getq_args.gqa_id, class)) {
    214 		/* failed, return noquota */
    215 		getq_rslt.status = Q_NOQUOTA;
    216 	} else {
    217 		gettimeofday(&timev, NULL);
    218 		getq_rslt.status = Q_OK;
    219 		getq_rslt.getquota_rslt_u.gqr_rquota.rq_active = TRUE;
    220 		getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize = DEV_BSIZE;
    221 		getq_rslt.getquota_rslt_u.gqr_rquota.rq_bhardlimit =
    222 		    qlim2rqlim(qe[QUOTA_LIMIT_BLOCK].ufsqe_hardlimit);
    223 		getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsoftlimit =
    224 		    qlim2rqlim(qe[QUOTA_LIMIT_BLOCK].ufsqe_softlimit);
    225 		getq_rslt.getquota_rslt_u.gqr_rquota.rq_curblocks =
    226 		    qe[QUOTA_LIMIT_BLOCK].ufsqe_cur;
    227 		getq_rslt.getquota_rslt_u.gqr_rquota.rq_fhardlimit =
    228 		    qlim2rqlim(qe[QUOTA_LIMIT_FILE].ufsqe_hardlimit);
    229 		getq_rslt.getquota_rslt_u.gqr_rquota.rq_fsoftlimit =
    230 		    qlim2rqlim(qe[QUOTA_LIMIT_FILE].ufsqe_softlimit);
    231 		getq_rslt.getquota_rslt_u.gqr_rquota.rq_curfiles =
    232 		    qe[QUOTA_LIMIT_FILE].ufsqe_cur;
    233 		getq_rslt.getquota_rslt_u.gqr_rquota.rq_btimeleft =
    234 		    qe[QUOTA_LIMIT_BLOCK].ufsqe_time - timev.tv_sec;
    235 		getq_rslt.getquota_rslt_u.gqr_rquota.rq_ftimeleft =
    236 		    qe[QUOTA_LIMIT_FILE].ufsqe_time - timev.tv_sec;
    237 	}
    238 out:
    239 	if (!svc_sendreply(transp, (xdrproc_t)xdr_getquota_rslt, (char *)&getq_rslt))
    240 		svcerr_systemerr(transp);
    241 	if (!svc_freeargs(transp, xdr_getquota_args, (caddr_t)&getq_args)) {
    242 		syslog(LOG_ERR, "unable to free arguments");
    243 		exit(1);
    244 	}
    245 }
    246