Example #1
0
int
main(int argc, char **argv)
{
	int nflag = 0;
	int c;
	int warn = 0;
	char *path = NULL;
	void *localhandle;
	SVCXPRT *transp;
	struct netconfig *nconf = NULL;

	__key_encryptsession_pk_LOCAL = &key_encrypt_pk_2_svc_prog;
	__key_decryptsession_pk_LOCAL = &key_decrypt_pk_2_svc_prog;
	__key_gendes_LOCAL = &key_gen_1_svc_prog;

	while ((c = getopt(argc, argv, "ndDvp:")) != -1)
		switch (c) {
		case 'n':
			nflag++;
			break;
		case 'd':
			pk_nodefaultkeys();
			break;
		case 'D':
			debugging = 1;
			break;
		case 'v':
			warn = 1;
			break;
		case 'p':
			path = optarg;
			break;
		default:
			usage();
		}

	load_des(warn, path);
	__des_crypt_LOCAL = _my_crypt;
	if (svc_auth_reg(AUTH_DES, _svcauth_des) == -1)
		errx(1, "failed to register AUTH_DES authenticator");

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

	/*
	 * Initialize
	 */
	umask(S_IXUSR|S_IXGRP|S_IXOTH);
	if (geteuid() != 0)
		errx(1, "keyserv must be run as root");
	setmodulus(HEXMODULUS);
	getrootkey(&masterkey, nflag);

	rpcb_unset(KEY_PROG, KEY_VERS, NULL);
	rpcb_unset(KEY_PROG, KEY_VERS2, NULL);

	if (svc_create(keyprogram, KEY_PROG, KEY_VERS,
		"netpath") == 0) {
		fprintf(stderr, "%s: unable to create service\n", argv[0]);
		exit(1);
	}

	if (svc_create(keyprogram, KEY_PROG, KEY_VERS2,
	"netpath") == 0) {
		fprintf(stderr, "%s: unable to create service\n", argv[0]);
		exit(1);
	}

	localhandle = setnetconfig();
	while ((nconf = getnetconfig(localhandle)) != NULL) {
		if (nconf->nc_protofmly != NULL &&
		    strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0)
			break;
	}

	if (nconf == NULL)
		errx(1, "getnetconfig: %s", nc_sperror());

	unlink(KEYSERVSOCK);
	rpcb_unset(CRYPT_PROG, CRYPT_VERS, nconf);
	transp = svcunix_create(RPC_ANYSOCK, 0, 0, KEYSERVSOCK);
	if (transp == NULL)
		errx(1, "cannot create AF_LOCAL service");
	if (!svc_reg(transp, KEY_PROG, KEY_VERS, keyprogram, nconf))
		errx(1, "unable to register (KEY_PROG, KEY_VERS, unix)");
	if (!svc_reg(transp, KEY_PROG, KEY_VERS2, keyprogram, nconf))
		errx(1, "unable to register (KEY_PROG, KEY_VERS2, unix)");
	if (!svc_reg(transp, CRYPT_PROG, CRYPT_VERS, crypt_prog_1, nconf))
		errx(1, "unable to register (CRYPT_PROG, CRYPT_VERS, unix)");

	endnetconfig(localhandle);

	umask(066);	/* paranoia */

	if (!debugging) {
		daemon(0,0);
	}

	signal(SIGPIPE, SIG_IGN);

	svc_run();
	abort();
	/* NOTREACHED */
}
Example #2
0
/*
 * The highest level interface for server creation.
 * Copied from svc_generic.c and cmd/keyserv/key_generic.c, but adapted
 * to work only for TPI_CLTS semantics, and to be called only once
 * from kwarnd.c. Returns 1 (interface created) on success and 0
 * (no interfaces created) on failure.
 */
