Example #1
0
void
fmd_rpc_init(void)
{
	int err, prog, mode = RPC_SVC_MT_USER;
	uint64_t sndsize = 0, rcvsize = 0;
	const char *s;

	if (rpc_control(RPC_SVC_MTMODE_SET, &mode) == FALSE)
		fmd_panic("failed to enable user-MT rpc mode");

	(void) fmd_conf_getprop(fmd.d_conf, "rpc.sndsize", &sndsize);
	(void) fmd_conf_getprop(fmd.d_conf, "rpc.rcvsize", &rcvsize);

	/*
	 * Infer whether we are the "default" fault manager or an alternate one
	 * based on whether the initial setting of rpc.adm.prog is non-zero.
	 */
	(void) fmd_conf_getprop(fmd.d_conf, "rpc.adm.prog", &prog);
	(void) fmd_conf_getprop(fmd.d_conf, "rpc.adm.path", &s);

	if (prog != 0) {
		err = fmd_rpc_svc_init(fmd_adm_1, "FMD_ADM", s, "rpc.adm.prog",
		    FMD_ADM, FMD_ADM, FMD_ADM_VERSION_1,
		    (uint_t)sndsize, (uint_t)rcvsize, TRUE);
	} else {
		err = fmd_rpc_svc_init(fmd_adm_1, "FMD_ADM", s, "rpc.adm.prog",
		    RPC_TRANS_MIN, RPC_TRANS_MAX, FMD_ADM_VERSION_1,
		    (uint_t)sndsize, (uint_t)rcvsize, FALSE);
	}

	if (err != 0)
		fmd_error(EFMD_EXIT, "failed to create rpc server bindings");

	if (fmd_thread_create(fmd.d_rmod, (fmd_thread_f *)svc_run, 0) == NULL)
		fmd_error(EFMD_EXIT, "failed to create rpc server thread");
}
Example #2
0
int
main(int argc, char *argv[])
{
	int	pid;
	int	c;
	int	rpc_svc_mode = RPC_SVC_MT_AUTO;
	int	maxthreads;
	int	maxrecsz = RPC_MAXDATASIZE;
	bool_t	exclbind = TRUE;
	bool_t	can_do_mlp;
	long	thr_flags = (THR_NEW_LWP|THR_DAEMON);

	/*
	 * Mountd requires uid 0 for:
	 *	/etc/rmtab updates (we could chown it to daemon)
	 *	/etc/dfs/dfstab reading (it wants to lock out share which
	 *		doesn't do any locking before first truncate;
	 *		NFS share does; should use fcntl locking instead)
	 *	Needed privileges:
	 *		auditing
	 *		nfs syscall
	 *		file dac search (so it can stat all files)
	 *	Optional privileges:
	 *		MLP
	 */
	can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP);
	if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, -1, -1,
	    PRIV_SYS_NFS, PRIV_PROC_AUDIT, PRIV_FILE_DAC_SEARCH,
	    can_do_mlp ? PRIV_NET_BINDMLP : NULL, NULL) == -1) {
		(void) fprintf(stderr,
			"%s must be run as with sufficient privileges\n",
			argv[0]);
		exit(1);
	}

	maxthreads = 0;

	while ((c = getopt(argc, argv, "vrm:")) != EOF) {
		switch (c) {
		case 'v':
			verbose++;
			break;
		case 'r':
			rejecting = 1;
			break;
		case 'm':
			maxthreads = atoi(optarg);
			if (maxthreads < 1) {
				(void) fprintf(stderr,
	"%s: must specify positive maximum threads count, using default\n",
						argv[0]);
				maxthreads = 0;
			}
			break;
		}
	}

	/*
	 * Read in the NFS version values from config file.
	 */
	if ((defopen(NFSADMIN)) == 0) {
		char *defval;
		int defvers;

		if ((defval = defread("NFS_SERVER_VERSMIN=")) != NULL) {
			errno = 0;
			defvers = strtol(defval, (char **)NULL, 10);
			if (errno == 0) {
				mount_vers_min = defvers;
				/*
				 * special because NFSv2 is
				 * supported by mount v1 & v2
				 */
				if (defvers == NFS_VERSION)
					mount_vers_min = MOUNTVERS;
			}
		}
		if ((defval = defread("NFS_SERVER_VERSMAX=")) != NULL) {
			errno = 0;
			defvers = strtol(defval, (char **)NULL, 10);
			if (errno == 0) {
				mount_vers_max = defvers;
			}
		}

		/* close defaults file */
		defopen(NULL);
	}

	/*
	 * Sanity check versions,
	 * even though we may get versions > MOUNTVERS3, we still need
	 * to start nfsauth service, so continue on regardless of values.
	 */
	if (mount_vers_min > mount_vers_max) {
		syslog(LOG_NOTICE, "NFS_SERVER_VERSMIN > NFS_SERVER_VERSMAX");
		mount_vers_max = mount_vers_min;
	}
	(void) setlocale(LC_ALL, "");
	(void) rwlock_init(&sharetab_lock, USYNC_THREAD, NULL);
	(void) mutex_init(&mnttab_lock, USYNC_THREAD, NULL);
	netgroup_init();

