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