int
svc_create_local_service(void (*dispatch) (),		/* Dispatch function */
			u_long prognum,			/* Program number */
			u_long versnum,			/* Version number */
			char *nettype,			/* Networktype token */
			char *servname)			/* name of the srvc */
{
	int num = 0;
	SVCXPRT *xprt;
	struct netconfig *nconf;
	struct t_bind *bind_addr;
	void *net;
	int fd;
	struct nd_hostserv ns;
	struct nd_addrlist *nas;

	if ((net = __rpc_setconf(nettype)) == 0) {
		(void) syslog(LOG_ERR,
		gettext("svc_create: could not read netconfig database"));
		return (0);
	}
	while (nconf = __rpc_getconf(net)) {
		if ((strcmp(nconf->nc_protofmly, NC_LOOPBACK)) ||
				(nconf->nc_semantics != NC_TPI_COTS_ORD))
			continue;

		if ((fd = t_open(nconf->nc_device, O_RDWR, NULL)) < 0) {
			(void) syslog(LOG_ERR,
			gettext("svc_create: %s: cannot open connection: %s"),
				nconf->nc_netid, t_errlist[t_errno]);
			break;
		}

		/*
		 * Negotiate for returning the uid of the caller.
		 * This should be done before enabling the endpoint for
		 * service via t_bind() (called in svc_tli_create())
		 * so that requests to kwarnd contain the uid.
		 */
		if (__rpc_negotiate_uid(fd) != 0) {
			syslog(LOG_ERR,
			gettext("Could not negotiate for"
				" uid with loopback transport %s"),
				nconf->nc_netid);
			t_close(fd);
			break;
		}

		/* LINTED pointer alignment */
		bind_addr = (struct t_bind *) t_alloc(fd, T_BIND, T_ADDR);
		if ((bind_addr == NULL)) {
			(void) t_close(fd);
			(void) syslog(LOG_ERR,
				gettext("svc_create: t_alloc failed\n"));
			break;
		}
		ns.h_host = HOST_SELF;
		ns.h_serv = servname;
		if (!netdir_getbyname(nconf, &ns, &nas)) {
			/* Copy the address */
			bind_addr->addr.len = nas->n_addrs->len;
			(void) memcpy(bind_addr->addr.buf, nas->n_addrs->buf,
				(int) nas->n_addrs->len);
			bind_addr->qlen = 8;
			netdir_free((char *) nas, ND_ADDRLIST);
		} else {
			(void) syslog(LOG_ERR,
			gettext("svc_create: no well known "
				"address for %s on %s\n"),
				servname, nconf->nc_netid);
			(void) t_free((char *) bind_addr, T_BIND);
			bind_addr = NULL;
		}

		xprt = svc_tli_create(fd, nconf, bind_addr, 0, 0);
		if (bind_addr)
			(void) t_free((char *) bind_addr, T_BIND);
		if (xprt == NULL) {
			(void) t_close(fd);
			(void) syslog(LOG_ERR,
			    gettext("svc_create: svc_tli_create failed\n"));
			break;
		} else {
			(void) rpcb_unset(prognum, versnum, nconf);
			if (svc_reg(xprt, prognum, versnum, dispatch, nconf)
					== FALSE) {
				(void) syslog(LOG_ERR,
				gettext("svc_create: cannot"
					" register %d vers %d on %s"),
					prognum, versnum, nconf->nc_netid);
				SVC_DESTROY(xprt);	/* also t_closes fd */
				break;
			}
			num = 1;
			break;
		}
	}
	__rpc_endconf(net);
	return (num);
}
Example #3
0
/*
 * For simplified, easy to use kind of rpc interfaces.
 * nettype indicates the type of transport on which the service will be
 * listening. Used for conservation of the system resource. Only one
 * handle is created for all the services (actually one of each netid)
 * and same xdrbuf is used for same netid. The size of the arguments
 * is also limited by the recvsize for that transport, even if it is
 * a COTS transport. This may be wrong, but for cases like these, they
 * should not use the simplified interfaces like this.
 *
 * prognum - program number
 * versnum - version number
 * procnum - procedure number
 * progname - Server routine
 * inproc, outproc - in/out XDR procedures
 * nettype - nettype
 */
