Correct PPTP server firewall rules chain.
[tomato/davidwu.git] / release / src / router / nfs-utils / utils / statd / statd.c
blob6da2ab283d145284d2f919e7c3ec3faf35933463
1 /*
2 * Copyright (C) 1995, 1997-1999 Jeffrey A. Uphoff
3 * Modified by Olaf Kirch, Oct. 1996.
4 * Modified by H.J. Lu, 1998.
5 * Modified by L. Hohberger of Mission Critical Linux, 2000.
7 * NSM for Linux.
8 */
10 #ifdef HAVE_CONFIG_H
11 #include <config.h>
12 #endif
14 #include <sys/stat.h>
15 #include <limits.h>
16 #include <signal.h>
17 #include <unistd.h>
18 #include <fcntl.h>
19 #include <errno.h>
20 #include <string.h>
21 #include <getopt.h>
22 #include <rpc/rpc.h>
23 #include <rpc/pmap_clnt.h>
24 #include <rpcmisc.h>
25 #include <sys/resource.h>
26 #include <sys/wait.h>
27 #include <grp.h>
28 #include "statd.h"
29 #include "version.h"
30 #include "nfslib.h"
32 /* Socket operations */
33 #include <sys/types.h>
34 #include <sys/socket.h>
36 /* Added to enable specification of state directory path at run-time
37 * j_carlos_gomez@yahoo.com
40 char * DIR_BASE = DEFAULT_DIR_BASE;
42 char * SM_DIR = DEFAULT_SM_DIR;
43 char * SM_BAK_DIR = DEFAULT_SM_BAK_DIR;
44 char * SM_STAT_PATH = DEFAULT_SM_STAT_PATH;
46 /* ----- end of state directory path stuff ------- */
48 int run_mode = 0; /* foreground logging mode */
50 /* LH - I had these local to main, but it seemed silly to have
51 * two copies of each - one in main(), one static in log.c...
52 * It also eliminates the 256-char static in log.c */
53 char *name_p = NULL;
54 const char *version_p = NULL;
56 /* PRC: a high-availability callout program can be specified with -H
57 * When this is done, the program will receive callouts whenever clients
58 * are added or deleted to the notify list */
59 char *ha_callout_prog = NULL;
61 static struct option longopts[] =
63 { "foreground", 0, 0, 'F' },
64 { "no-syslog", 0, 0, 'd' },
65 { "help", 0, 0, 'h' },
66 { "version", 0, 0, 'v' },
67 { "outgoing-port", 1, 0, 'o' },
68 { "port", 1, 0, 'p' },
69 { "name", 1, 0, 'n' },
70 { "state-directory-path", 1, 0, 'P' },
71 { "notify-mode", 0, 0, 'N' },
72 { "ha-callout", 1, 0, 'H' },
73 { "no-notify", 0, 0, 'L' },
74 { NULL, 0, 0, 0 }
77 extern void sm_prog_1 (struct svc_req *, register SVCXPRT *);
78 static void load_state_number(void);
80 #ifdef SIMULATIONS
81 extern void simulator (int, char **);
82 #endif
85 #ifdef HAVE_TCP_WRAPPER
86 #include "tcpwrapper.h"
88 static void
89 sm_prog_1_wrapper (struct svc_req *rqstp, register SVCXPRT *transp)
91 struct sockaddr_in *sin = nfs_getrpccaller_in(transp);
93 /* remote host authorization check */
94 if (sin->sin_family == AF_INET &&
95 !check_default("statd", sin, rqstp->rq_proc, SM_PROG)) {
96 svcerr_auth (transp, AUTH_FAILED);
97 return;
100 sm_prog_1 (rqstp, transp);
103 #define sm_prog_1 sm_prog_1_wrapper
104 #endif
107 * Signal handler.
109 static void
110 killer (int sig)
112 note (N_FATAL, "Caught signal %d, un-registering and exiting.", sig);
113 pmap_unset (SM_PROG, SM_VERS);
115 exit (0);
118 static void
119 sigusr (int sig)
121 extern void my_svc_exit (void);
122 dprintf (N_DEBUG, "Caught signal %d, re-notifying (state %d).", sig,
123 MY_STATE);
124 my_svc_exit();
128 * Startup information.
130 static void log_modes(void)
132 char buf[128]; /* watch stack size... */
134 /* No flags = no message */
135 if (!run_mode) return;
137 memset(buf,0,128);
138 sprintf(buf,"Flags: ");
139 if (run_mode & MODE_NODAEMON)
140 strcat(buf,"No-Daemon ");
141 if (run_mode & MODE_LOG_STDERR)
142 strcat(buf,"Log-STDERR ");
144 note(N_WARNING,buf);
148 * Since we do more than standard statd stuff, we might need to
149 * help the occasional admin.
151 static void
152 usage(void)
154 fprintf(stderr,"usage: %s [options]\n", name_p);
155 fprintf(stderr," -h, -?, --help Print this help screen.\n");
156 fprintf(stderr," -F, --foreground Foreground (no-daemon mode)\n");
157 fprintf(stderr," -d, --no-syslog Verbose logging to stderr. Foreground mode only.\n");
158 fprintf(stderr," -p, --port Port to listen on\n");
159 fprintf(stderr," -o, --outgoing-port Port for outgoing connections\n");
160 fprintf(stderr," -V, -v, --version Display version information and exit.\n");
161 fprintf(stderr," -n, --name Specify a local hostname.\n");
162 fprintf(stderr," -P State directory path.\n");
163 fprintf(stderr," -N Run in notify only mode.\n");
164 fprintf(stderr," -L, --no-notify Do not perform any notification.\n");
165 fprintf(stderr," -H Specify a high-availability callout program.\n");
168 static const char *pidfile = "/var/run/rpc.statd.pid";
170 int pidfd = -1;
171 static void create_pidfile(void)
173 FILE *fp;
175 unlink(pidfile);
176 fp = fopen(pidfile, "w");
177 if (!fp)
178 die("Opening %s failed: %s\n",
179 pidfile, strerror(errno));
180 fprintf(fp, "%d\n", getpid());
181 pidfd = dup(fileno(fp));
182 if (fclose(fp) < 0)
183 note(N_WARNING, "Flushing pid file failed.\n");
186 static void truncate_pidfile(void)
188 if (pidfd >= 0)
189 ftruncate(pidfd, 0);
192 static void drop_privs(void)
194 struct stat st;
196 if (stat(SM_DIR, &st) == -1 &&
197 stat(DIR_BASE, &st) == -1) {
198 st.st_uid = 0;
199 st.st_gid = 0;
202 if (st.st_uid == 0) {
203 note(N_WARNING, "statd running as root. chown %s to choose different user\n",
204 SM_DIR);
205 return;
207 /* better chown the pid file before dropping, as if it
208 * if over nfs we might loose access
210 if (pidfd >= 0)
211 fchown(pidfd, st.st_uid, st.st_gid);
213 setgroups(0, NULL);
214 if (setgid(st.st_gid) == -1
215 || setuid(st.st_uid) == -1) {
216 note(N_ERROR, "Fail to drop privileges");
217 exit(1);
221 static void run_sm_notify(int outport)
223 char op[20];
224 char *av[6];
225 int ac = 0;
227 av[ac++] = "/usr/sbin/sm-notify";
228 if (run_mode & MODE_NODAEMON)
229 av[ac++] = "-d";
230 if (outport) {
231 sprintf(op, "-p%d", outport);
232 av[ac++] = op;
234 if (run_mode & STATIC_HOSTNAME) {
235 av[ac++] = "-v";
236 av[ac++] = MY_NAME;
238 av[ac] = NULL;
239 execv(av[0], av);
240 fprintf(stderr, "%s: failed to run %s\n", name_p, av[0]);
241 exit(2);
245 * Entry routine/main loop.
247 int main (int argc, char **argv)
249 extern char *optarg;
250 int pid;
251 int arg;
252 int port = 0, out_port = 0;
253 struct rlimit rlim;
255 int pipefds[2] = { -1, -1};
256 char status;
258 /* Default: daemon mode, no other options */
259 run_mode = 0;
261 /* Set the basename */
262 if ((name_p = strrchr(argv[0],'/')) != NULL) {
263 name_p ++;
264 } else {
265 name_p = argv[0];
268 /* Get the version */
269 if ((version_p = strrchr(VERSION,' ')) != NULL) {
270 version_p++;
271 } else {
272 version_p = VERSION;
275 /* Set hostname */
276 MY_NAME = NULL;
278 /* Process command line switches */
279 while ((arg = getopt_long(argc, argv, "h?vVFNH:dn:p:o:P:L", longopts, NULL)) != EOF) {
280 switch (arg) {
281 case 'V': /* Version */
282 case 'v':
283 printf("%s version %s\n",name_p,version_p);
284 exit(0);
285 case 'F': /* Foreground/nodaemon mode */
286 run_mode |= MODE_NODAEMON;
287 break;
288 case 'N':
289 run_mode |= MODE_NOTIFY_ONLY;
290 break;
291 case 'L': /* Listen only */
292 run_mode |= MODE_NO_NOTIFY;
293 break;
294 case 'd': /* No daemon only - log to stderr */
295 run_mode |= MODE_LOG_STDERR;
296 break;
297 case 'o':
298 out_port = atoi(optarg);
299 if (out_port < 1 || out_port > 65535) {
300 fprintf(stderr, "%s: bad port number: %s\n",
301 argv[0], optarg);
302 usage();
303 exit(1);
305 break;
306 case 'p':
307 port = atoi(optarg);
308 if (port < 1 || port > 65535) {
309 fprintf(stderr, "%s: bad port number: %s\n",
310 argv[0], optarg);
311 usage();
312 exit(1);
314 break;
315 case 'n': /* Specify local hostname */
316 run_mode |= STATIC_HOSTNAME;
317 MY_NAME = xstrdup(optarg);
318 break;
319 case 'P':
321 if ((DIR_BASE = xstrdup(optarg)) == NULL) {
322 fprintf(stderr, "%s: xstrdup(%s) failed!\n",
323 argv[0], optarg);
324 exit(1);
327 SM_DIR = xmalloc(strlen(DIR_BASE) + 1 + sizeof("sm"));
328 SM_BAK_DIR = xmalloc(strlen(DIR_BASE) + 1 + sizeof("sm.bak"));
329 SM_STAT_PATH = xmalloc(strlen(DIR_BASE) + 1 + sizeof("state"));
331 if ((SM_DIR == NULL)
332 || (SM_BAK_DIR == NULL)
333 || (SM_STAT_PATH == NULL)) {
335 fprintf(stderr, "%s: xmalloc() failed!\n",
336 argv[0]);
337 exit(1);
339 if (DIR_BASE[strlen(DIR_BASE)-1] == '/') {
340 sprintf(SM_DIR, "%ssm", DIR_BASE );
341 sprintf(SM_BAK_DIR, "%ssm.bak", DIR_BASE );
342 sprintf(SM_STAT_PATH, "%sstate", DIR_BASE );
343 } else {
344 sprintf(SM_DIR, "%s/sm", DIR_BASE );
345 sprintf(SM_BAK_DIR, "%s/sm.bak", DIR_BASE );
346 sprintf(SM_STAT_PATH, "%s/state", DIR_BASE );
348 break;
349 case 'H': /* PRC: specify the ha-callout program */
350 if ((ha_callout_prog = xstrdup(optarg)) == NULL) {
351 fprintf(stderr, "%s: xstrdup(%s) failed!\n",
352 argv[0], optarg);
353 exit(1);
355 break;
356 case '?': /* heeeeeelllllllpppp? heh */
357 case 'h':
358 usage();
359 exit (0);
360 default: /* oh dear ... heh */
361 usage();
362 exit(-1);
366 if (port == out_port && port != 0) {
367 fprintf(stderr, "Listening and outgoing ports cannot be the same!\n");
368 exit(-1);
371 if (run_mode & MODE_NOTIFY_ONLY) {
372 fprintf(stderr, "%s: -N deprecated, consider using /usr/sbin/sm-notify directly\n",
373 name_p);
374 run_sm_notify(out_port);
378 if (!(run_mode & MODE_NODAEMON)) {
379 run_mode &= ~MODE_LOG_STDERR; /* Never log to console in
380 daemon mode. */
383 if (getrlimit (RLIMIT_NOFILE, &rlim) != 0)
384 fprintf(stderr, "%s: getrlimit (RLIMIT_NOFILE) failed: %s\n",
385 argv [0], strerror(errno));
386 else {
387 /* glibc sunrpc code dies if getdtablesize > FD_SETSIZE */
388 if (rlim.rlim_cur > FD_SETSIZE) {
389 rlim.rlim_cur = FD_SETSIZE;
391 if (setrlimit (RLIMIT_NOFILE, &rlim) != 0) {
392 fprintf(stderr, "%s: setrlimit (RLIMIT_NOFILE) failed: %s\n",
393 argv [0], strerror(errno));
398 #ifdef SIMULATIONS
399 if (argc > 1)
400 /* LH - I _really_ need to update simulator... */
401 simulator (--argc, ++argv); /* simulator() does exit() */
402 #endif
404 if (!(run_mode & MODE_NODAEMON)) {
405 int tempfd;
407 if (pipe(pipefds)<0) {
408 perror("statd: unable to create pipe");
409 exit(1);
411 if ((pid = fork ()) < 0) {
412 perror ("statd: Could not fork");
413 exit (1);
414 } else if (pid != 0) {
415 /* Parent.
416 * Wait for status from child.
418 close(pipefds[1]);
419 if (read(pipefds[0], &status, 1) != 1)
420 exit(1);
421 exit (0);
423 /* Child. */
424 close(pipefds[0]);
425 setsid ();
426 if (chdir (DIR_BASE) == -1) {
427 perror("statd: Could not chdir");
428 exit(1);
431 while (pipefds[1] <= 2) {
432 pipefds[1] = dup(pipefds[1]);
433 if (pipefds[1]<0) {
434 perror("statd: dup");
435 exit(1);
438 tempfd = open("/dev/null", O_RDWR);
439 dup2(tempfd, 0);
440 dup2(tempfd, 1);
441 dup2(tempfd, 2);
442 dup2(pipefds[1], 3);
443 pipefds[1] = 3;
444 closeall(4);
447 /* Child. */
449 log_init (/*name_p,version_p*/);
451 log_modes();
453 signal (SIGHUP, killer);
454 signal (SIGINT, killer);
455 signal (SIGTERM, killer);
456 /* PRC: trap SIGUSR1 to re-read notify list from disk */
457 signal(SIGUSR1, sigusr);
458 /* WARNING: the following works on Linux and SysV, but not BSD! */
459 signal(SIGCHLD, SIG_IGN);
461 * Ignore SIGPIPE to avoid statd dying when peers close their
462 * TCP connection while we're trying to reply to them.
464 signal(SIGPIPE, SIG_IGN);
466 create_pidfile();
467 atexit(truncate_pidfile);
469 if (! (run_mode & MODE_NO_NOTIFY))
470 switch (pid = fork()) {
471 case 0:
472 run_sm_notify(out_port);
473 break;
474 case -1:
475 break;
476 default:
477 waitpid(pid, NULL, 0);
480 /* Make sure we have a privilege port for calling into the kernel */
481 if (statd_get_socket() < 0)
482 exit(1);
484 /* If sm-notify didn't take all the state files, load
485 * state information into our notify-list so we can
486 * pass on any SM_NOTIFY that arrives
488 load_state();
489 load_state_number();
490 pmap_unset (SM_PROG, SM_VERS);
492 /* this registers both UDP and TCP services */
493 rpc_init("statd", SM_PROG, SM_VERS, sm_prog_1, port);
495 /* If we got this far, we have successfully started, so notify parent */
496 if (pipefds[1] > 0) {
497 status = 0;
498 write(pipefds[1], &status, 1);
499 close(pipefds[1]);
500 pipefds[1] = -1;
503 drop_privs();
505 for (;;) {
507 * Handle incoming requests: SM_NOTIFY socket requests, as
508 * well as callbacks from lockd.
510 my_svc_run(); /* I rolled my own, Olaf made it better... */
512 /* Only get here when simulating a crash so we should probably
513 * start sm-notify running again. As we have already dropped
514 * privileges, this might not work, but I don't think
515 * responding to SM_SIMU_CRASH is an important use cases to
516 * get perfect.
518 if (! (run_mode & MODE_NO_NOTIFY))
519 switch (pid = fork()) {
520 case 0:
521 run_sm_notify(out_port);
522 break;
523 case -1:
524 break;
525 default:
526 waitpid(pid, NULL, 0);
530 return 0;
533 static void
534 load_state_number(void)
536 int fd;
538 if ((fd = open(SM_STAT_PATH, O_RDONLY)) == -1)
539 return;
541 read(fd, &MY_STATE, sizeof(MY_STATE));
542 close(fd);
543 fd = open("/proc/sys/fs/nfs/nsm_local_state",O_WRONLY);
544 if (fd >= 0) {
545 char buf[20];
546 snprintf(buf, sizeof(buf), "%d", MY_STATE);
547 write(fd, buf, strlen(buf));
548 close(fd);