int main(int argc, char *argv[]) { struct netconfig *nconf; void *nc_handle; /* Net config handle */ struct rlimit rl; int maxrec = RPC_MAXDATASIZE; parseargs(argc, argv); update_bound_sa(); /* Check that another rpcbind isn't already running. */ if ((rpcbindlockfd = (open(RPCBINDDLOCK, O_RDONLY|O_CREAT, 0444))) == -1) err(1, "%s", RPCBINDDLOCK); if(flock(rpcbindlockfd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK) errx(1, "another rpcbind is already running. Aborting"); getrlimit(RLIMIT_NOFILE, &rl); if (rl.rlim_cur < 128) { if (rl.rlim_max <= 128) rl.rlim_cur = rl.rlim_max; else rl.rlim_cur = 128; setrlimit(RLIMIT_NOFILE, &rl); } openlog("rpcbind", LOG_CONS, LOG_DAEMON); if (geteuid()) { /* This command allowed only to root */ fprintf(stderr, "Sorry. You are not superuser\n"); exit(1); } nc_handle = setnetconfig(); /* open netconfig file */ if (nc_handle == NULL) { syslog(LOG_ERR, "could not read /etc/netconfig"); exit(1); } #ifdef PORTMAP udptrans = ""; tcptrans = ""; #endif nconf = getnetconfigent("local"); if (nconf == NULL) nconf = getnetconfigent("unix"); if (nconf == NULL) { syslog(LOG_ERR, "%s: can't find local transport\n", argv[0]); exit(1); } rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); init_transport(nconf); while ((nconf = getnetconfig(nc_handle))) { if (nconf->nc_flag & NC_VISIBLE) { if (ipv6_only == 1 && strcmp(nconf->nc_protofmly, "inet") == 0) { /* DO NOTHING */ } else init_transport(nconf); } } endnetconfig(nc_handle); /* catch the usual termination signals for graceful exit */ (void) signal(SIGCHLD, reap); (void) signal(SIGINT, terminate); (void) signal(SIGTERM, terminate); (void) signal(SIGQUIT, terminate); /* ignore others that could get sent */ (void) signal(SIGPIPE, SIG_IGN); (void) signal(SIGHUP, SIG_IGN); (void) signal(SIGUSR1, SIG_IGN); (void) signal(SIGUSR2, SIG_IGN); #ifdef WARMSTART if (warmstart) { read_warmstart(); } #endif if (debugging) { printf("rpcbind debugging enabled."); if (doabort) { printf(" Will abort on errors!\n"); } else { printf("\n"); } } else { if (daemon(0, 0)) err(1, "fork failed"); } if (runasdaemon) { struct passwd *p; if((p = getpwnam(RUN_AS)) == NULL) { syslog(LOG_ERR, "cannot get uid of daemon: %m"); exit(1); } if (setuid(p->pw_uid) == -1) { syslog(LOG_ERR, "setuid to daemon failed: %m"); exit(1); } } network_init(); my_svc_run(); syslog(LOG_ERR, "svc_run returned unexpectedly"); rpcbind_abort(); /* NOTREACHED */ return 0; }
/* * Entry routine/main loop. */ int main (int argc, char **argv) { extern char *optarg; int pid; int arg; int port = 0, out_port = 0; struct rlimit rlim; int pipefds[2] = { -1, -1}; char status; /* Default: daemon mode, no other options */ run_mode = 0; /* Set the basename */ if ((name_p = strrchr(argv[0],'/')) != NULL) { name_p ++; } else { name_p = argv[0]; } /* Get the version */ if ((version_p = strrchr(VERSION,' ')) != NULL) { version_p++; } else { version_p = VERSION; } /* Set hostname */ MY_NAME = NULL; /* Process command line switches */ while ((arg = getopt_long(argc, argv, "h?vVFNH:dn:p:o:P:L", longopts, NULL)) != EOF) { switch (arg) { case 'V': /* Version */ case 'v': printf("%s version %s\n",name_p,version_p); exit(0); case 'F': /* Foreground/nodaemon mode */ run_mode |= MODE_NODAEMON; break; case 'N': run_mode |= MODE_NOTIFY_ONLY; break; case 'L': /* Listen only */ run_mode |= MODE_NO_NOTIFY; break; case 'd': /* No daemon only - log to stderr */ run_mode |= MODE_LOG_STDERR; break; case 'o': out_port = atoi(optarg); if (out_port < 1 || out_port > 65535) { fprintf(stderr, "%s: bad port number: %s\n", argv[0], optarg); usage(); exit(1); } break; case 'p': port = atoi(optarg); if (port < 1 || port > 65535) { fprintf(stderr, "%s: bad port number: %s\n", argv[0], optarg); usage(); exit(1); } break; case 'n': /* Specify local hostname */ run_mode |= STATIC_HOSTNAME; MY_NAME = xstrdup(optarg); break; case 'P': if ((DIR_BASE = xstrdup(optarg)) == NULL) { fprintf(stderr, "%s: xstrdup(%s) failed!\n", argv[0], optarg); exit(1); } SM_DIR = xmalloc(strlen(DIR_BASE) + 1 + sizeof("sm")); SM_BAK_DIR = xmalloc(strlen(DIR_BASE) + 1 + sizeof("sm.bak")); SM_STAT_PATH = xmalloc(strlen(DIR_BASE) + 1 + sizeof("state")); if ((SM_DIR == NULL) || (SM_BAK_DIR == NULL) || (SM_STAT_PATH == NULL)) { fprintf(stderr, "%s: xmalloc() failed!\n", argv[0]); exit(1); } if (DIR_BASE[strlen(DIR_BASE)-1] == '/') { sprintf(SM_DIR, "%ssm", DIR_BASE ); sprintf(SM_BAK_DIR, "%ssm.bak", DIR_BASE ); sprintf(SM_STAT_PATH, "%sstate", DIR_BASE ); } else { sprintf(SM_DIR, "%s/sm", DIR_BASE ); sprintf(SM_BAK_DIR, "%s/sm.bak", DIR_BASE ); sprintf(SM_STAT_PATH, "%s/state", DIR_BASE ); } break; case 'H': /* PRC: specify the ha-callout program */ if ((ha_callout_prog = xstrdup(optarg)) == NULL) { fprintf(stderr, "%s: xstrdup(%s) failed!\n", argv[0], optarg); exit(1); } break; case '?': /* heeeeeelllllllpppp? heh */ case 'h': usage(); exit (0); default: /* oh dear ... heh */ usage(); exit(-1); } } if (port == out_port && port != 0) { fprintf(stderr, "Listening and outgoing ports cannot be the same!\n"); exit(-1); } if (run_mode & MODE_NOTIFY_ONLY) { fprintf(stderr, "%s: -N deprecated, consider using /usr/sbin/sm-notify directly\n", name_p); run_sm_notify(out_port); } if (!(run_mode & MODE_NODAEMON)) { run_mode &= ~MODE_LOG_STDERR; /* Never log to console in daemon mode. */ } if (getrlimit (RLIMIT_NOFILE, &rlim) != 0) fprintf(stderr, "%s: getrlimit (RLIMIT_NOFILE) failed: %s\n", argv [0], strerror(errno)); else { /* glibc sunrpc code dies if getdtablesize > FD_SETSIZE */ if (rlim.rlim_cur > FD_SETSIZE) { rlim.rlim_cur = FD_SETSIZE; if (setrlimit (RLIMIT_NOFILE, &rlim) != 0) { fprintf(stderr, "%s: setrlimit (RLIMIT_NOFILE) failed: %s\n", argv [0], strerror(errno)); } } } #ifdef SIMULATIONS if (argc > 1) /* LH - I _really_ need to update simulator... */ simulator (--argc, ++argv); /* simulator() does exit() */ #endif if (!(run_mode & MODE_NODAEMON)) { int tempfd; if (pipe(pipefds)<0) { perror("statd: unable to create pipe"); exit(1); } if ((pid = fork ()) < 0) { perror ("statd: Could not fork"); exit (1); } else if (pid != 0) { /* Parent. * Wait for status from child. */ close(pipefds[1]); if (read(pipefds[0], &status, 1) != 1) exit(1); exit (0); } /* Child. */ close(pipefds[0]); setsid (); if (chdir (DIR_BASE) == -1) { perror("statd: Could not chdir"); exit(1); } while (pipefds[1] <= 2) { pipefds[1] = dup(pipefds[1]); if (pipefds[1]<0) { perror("statd: dup"); exit(1); } } tempfd = open("/dev/null", O_RDWR); dup2(tempfd, 0); dup2(tempfd, 1); dup2(tempfd, 2); dup2(pipefds[1], 3); pipefds[1] = 3; closeall(4); } /* Child. */ log_init (/*name_p,version_p*/); log_modes(); signal (SIGHUP, killer); signal (SIGINT, killer); signal (SIGTERM, killer); /* PRC: trap SIGUSR1 to re-read notify list from disk */ signal(SIGUSR1, sigusr); /* WARNING: the following works on Linux and SysV, but not BSD! */ signal(SIGCHLD, SIG_IGN); /* * Ignore SIGPIPE to avoid statd dying when peers close their * TCP connection while we're trying to reply to them. */ signal(SIGPIPE, SIG_IGN); create_pidfile(); atexit(truncate_pidfile); if (! (run_mode & MODE_NO_NOTIFY)) switch (pid = fork()) { case 0: run_sm_notify(out_port); break; case -1: break; default: waitpid(pid, NULL, 0); } /* Make sure we have a privilege port for calling into the kernel */ if (statd_get_socket() < 0) exit(1); /* If sm-notify didn't take all the state files, load * state information into our notify-list so we can * pass on any SM_NOTIFY that arrives */ load_state(); load_state_number(); pmap_unset (SM_PROG, SM_VERS); /* this registers both UDP and TCP services */ rpc_init("statd", SM_PROG, SM_VERS, sm_prog_1, port); /* If we got this far, we have successfully started, so notify parent */ if (pipefds[1] > 0) { status = 0; write(pipefds[1], &status, 1); close(pipefds[1]); pipefds[1] = -1; } drop_privs(); for (;;) { /* * Handle incoming requests: SM_NOTIFY socket requests, as * well as callbacks from lockd. */ my_svc_run(); /* I rolled my own, Olaf made it better... */ /* Only get here when simulating a crash so we should probably * start sm-notify running again. As we have already dropped * privileges, this might not work, but I don't think * responding to SM_SIMU_CRASH is an important use cases to * get perfect. */ if (! (run_mode & MODE_NO_NOTIFY)) switch (pid = fork()) { case 0: run_sm_notify(out_port); break; case -1: break; default: waitpid(pid, NULL, 0); } } return 0; }
int main(int argc, char *argv[]) { struct netconfig *nconf; void *nc_handle; /* Net config handle */ struct rlimit rl; int maxrec = RPC_MAXDATASIZE; parseargs(argc, argv); /* Check that another rpcbind isn't already running. */ if ((rpcbindlockfd = (open(RPCBINDDLOCK, O_RDONLY|O_CREAT, 0444))) == -1) err(1, "%s", RPCBINDDLOCK); if(flock(rpcbindlockfd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK) errx(1, "another rpcbind is already running. Aborting"); getrlimit(RLIMIT_NOFILE, &rl); if (rl.rlim_cur < 128) { if (rl.rlim_max <= 128) rl.rlim_cur = rl.rlim_max; else rl.rlim_cur = 128; setrlimit(RLIMIT_NOFILE, &rl); } openlog("rpcbind", LOG_CONS, LOG_DAEMON); if (geteuid()) { /* This command allowed only to root */ fprintf(stderr, "Sorry. You are not superuser\n"); exit(1); } /* * Make sure we use the local service file * for service lookkups */ __nss_configure_lookup("services", "files"); nc_handle = setnetconfig(); /* open netconfig file */ if (nc_handle == NULL) { syslog(LOG_ERR, "could not read /etc/netconfig"); exit(1); } nconf = getnetconfigent("local"); if (nconf == NULL) nconf = getnetconfigent("unix"); if (nconf == NULL) { syslog(LOG_ERR, "%s: can't find local transport\n", argv[0]); exit(1); } rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); init_transport(nconf); while ((nconf = getnetconfig(nc_handle))) { if (nconf->nc_flag & NC_VISIBLE) init_transport(nconf); } endnetconfig(nc_handle); #ifdef PORTMAP if (!udptrans) udptrans = ""; if (!tcptrans) tcptrans = ""; #endif /* catch the usual termination signals for graceful exit */ (void) signal(SIGCHLD, reap); (void) signal(SIGINT, terminate); (void) signal(SIGTERM, terminate); (void) signal(SIGQUIT, terminate); /* ignore others that could get sent */ (void) signal(SIGPIPE, SIG_IGN); (void) signal(SIGHUP, SIG_IGN); (void) signal(SIGUSR1, SIG_IGN); (void) signal(SIGUSR2, SIG_IGN); if (debugging) { #ifdef RPCBIND_DEBUG printf("rpcbind debugging enabled."); if (doabort) { printf(" Will abort on errors!\n"); } else { printf("\n"); } #endif } else if (dofork) { if (daemon(0, 0)) err(1, "fork failed"); } if (runasdaemon || rpcbinduser) { struct passwd *p; char *id = runasdaemon ? RUN_AS : rpcbinduser; /* * Make sure we use the local password file * for these lookups. */ __nss_configure_lookup("passwd", "files"); if((p = getpwnam(id)) == NULL) { syslog(LOG_ERR, "cannot get uid of '%s': %m", id); exit(1); } if (setgid(p->pw_gid) == -1) { syslog(LOG_ERR, "setgid to '%s' (%d) failed: %m", id, p->pw_gid); exit(1); } if (setgroups(0, NULL) == -1) { syslog(LOG_ERR, "dropping supplemental groups failed: %m"); exit(1); } if (setuid(p->pw_uid) == -1) { syslog(LOG_ERR, "setuid to '%s' (%d) failed: %m", id, p->pw_uid); exit(1); } } #ifdef WARMSTART if (warmstart) { read_warmstart(); } #endif network_init(); my_svc_run(); syslog(LOG_ERR, "svc_run returned unexpectedly"); rpcbind_abort(); /* NOTREACHED */ return 0; }