Home | History | Annotate | Line # | Download | only in rpc.rquotad
rquotad.c revision 1.26
      1 /*	$NetBSD: rquotad.c,v 1.26 2011/03/12 12:30:39 bouyer 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.26 2011/03/12 12:30:39 bouyer 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 <ufs/ufs/quota2_prop.h>
     33 #include <ufs/ufs/quota1.h>
     34 #include <rpc/rpc.h>
     35 #include <rpcsvc/rquota.h>
     36 #include <arpa/inet.h>
     37 
     38 #include <getvfsquota.h>
     39 
     40 const char *qfextension[MAXQUOTAS] = INITQFNAMES;
     41 
     42 void rquota_service(struct svc_req *request, SVCXPRT *transp);
     43 void ext_rquota_service(struct svc_req *request, SVCXPRT *transp);
     44 void sendquota(struct svc_req *request, int vers, SVCXPRT *transp);
     45 void cleanup(int);
     46 int main(int, char *[]);
     47 
     48 int from_inetd = 1;
     49 
     50 void
     51 cleanup(int dummy)
     52 {
     53 
     54 	(void)rpcb_unset(RQUOTAPROG, RQUOTAVERS, NULL);
     55 	(void)rpcb_unset(RQUOTAPROG, EXT_RQUOTAVERS, NULL);
     56 	exit(0);
     57 }
     58 
     59 int
     60 main(int argc, char *argv[])
     61 {
     62 	SVCXPRT *transp;
     63 	struct sockaddr_storage from;
     64 	socklen_t fromlen;
     65 
     66 	fromlen = sizeof(from);
     67 	if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0)
     68 		from_inetd = 0;
     69 
     70 	if (!from_inetd) {
     71 		daemon(0, 0);
     72 
     73 		(void) rpcb_unset(RQUOTAPROG, RQUOTAVERS, NULL);
     74 		(void) rpcb_unset(RQUOTAPROG, EXT_RQUOTAVERS, NULL);
     75 		(void) signal(SIGINT, cleanup);
     76 		(void) signal(SIGTERM, cleanup);
     77 		(void) signal(SIGHUP, cleanup);
     78 	}
     79 
     80 	openlog("rpc.rquotad", LOG_PID, LOG_DAEMON);
     81 
     82 	/* create and register the service */
     83 	if (from_inetd) {
     84 		transp = svc_dg_create(0, 0, 0);
     85 		if (transp == NULL) {
     86 			syslog(LOG_ERR, "couldn't create udp service.");
     87 			exit(1);
     88 		}
     89 		if (!svc_reg(transp, RQUOTAPROG, RQUOTAVERS, rquota_service,
     90 		    NULL)) {
     91 			syslog(LOG_ERR,
     92 			    "unable to register (RQUOTAPROG, RQUOTAVERS).");
     93 			exit(1);
     94 		}
     95 		if (!svc_reg(transp, RQUOTAPROG, EXT_RQUOTAVERS,
     96 		    ext_rquota_service, NULL)) {
     97 			syslog(LOG_ERR,
     98 			    "unable to register (RQUOTAPROG, EXT_RQUOTAVERS).");
     99 			exit(1);
    100 		}
    101 	} else {
    102 		if (!svc_create(rquota_service, RQUOTAPROG, RQUOTAVERS, "udp")){
    103 			syslog(LOG_ERR,
    104 			    "unable to create (RQUOTAPROG, RQUOTAVERS).");
    105 			exit(1);
    106 		}
    107 		if (!svc_create(ext_rquota_service, RQUOTAPROG,
    108 		    EXT_RQUOTAVERS, "udp")){
    109 			syslog(LOG_ERR,
    110 			    "unable to create (RQUOTAPROG, EXT_RQUOTAVERS).");
    111 			exit(1);
    112 		}
    113 	}
    114 
    115 	svc_run();
    116 	syslog(LOG_ERR, "svc_run returned");
    117 	exit(1);
    118 }
    119 
    120 void
    121 rquota_service(struct svc_req *request, SVCXPRT *transp)
    122 {
    123 	switch (request->rq_proc) {
    124 	case NULLPROC:
    125 		(void)svc_sendreply(transp, xdr_void, (char *)NULL);
    126 		break;
    127 
    128 	case RQUOTAPROC_GETQUOTA:
    129 	case RQUOTAPROC_GETACTIVEQUOTA:
    130 		sendquota(request, RQUOTAVERS, transp);
    131 		break;
    132 
    133 	default:
    134 		svcerr_noproc(transp);
    135 		break;
    136 	}
    137 	if (from_inetd)
    138 		exit(0);
    139 }
    140 
    141 void
    142 ext_rquota_service(struct svc_req *request, SVCXPRT *transp)
    143 {
    144 	switch (request->rq_proc) {
    145 	case NULLPROC:
    146 		(void)svc_sendreply(transp, xdr_void, (char *)NULL);
    147 		break;
    148 
    149 	case RQUOTAPROC_GETQUOTA:
    150 	case RQUOTAPROC_GETACTIVEQUOTA:
    151 		sendquota(request, EXT_RQUOTAVERS, transp);
    152 		break;
    153 
    154 	default:
    155 		svcerr_noproc(transp);
    156 		break;
    157 	}
    158 	if (from_inetd)
    159 		exit(0);
    160 }
    161 
    162 /* read quota for the specified id, and send it */
    163 void
    164 sendquota(struct svc_req *request, int vers, SVCXPRT *transp)
    165 {
    166 	struct getquota_args getq_args;
    167 	struct ext_getquota_args ext_getq_args;
    168 	struct getquota_rslt getq_rslt;
    169 	struct quota2_entry q2e;
    170 	struct dqblk dqblk;
    171 	int type;
    172 	int8_t version;
    173 	struct timeval timev;
    174 
    175 	memset((char *)&getq_args, 0, sizeof(getq_args));
    176 	memset((char *)&ext_getq_args, 0, sizeof(ext_getq_args));
    177 	switch (vers) {
    178 	case RQUOTAVERS:
    179 		if (!svc_getargs(transp, xdr_getquota_args,
    180 		    (caddr_t)&getq_args)) {
    181 			svcerr_decode(transp);
    182 			return;
    183 		}
    184 		ext_getq_args.gqa_pathp = getq_args.gqa_pathp;
    185 		ext_getq_args.gqa_id = getq_args.gqa_uid;
    186 		ext_getq_args.gqa_type = RQUOTA_USRQUOTA;
    187 		break;
    188 	case EXT_RQUOTAVERS:
    189 		if (!svc_getargs(transp, xdr_ext_getquota_args,
    190 		    (caddr_t)&ext_getq_args)) {
    191 			svcerr_decode(transp);
    192 			return;
    193 		}
    194 		break;
    195 	}
    196 	switch (ext_getq_args.gqa_type) {
    197 	case RQUOTA_USRQUOTA:
    198 		type = USRQUOTA;
    199 		break;
    200 	case RQUOTA_GRPQUOTA:
    201 		type = GRPQUOTA;
    202 		break;
    203 	default:
    204 		getq_rslt.status = Q_NOQUOTA;
    205 		goto out;
    206 	}
    207 	if (request->rq_cred.oa_flavor != AUTH_UNIX) {
    208 		/* bad auth */
    209 		getq_rslt.status = Q_EPERM;
    210 	} else if (!getvfsquota(ext_getq_args.gqa_pathp, &q2e, &version, ext_getq_args.gqa_id, ext_getq_args.gqa_type, 0, 0)) {
    211 		/* failed, return noquota */
    212 		getq_rslt.status = Q_NOQUOTA;
    213 	} else {
    214 		q2e2dqblk(&q2e, &dqblk);
    215 		gettimeofday(&timev, NULL);
    216 		getq_rslt.status = Q_OK;
    217 		getq_rslt.getquota_rslt_u.gqr_rquota.rq_active = TRUE;
    218 		getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsize = DEV_BSIZE;
    219 		getq_rslt.getquota_rslt_u.gqr_rquota.rq_bhardlimit =
    220 		    dqblk.dqb_bhardlimit;
    221 		getq_rslt.getquota_rslt_u.gqr_rquota.rq_bsoftlimit =
    222 		    dqblk.dqb_bsoftlimit;
    223 		getq_rslt.getquota_rslt_u.gqr_rquota.rq_curblocks =
    224 		    dqblk.dqb_curblocks;
    225 		getq_rslt.getquota_rslt_u.gqr_rquota.rq_fhardlimit =
    226 		    dqblk.dqb_ihardlimit;
    227 		getq_rslt.getquota_rslt_u.gqr_rquota.rq_fsoftlimit =
    228 		    dqblk.dqb_isoftlimit;
    229 		getq_rslt.getquota_rslt_u.gqr_rquota.rq_curfiles =
    230 		    dqblk.dqb_curinodes;
    231 		getq_rslt.getquota_rslt_u.gqr_rquota.rq_btimeleft =
    232 		    dqblk.dqb_btime;
    233 		getq_rslt.getquota_rslt_u.gqr_rquota.rq_ftimeleft =
    234 		    dqblk.dqb_itime;
    235 	}
    236 out:
    237 	if (!svc_sendreply(transp, xdr_getquota_rslt, (char *)&getq_rslt))
    238 		svcerr_systemerr(transp);
    239 	if (!svc_freeargs(transp, xdr_getquota_args, (caddr_t)&getq_args)) {
    240 		syslog(LOG_ERR, "unable to free arguments");
    241 		exit(1);
    242 	}
    243 }
    244