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.
9 * Rquota service handlers.
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>
15 * Version: $Id: rquota_svc.c,v 1.22 2010/01/05 16:04:57 jkar8572 Exp $
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License as
19 * published by the Free Software Foundation; either version 2 of
20 * the License, or (at your option) any later version.
26 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29 #include <rpc/pmap_clnt.h> /* for pmap_unset */
31 #include <stdlib.h> /* getenv, exit */
32 #include <string.h> /* strcmp */
42 int deny_severity, allow_severity; /* Needed by some versions of libwrap */
46 #define SIG_PF void(*)(int)
49 extern int svctcp_socket (u_long __number, int __port, int __reuse);
50 extern int svcudp_socket (u_long __number, int __port, int __reuse);
60 * Global authentication credentials.
62 struct authunix_parms *unix_cred;
64 #define FL_SETQUOTA 1 /* Enable setquota rpc */
65 #define FL_NODAEMON 2 /* Disable daemon() call */
66 #define FL_AUTOFS 4 /* Don't ignore autofs mountpoints */
68 int flags; /* Options specified on command line */
69 static int port; /* Port to use (0 for default one) */
70 static char xtab_path[PATH_MAX]; /* Path to NFSD export table */
71 char nfs_pseudoroot[PATH_MAX]; /* Root of the virtual NFS filesystem ('/' for NFSv3) */
73 static struct option options[]= {
74 { "version", 0, NULL, 'V' },
75 { "help", 0, NULL, 'h' },
76 { "foreground", 0 , NULL, 'F' },
78 { "no-setquota", 0 , NULL, 's' },
79 { "setquota", 0, NULL, 'S' },
81 { "autofs", 0, NULL, 'I'},
82 { "port", 1, NULL, 'p' },
83 { "xtab", 1, NULL, 'x' },
87 static void show_help(void)
90 errstr(_("Usage: %s [options]\nOptions are:\n\
91 -h --help shows this text\n\
92 -V --version shows version information\n\
93 -F --foreground starts the quota service in foreground\n\
94 -I --autofs do not ignore mountpoints mounted by automounter\n\
95 -p --port <port> listen on given port\n\
96 -s --no-setquota disables remote calls to setquota (default)\n\
97 -S --setquota enables remote calls to setquota\n\
98 -x --xtab <path> set an alternative file with NFSD export table\n"), progname);
101 errstr(_("Usage: %s [options]\nOptions are:\n\
102 -h --help shows this text\n\
103 -V --version shows version information\n\
104 -F --foreground starts the quota service in foreground\n\
105 -I --autofs do not ignore mountpoints mounted by automounter\n\
106 -p --port <port> listen on given port\n\
107 -x --xtab <path> set an alternative file with NFSD export table\n"), progname);
111 static void parse_options(int argc, char **argv)
113 char ostr[128]="", *endptr;
117 sstrncpy(xtab_path, NFSD_XTAB_PATH, PATH_MAX);
118 for(i=0; options[i].name; i++) {
119 ostr[j++] = options[i].val;
120 if (options[i].has_arg)
123 while ((opt=getopt_long(argc, argv, ostr, options, NULL))>=0) {
132 flags |= FL_NODAEMON;
136 flags &= ~FL_SETQUOTA;
139 flags |= FL_SETQUOTA;
146 port = strtol(optarg, &endptr, 0);
147 if (*endptr || port <= 0) {
148 errstr(_("Illegal port number: %s\n"), optarg);
154 if (access(optarg, R_OK) < 0) {
155 errstr(_("Cannot access the specified xtab file %s: %s\n"), optarg, strerror(errno));
159 sstrncpy(xtab_path, optarg, PATH_MAX);
162 errstr(_("Unknown option '%c'.\n"), opt);
171 * good_client checks if an quota client should be allowed to
172 * execute the requested rpc call.
174 int good_client(struct sockaddr_in *addr, ulong rq_proc)
177 struct request_info req;
179 char *remote = inet_ntoa(addr->sin_addr);
181 if (rq_proc==RQUOTAPROC_SETQUOTA ||
182 rq_proc==RQUOTAPROC_SETACTIVEQUOTA) {
183 /* If setquota is disabled, fail always */
184 if (!(flags & FL_SETQUOTA)) {
185 errstr(_("host %s attempted to call setquota when disabled\n"),
190 /* Require that SETQUOTA calls originate from port < 1024 */
191 if (ntohs(addr->sin_port)>=1024) {
192 errstr(_("host %s attempted to call setquota from port >= 1024\n"),
200 /* NOTE: we could use different servicename for setquota calls to
201 * allow only some hosts to call setquota. */
203 request_init(&req, RQ_DAEMON, "rquotad", RQ_CLIENT_SIN, addr, 0);
205 if (hosts_access(&req))
207 errstr(_("Denied access to host %s\n"), remote);
210 /* If no access checking is available, OK always */
215 static void rquotaprog_1(struct svc_req *rqstp, register SVCXPRT * transp)
218 getquota_args rquotaproc_getquota_1_arg;
219 setquota_args rquotaproc_setquota_1_arg;
220 getquota_args rquotaproc_getactivequota_1_arg;
221 setquota_args rquotaproc_setactivequota_1_arg;
224 xdrproc_t xdr_argument, xdr_result;
225 char *(*local) (char *, struct svc_req *);
230 if (!good_client(svc_getcaller(rqstp->rq_xprt),rqstp->rq_proc)) {
231 svcerr_auth (transp, AUTH_FAILED);
236 * Don't bother authentication for NULLPROC.
238 if (rqstp->rq_proc == NULLPROC) {
239 (void)svc_sendreply(transp, (xdrproc_t) xdr_void, (char *)NULL);
244 * Get authentication.
246 switch (rqstp->rq_cred.oa_flavor) {
248 unix_cred = (struct authunix_parms *)rqstp->rq_clntcred;
252 svcerr_weakauth(transp);
256 switch (rqstp->rq_proc) {
257 case RQUOTAPROC_GETQUOTA:
258 xdr_argument = (xdrproc_t) xdr_getquota_args;
259 xdr_result = (xdrproc_t) xdr_getquota_rslt;
260 local = (char *(*)(char *, struct svc_req *))rquotaproc_getquota_1_svc;
263 case RQUOTAPROC_SETQUOTA:
264 xdr_argument = (xdrproc_t) xdr_setquota_args;
265 xdr_result = (xdrproc_t) xdr_setquota_rslt;
266 local = (char *(*)(char *, struct svc_req *))rquotaproc_setquota_1_svc;
269 case RQUOTAPROC_GETACTIVEQUOTA:
270 xdr_argument = (xdrproc_t) xdr_getquota_args;
271 xdr_result = (xdrproc_t) xdr_getquota_rslt;
272 local = (char *(*)(char *, struct svc_req *))rquotaproc_getactivequota_1_svc;
275 case RQUOTAPROC_SETACTIVEQUOTA:
276 xdr_argument = (xdrproc_t) xdr_setquota_args;
277 xdr_result = (xdrproc_t) xdr_setquota_rslt;
278 local = (char *(*)(char *, struct svc_req *))rquotaproc_setactivequota_1_svc;
282 svcerr_noproc(transp);
285 memset(&argument, 0, sizeof(argument));
286 if (!svc_getargs(transp, xdr_argument, (caddr_t) & argument)) {
287 svcerr_decode(transp);
290 result = (*local) ((char *)&argument, rqstp);
291 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
292 svcerr_systemerr(transp);
294 if (!svc_freeargs(transp, xdr_argument, (caddr_t) & argument)) {
295 errstr(_("unable to free arguments\n"));
301 static void rquotaprog_2(struct svc_req *rqstp, register SVCXPRT * transp)
304 ext_getquota_args rquotaproc_getquota_2_arg;
305 ext_setquota_args rquotaproc_setquota_2_arg;
306 ext_getquota_args rquotaproc_getactivequota_2_arg;
307 ext_setquota_args rquotaproc_setactivequota_2_arg;
310 xdrproc_t xdr_argument, xdr_result;
311 char *(*local) (char *, struct svc_req *);
316 if (!good_client(svc_getcaller(rqstp->rq_xprt),rqstp->rq_proc)) {
317 svcerr_auth (transp, AUTH_FAILED);
322 * Don't bother authentication for NULLPROC.
324 if (rqstp->rq_proc == NULLPROC) {
325 (void)svc_sendreply(transp, (xdrproc_t) xdr_void, (char *)NULL);
330 * Get authentication.
332 switch (rqstp->rq_cred.oa_flavor) {
334 unix_cred = (struct authunix_parms *)rqstp->rq_clntcred;
338 svcerr_weakauth(transp);
342 switch (rqstp->rq_proc) {
343 case RQUOTAPROC_GETQUOTA:
344 xdr_argument = (xdrproc_t) xdr_ext_getquota_args;
345 xdr_result = (xdrproc_t) xdr_getquota_rslt;
346 local = (char *(*)(char *, struct svc_req *))rquotaproc_getquota_2_svc;
349 case RQUOTAPROC_SETQUOTA:
350 xdr_argument = (xdrproc_t) xdr_ext_setquota_args;
351 xdr_result = (xdrproc_t) xdr_setquota_rslt;
352 local = (char *(*)(char *, struct svc_req *))rquotaproc_setquota_2_svc;
355 case RQUOTAPROC_GETACTIVEQUOTA:
356 xdr_argument = (xdrproc_t) xdr_ext_getquota_args;
357 xdr_result = (xdrproc_t) xdr_getquota_rslt;
358 local = (char *(*)(char *, struct svc_req *))rquotaproc_getactivequota_2_svc;
361 case RQUOTAPROC_SETACTIVEQUOTA:
362 xdr_argument = (xdrproc_t) xdr_ext_setquota_args;
363 xdr_result = (xdrproc_t) xdr_setquota_rslt;
364 local = (char *(*)(char *, struct svc_req *))rquotaproc_setactivequota_2_svc;
368 svcerr_noproc(transp);
371 memset(&argument, 0, sizeof(argument));
372 if (!svc_getargs(transp, xdr_argument, (caddr_t) & argument)) {
373 svcerr_decode(transp);
376 result = (*local) ((char *)&argument, rqstp);
377 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
378 svcerr_systemerr(transp);
380 if (!svc_freeargs(transp, xdr_argument, (caddr_t) & argument)) {
381 errstr(_("unable to free arguments\n"));
390 pmap_unset(RQUOTAPROG, RQUOTAVERS);
391 pmap_unset(RQUOTAPROG, EXT_RQUOTAVERS);
395 /* Parse NFSD export table and find a filesystem pseudoroot if it is there */
396 static void get_pseudoroot(void)
402 strcpy(nfs_pseudoroot, "/");
403 if (!(f = fopen(xtab_path, "r"))) {
404 errstr(_("Warning: Cannot open export table %s: %s\nUsing '/' as a pseudofilesystem root.\n"), xtab_path, strerror(errno));
407 while (fgets(exp_line, sizeof(exp_line), f)) {
408 if (exp_line[0] == '#' || exp_line[0] == '\n') /* Comment, empty line? */
410 c = strchr(exp_line, '\t');
411 if (!c) /* Huh, line we don't understand... */
414 /* Find the beginning of export options */
415 c = strchr(c+1, '(');
418 c = strstr(c, "fsid=0");
420 sstrncpy(nfs_pseudoroot, exp_line, PATH_MAX);
421 sstrncat(nfs_pseudoroot, "/", PATH_MAX);
428 int main(int argc, char **argv)
430 register SVCXPRT *transp;
435 progname = basename(argv[0]);
436 parse_options(argc, argv);
438 init_kernel_interface();
440 pmap_unset(RQUOTAPROG, RQUOTAVERS);
441 pmap_unset(RQUOTAPROG, EXT_RQUOTAVERS);
443 sa.sa_handler = SIG_IGN;
445 sigemptyset(&sa.sa_mask);
446 sigaction(SIGCHLD, &sa, NULL);
448 sa.sa_handler = unregister;
449 sigaction(SIGHUP, &sa, NULL);
450 sigaction(SIGINT, &sa, NULL);
451 sigaction(SIGTERM, &sa, NULL);
453 sock = svcudp_socket(RQUOTAPROG, port, 1);
454 transp = svcudp_create(sock == -1 ? RPC_ANYSOCK : sock);
455 if (transp == NULL) {
456 errstr(_("cannot create udp service.\n"));
459 if (!svc_register(transp, RQUOTAPROG, RQUOTAVERS, rquotaprog_1, IPPROTO_UDP)) {
460 errstr(_("unable to register (RQUOTAPROG, RQUOTAVERS, udp).\n"));
463 if (!svc_register(transp, RQUOTAPROG, EXT_RQUOTAVERS, rquotaprog_2, IPPROTO_UDP)) {
464 errstr(_("unable to register (RQUOTAPROG, EXT_RQUOTAVERS, udp).\n"));
468 sock = svctcp_socket(RQUOTAPROG, port, 1);
469 transp = svctcp_create(sock == -1 ? RPC_ANYSOCK : sock, 0, 0);
470 if (transp == NULL) {
471 errstr(_("cannot create tcp service.\n"));
474 if (!svc_register(transp, RQUOTAPROG, RQUOTAVERS, rquotaprog_1, IPPROTO_TCP)) {
475 errstr(_("unable to register (RQUOTAPROG, RQUOTAVERS, tcp).\n"));
478 if (!svc_register(transp, RQUOTAPROG, EXT_RQUOTAVERS, rquotaprog_2, IPPROTO_TCP)) {
479 errstr(_("unable to register (RQUOTAPROG, EXT_RQUOTAVERS, tcp).\n"));
483 if (!(flags & FL_NODAEMON)) {
488 errstr(_("svc_run returned\n"));