rquotad.c revision 1.30 1 /* $NetBSD: rquotad.c,v 1.30 2011/09/16 16:13:17 plunky 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.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