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