xref: /netbsd-src/libexec/rpc.rquotad/rquotad.c (revision a5847cc334d9a7029f6352b847e9e8d71a0f9e0c)
1 /*	$NetBSD: rquotad.c,v 1.30 2011/09/16 16:13:17 plunky Exp $	*/
2 
3 /*
4  * by Manuel Bouyer (bouyer@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