int
rpc_reg(rpcprog_t prognum, rpcvers_t versnum, rpcproc_t procnum,
    char *(*progname)(char *), xdrproc_t inproc, xdrproc_t outproc,
    char *nettype)
{
	struct netconfig *nconf;
	int done = FALSE;
	void *handle;


	if (procnum == NULLPROC) {
		warnx("%s can't reassign procedure number %u", rpc_reg_msg,
			NULLPROC);
		return (-1);
	}

	if (nettype == NULL)
		nettype = "netpath";		/* The default behavior */
	if ((handle = __rpc_setconf(nettype)) == NULL) {
		warnx(rpc_reg_err, rpc_reg_msg, __reg_err1);
		return (-1);
	}
/* VARIABLES PROTECTED BY proglst_lock: proglst */
	mutex_lock(&proglst_lock);
	while ((nconf = __rpc_getconf(handle)) != NULL) {
		struct proglst *pl;
		SVCXPRT *svcxprt;
		int madenow;
		u_int recvsz;
		char *xdrbuf;
		char *netid;

		madenow = FALSE;
		svcxprt = NULL;
		recvsz = 0;
		xdrbuf = netid = NULL;
		for (pl = proglst; pl; pl = pl->p_nxt) {
			if (strcmp(pl->p_netid, nconf->nc_netid) == 0) {
				svcxprt = pl->p_transp;
				xdrbuf = pl->p_xdrbuf;
				recvsz = pl->p_recvsz;
				netid = pl->p_netid;
				break;
			}
		}

		if (svcxprt == NULL) {
			struct __rpc_sockinfo si;

			svcxprt = svc_tli_create(RPC_ANYFD, nconf, NULL, 0, 0);
			if (svcxprt == NULL)
				continue;
			if (!__rpc_fd2sockinfo(svcxprt->xp_fd, &si)) {
				warnx(rpc_reg_err, rpc_reg_msg, __reg_err2);
				SVC_DESTROY(svcxprt);
				continue;
			}
			recvsz = __rpc_get_t_size(si.si_af, si.si_proto, 0);
			if (recvsz == 0) {
				warnx(rpc_reg_err, rpc_reg_msg, __reg_err3);
				SVC_DESTROY(svcxprt);
				continue;
			}
			if (((xdrbuf = malloc((unsigned)recvsz)) == NULL) ||
				((netid = strdup(nconf->nc_netid)) == NULL)) {
				warnx(rpc_reg_err, rpc_reg_msg, __no_mem_str);
				free(xdrbuf);
				free(netid);
				SVC_DESTROY(svcxprt);
				break;
			}
			madenow = TRUE;
		}
		/*
		 * Check if this (program, version, netid) had already been
		 * registered.  The check may save a few RPC calls to rpcbind
		 */
		for (pl = proglst; pl; pl = pl->p_nxt)
			if ((pl->p_prognum == prognum) &&
				(pl->p_versnum == versnum) &&
				(strcmp(pl->p_netid, netid) == 0))
				break;
		if (pl == NULL) { /* Not yet */
			(void) rpcb_unset(prognum, versnum, nconf);
		} else {
			/* so that svc_reg does not call rpcb_set() */
			nconf = NULL;
		}

		if (!svc_reg(svcxprt, prognum, versnum, universal, nconf)) {
			warnx("%s couldn't register prog %u vers %u for %s",
				rpc_reg_msg, (unsigned)prognum,
				(unsigned)versnum, netid);
			if (madenow) {
				SVC_DESTROY(svcxprt);
				free(xdrbuf);
				free(netid);
			}
			continue;
		}

		pl = malloc(sizeof (struct proglst));
		if (pl == NULL) {
			warnx(rpc_reg_err, rpc_reg_msg, __no_mem_str);
			if (madenow) {
				SVC_DESTROY(svcxprt);
				free(xdrbuf);
				free(netid);
			}
			break;
		}
		pl->p_progname = progname;
		pl->p_prognum = prognum;
		pl->p_versnum = versnum;
		pl->p_procnum = procnum;
		pl->p_inproc = inproc;
		pl->p_outproc = outproc;
		pl->p_transp = svcxprt;
		pl->p_xdrbuf = xdrbuf;
		pl->p_recvsz = recvsz;
		pl->p_netid = netid;
		pl->p_nxt = proglst;
		proglst = pl;
		done = TRUE;
	}
	__rpc_endconf(handle);
	mutex_unlock(&proglst_lock);

	if (done == FALSE) {
		warnx("%s can't find suitable transport for %s",
			rpc_reg_msg, nettype);
		return (-1);
	}
	return (0);
}
Example #4
0
/*
 * Called to set up service over a particular transport.
 */
