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