#if !defined(TEXT_DOMAIN)
#define	TEXT_DOMAIN "SYS_TEST"
#endif
	(void) textdomain(TEXT_DOMAIN);

	/* Don't drop core if the NFS module isn't loaded. */
	(void) signal(SIGSYS, SIG_IGN);

	(void) signal(SIGHUP, sigexit);
	(void) signal(SIGCLD, sigexit);

	switch (fork()) {
	case 0:		/* child */
		break;
	case -1:
		perror("mountd: can't fork");
		exit(1);
	default:	/* parent */
		for (;;)
			(void) pause();
		/* NOTREACHED */
	}

	(void) signal(SIGHUP, SIG_DFL);
	(void) signal(SIGCLD, SIG_DFL);

	/*
	 * If we coredump it'll be in /core
	 */
	if (chdir("/") < 0)
		syslog(LOG_ERR, "chdir /: %m");

	/*
	 * Close existing file descriptors, open "/dev/null" as
	 * standard input, output, and error, and detach from
	 * controlling terminal.
	 */
	closefrom(0);
	(void) open("/dev/null", O_RDONLY);
	(void) open("/dev/null", O_WRONLY);
	(void) dup(1);
	(void) setsid();

	openlog("mountd", LOG_PID, LOG_DAEMON);

	/*
	 * establish our lock on the lock file and write our pid to it.
	 * exit if some other process holds the lock, or if there's any
	 * error in writing/locking the file.
	 */
	pid = _enter_daemon_lock(MOUNTD);
	switch (pid) {
	case 0:
		break;
	case -1:
		syslog(LOG_ERR, "error locking for %s: %s", MOUNTD,
		    strerror(errno));
		exit(2);
	default:
		/* daemon was already running */
		exit(0);
	}

	audit_mountd_setup();	/* BSM */

	/*
	 * Tell RPC that we want automatic thread mode.
	 * A new thread will be spawned for each request.
	 */
	if (!rpc_control(RPC_SVC_MTMODE_SET, &rpc_svc_mode)) {
		syslog(LOG_ERR, "unable to set automatic MT mode");
		exit(1);
	}

	/*
	 * Enable non-blocking mode and maximum record size checks for
	 * connection oriented transports.
	 */
	if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrecsz)) {
		syslog(LOG_INFO, "unable to set RPC max record size");
	}

	/*
	 * Prevent our non-priv udp and tcp ports bound w/wildcard addr
	 * from being hijacked by a bind to a more specific addr.
	 */
	if (!rpc_control(__RPC_SVC_EXCLBIND_SET, &exclbind)) {
		syslog(LOG_INFO,  "warning: unable to set udp/tcp EXCLBIND");
	}

	/*
	 * If the -m argument was specified, then set the
	 * maximum number of threads to the value specified.
	 */
	if (maxthreads > 0 && !rpc_control(RPC_SVC_THRMAX_SET, &maxthreads)) {
		syslog(LOG_ERR, "unable to set maxthreads");
		exit(1);
	}

	/*
	 * Make sure to unregister any previous versions in case the
	 * user is reconfiguring the server in interesting ways.
	 */
	svc_unreg(MOUNTPROG, MOUNTVERS);
	svc_unreg(MOUNTPROG, MOUNTVERS_POSIX);
	svc_unreg(MOUNTPROG, MOUNTVERS3);

	/*
	 * Create the nfsauth thread with same signal disposition
	 * as the main thread. We need to create a separate thread
	 * since mountd() will be both an RPC server (for remote
	 * traffic) _and_ a doors server (for kernel upcalls).
	 */
	if (thr_create(NULL, 0, nfsauth_svc, 0, thr_flags, &nfsauth_thread)) {
		syslog(LOG_ERR, gettext("Failed to create NFSAUTH svc thread"));
		exit(2);
	}

	/*
	 * Create datagram and connection oriented services
	 */
	if (mount_vers_max >= MOUNTVERS) {
		if (svc_create(mnt, MOUNTPROG, MOUNTVERS, "datagram_v") == 0) {
			syslog(LOG_ERR,
				"couldn't register datagram_v MOUNTVERS");
			exit(1);
		}
		if (svc_create(mnt, MOUNTPROG, MOUNTVERS, "circuit_v") == 0) {
			syslog(LOG_ERR,
				"couldn't register circuit_v MOUNTVERS");
			exit(1);
		}
	}
	if (mount_vers_max >= MOUNTVERS_POSIX) {
		if (svc_create(mnt, MOUNTPROG, MOUNTVERS_POSIX,
							"datagram_v") == 0) {
			syslog(LOG_ERR,
				"couldn't register datagram_v MOUNTVERS_POSIX");
			exit(1);
		}
		if (svc_create(mnt, MOUNTPROG, MOUNTVERS_POSIX,
							"circuit_v") == 0) {
			syslog(LOG_ERR,
				"couldn't register circuit_v MOUNTVERS_POSIX");
			exit(1);
		}
	}

	if (mount_vers_max >= MOUNTVERS3) {
		if (svc_create(mnt, MOUNTPROG, MOUNTVERS3, "datagram_v") == 0) {
			syslog(LOG_ERR,
				"couldn't register datagram_v MOUNTVERS3");
			exit(1);
		}
		if (svc_create(mnt, MOUNTPROG, MOUNTVERS3, "circuit_v") == 0) {
			syslog(LOG_ERR,
				"couldn't register circuit_v MOUNTVERS3");
			exit(1);
		}
	}

	/*
	 * Start serving
	 */
	rmtab_load();
	(void) kill(getppid(), SIGHUP);

	/* Get rid of the most dangerous basic privileges. */
	__fini_daemon_priv(PRIV_PROC_EXEC, PRIV_PROC_INFO, PRIV_PROC_SESSION,
	    (char *)NULL);

	svc_run();
	syslog(LOG_ERR, "Error: svc_run shouldn't have returned");
	abort();
	/* NOTREACHED */
	return (0);
}
Example #3
0
int
main(int argc, char *argv[])
{
	int sflag = 0, s1flag = 0, s2flag = 0, nflag = 0, dflag = 0, eflag = 0;
	char *options, *value;
	extern char *optarg;
	extern int optind;
	int c, d;
	struct rlimit rl;
	int mode = RPC_SVC_MT_AUTO;
	int maxrecsz = RPC_MAXDATASIZE;

	void detachfromtty(void);
	int setmodulus();
	int pk_nodefaultkeys();
	int svc_create_local_service();

	char domainname[MAXNETNAMELEN + 1];

	/*
	 * Set our allowed number of file descriptors to the max
	 * of what the system will allow, limited by FD_SETSIZE.
	 */
	if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
		rlim_t limit;

		if ((limit = rl.rlim_max) > FD_SETSIZE)
			limit = FD_SETSIZE;
		rl.rlim_cur = limit;
		(void) setrlimit(RLIMIT_NOFILE, &rl);
		(void) enable_extended_FILE_stdio(-1, -1);
	}

	__key_encryptsession_pk_LOCAL = &__key_encrypt_pk_2_svc;
	__key_decryptsession_pk_LOCAL = &__key_decrypt_pk_2_svc;
	__key_gendes_LOCAL = &__key_gen_1_svc;

	/*
	 * Pre-option initialisation
	 */
	(void) umask(066);	/* paranoia */
	if (geteuid() != 0) {
		(void) fprintf(stderr, "%s must be run as root\n", argv[0]);
		exit(1);
	}
	setmodulus(HEXMODULUS);
	openlog("keyserv", LOG_PID, LOG_DAEMON);

	/*
	 * keyserv will not work with a null domainname.
	 */
	if (getdomainname(domainname, MAXNETNAMELEN+1) ||
	    (domainname[0] == '\0')) {
		syslog(LOG_ERR, "could not get a valid domainname.\n");
		exit(SMF_EXIT_ERR_CONFIG);
	}

	/*
	 * Initialise security mechanisms
	 */
	cache_size = NULL;
	cache_options = NULL;
	if (init_mechs() == -1) {
		disk_caching = 0;
	}

	defaults();

	while ((c = getopt(argc, argv, "ndDet:cs:")) != -1)
		switch (c) {
		case 'n':
			nflag++;
			break;
		case 'd':
			dflag++;
			use_nobody_keys = FALSE;
			break;
		case 'e':
			eflag++;
			use_nobody_keys = TRUE;
			break;
		case 'D':
			debugging = 1;
			break;
		case 't':
			nthreads = atoi(optarg);
			break;
		case 'c':
			disk_caching = 0;
			break;
		case 's':
			if (!disk_caching) {
				fprintf(stderr, "missing configuration file");
				fprintf(stderr, " or -c option specified\n");
				usage();
			}
			sflag++;
			/*
			 * Which version of [-s] do we have...?
			 */
			if (strchr((const char *) optarg, '=') == NULL) {
				/*
				 * -s <size>
				 */
				if (s1flag) {
					fprintf(stderr, "duplicate"
					    " [-s <size>]\n");
					usage();
				}
				s1flag++;
				default_cache = get_cache_size(optarg);
				break;
			}
			/*
			 * -s <mechtype>=<size>[,...]
			 */
			s2flag++;
			options = optarg;
			while (*options != '\0') {
				d = getsubopt(&options, cache_options, &value);
				if (d == -1) {
					/* Ignore unknown mechtype */
					continue;
				}
				if (value == NULL) {
					fprintf(stderr,
					    "missing cache size for "
					    "mechtype %s\n", cache_options[d]);
					usage();
				}
				cache_size[d] = get_cache_size(value);
			}
			break;
		default:
			usage();
			break;
		}


	if (dflag && eflag) {
		(void) fprintf(stderr, "specify only one of -d and -e\n");
		usage();
	}

	if (use_nobody_keys == FALSE) {
		pk_nodefaultkeys();
	}

	if (optind != argc) {
		usage();
	}

	if (!disk_caching && sflag) {
		fprintf(stderr, "missing configuration file");
		fprintf(stderr, " or -c option specified\n");
		usage();
	}

	if (debugging) {
		if (disk_caching) {
			char **cpp = cache_options;
			int *ip = cache_size;
			(void) fprintf(stderr, "default disk cache size: ");
			if (default_cache < 0) {
				(void) fprintf(stderr, "%d entries\n",
				    abs(default_cache));
			} else {
				(void) fprintf(stderr, "%dMB\n", default_cache);
			}

			(void) fprintf(stderr, "supported mechanisms:\n");
			(void) fprintf(stderr, "\talias\t\tdisk cache size\n");
			(void) fprintf(stderr, "\t=====\t\t===============\n");
			while (*cpp != NULL) {
				(void) fprintf(stderr, "\t%s\t\t", *cpp++);
				if (*ip < 0) {
					(void) fprintf(stderr, "%d entries\n",
					    abs(*ip));
				} else {
					(void) fprintf(stderr, "%dMB\n", *ip);
				}
				ip++;
			}
		} else {
			(void) fprintf(stderr,
			    "common key disk caching disabled\n");
		}
	}
	/*
	 * Post-option initialisation
	 */
	if (disk_caching) {
		int i;
		for (i = 0; mechs[i]; i++) {
			if ((AUTH_DES_COMPAT_CHK(mechs[i])) ||
			    (mechs[i]->keylen < 0) || (mechs[i]->algtype < 0))
				continue;
			create_cache_file(mechs[i]->keylen, mechs[i]->algtype,
			    cache_size[i] ? cache_size[i] : default_cache);
		}
	}
	getrootkey(&masterkey, nflag);

	/*
	 * Set MT mode
	 */
	if (nthreads > 0) {
		(void) rpc_control(RPC_SVC_MTMODE_SET, &mode);
		(void) rpc_control(RPC_SVC_THRMAX_SET, &nthreads);
	}

	/*
	 * Enable non-blocking mode and maximum record size checks for
	 * connection oriented transports.
	 */
	if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrecsz)) {
		syslog(LOG_INFO, "unable to set max RPC record size");
	}

	if (svc_create_local_service(keyprogram, KEY_PROG, KEY_VERS,
	    "netpath", "keyserv") == 0) {
		syslog(LOG_ERR,
		    "%s: unable to create service for version %d\n",
		    argv[0], KEY_VERS);
		exit(1);
	}

	if (svc_create_local_service(keyprogram, KEY_PROG, KEY_VERS2,
	    "netpath", "keyserv") == 0) {
		syslog(LOG_ERR,
		    "%s: unable to create service for version %d\n",
		    argv[0], KEY_VERS2);
		exit(1);
	}

	if (svc_create_local_service(keyprogram, KEY_PROG, KEY_VERS3,
	    "netpath", "keyserv") == 0) {
		syslog(LOG_ERR,
		    "%s: unable to create service for version %d\n",
		    argv[0], KEY_VERS3);
		exit(1);
	}

	if (!debugging) {
		detachfromtty();
	}

	if (svc_create(keyprogram, KEY_PROG, KEY_VERS, "door") == 0) {
		syslog(LOG_ERR,
		    "%s: unable to create service over doors for version %d\n",
		    argv[0], KEY_VERS);
		exit(1);
	}

	if (svc_create(keyprogram, KEY_PROG, KEY_VERS2, "door") == 0) {
		syslog(LOG_ERR,
		    "%s: unable to create service over doors for version %d\n",
		    argv[0], KEY_VERS2);
		exit(1);
	}

	if (svc_create(keyprogram, KEY_PROG, KEY_VERS3, "door") == 0) {
		syslog(LOG_ERR,
		    "%s: unable to create service over doors for version %d\n",
		    argv[0], KEY_VERS3);
		exit(1);
	}

	svc_run();
	abort();
	/* NOTREACHED */
	return (0);
}
Example #4
0
int
main(int argc, char *argv[])
{
	pid_t pid;
	int c;
	char *progname = argv[0];
	int connmaxrec = RPC_MAXDATASIZE;

	while ((c = getopt(argc, argv, "d")) != -1)
		switch ((char)c) {
		case 'd':
			debug++;
			break;
		default:
			(void) fprintf(stderr, "usage: %s [-d]\n", progname);
			exit(EXIT_FAILURE);
		}


	/*
	 * Set non-blocking mode and maximum record size for
	 * connection oriented RPC transports.
	 */
	if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) {
		msgout("unable to set maximum RPC record size");
	}

	/*
	 * If stdin looks like a TLI endpoint, we assume
	 * that we were started by a port monitor. If
	 * t_getstate fails with TBADF, this is not a
	 * TLI endpoint.
	 */
	if (t_getstate(0) != -1 || t_errno != TBADF) {
		char *netid;
		struct netconfig *nconf = NULL;
		SVCXPRT *transp;
		int pmclose;

		if ((netid = getenv("NLSPROVIDER")) == NULL) {
			if (debug)
				msgout("cannot get transport name");
		} else if ((nconf = getnetconfigent(netid)) == NULL) {
			if (debug)
				msgout("cannot get transport info");
		}
		pmclose = (t_getstate(0) != T_DATAXFER);
		if ((transp = svc_tli_create(0, nconf, NULL, 0, 0)) == NULL) {
			msgout("cannot create server handle");
			exit(EXIT_FAILURE);
		}
		if (nconf)
			freenetconfigent(nconf);
		if (!svc_reg(transp, BOOTPARAMPROG, BOOTPARAMVERS,
		    bootparamprog_1, 0)) {
			msgout("unable to register (BOOTPARAMPROG, "
			    "BOOTPARAMVERS).");
			exit(EXIT_FAILURE);
		}
		if (pmclose) {
			(void) signal(SIGALRM, closedown);
			(void) alarm(_RPCSVC_CLOSEDOWN);
		}

		svc_run();
		exit(EXIT_FAILURE);
		/* NOTREACHED */
	}

	/*
	 * run this process in the background only if it was started from
	 * a shell and the debug flag was not given.
	 */
	if (!server_child && !debug) {
		pid = fork();
		if (pid < 0) {
			perror("cannot fork");
			exit(EXIT_FAILURE);
		}
		if (pid)
			exit(EXIT_SUCCESS);

		closefrom(0);
		(void) setsid();
	}

	/*
	 * messges go to syslog if the program was started by
	 * another server, or if it was run from the command line without
	 * the debug flag.
	 */
	if (server_child || !debug)
		openlog("bootparam_prot", LOG_PID, LOG_DAEMON);

	if (debug) {
		if (debug == 1)
			msgout("in debug mode.");
		else
			msgout("in debug mode (level %d).", debug);
	}

	if (!svc_create(bootparamprog_1, BOOTPARAMPROG, BOOTPARAMVERS,
			"netpath")) {
		msgout("unable to create (BOOTPARAMPROG, BOOTPARAMVERS) "
		    "for netpath.");
		exit(EXIT_FAILURE);
	}

	svc_run();
	msgout("svc_run returned");
	return (EXIT_FAILURE);
}
Example #5
0
int
main(int argc, char **argv)
{
  struct sigaction sa;
  struct netconfig *nconf;
  void *nc_handle;
  in_port_t svcport;
  int ch, i, s;
  char *endptr, **hosts_bak;
  int have_v6 = 1;
  int maxrec = RPC_MAXDATASIZE;
  int attempt_cnt, port_len, port_pos, ret;
  char **port_list;

  while ((ch = getopt(argc, argv, "dh:p:")) != -1)
    switch (ch) {
    case 'd':
      debug = 1;
      break;
    case 'h':
      ++nhosts;
      hosts_bak = hosts;
      hosts_bak = realloc(hosts, nhosts * sizeof(char *));
      if (hosts_bak == NULL) {
	      if (hosts != NULL) {
		      for (i = 0; i < nhosts; i++) 
			      free(hosts[i]);
		      free(hosts);
		      out_of_mem();
	      }
      }
      hosts = hosts_bak;
      hosts[nhosts - 1] = strdup(optarg);
      if (hosts[nhosts - 1] == NULL) {
	      for (i = 0; i < (nhosts - 1); i++) 
		      free(hosts[i]);
	      free(hosts);
	      out_of_mem();
      }
      break;
    case 'p':
      endptr = NULL;
      svcport = (in_port_t)strtoul(optarg, &endptr, 10);
      if (endptr == NULL || *endptr != '\0' || svcport == 0 || 
          svcport >= IPPORT_MAX)
	usage();
      
      svcport_str = strdup(optarg);
      break;
    default:
      usage();
    }
  argc -= optind;
  argv += optind;

  (void)rpcb_unset(SM_PROG, SM_VERS, NULL);

  /*
   * Check if IPv6 support is present.
   */
  s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
  if (s < 0)
      have_v6 = 0;
  else 
      close(s);

  rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec);

  /*
   * If no hosts were specified, add a wildcard entry to bind to
   * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the
   * list.
   */
  if (nhosts == 0) {
	  hosts = malloc(sizeof(char *));
	  if (hosts == NULL)
		  out_of_mem();

	  hosts[0] = "*";
	  nhosts = 1;
  } else {
	  hosts_bak = hosts;
	  if (have_v6) {
		  hosts_bak = realloc(hosts, (nhosts + 2) *
		      sizeof(char *));
		  if (hosts_bak == NULL) {
			  for (i = 0; i < nhosts; i++)
				  free(hosts[i]);
			  free(hosts);
			  out_of_mem();
		  } else
			  hosts = hosts_bak;

		  nhosts += 2;
		  hosts[nhosts - 2] = "::1";
	  } else {
		  hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *));
		  if (hosts_bak == NULL) {
			  for (i = 0; i < nhosts; i++)
				  free(hosts[i]);

			  free(hosts);
			  out_of_mem();
		  } else {
			  nhosts += 1;
			  hosts = hosts_bak;
		  }
	  }
	  hosts[nhosts - 1] = "127.0.0.1";
  }

  attempt_cnt = 1;
  sock_fdcnt = 0;
  sock_fd = NULL;
  port_list = NULL;
  port_len = 0;
  nc_handle = setnetconfig();
  while ((nconf = getnetconfig(nc_handle))) {
	  /* We want to listen only on udp6, tcp6, udp, tcp transports */
	  if (nconf->nc_flag & NC_VISIBLE) {
		  /* Skip if there's no IPv6 support */
		  if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) {
	      /* DO NOTHING */
		  } else {
			ret = create_service(nconf);
			if (ret == 1)
				/* Ignore this call */
				continue;
			if (ret < 0) {
				/*
				 * Failed to bind port, so close off
				 * all sockets created and try again
				 * if the port# was dynamically
				 * assigned via bind(2).
				 */
				clearout_service();
				if (mallocd_svcport != 0 &&
				    attempt_cnt < GETPORT_MAXTRY) {
					free(svcport_str);
					svcport_str = NULL;
					mallocd_svcport = 0;
				} else {
					errno = EADDRINUSE;
					syslog(LOG_ERR,
					    "bindresvport_sa: %m");
					exit(1);
				}

				/* Start over at the first service. */
				free(sock_fd);
				sock_fdcnt = 0;
				sock_fd = NULL;
				nc_handle = setnetconfig();
				attempt_cnt++;
			} else if (mallocd_svcport != 0 &&
			    attempt_cnt == GETPORT_MAXTRY) {
				/*
				 * For the last attempt, allow
				 * different port #s for each nconf
				 * by saving the svcport_str and
				 * setting it back to NULL.
				 */
				port_list = realloc(port_list,
				    (port_len + 1) * sizeof(char *));
				if (port_list == NULL)
					out_of_mem();
				port_list[port_len++] = svcport_str;
				svcport_str = NULL;
				mallocd_svcport = 0;
			}
		  }
	  }
  }

  /*
   * Successfully bound the ports, so call complete_service() to
   * do the rest of the setup on the service(s).
   */
  sock_fdpos = 0;
  port_pos = 0;
  nc_handle = setnetconfig();
  while ((nconf = getnetconfig(nc_handle))) {
	  /* We want to listen only on udp6, tcp6, udp, tcp transports */
	  if (nconf->nc_flag & NC_VISIBLE) {
		  /* Skip if there's no IPv6 support */
		  if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) {
	      /* DO NOTHING */
		  } else if (port_list != NULL) {
			if (port_pos >= port_len) {
				syslog(LOG_ERR, "too many port#s");
				exit(1);
			}
			complete_service(nconf, port_list[port_pos++]);
		  } else
			complete_service(nconf, svcport_str);
	  }
  }
  endnetconfig(nc_handle);
  free(sock_fd);
  if (port_list != NULL) {
  	for (port_pos = 0; port_pos < port_len; port_pos++)
  		free(port_list[port_pos]);
  	free(port_list);
  }

  init_file("/var/db/statd.status");

  /* Note that it is NOT sensible to run this program from inetd - the 	*/
  /* protocol assumes that it will run immediately at boot time.	*/
  daemon(0, 0);
  openlog("rpc.statd", 0, LOG_DAEMON);
  if (debug) syslog(LOG_INFO, "Starting - debug enabled");
  else syslog(LOG_INFO, "Starting");

  /* Install signal handler to collect exit status of child processes	*/
  sa.sa_handler = handle_sigchld;
  sigemptyset(&sa.sa_mask);
  sigaddset(&sa.sa_mask, SIGCHLD);
  sa.sa_flags = SA_RESTART;
  sigaction(SIGCHLD, &sa, NULL);

  /* Initialisation now complete - start operating			*/
  notify_hosts();	/* Forks a process (if necessary) to do the	*/
			/* SM_NOTIFY calls, which may be slow.		*/

  svc_run();	/* Should never return					*/
  exit(1);
}
Example #6
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 (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 (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;
}
Example #7
0
int
main(int argc, char **argv)
{
	int ch, i, s;
	void *nc_handle;
	char *endptr, **hosts_bak;
	struct sigaction sigalarm;
	int grace_period = 30;
	struct netconfig *nconf;
	int have_v6 = 1;
	int maxrec = RPC_MAXDATASIZE;
	in_port_t svcport = 0;
	int attempt_cnt, port_len, port_pos, ret;
	char **port_list;

	while ((ch = getopt(argc, argv, "d:g:h:p:")) != (-1)) {
		switch (ch) {
		case 'd':
			debug_level = atoi(optarg);
			if (!debug_level) {
				usage();
				/* NOTREACHED */
			}
			break;
		case 'g':
			grace_period = atoi(optarg);
			if (!grace_period) {
				usage();
				/* NOTREACHED */
			}
			break;
		case 'h':
			++nhosts;
			hosts_bak = hosts;
			hosts_bak = realloc(hosts, nhosts * sizeof(char *));
			if (hosts_bak == NULL) {
				if (hosts != NULL) {
					for (i = 0; i < nhosts; i++) 
						free(hosts[i]);
					free(hosts);
					out_of_mem();
				}
			}
			hosts = hosts_bak;
			hosts[nhosts - 1] = strdup(optarg);
			if (hosts[nhosts - 1] == NULL) {
				for (i = 0; i < (nhosts - 1); i++) 
					free(hosts[i]);
				free(hosts);
				out_of_mem();
			}
			break;
		case 'p':
			endptr = NULL;
			svcport = (in_port_t)strtoul(optarg, &endptr, 10);
			if (endptr == NULL || *endptr != '\0' ||
			    svcport == 0 || svcport >= IPPORT_MAX)
				usage();
			svcport_str = strdup(optarg);
			break;
		default:
		case '?':
			usage();
			/* NOTREACHED */
		}
	}
	if (geteuid()) { /* This command allowed only to root */
		fprintf(stderr, "Sorry. You are not superuser\n");
		exit(1);
        }

	kernel_lockd = FALSE;
	kernel_lockd_client = FALSE;
	if (modfind("nfslockd") < 0) {
		if (kldload("nfslockd") < 0) {
			fprintf(stderr, "Can't find or load kernel support for rpc.lockd - using non-kernel implementation\n");
		} else {
			kernel_lockd = TRUE;
		}
	} else {
		kernel_lockd = TRUE;
	}
	if (kernel_lockd) {
		if (getosreldate() >= 800040)
			kernel_lockd_client = TRUE;
	}

	(void)rpcb_unset(NLM_PROG, NLM_SM, NULL);
	(void)rpcb_unset(NLM_PROG, NLM_VERS, NULL);
	(void)rpcb_unset(NLM_PROG, NLM_VERSX, NULL);
	(void)rpcb_unset(NLM_PROG, NLM_VERS4, NULL);

	/*
	 * Check if IPv6 support is present.
	 */
	s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
	if (s < 0)
		have_v6 = 0;
	else 
		close(s);

	rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec);

	/*
	 * If no hosts were specified, add a wildcard entry to bind to
	 * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the
	 * list.
	 */
	if (nhosts == 0) {
		hosts = malloc(sizeof(char**));
		if (hosts == NULL)
			out_of_mem();

		hosts[0] = "*";
		nhosts = 1;
	} else {
		hosts_bak = hosts;
		if (have_v6) {
			hosts_bak = realloc(hosts, (nhosts + 2) *
			    sizeof(char *));
			if (hosts_bak == NULL) {
				for (i = 0; i < nhosts; i++)
					free(hosts[i]);
				free(hosts);
				out_of_mem();
			} else
				hosts = hosts_bak;

			nhosts += 2;
			hosts[nhosts - 2] = "::1";
		} else {
			hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *));
			if (hosts_bak == NULL) {
				for (i = 0; i < nhosts; i++)
					free(hosts[i]);

				free(hosts);
				out_of_mem();
			} else {
				nhosts += 1;
				hosts = hosts_bak;
			}
		}
		hosts[nhosts - 1] = "127.0.0.1";
	}

	if (kernel_lockd) {
		if (!kernel_lockd_client) {
			/*
			 * For the case where we have a kernel lockd but it
			 * doesn't provide client locking, we run a cut-down
			 * RPC service on a local-domain socket. The kernel's
			 * RPC server will pass what it can't handle (mainly
			 * client replies) down to us.
			 */
			struct sockaddr_un sun;
			int fd, oldmask;
			SVCXPRT *xprt;

			memset(&sun, 0, sizeof sun);
			sun.sun_family = AF_LOCAL;
			unlink(_PATH_RPCLOCKDSOCK);
			strcpy(sun.sun_path, _PATH_RPCLOCKDSOCK);
			sun.sun_len = SUN_LEN(&sun);
			fd = socket(AF_LOCAL, SOCK_STREAM, 0);
			if (!fd) {
				err(1, "Can't create local lockd socket");
			}
			oldmask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
			if (bind(fd, (struct sockaddr *) &sun, sun.sun_len) < 0) {
				err(1, "Can't bind local lockd socket");
			}
			umask(oldmask);
			if (listen(fd, SOMAXCONN) < 0) {
				err(1, "Can't listen on local lockd socket");
			}
			xprt = svc_vc_create(fd, RPC_MAXDATASIZE, RPC_MAXDATASIZE);
			if (!xprt) {
				err(1, "Can't create transport for local lockd socket");
			}
			if (!svc_reg(xprt, NLM_PROG, NLM_VERS4, nlm_prog_4, NULL)) {
				err(1, "Can't register service for local lockd socket");
			}
		}

		/*
		 * We need to look up the addresses so that we can
		 * hand uaddrs (ascii encoded address+port strings) to
		 * the kernel.
		 */
		nc_handle = setnetconfig();
		while ((nconf = getnetconfig(nc_handle))) {
			/* We want to listen only on udp6, tcp6, udp, tcp transports */
			if (nconf->nc_flag & NC_VISIBLE) {
				/* Skip if there's no IPv6 support */
				if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) {
					/* DO NOTHING */
				} else {
					lookup_addresses(nconf);
				}
			}
		}
		endnetconfig(nc_handle);
	} else {
		attempt_cnt = 1;
		sock_fdcnt = 0;
		sock_fd = NULL;
		port_list = NULL;
		port_len = 0;
		nc_handle = setnetconfig();
		while ((nconf = getnetconfig(nc_handle))) {
			/* We want to listen only on udp6, tcp6, udp, tcp transports */
			if (nconf->nc_flag & NC_VISIBLE) {
				/* Skip if there's no IPv6 support */
				if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) {
					/* DO NOTHING */
				} else {
					ret = create_service(nconf);
					if (ret == 1)
						/* Ignore this call */
						continue;
					if (ret < 0) {
						/*
						 * Failed to bind port, so close
						 * off all sockets created and
						 * try again if the port# was
						 * dynamically assigned via
						 * bind(2).
						 */
						clearout_service();
						if (mallocd_svcport != 0 &&
						    attempt_cnt <
						    GETPORT_MAXTRY) {
							free(svcport_str);
							svcport_str = NULL;
							mallocd_svcport = 0;
						} else {
							errno = EADDRINUSE;
							syslog(LOG_ERR,
							 "bindresvport_sa: %m");
							exit(1);
						}
	
						/*
						 * Start over at the first
						 * service.
						 */
						free(sock_fd);
						sock_fdcnt = 0;
						sock_fd = NULL;
						nc_handle = setnetconfig();
						attempt_cnt++;
					} else if (mallocd_svcport != 0 &&
					    attempt_cnt == GETPORT_MAXTRY) {
						/*
						 * For the last attempt, allow
						 * different port #s for each
						 * nconf by saving the
						 * svcport_str and setting it
						 * back to NULL.
						 */
						port_list = realloc(port_list,
						    (port_len + 1) *
						    sizeof(char *));
						if (port_list == NULL)
							out_of_mem();
						port_list[port_len++] =
						    svcport_str;
						svcport_str = NULL;
						mallocd_svcport = 0;
					}
				}
			}
		}

		/*
		 * Successfully bound the ports, so call complete_service() to
		 * do the rest of the setup on the service(s).
		 */
		sock_fdpos = 0;
		port_pos = 0;
		nc_handle = setnetconfig();
		while ((nconf = getnetconfig(nc_handle))) {
			/* We want to listen only on udp6, tcp6, udp, tcp transports */
			if (nconf->nc_flag & NC_VISIBLE) {
				/* Skip if there's no IPv6 support */
				if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) {
					/* DO NOTHING */
				} else if (port_list != NULL) {
					if (port_pos >= port_len) {
						syslog(LOG_ERR,
						    "too many port#s");
						exit(1);
					}
					complete_service(nconf,
					    port_list[port_pos++]);
				} else
					complete_service(nconf, svcport_str);
			}
		}
		endnetconfig(nc_handle);
		free(sock_fd);
		if (port_list != NULL) {
			for (port_pos = 0; port_pos < port_len; port_pos++)
				free(port_list[port_pos]);
			free(port_list);
		}
	}

	/*
	 * Note that it is NOT sensible to run this program from inetd - the
	 * protocol assumes that it will run immediately at boot time.
	 */
	if (daemon(0, debug_level > 0)) {
		err(1, "cannot fork");
		/* NOTREACHED */
	}

	openlog("rpc.lockd", 0, LOG_DAEMON);
	if (debug_level)
		syslog(LOG_INFO, "Starting, debug level %d", debug_level);
	else
		syslog(LOG_INFO, "Starting");

	sigalarm.sa_handler = (sig_t) sigalarm_handler;
	sigemptyset(&sigalarm.sa_mask);
	sigalarm.sa_flags = SA_RESETHAND; /* should only happen once */
	sigalarm.sa_flags |= SA_RESTART;
	if (sigaction(SIGALRM, &sigalarm, NULL) != 0) {
		syslog(LOG_WARNING, "sigaction(SIGALRM) failed: %s",
		    strerror(errno));
		exit(1);
	}

	if (kernel_lockd) {
		if (!kernel_lockd_client) {
			init_nsm();
			client_pid = client_request();

			/*
			 * Create a child process to enter the kernel and then
			 * wait for RPCs on our local domain socket.
			 */
			if (!fork())
				nlm_syscall(debug_level, grace_period,
				    naddrs, addrs);
			else
				svc_run();
		} else {
			/*
			 * The kernel lockd implementation provides
			 * both client and server so we don't need to
			 * do anything else.
			 */
			nlm_syscall(debug_level, grace_period, naddrs, addrs);
		}
	} else {
		grace_expired = 0;
		alarm(grace_period);

		init_nsm();

		client_pid = client_request();

		svc_run();		/* Should never return */
	}
	exit(1);
}
Example #8
0
int
rpcbind_main(void *arg)
#endif
{
	struct netconfig *nconf;
	void *nc_handle;	/* Net config handle */
	struct rlimit rl;
	int maxrec = RPC_MAXDATASIZE;

#ifdef RPCBIND_RUMP
	svc_fdset_init(SVC_FDSET_MT);
#else
	parseargs(argc, argv);
#endif

	if (getrlimit(RLIMIT_NOFILE, &rl) == -1)
		err(EXIT_FAILURE, "getrlimit(RLIMIT_NOFILE)");

	if (rl.rlim_cur < 128) {
		if (rl.rlim_max <= 128)
			rl.rlim_cur = rl.rlim_max;
		else
			rl.rlim_cur = 128;
		if (setrlimit(RLIMIT_NOFILE, &rl) < 0)
			err(EXIT_FAILURE, "setrlimit(RLIMIT_NOFILE)");
	}
	nc_handle = setnetconfig(); 	/* open netconfig file */
	if (nc_handle == NULL)
		errx(EXIT_FAILURE, "could not read /etc/netconfig");
#ifdef PORTMAP
	udptrans = "";
	tcptrans = "";
#endif

	nconf = getnetconfigent("local");
	if (nconf == NULL)
		errx(EXIT_FAILURE, "can't find local transport");

	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);

	/* 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);
#ifndef RPCBIND_RUMP
	(void) signal(SIGHUP, SIG_IGN);
#endif
	(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(EXIT_FAILURE, "fork failed");
	}

	openlog("rpcbind", 0, LOG_DAEMON);
	pidfile(NULL);

	if (runasdaemon) {
		struct passwd *p;

		if((p = getpwnam(RUN_AS)) == NULL) {
			syslog(LOG_ERR, "cannot get uid of daemon: %m");
			exit(EXIT_FAILURE);
		}
		if (setuid(p->pw_uid) == -1) {
			syslog(LOG_ERR, "setuid to daemon failed: %m");
			exit(EXIT_FAILURE);
		}
	}

	network_init();

#ifdef RPCBIND_RUMP
	sem_post(&gensem);
#endif
	my_svc_run();
	syslog(LOG_ERR, "svc_run returned unexpectedly");
	rpcbind_abort();
	/* NOTREACHED */

	return EXIT_SUCCESS;
}
Example #9
0
int
main(int argc, char *argv[])
{
	pid_t pid;
	int i;
	int connmaxrec = RPC_MAXDATASIZE;

	/*
	 * Set non-blocking mode and maximum record size for
	 * connection oriented RPC transports.
	 */
	if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) {
		msgout("unable to set maximum RPC record size");
	}

	/*
	 * If stdin looks like a TLI endpoint, we assume
	 * that we were started by a port monitor. If
	 * t_getstate fails with TBADF, this is not a
	 * TLI endpoint.
	 */
	if (t_getstate(0) != -1 || t_errno != TBADF) {
		char *netid;
		struct netconfig *nconf = NULL;
		SVCXPRT *transp;
		int pmclose;
		extern char *getenv();

		_rpcpmstart = 1;
		openlog("rusers", LOG_PID, LOG_DAEMON);
		if ((netid = getenv("NLSPROVIDER")) == NULL) {
#ifdef DEBUG
			msgout("cannot get transport name");
#endif
		} else if ((nconf = getnetconfigent(netid)) == NULL) {
#ifdef DEBUG
			msgout("cannot get transport info");
#endif
		}
		if ((transp = svc_tli_create(0, nconf, NULL, 0, 0)) == NULL) {
			msgout("cannot create server handle");
			exit(1);
		}
		if (nconf)
			freenetconfigent(nconf);
		if (!svc_reg(transp, RUSERSPROG, RUSERSVERS_3, rusers_service,
				0)) {
	msgout("unable to register (RUSERSPROG, RUSERSVERS_3).");
			exit(1);
		}
		if (!svc_reg(transp, RUSERSPROG, RUSERSVERS_IDLE,
				rusers_service, 0)) {
	msgout("unable to register (RUSERSPROG, RUSERSVERS_IDLE).");
			exit(1);
		}
		(void) signal(SIGALRM, closedown);
		(void) alarm(_RPCSVC_CLOSEDOWN);
		svc_run();
		msgout("svc_run returned");
		exit(1);
		/* NOTREACHED */
	}
#ifndef RPC_SVC_FG
	pid = fork();
	if (pid < 0) {
		perror("rpc.rusersd: cannot fork");
		exit(1);
	}
	if (pid)
		exit(0);
	for (i = 0; i < 20; i++)
		(void) close(i);
	setsid();
	openlog("rusers", LOG_PID, LOG_DAEMON);
#endif
	if (!svc_create(rusers_service, RUSERSPROG, RUSERSVERS_3, "netpath")) {
	    msgout("unable to create (RUSERSPROG, RUSERSVERS_3) for netpath");
		exit(1);
	}
	if (!svc_create(rusers_service, RUSERSPROG, RUSERSVERS_IDLE,
			"netpath")) {
	    msgout(
		"unable to create (RUSERSPROG, RUSERSVERS_IDLE) for netpath");
		exit(1);
	}

	svc_run();
	msgout("svc_run returned");
	return (1);
}