]> git.decadent.org.uk Git - nfs-utils.git/blob - utils/rquotad/rquota_svc.c
0785551472aa6e1f3f8109b814b321347c709e44
[nfs-utils.git] / utils / rquotad / rquota_svc.c
1 /*
2  * QUOTA    An implementation of the diskquota system for the LINUX
3  *          operating system. QUOTA is implemented using the BSD systemcall
4  *          interface as the means of communication with the user level.
5  *          Should work for all filesystems because of integration into the
6  *          VFS layer of the operating system.
7  *          This is based on the Melbourne quota system wich uses both user and
8  *          group quota files.
9  *
10  *          This part accepts the rquota rpc-requests.
11  *
12  * Version: $Id: rquota_svc.c,v 2.6 1996/11/17 16:59:46 mvw Exp mvw $
13  *
14  * Author:  Marco van Wieringen <mvw@planets.elm.net>
15  *
16  *          This program is free software; you can redistribute it and/or
17  *          modify it under the terms of the GNU General Public License
18  *          as published by the Free Software Foundation; either version
19  *          2 of the License, or (at your option) any later version.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #ifdef HAVE_TCP_WRAPPER
27 #include "tcpwrapper.h"
28 #endif
29
30 #include <unistd.h>
31 #include <errno.h>
32 #include <rpc/rpc.h>
33 #include "rquota.h"
34 #include <stdlib.h>
35 #include <rpc/pmap_clnt.h>
36 #include <string.h>
37 #include <memory.h>
38 #include <sys/socket.h>
39 #include <netinet/in.h>
40 #include <syslog.h>
41 #include <signal.h>
42 #include <getopt.h>
43 #include <rpcmisc.h>
44 #include <nfslib.h>
45
46 #ifdef __STDC__
47 #define SIG_PF void(*)(int)
48 #endif
49
50 extern getquota_rslt *rquotaproc_getquota_1(getquota_args *argp,
51                                             struct svc_req *rqstp);
52 extern getquota_rslt *rquotaproc_getactivequota_1(getquota_args *argp,
53                                                   struct svc_req *rqstp);
54 extern getquota_rslt *rquotaproc_getquota_2(ext_getquota_args *argp,
55                                             struct svc_req *rqstp);
56 extern getquota_rslt *rquotaproc_getactivequota_2(ext_getquota_args *argp,
57                                                   struct svc_req *rqstp);
58
59 static struct option longopts[] =
60 {
61         { "help", 0, 0, 'h' },
62         { "version", 0, 0, 'v' },
63         { "port", 1, 0, 'p' },
64         { NULL, 0, 0, 0 }
65 };
66
67 /*
68  * Global authentication credentials.
69  */
70 struct authunix_parms *unix_cred;
71
72 static void rquotaprog_1(struct svc_req *rqstp, register SVCXPRT *transp)
73 {
74    union {
75       getquota_args rquotaproc_getquota_1_arg;
76       getquota_args rquotaproc_getactivequota_1_arg;
77    } argument;
78    char *result;
79    xdrproc_t xdr_argument, xdr_result;
80    char *(*local)(char *, struct svc_req *);
81
82 #ifdef HAVE_TCP_WRAPPER
83    /* remote host authorization check */
84    if (!check_default("rquotad", svc_getcaller(transp),
85                       rqstp->rq_proc, RQUOTAPROG)) {
86          svcerr_auth (transp, AUTH_FAILED);
87          return;
88    }
89 #endif
90
91    /*
92     * Don't bother authentication for NULLPROC.
93     */
94    if (rqstp->rq_proc == NULLPROC) {
95       (void) svc_sendreply(transp, (xdrproc_t) xdr_void, (char *)NULL);
96       return;
97    }
98
99    /*
100     * First get authentication.
101     */
102    switch (rqstp->rq_cred.oa_flavor) {
103       case AUTH_UNIX:
104          unix_cred = (struct authunix_parms *)rqstp->rq_clntcred;
105          break;
106       case AUTH_NULL:
107       default:
108          svcerr_weakauth(transp);
109          return;
110    }
111
112    switch (rqstp->rq_proc) {
113       case RQUOTAPROC_GETQUOTA:
114          xdr_argument = (xdrproc_t) xdr_getquota_args;
115          xdr_result = (xdrproc_t) xdr_getquota_rslt;
116          local = (char *(*)(char *, struct svc_req *)) rquotaproc_getquota_1;
117          break;
118
119       case RQUOTAPROC_GETACTIVEQUOTA:
120          xdr_argument = (xdrproc_t) xdr_getquota_args;
121          xdr_result = (xdrproc_t) xdr_getquota_rslt;
122          local = (char *(*)(char *, struct svc_req *)) rquotaproc_getactivequota_1;
123          break;
124
125       default:
126          svcerr_noproc(transp);
127          return;
128    }
129
130    (void) memset((char *)&argument, 0, sizeof (argument));
131    if (!svc_getargs(transp, xdr_argument, (caddr_t) &argument)) {
132       svcerr_decode(transp);
133       return;
134    }
135    result = (*local)((char *)&argument, rqstp);
136    if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
137       svcerr_systemerr(transp);
138    }
139
140    if (!svc_freeargs(transp, xdr_argument, (caddr_t) &argument)) {
141       syslog(LOG_ERR, "unable to free arguments");
142       exit(1);
143    }
144    return;
145 }
146
147 static void rquotaprog_2(struct svc_req *rqstp, register SVCXPRT *transp)
148 {
149    union {
150       ext_getquota_args rquotaproc_getquota_2_arg;
151       ext_getquota_args rquotaproc_getactivequota_2_arg;
152    } argument;
153    char *result;
154    xdrproc_t xdr_argument, xdr_result;
155    char *(*local)(char *, struct svc_req *);
156
157 #ifdef HAVE_TCP_WRAPPER
158    /* remote host authorization check */
159    if (!check_default("rquotad", svc_getcaller(transp),
160                       rqstp->rq_proc, RQUOTAPROG)) {
161          svcerr_auth (transp, AUTH_FAILED);
162          return;
163    }
164 #endif
165
166    /*
167     * Don't bother authentication for NULLPROC.
168     */
169    if (rqstp->rq_proc == NULLPROC) {
170       (void) svc_sendreply(transp, (xdrproc_t) xdr_void, (char *)NULL);
171       return;
172    }
173
174    /*
175     * First get authentication.
176     */
177    switch (rqstp->rq_cred.oa_flavor) {
178       case AUTH_UNIX:
179          unix_cred = (struct authunix_parms *)rqstp->rq_clntcred;
180          break;
181       case AUTH_NULL:
182       default:
183          svcerr_weakauth(transp);
184          return;
185    }
186
187    switch (rqstp->rq_proc) {
188       case RQUOTAPROC_GETQUOTA:
189          xdr_argument = (xdrproc_t) xdr_ext_getquota_args;
190          xdr_result = (xdrproc_t) xdr_getquota_rslt;
191          local = (char *(*)(char *, struct svc_req *)) rquotaproc_getquota_2;
192          break;
193
194       case RQUOTAPROC_GETACTIVEQUOTA:
195          xdr_argument = (xdrproc_t) xdr_ext_getquota_args;
196          xdr_result = (xdrproc_t) xdr_getquota_rslt;
197          local = (char *(*)(char *, struct svc_req *)) rquotaproc_getactivequota_2;
198          break;
199
200       default:
201          svcerr_noproc(transp);
202          return;
203    }
204
205    (void) memset((char *)&argument, 0, sizeof (argument));
206    if (!svc_getargs(transp, xdr_argument, (caddr_t) &argument)) {
207       svcerr_decode(transp);
208       return;
209    }
210    result = (*local)((char *)&argument, rqstp);
211    if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
212       svcerr_systemerr(transp);
213    }
214
215    if (!svc_freeargs(transp, xdr_argument, (caddr_t) &argument)) {
216       syslog(LOG_ERR, "unable to free arguments");
217       exit(1);
218    }
219    return;
220 }
221
222 static void
223 usage(const char *prog, int n)
224 {
225   fprintf(stderr, "Usage: %s [-p|--port port] [-h|-?|--help] [-v|--version]\n", prog);
226   exit(n);
227 }
228
229 static void
230 killer (int sig)
231 {
232    (void) pmap_unset(RQUOTAPROG, RQUOTAVERS);
233    (void) pmap_unset(RQUOTAPROG, EXT_RQUOTAVERS);
234    syslog(LOG_ERR, "caught signal %d, un-registering and exiting.", sig);
235 }
236
237 int main(int argc, char **argv)
238 {
239    register SVCXPRT *transp;
240    int c;
241    int port = 0;
242    struct sigaction sa;
243
244    (void) pmap_unset(RQUOTAPROG, RQUOTAVERS);
245    (void) pmap_unset(RQUOTAPROG, EXT_RQUOTAVERS);
246
247    openlog("rquota", LOG_PID, LOG_DAEMON);
248
249    while ((c = getopt_long(argc, argv, "hp:v", longopts, NULL)) != EOF) {
250      switch (c) {
251      case '?':
252      case 'h':
253        usage(argv[0], 0);
254        break;
255      case 'p':
256        port = atoi(optarg);
257        if (port < 1 || port > 65535) {
258          fprintf(stderr, "%s: bad port number: %s\n",
259                  argv[0], optarg);
260          usage(argv[0], 1);
261        }
262        break;
263      case 'v':
264        printf("rquotad %s\n", VERSION);
265        exit(0);
266      default:
267        usage(argv[0], 1);
268      }
269    }
270
271    if (chdir(NFS_STATEDIR)) {
272      fprintf(stderr, "%s: chdir(%s) failed: %s\n",
273              argv [0], NFS_STATEDIR, strerror(errno));
274
275      exit(1);
276    }
277
278    /* WARNING: the following works on Linux and SysV, but not BSD! */
279    sa.sa_handler = SIG_IGN;
280    sa.sa_flags = 0;
281    sigemptyset(&sa.sa_mask);
282    sigaction(SIGCHLD, &sa, NULL);
283
284    sa.sa_handler = killer;
285    sigaction(SIGHUP, &sa, NULL);
286    sigaction(SIGINT, &sa, NULL);
287    sigaction(SIGTERM, &sa, NULL);
288
289    if (port)
290      transp = svcudp_create(makesock(port, IPPROTO_UDP));
291    else
292      transp = svcudp_create(svcudp_socket (RQUOTAPROG, 1));
293    if (transp == NULL) {
294       syslog(LOG_ERR, "cannot create udp service.");
295       exit(1);
296    }
297    if (!svc_register(transp, RQUOTAPROG, RQUOTAVERS, rquotaprog_1, IPPROTO_UDP)) {
298       syslog(LOG_ERR, "unable to register (RQUOTAPROG, RQUOTAVERS, udp).");
299       exit(1);
300    }
301    if (!svc_register(transp, RQUOTAPROG, EXT_RQUOTAVERS, rquotaprog_2, IPPROTO_UDP)) {
302       syslog(LOG_ERR, "unable to register (RQUOTAPROG, EXT_RQUOTAVERS, udp).");
303       exit(1);
304    }
305
306    daemon(1,1);
307    svc_run();
308
309    syslog(LOG_ERR, "svc_run returned");
310    exit(1);
311    /* NOTREACHED */
312 }