void
do_one(char *provider, NETSELDECL(proto), struct protob *protobp0,
	int (*svc)(int, struct netbuf, struct netconfig *), int use_pmap)
{
	register int sock;
	struct protob *protobp;
	struct netbuf *retaddr;
	struct netconfig *retnconf;
	struct netbuf addrmask;
	int vers;
	int err;
	int l;

	if (provider)
		sock = bind_to_provider(provider, protobp0->serv, &retaddr,
		    &retnconf);
	else
		sock = bind_to_proto(proto, protobp0->serv, &retaddr,
		    &retnconf);

	if (sock == -1) {
		(void) syslog(LOG_ERR,
	"Cannot establish %s service over %s: transport setup problem.",
		    protobp0->serv, provider ? provider : proto);
		return;
	}

	if (set_addrmask(sock, retnconf, &addrmask) < 0) {
		(void) syslog(LOG_ERR,
		    "Cannot set address mask for %s", retnconf->nc_netid);
		return;
	}

	/*
	 * Register all versions of the programs in the protocol block list.
	 */
	l = strlen(NC_UDP);
	for (protobp = protobp0; protobp; protobp = protobp->next) {
		for (vers = protobp->versmin; vers <= protobp->versmax;
		    vers++) {
			if ((protobp->program == NFS_PROGRAM ||
			    protobp->program == NFS_ACL_PROGRAM) &&
			    vers == NFS_V4 &&
			    strncasecmp(retnconf->nc_proto, NC_UDP, l) == 0)
				continue;

			if (protobp->flags & PROTOB_NO_REGISTER)
				continue;

			if (use_pmap) {
				/*
				 * Note that if we're using a portmapper
				 * instead of rpcbind then we can't do an
				 * unregister operation here.
				 *
				 * The reason is that the portmapper unset
				 * operation removes all the entries for a
				 * given program/version regardelss of
				 * transport protocol.
				 *
				 * The caller of this routine needs to ensure
				 * that __pmap_unset() has been called for all
				 * program/version service pairs they plan
				 * to support before they start registering
				 * each program/version/protocol triplet.
				 */
				(void) __pmap_set(protobp->program, vers,
				    retnconf, retaddr);
			} else {
				(void) rpcb_unset(protobp->program, vers,
				    retnconf);
				(void) rpcb_set(protobp->program, vers,
				    retnconf, retaddr);
			}
		}
	}

	if (retnconf->nc_semantics == NC_TPI_CLTS) {
		/* Don't drop core if supporting module(s) aren't loaded. */
		(void) signal(SIGSYS, SIG_IGN);

		/*
		 * svc() doesn't block, it returns success or failure.
		 */

		if (svc == NULL && Mysvc4 != NULL)
			err = (*Mysvc4)(sock, &addrmask, retnconf,
			    NFS4_SETPORT|NFS4_KRPC_START, retaddr);
		else
			err = (*svc)(sock, addrmask, retnconf);

		if (err < 0) {
			(void) syslog(LOG_ERR,
			    "Cannot establish %s service over <file desc."
			    " %d, protocol %s> : %m. Exiting",
			    protobp0->serv, sock, retnconf->nc_proto);
			exit(1);
		}
	}

	/*
	 * We successfully set up the server over this transport.
	 * Add this descriptor to the one being polled on.
	 */
	add_to_poll_list(sock, retnconf);
}
Example #5
0
/*
 * Called to set up service over a particular transport.
 */
