Update to 4.01.
[profile/ivi/quota.git] / rquota_svc.c
1 /*
2  * QUOTA    An implementation of the diskquota system for the LINUX operating
3  *          system. QUOTA is implemented using the BSD systemcall interface
4  *          as the means of communication with the user level. Should work for
5  *          all filesystems because of integration into the VFS layer of the
6  *          operating system. This is based on the Melbourne quota system wich
7  *          uses both user and group quota files.
8  *
9  *          Rquota service handlers.
10  *
11  * Author:  Marco van Wieringen <mvw@planets.elm.net>
12  *          changes for new utilities by Jan Kara <jack@suse.cz>
13  *          patches by Jani Jaakkola <jjaakkol@cs.helsinki.fi>
14  *
15  *          This program is free software; you can redistribute it and/or
16  *          modify it under the terms of the GNU General Public License as
17  *          published by the Free Software Foundation; either version 2 of
18  *          the License, or (at your option) any later version.
19  */
20                                                                                                           
21 #include "config.h"
22
23 #include <rpc/rpc.h>
24 #include <sys/socket.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27 #include <rpc/pmap_clnt.h>      /* for pmap_unset */
28 #include <stdio.h>
29 #include <stdlib.h>             /* getenv, exit */
30 #include <string.h>             /* strcmp */
31 #include <memory.h>
32 #include <unistd.h>
33 #include <getopt.h>
34 #include <signal.h>
35 #include <errno.h>
36 #ifdef HOSTS_ACCESS
37 #include <tcpd.h>
38 #include <netdb.h>
39
40 int deny_severity, allow_severity;      /* Needed by some versions of libwrap */
41 #endif
42
43 #ifdef __STDC__
44 #define SIG_PF void(*)(int)
45 #endif
46
47 extern int svctcp_socket (u_long __number, int __port, int __reuse);
48 extern int svcudp_socket (u_long __number, int __port, int __reuse);
49
50 #include "pot.h"
51 #include "common.h"
52 #include "rquota.h"
53 #include "quotasys.h"
54
55 char *progname;
56
57 /*
58  * Global authentication credentials.
59  */
60 struct authunix_parms *unix_cred;
61
62 #define FL_SETQUOTA 1   /* Enable setquota rpc */
63 #define FL_NODAEMON 2   /* Disable daemon() call */
64 #define FL_AUTOFS   4   /* Don't ignore autofs mountpoints */
65
66 int flags;                              /* Options specified on command line */ 
67 static int port;                        /* Port to use (0 for default one) */
68 static char xtab_path[PATH_MAX];        /* Path to NFSD export table */
69 char nfs_pseudoroot[PATH_MAX];          /* Root of the virtual NFS filesystem ('/' for NFSv3) */
70
71 static struct option options[]= {
72         { "version", 0, NULL, 'V' },
73         { "help", 0, NULL, 'h' },
74         { "foreground", 0 , NULL, 'F' },
75 #ifdef RPC_SETQUOTA
76         { "no-setquota", 0 , NULL, 's' },
77         { "setquota", 0, NULL, 'S' },
78 #endif
79         { "autofs", 0, NULL, 'I'},
80         { "port", 1, NULL, 'p' },
81         { "xtab", 1, NULL, 'x' },
82         { NULL, 0, NULL , 0 }
83 };
84
85 static void show_help(void)
86 {
87 #ifdef RPC_SETQUOTA
88         errstr(_("Usage: %s [options]\nOptions are:\n\
89  -h --help             shows this text\n\
90  -V --version          shows version information\n\
91  -F --foreground       starts the quota service in foreground\n\
92  -I --autofs           do not ignore mountpoints mounted by automounter\n\
93  -p --port <port>      listen on given port\n\
94  -s --no-setquota      disables remote calls to setquota (default)\n\
95  -S --setquota         enables remote calls to setquota\n\
96  -x --xtab <path>      set an alternative file with NFSD export table\n"), progname);
97
98 #else
99         errstr(_("Usage: %s [options]\nOptions are:\n\
100  -h --help             shows this text\n\
101  -V --version          shows version information\n\
102  -F --foreground       starts the quota service in foreground\n\
103  -I --autofs           do not ignore mountpoints mounted by automounter\n\
104  -p --port <port>      listen on given port\n\
105  -x --xtab <path>      set an alternative file with NFSD export table\n"), progname);
106 #endif
107 }
108
109 static void parse_options(int argc, char **argv)
110 {
111         char ostr[128]="", *endptr;
112         int i,opt;
113         int j=0;
114
115         sstrncpy(xtab_path, NFSD_XTAB_PATH, PATH_MAX);
116         for(i=0; options[i].name; i++) {
117                 ostr[j++] = options[i].val;
118                 if (options[i].has_arg)
119                         ostr[j++] = ':';
120         }
121         while ((opt=getopt_long(argc, argv, ostr, options, NULL))>=0) {
122                 switch(opt) {
123                         case 'V': 
124                                 version();
125                                 exit(0);
126                         case 'h':
127                                 show_help();
128                                 exit(0);
129                         case 'F':
130                                 flags |= FL_NODAEMON;
131                                 break;
132 #ifdef RPC_SETQUOTA
133                         case 's':
134                                 flags &= ~FL_SETQUOTA;
135                                 break;
136                         case 'S':       
137                                 flags |= FL_SETQUOTA;
138                                 break;
139 #endif
140                         case 'I':
141                                 flags |= FL_AUTOFS;
142                                 break;
143                         case 'p': 
144                                 port = strtol(optarg, &endptr, 0);
145                                 if (*endptr || port <= 0) {
146                                         errstr(_("Illegal port number: %s\n"), optarg);
147                                         show_help();
148                                         exit(1);
149                                 }
150                                 break;
151                         case 'x':
152                                 if (access(optarg, R_OK) < 0) {
153                                         errstr(_("Cannot access the specified xtab file %s: %s\n"), optarg, strerror(errno));
154                                         show_help();
155                                         exit(1);
156                                 }
157                                 sstrncpy(xtab_path, optarg, PATH_MAX);
158                                 break;
159                         default:
160                                 errstr(_("Unknown option '%c'.\n"), opt);
161                                 show_help();
162                                 exit(1);
163                 }
164         }
165 }
166
167
168 /*
169  * good_client checks if an quota client should be allowed to
170  * execute the requested rpc call.
171  */
172 static int good_client(struct sockaddr_in *addr, ulong rq_proc)
173 {
174 #ifdef HOSTS_ACCESS
175         struct request_info req;
176 #endif
177         char *remote = inet_ntoa(addr->sin_addr);
178
179         if (rq_proc==RQUOTAPROC_SETQUOTA ||
180              rq_proc==RQUOTAPROC_SETACTIVEQUOTA) {
181                 /* If setquota is disabled, fail always */
182                 if (!(flags & FL_SETQUOTA)) {
183                         errstr(_("host %s attempted to call setquota when disabled\n"),
184                                remote);
185
186                         return 0;
187                 }
188                 /* Require that SETQUOTA calls originate from port < 1024 */
189                 if (ntohs(addr->sin_port)>=1024) {
190                         errstr(_("host %s attempted to call setquota from port >= 1024\n"),
191                                remote);
192                         return 0;
193                 }
194                 /* Setquota OK */
195         }
196
197 #ifdef HOSTS_ACCESS
198         /* NOTE: we could use different servicename for setquota calls to
199          * allow only some hosts to call setquota. */
200
201         request_init(&req, RQ_DAEMON, "rquotad", RQ_CLIENT_SIN, addr, 0);
202         sock_methods(&req);
203         if (hosts_access(&req))
204                 return 1;
205         errstr(_("Denied access to host %s\n"), remote);
206         return 0;
207 #else
208         /* If no access checking is available, OK always */
209         return 1;
210 #endif
211 }
212
213 static void rquotaprog_1(struct svc_req *rqstp, register SVCXPRT * transp)
214 {
215         union {
216                 getquota_args rquotaproc_getquota_1_arg;
217                 setquota_args rquotaproc_setquota_1_arg;
218                 getquota_args rquotaproc_getactivequota_1_arg;
219                 setquota_args rquotaproc_setactivequota_1_arg;
220         } argument;
221         char *result;
222         xdrproc_t xdr_argument, xdr_result;
223         char *(*local) (char *, struct svc_req *);
224
225         /*
226          *  Authenticate host
227          */
228         if (!good_client(svc_getcaller(rqstp->rq_xprt),rqstp->rq_proc)) {
229                 svcerr_auth (transp, AUTH_FAILED);
230                 return;
231         }
232
233         /*
234          * Don't bother authentication for NULLPROC.
235          */
236         if (rqstp->rq_proc == NULLPROC) {
237                 (void)svc_sendreply(transp, (xdrproc_t) xdr_void, (char *)NULL);
238                 return;
239         }
240
241         /*
242          * Get authentication.
243          */
244         switch (rqstp->rq_cred.oa_flavor) {
245           case AUTH_UNIX:
246                   unix_cred = (struct authunix_parms *)rqstp->rq_clntcred;
247                   break;
248           case AUTH_NULL:
249           default:
250                   svcerr_weakauth(transp);
251                   return;
252         }
253
254         switch (rqstp->rq_proc) {
255           case RQUOTAPROC_GETQUOTA:
256                   xdr_argument = (xdrproc_t) xdr_getquota_args;
257                   xdr_result = (xdrproc_t) xdr_getquota_rslt;
258                   local = (char *(*)(char *, struct svc_req *))rquotaproc_getquota_1_svc;
259                   break;
260
261           case RQUOTAPROC_SETQUOTA:
262                   xdr_argument = (xdrproc_t) xdr_setquota_args;
263                   xdr_result = (xdrproc_t) xdr_setquota_rslt;
264                   local = (char *(*)(char *, struct svc_req *))rquotaproc_setquota_1_svc;
265                   break;
266
267           case RQUOTAPROC_GETACTIVEQUOTA:
268                   xdr_argument = (xdrproc_t) xdr_getquota_args;
269                   xdr_result = (xdrproc_t) xdr_getquota_rslt;
270                   local = (char *(*)(char *, struct svc_req *))rquotaproc_getactivequota_1_svc;
271                   break;
272
273           case RQUOTAPROC_SETACTIVEQUOTA:
274                   xdr_argument = (xdrproc_t) xdr_setquota_args;
275                   xdr_result = (xdrproc_t) xdr_setquota_rslt;
276                   local = (char *(*)(char *, struct svc_req *))rquotaproc_setactivequota_1_svc;
277                   break;
278
279           default:
280                   svcerr_noproc(transp);
281                   return;
282         }
283         memset(&argument, 0, sizeof(argument));
284         if (!svc_getargs(transp, xdr_argument, (caddr_t) & argument)) {
285                 svcerr_decode(transp);
286                 return;
287         }
288         result = (*local) ((char *)&argument, rqstp);
289         if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
290                 svcerr_systemerr(transp);
291         }
292         if (!svc_freeargs(transp, xdr_argument, (caddr_t) & argument)) {
293                 errstr(_("unable to free arguments\n"));
294                 exit(1);
295         }
296         return;
297 }
298
299 static void rquotaprog_2(struct svc_req *rqstp, register SVCXPRT * transp)
300 {
301         union {
302                 ext_getquota_args rquotaproc_getquota_2_arg;
303                 ext_setquota_args rquotaproc_setquota_2_arg;
304                 ext_getquota_args rquotaproc_getactivequota_2_arg;
305                 ext_setquota_args rquotaproc_setactivequota_2_arg;
306         } argument;
307         char *result;
308         xdrproc_t xdr_argument, xdr_result;
309         char *(*local) (char *, struct svc_req *);
310
311         /*
312          *  Authenticate host
313          */
314         if (!good_client(svc_getcaller(rqstp->rq_xprt),rqstp->rq_proc)) {
315                 svcerr_auth (transp, AUTH_FAILED);
316                 return;
317         }
318
319         /*
320          * Don't bother authentication for NULLPROC.
321          */
322         if (rqstp->rq_proc == NULLPROC) {
323                 (void)svc_sendreply(transp, (xdrproc_t) xdr_void, (char *)NULL);
324                 return;
325         }
326
327         /*
328          * Get authentication.
329          */
330         switch (rqstp->rq_cred.oa_flavor) {
331           case AUTH_UNIX:
332                   unix_cred = (struct authunix_parms *)rqstp->rq_clntcred;
333                   break;
334           case AUTH_NULL:
335           default:
336                   svcerr_weakauth(transp);
337                   return;
338         }
339
340         switch (rqstp->rq_proc) {
341           case RQUOTAPROC_GETQUOTA:
342                   xdr_argument = (xdrproc_t) xdr_ext_getquota_args;
343                   xdr_result = (xdrproc_t) xdr_getquota_rslt;
344                   local = (char *(*)(char *, struct svc_req *))rquotaproc_getquota_2_svc;
345                   break;
346
347           case RQUOTAPROC_SETQUOTA:
348                   xdr_argument = (xdrproc_t) xdr_ext_setquota_args;
349                   xdr_result = (xdrproc_t) xdr_setquota_rslt;
350                   local = (char *(*)(char *, struct svc_req *))rquotaproc_setquota_2_svc;
351                   break;
352
353           case RQUOTAPROC_GETACTIVEQUOTA:
354                   xdr_argument = (xdrproc_t) xdr_ext_getquota_args;
355                   xdr_result = (xdrproc_t) xdr_getquota_rslt;
356                   local = (char *(*)(char *, struct svc_req *))rquotaproc_getactivequota_2_svc;
357                   break;
358
359           case RQUOTAPROC_SETACTIVEQUOTA:
360                   xdr_argument = (xdrproc_t) xdr_ext_setquota_args;
361                   xdr_result = (xdrproc_t) xdr_setquota_rslt;
362                   local = (char *(*)(char *, struct svc_req *))rquotaproc_setactivequota_2_svc;
363                   break;
364
365           default:
366                   svcerr_noproc(transp);
367                   return;
368         }
369         memset(&argument, 0, sizeof(argument));
370         if (!svc_getargs(transp, xdr_argument, (caddr_t) & argument)) {
371                 svcerr_decode(transp);
372                 return;
373         }
374         result = (*local) ((char *)&argument, rqstp);
375         if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
376                 svcerr_systemerr(transp);
377         }
378         if (!svc_freeargs(transp, xdr_argument, (caddr_t) & argument)) {
379                 errstr(_("unable to free arguments\n"));
380                 exit(1);
381         }
382         return;
383 }
384
385 static void
386 unregister (int sig)
387 {
388         pmap_unset(RQUOTAPROG, RQUOTAVERS);
389         pmap_unset(RQUOTAPROG, EXT_RQUOTAVERS);
390         exit(0);
391 }
392
393 /* Parse NFSD export table and find a filesystem pseudoroot if it is there */
394 static void get_pseudoroot(void)
395 {
396         FILE *f;
397         char exp_line[1024];
398         char *c;
399
400         strcpy(nfs_pseudoroot, "/");
401         if (!(f = fopen(xtab_path, "r"))) {
402                 errstr(_("Warning: Cannot open export table %s: %s\nUsing '/' as a pseudofilesystem root.\n"), xtab_path, strerror(errno));
403                 return;
404         }
405         while (fgets(exp_line, sizeof(exp_line), f)) {
406                 if (exp_line[0] == '#' || exp_line[0] == '\n')  /* Comment, empty line? */
407                         continue;
408                 c = strchr(exp_line, '\t');
409                 if (!c) /* Huh, line we don't understand... */
410                         continue;
411                 *c = 0;
412                 /* Find the beginning of export options */
413                 c = strchr(c+1, '(');
414                 if (!c)
415                         continue;
416                 c = strstr(c, "fsid=0");
417                 if (c) {
418                         sstrncpy(nfs_pseudoroot, exp_line, PATH_MAX);
419                         sstrncat(nfs_pseudoroot, "/", PATH_MAX);
420                         break;
421                 }
422         }
423         fclose(f);
424 }
425
426 int main(int argc, char **argv)
427 {
428         register SVCXPRT *transp;
429         struct sigaction sa;
430         int sock;
431
432         gettexton();
433         progname = basename(argv[0]);
434         parse_options(argc, argv);
435
436         init_kernel_interface();
437         get_pseudoroot();
438         pmap_unset(RQUOTAPROG, RQUOTAVERS);
439         pmap_unset(RQUOTAPROG, EXT_RQUOTAVERS);
440
441         sa.sa_handler = SIG_IGN;
442         sa.sa_flags = 0;
443         sigemptyset(&sa.sa_mask);
444         sigaction(SIGCHLD, &sa, NULL);
445
446         sa.sa_handler = unregister;
447         sigaction(SIGHUP, &sa, NULL);
448         sigaction(SIGINT, &sa, NULL);
449         sigaction(SIGTERM, &sa, NULL);
450
451         sock = svcudp_socket(RQUOTAPROG, port, 1);
452         transp = svcudp_create(sock == -1 ? RPC_ANYSOCK : sock);
453         if (transp == NULL) {
454                 errstr(_("cannot create udp service.\n"));
455                 exit(1);
456         }
457         if (!svc_register(transp, RQUOTAPROG, RQUOTAVERS, rquotaprog_1, IPPROTO_UDP)) {
458                 errstr(_("unable to register (RQUOTAPROG, RQUOTAVERS, UDP).\n"));
459                 exit(1);
460         }
461         if (!svc_register(transp, RQUOTAPROG, EXT_RQUOTAVERS, rquotaprog_2, IPPROTO_UDP)) {
462                 errstr(_("unable to register (RQUOTAPROG, EXT_RQUOTAVERS, UDP).\n"));
463                 exit(1);
464         }
465
466         sock = svctcp_socket(RQUOTAPROG, port, 1);
467         transp = svctcp_create(sock == -1 ? RPC_ANYSOCK : sock, 0, 0);
468         if (transp == NULL) {
469                 errstr(_("cannot create TCP service.\n"));
470                 exit(1);
471         }
472         if (!svc_register(transp, RQUOTAPROG, RQUOTAVERS, rquotaprog_1, IPPROTO_TCP)) {
473                 errstr(_("unable to register (RQUOTAPROG, RQUOTAVERS, TCP).\n"));
474                 exit(1);
475         }
476         if (!svc_register(transp, RQUOTAPROG, EXT_RQUOTAVERS, rquotaprog_2, IPPROTO_TCP)) {
477                 errstr(_("unable to register (RQUOTAPROG, EXT_RQUOTAVERS, TCP).\n"));
478                 exit(1);
479         }
480
481         if (!(flags & FL_NODAEMON)) {
482                 use_syslog();
483                 daemon(0, 0);
484         }
485         svc_run();
486         errstr(_("svc_run returned\n"));
487         exit(1);
488         /* NOTREACHED */
489 }