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