void
do_one(char *provider, NETSELDECL(proto), struct protob *protobp0,
	int (*svc)(int, struct netbuf, struct netconfig *))
{
	register int sock;
	struct protob *protobp;
	struct netbuf *retaddr;
	struct netconfig *retnconf;
	struct netbuf addrmask;
	int vers;
	int err;
	int l;

	if (provider)
		sock = bind_to_provider(provider, protobp0->serv, &retaddr,
					&retnconf);
	else
		sock = bind_to_proto(proto, protobp0->serv, &retaddr,
					&retnconf);

	if (sock == -1) {
		(void) syslog(LOG_ERR,
	"Cannot establish %s service over %s: transport setup problem.",
			protobp0->serv, provider ? provider : proto);
		return;
	}

	if (set_addrmask(sock, retnconf, &addrmask) < 0) {
		(void) syslog(LOG_ERR,
		    "Cannot set address mask for %s", retnconf->nc_netid);
		return;
	}

	/*
	 * Register all versions of the programs in the protocol block list.
	 */
	l = strlen(NC_UDP);
	for (protobp = protobp0; protobp; protobp = protobp->next) {
		for (vers = protobp->versmin; vers <= protobp->versmax;
			vers++) {
			if ((protobp->program == NFS_PROGRAM ||
				protobp->program == NFS_ACL_PROGRAM) &&
				vers == NFS_V4 &&
				strncasecmp(retnconf->nc_proto, NC_UDP, l) == 0)
				continue;

			(void) rpcb_unset(protobp->program, vers, retnconf);
			(void) rpcb_set(protobp->program, vers, retnconf,
					retaddr);
		}
	}

	if (retnconf->nc_semantics == NC_TPI_CLTS) {
		/* Don't drop core if supporting module(s) aren't loaded. */
		(void) signal(SIGSYS, SIG_IGN);

		/*
		 * svc() doesn't block, it returns success or failure.
		 */

		if (svc == NULL && Mysvc4 != NULL)
			err = (*Mysvc4)(sock, &addrmask, retnconf,
					NFS4_SETPORT|NFS4_KRPC_START, retaddr);
		else
			err = (*svc)(sock, addrmask, retnconf);

		if (err < 0) {
			(void) syslog(LOG_ERR,
				"Cannot establish %s service over <file desc."
				" %d, protocol %s> : %m. Exiting",
				protobp0->serv, sock, retnconf->nc_proto);
			exit(1);
		}
	}

	/*
	 * We successfully set up the server over this transport.
	 * Add this descriptor to the one being polled on.
	 */
	add_to_poll_list(sock, retnconf);
}
Example #6
0
void
cleanup(int sig __unused)
{
	(void) rpcb_unset(SPRAYPROG, SPRAYVERS, NULL);
	exit(0);
}
Example #7
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 #8
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 #9
0
int
main(int argc, char *argv[])
{
	SVCXPRT *transp;
	int ok;
	struct sockaddr_storage from;
	socklen_t fromlen;

        if (argc == 2)
                closedown = atoi(argv[1]);
        if (closedown <= 0)
                closedown = 20;

        /*
         * See if inetd started us
         */
	fromlen = sizeof(from);
        if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0) {
                from_inetd = 0;
        }

        if (!from_inetd) {
                daemon(0, 0);

                (void)rpcb_unset(RSTATPROG, RSTATVERS_TIME, NULL);
                (void)rpcb_unset(RSTATPROG, RSTATVERS_SWTCH, NULL);
                (void)rpcb_unset(RSTATPROG, RSTATVERS_ORIG, NULL);

		(void) signal(SIGINT, cleanup);
		(void) signal(SIGTERM, cleanup);
		(void) signal(SIGHUP, cleanup);
        }

        openlog("rpc.rstatd", LOG_CONS|LOG_PID, LOG_DAEMON);

	if (from_inetd) {
		transp = svc_tli_create(0, NULL, NULL, 0, 0);
		if (transp == NULL) {
			syslog(LOG_ERR, "cannot create udp service.");
			exit(1);
		}
		ok = svc_reg(transp, RSTATPROG, RSTATVERS_TIME,
			     rstat_service, NULL);
	} else
		ok = svc_create(rstat_service,
				RSTATPROG, RSTATVERS_TIME, "udp");
	if (!ok) {
		syslog(LOG_ERR, "unable to register (RSTATPROG, RSTATVERS_TIME, %s)", (!from_inetd)?"udp":"(inetd)");
  		exit(1);
	}
	if (from_inetd)
		ok = svc_reg(transp, RSTATPROG, RSTATVERS_SWTCH,
			     rstat_service, NULL);
	else
		ok = svc_create(rstat_service,
				RSTATPROG, RSTATVERS_SWTCH, "udp");
	if (!ok) {
		syslog(LOG_ERR, "unable to register (RSTATPROG, RSTATVERS_SWTCH, %s)", (!from_inetd)?"udp":"(inetd)");
  		exit(1);
	}
	if (from_inetd)
		ok = svc_reg(transp, RSTATPROG, RSTATVERS_ORIG,
			     rstat_service, NULL);
	else
		ok = svc_create(rstat_service,
				RSTATPROG, RSTATVERS_ORIG, "udp");
	if (!ok) {
		syslog(LOG_ERR, "unable to register (RSTATPROG, RSTATVERS_ORIG, %s)", (!from_inetd)?"udp":"(inetd)");
  		exit(1);
	}

        svc_run();
	syslog(LOG_ERR, "svc_run returned");
	exit(1);
}