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 * 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.
24 #include <sys/socket.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27 #include <rpc/pmap_clnt.h> /* for pmap_unset */
29 #include <stdlib.h> /* getenv, exit */
30 #include <string.h> /* strcmp */
40 int deny_severity, allow_severity; /* Needed by some versions of libwrap */
44 #define SIG_PF void(*)(int)
47 extern int svctcp_socket (u_long __number, int __port, int __reuse);
48 extern int svcudp_socket (u_long __number, int __port, int __reuse);
58 * Global authentication credentials.
60 struct authunix_parms *unix_cred;
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 */
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) */
71 static struct option options[]= {
72 { "version", 0, NULL, 'V' },
73 { "help", 0, NULL, 'h' },
74 { "foreground", 0 , NULL, 'F' },
76 { "no-setquota", 0 , NULL, 's' },
77 { "setquota", 0, NULL, 'S' },
79 { "autofs", 0, NULL, 'I'},
80 { "port", 1, NULL, 'p' },
81 { "xtab", 1, NULL, 'x' },
85 static void show_help(void)
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);
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);
109 static void parse_options(int argc, char **argv)
111 char ostr[128]="", *endptr;
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)
121 while ((opt=getopt_long(argc, argv, ostr, options, NULL))>=0) {
130 flags |= FL_NODAEMON;
134 flags &= ~FL_SETQUOTA;
137 flags |= FL_SETQUOTA;
144 port = strtol(optarg, &endptr, 0);
145 if (*endptr || port <= 0) {
146 errstr(_("Illegal port number: %s\n"), optarg);
152 if (access(optarg, R_OK) < 0) {
153 errstr(_("Cannot access the specified xtab file %s: %s\n"), optarg, strerror(errno));
157 sstrncpy(xtab_path, optarg, PATH_MAX);
160 errstr(_("Unknown option '%c'.\n"), opt);
169 * good_client checks if an quota client should be allowed to
170 * execute the requested rpc call.
172 static int good_client(struct sockaddr_in *addr, ulong rq_proc)
175 struct request_info req;
177 char *remote = inet_ntoa(addr->sin_addr);
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"),
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"),
198 /* NOTE: we could use different servicename for setquota calls to
199 * allow only some hosts to call setquota. */
201 request_init(&req, RQ_DAEMON, "rquotad", RQ_CLIENT_SIN, addr, 0);
203 if (hosts_access(&req))
205 errstr(_("Denied access to host %s\n"), remote);
208 /* If no access checking is available, OK always */
213 static void rquotaprog_1(struct svc_req *rqstp, register SVCXPRT * transp)
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;
222 xdrproc_t xdr_argument, xdr_result;
223 char *(*local) (char *, struct svc_req *);
228 if (!good_client(svc_getcaller(rqstp->rq_xprt),rqstp->rq_proc)) {
229 svcerr_auth (transp, AUTH_FAILED);
234 * Don't bother authentication for NULLPROC.
236 if (rqstp->rq_proc == NULLPROC) {
237 (void)svc_sendreply(transp, (xdrproc_t) xdr_void, (char *)NULL);
242 * Get authentication.
244 switch (rqstp->rq_cred.oa_flavor) {
246 unix_cred = (struct authunix_parms *)rqstp->rq_clntcred;
250 svcerr_weakauth(transp);
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;
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;
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;
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;
280 svcerr_noproc(transp);
283 memset(&argument, 0, sizeof(argument));
284 if (!svc_getargs(transp, xdr_argument, (caddr_t) & argument)) {
285 svcerr_decode(transp);
288 result = (*local) ((char *)&argument, rqstp);
289 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
290 svcerr_systemerr(transp);
292 if (!svc_freeargs(transp, xdr_argument, (caddr_t) & argument)) {
293 errstr(_("unable to free arguments\n"));
299 static void rquotaprog_2(struct svc_req *rqstp, register SVCXPRT * transp)
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;
308 xdrproc_t xdr_argument, xdr_result;
309 char *(*local) (char *, struct svc_req *);
314 if (!good_client(svc_getcaller(rqstp->rq_xprt),rqstp->rq_proc)) {
315 svcerr_auth (transp, AUTH_FAILED);
320 * Don't bother authentication for NULLPROC.
322 if (rqstp->rq_proc == NULLPROC) {
323 (void)svc_sendreply(transp, (xdrproc_t) xdr_void, (char *)NULL);
328 * Get authentication.
330 switch (rqstp->rq_cred.oa_flavor) {
332 unix_cred = (struct authunix_parms *)rqstp->rq_clntcred;
336 svcerr_weakauth(transp);
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;
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;
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;
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;
366 svcerr_noproc(transp);
369 memset(&argument, 0, sizeof(argument));
370 if (!svc_getargs(transp, xdr_argument, (caddr_t) & argument)) {
371 svcerr_decode(transp);
374 result = (*local) ((char *)&argument, rqstp);
375 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
376 svcerr_systemerr(transp);
378 if (!svc_freeargs(transp, xdr_argument, (caddr_t) & argument)) {
379 errstr(_("unable to free arguments\n"));
388 pmap_unset(RQUOTAPROG, RQUOTAVERS);
389 pmap_unset(RQUOTAPROG, EXT_RQUOTAVERS);
393 /* Parse NFSD export table and find a filesystem pseudoroot if it is there */
394 static void get_pseudoroot(void)
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));
405 while (fgets(exp_line, sizeof(exp_line), f)) {
406 if (exp_line[0] == '#' || exp_line[0] == '\n') /* Comment, empty line? */
408 c = strchr(exp_line, '\t');
409 if (!c) /* Huh, line we don't understand... */
412 /* Find the beginning of export options */
413 c = strchr(c+1, '(');
416 c = strstr(c, "fsid=0");
418 sstrncpy(nfs_pseudoroot, exp_line, PATH_MAX);
419 sstrncat(nfs_pseudoroot, "/", PATH_MAX);
426 int main(int argc, char **argv)
428 register SVCXPRT *transp;
433 progname = basename(argv[0]);
434 parse_options(argc, argv);
436 init_kernel_interface();
438 pmap_unset(RQUOTAPROG, RQUOTAVERS);
439 pmap_unset(RQUOTAPROG, EXT_RQUOTAVERS);
441 sa.sa_handler = SIG_IGN;
443 sigemptyset(&sa.sa_mask);
444 sigaction(SIGCHLD, &sa, NULL);
446 sa.sa_handler = unregister;
447 sigaction(SIGHUP, &sa, NULL);
448 sigaction(SIGINT, &sa, NULL);
449 sigaction(SIGTERM, &sa, NULL);
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"));
457 if (!svc_register(transp, RQUOTAPROG, RQUOTAVERS, rquotaprog_1, IPPROTO_UDP)) {
458 errstr(_("unable to register (RQUOTAPROG, RQUOTAVERS, UDP).\n"));
461 if (!svc_register(transp, RQUOTAPROG, EXT_RQUOTAVERS, rquotaprog_2, IPPROTO_UDP)) {
462 errstr(_("unable to register (RQUOTAPROG, EXT_RQUOTAVERS, UDP).\n"));
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"));
472 if (!svc_register(transp, RQUOTAPROG, RQUOTAVERS, rquotaprog_1, IPPROTO_TCP)) {
473 errstr(_("unable to register (RQUOTAPROG, RQUOTAVERS, TCP).\n"));
476 if (!svc_register(transp, RQUOTAPROG, EXT_RQUOTAVERS, rquotaprog_2, IPPROTO_TCP)) {
477 errstr(_("unable to register (RQUOTAPROG, EXT_RQUOTAVERS, TCP).\n"));
481 if (!(flags & FL_NODAEMON)) {
486 errstr(_("svc_run returned\n"));