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