Beispiel #1
0
/**
 * nfs_svc_create - start up RPC svc listeners
 * @name: C string containing name of new service
 * @program: RPC program number to register
 * @version: RPC version number to register
 * @dispatch: address of function that handles incoming RPC requests
 * @port: if not zero, transport listens on this port
 *
 * Sets up network transports for receiving RPC requests, and starts
 * the RPC dispatcher.  Returns the number of started network transports.
 */
unsigned int
nfs_svc_create(char *name, const rpcprog_t program, const rpcvers_t version,
               void (*dispatch)(struct svc_req *, SVCXPRT *),
               const uint16_t port)
{
    const struct sigaction create_sigaction = {
        .sa_handler	= SIG_IGN,
    };
    unsigned int visible, up, servport;
    struct netconfig *nconf;
    void *handlep;

    /*
     * Ignore SIGPIPE to avoid exiting sideways when peers
     * close their TCP connection while we're trying to reply
     * to them.
     */
    (void)sigaction(SIGPIPE, &create_sigaction, NULL);

    handlep = setnetconfig();
    if (handlep == NULL) {
        xlog(L_ERROR, "Failed to access local netconfig database: %s",
             nc_sperror());
        return 0;
    }

    visible = 0;
    up = 0;
    while ((nconf = getnetconfig(handlep)) != NULL) {
        if (!(nconf->nc_flag & NC_VISIBLE))
            continue;
        visible++;
        if (port == 0)
            servport = getservport(program, nconf->nc_proto);
        else
            servport = port;

        up += svc_create_nconf(name, program, version, dispatch,
                               servport, nconf);
    }

    if (visible == 0)
        xlog(L_ERROR, "Failed to find any visible netconfig entries");

    if (endnetconfig(handlep) == -1)
        xlog(L_ERROR, "Failed to close local netconfig database: %s",
             nc_sperror());

    return up;
}
Beispiel #2
0
/* Unregister all the registrations done by register_rpc_service */
void
unregister_rpc_service(const char *fmri, const rpc_info_t *rpc)
{
	int			ver;
	struct netconfig	*nconf;

	debug_msg("Entering unregister_rpc_service, instance: %s", fmri);

	if ((nconf = getnetconfigent(rpc->netid)) == NULL) {
		/*
		 * Don't output an error message if getnetconfigent() fails for
		 * a v6 netid when an IPv6 interface isn't configured.
		 */
		if (!(is_v6_netid(rpc->netid) && !can_use_af(AF_INET6))) {
			error_msg(gettext(
			    "Failed to lookup netid '%s' for instance %s: %s"),
			    rpc->netid, fmri, nc_sperror());
		}
		return;
	}

	for (ver = rpc->lowver; ver <= rpc->highver; ver++)
		(void) rpcb_unset(rpc->prognum, ver, nconf);

	freenetconfigent(nconf);
}
Beispiel #3
0
int
_des_crypt_call(char *buf, int len, struct desparams *dparms)
{
	CLIENT *clnt;
	desresp  *result_1;
	desargs  des_crypt_1_arg;
	struct netconfig *nconf;
	void *localhandle;
	int stat;

	nconf = NULL;
	localhandle = setnetconfig();
	while ((nconf = getnetconfig(localhandle)) != NULL) {
		if (nconf->nc_protofmly != NULL &&
		     strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0)
			break;
	}
	if (nconf == NULL) {
		warnx("getnetconfig: %s", nc_sperror());
		endnetconfig(localhandle);
		return(DESERR_HWERROR);
	}
	clnt = clnt_tp_create(NULL, CRYPT_PROG, CRYPT_VERS, nconf);
	if (clnt == (CLIENT *) NULL) {
		endnetconfig(localhandle);
		return(DESERR_HWERROR);
	}
	endnetconfig(localhandle);

	des_crypt_1_arg.desbuf.desbuf_len = len;
	des_crypt_1_arg.desbuf.desbuf_val = buf;
	des_crypt_1_arg.des_dir = (dparms->des_dir == ENCRYPT) ? ENCRYPT_DES : DECRYPT_DES;
	des_crypt_1_arg.des_mode = (dparms->des_mode == CBC) ? CBC_DES : ECB_DES;
	bcopy(dparms->des_ivec, des_crypt_1_arg.des_ivec, 8);
	bcopy(dparms->des_key, des_crypt_1_arg.des_key, 8);

	result_1 = des_crypt_1(&des_crypt_1_arg, clnt);
	if (result_1 == (desresp *) NULL) {
		clnt_destroy(clnt);
		return(DESERR_HWERROR);
	}

	stat = result_1->stat;

	if (result_1->stat == DESERR_NONE ||
	    result_1->stat == DESERR_NOHWDEVICE) {
		bcopy(result_1->desbuf.desbuf_val, buf, len);
		bcopy(result_1->des_ivec, dparms->des_ivec, 8);
	}

	clnt_freeres(clnt, (xdrproc_t)xdr_desresp, result_1);
	clnt_destroy(clnt);

	return(stat);
}
Beispiel #4
0
/*
 * Determines the availability of rpc.yppasswdd.  Returns -1 for not
 * available (or unable to determine), 0 for available, 1 for available in
 * master mode.
 */
int
ypclnt_havepasswdd(ypclnt_t *ypclnt)
{
	struct netconfig *nc = NULL;
	void *localhandle = 0;
	CLIENT *clnt = NULL;
	int ret;

	/* check if rpc.yppasswdd is running */
	if (getrpcport(ypclnt->server, YPPASSWDPROG,
		YPPASSWDPROC_UPDATE, IPPROTO_UDP) == 0) {
		ypclnt_error(ypclnt, __func__, "no rpc.yppasswdd on server");
		return (-1);
	}

	/* if we're not root, use remote method */
	if (getuid() != 0)
		return (0);

	/* try to connect to rpc.yppasswdd */
	localhandle = setnetconfig();
	while ((nc = getnetconfig(localhandle)) != NULL) {
		if (nc->nc_protofmly != NULL &&
			strcmp(nc->nc_protofmly, NC_LOOPBACK) == 0)
				break;
	}
	if (nc == NULL) {
		ypclnt_error(ypclnt, __func__,
		    "getnetconfig: %s", nc_sperror());
		ret = 0;
		goto done;
	}
	if ((clnt = clnt_tp_create(NULL, MASTER_YPPASSWDPROG,
	    MASTER_YPPASSWDVERS, nc)) == NULL) {
		ypclnt_error(ypclnt, __func__,
		    "failed to connect to rpc.yppasswdd: %s",
		    clnt_spcreateerror(ypclnt->server));
		ret = 0;
		goto done;
	} else 
		ret = 1;

done:
	if (clnt != NULL) {
		clnt_destroy(clnt);
	}
	endnetconfig(localhandle);
	return (ret);
}
Beispiel #5
0
/*
 * Registers with rpcbind the program number with all versions, from low to
 * high, with the netid, all specified in 'rpc'. If registration fails,
 * returns -1, else 0.
 */
int
register_rpc_service(const char *fmri, const rpc_info_t *rpc)
{
	struct netconfig	*nconf;
	int			ver;

	debug_msg("Entering register_rpc_service: instance: %s", fmri);

	if ((nconf = getnetconfigent(rpc->netid)) == NULL) {
		/*
		 * Check whether getnetconfigent() failed as a result of
		 * having no IPv6 interfaces configured for a v6 netid, or
		 * as a result of a 'real' error, and output an appropriate
		 * message with an appropriate severity.
		 */
		if (is_v6_netid(rpc->netid) && !can_use_af(AF_INET6)) {
			warn_msg(gettext(
			    "Couldn't register netid %s for RPC instance %s "
			    "because no IPv6 interfaces are plumbed"),
			    rpc->netid, fmri);
		} else {
			error_msg(gettext(
			    "Failed to lookup netid '%s' for instance %s: %s"),
			    rpc->netid, fmri, nc_sperror());
		}
		return (-1);
	}

	for (ver = rpc->lowver; ver <= rpc->highver; ver++) {
		if (!rpcb_set(rpc->prognum, ver, nconf, &(rpc->netbuf))) {
			error_msg(gettext("Failed to register version %d "
			    "of RPC service instance %s, netid %s"), ver,
			    fmri, rpc->netid);

			for (ver--; ver >= rpc->lowver; ver--)
				(void) rpcb_unset(rpc->prognum, ver, nconf);

			freenetconfigent(nconf);
			return (-1);
		}
	}

	freenetconfigent(nconf);
	return (0);
}
Beispiel #6
0
static int
yppasswd_local(ypclnt_t *ypclnt, const struct passwd *pwd)
{
	struct master_yppasswd yppwd;
	struct rpc_err rpcerr;
	struct netconfig *nc = NULL;
	void *localhandle = 0;
	CLIENT *clnt = NULL;
	int ret, *result;

	/* fill the master_yppasswd structure */
	memset(&yppwd, 0, sizeof yppwd);
	yppwd.newpw.pw_uid = pwd->pw_uid;
	yppwd.newpw.pw_gid = pwd->pw_gid;
	yppwd.newpw.pw_change = pwd->pw_change;
	yppwd.newpw.pw_expire = pwd->pw_expire;
	yppwd.newpw.pw_fields = pwd->pw_fields;
	yppwd.oldpass = strdup("");
	yppwd.domain = strdup(ypclnt->domain);
	if ((yppwd.newpw.pw_name = strdup(pwd->pw_name)) == NULL ||
	    (yppwd.newpw.pw_passwd = strdup(pwd->pw_passwd)) == NULL ||
	    (yppwd.newpw.pw_class = strdup(pwd->pw_class)) == NULL ||
	    (yppwd.newpw.pw_gecos = strdup(pwd->pw_gecos)) == NULL ||
	    (yppwd.newpw.pw_dir = strdup(pwd->pw_dir)) == NULL ||
	    (yppwd.newpw.pw_shell = strdup(pwd->pw_shell)) == NULL) {
		ypclnt_error(ypclnt, __func__, strerror(errno));
		ret = -1;
		goto done;
	}

	/* connect to rpc.yppasswdd */
	localhandle = setnetconfig();
	while ((nc = getnetconfig(localhandle)) != NULL) {
		if (nc->nc_protofmly != NULL &&
		    strcmp(nc->nc_protofmly, NC_LOOPBACK) == 0)
			break;
	}
	if (nc == NULL) {
		ypclnt_error(ypclnt, __func__,
		    "getnetconfig: %s", nc_sperror());
		ret = -1;
		goto done;
	}
	if ((clnt = clnt_tp_create(NULL, MASTER_YPPASSWDPROG,
	    MASTER_YPPASSWDVERS, nc)) == NULL) {
		ypclnt_error(ypclnt, __func__,
		    "failed to connect to rpc.yppasswdd: %s",
		    clnt_spcreateerror(ypclnt->server));
		ret = -1;
		goto done;
	}
	clnt->cl_auth = authunix_create_default();

	/* request the update */
	result = yppasswdproc_update_master_1(&yppwd, clnt);

	/* check for RPC errors */
	clnt_geterr(clnt, &rpcerr);
	if (rpcerr.re_status != RPC_SUCCESS) {
		ypclnt_error(ypclnt, __func__,
		    "NIS password update failed: %s",
		    clnt_sperror(clnt, ypclnt->server));
		ret = -1;
		goto done;
	}

	/* check the result of the update */
	if (result == NULL || *result != 0) {
		ypclnt_error(ypclnt, __func__,
		    "NIS password update failed");
		/* XXX how do we get more details? */
		ret = -1;
		goto done;
	}

	ypclnt_error(ypclnt, NULL, NULL);
	ret = 0;

 done:
	if (clnt != NULL) {
		auth_destroy(clnt->cl_auth);
		clnt_destroy(clnt);
	}
	endnetconfig(localhandle);
	free(yppwd.newpw.pw_name);
	if (yppwd.newpw.pw_passwd != NULL) {
		memset(yppwd.newpw.pw_passwd, 0, strlen(yppwd.newpw.pw_passwd));
		free(yppwd.newpw.pw_passwd);
	}
	free(yppwd.newpw.pw_class);
	free(yppwd.newpw.pw_gecos);
	free(yppwd.newpw.pw_dir);
	free(yppwd.newpw.pw_shell);
	if (yppwd.oldpass != NULL) {
		memset(yppwd.oldpass, 0, strlen(yppwd.oldpass));
		free(yppwd.oldpass);
	}
	return (ret);
}
Beispiel #7
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 */
}
Beispiel #8
0
/*
 * Prints a message onto standard error describing the reason for failure.
 */
void
nc_perror(const char *s)
{
    fprintf(stderr, "%s: %s\n", s, nc_sperror());
}
Beispiel #9
0
/*
 * Create an rpc client attached to the mount daemon.
 */
CLIENT *
get_mount_client(char *host, struct sockaddr_in *unused_sin, struct timeval *tv, int *sock, u_long mnt_version)
{
  CLIENT *client;
  struct netbuf nb;
  struct netconfig *nc = NULL;
  struct sockaddr_in sin;

  nb.maxlen = sizeof(sin);
  nb.buf = (char *) &sin;

  /*
   * First try a TCP handler
   */

  /*
   * Find mountd address on TCP
   */
  if ((nc = getnetconfigent(NC_TCP)) == NULL) {
    plog(XLOG_ERROR, "getnetconfig for tcp failed: %s", nc_sperror());
    goto tryudp;
  }
  if (!rpcb_getaddr(MOUNTPROG, mnt_version, nc, &nb, host)) {
    /*
     * don't print error messages here, since mountd might legitimately
     * serve udp only
     */
    goto tryudp;
  }
  /*
   * Create privileged TCP socket
   */
  *sock = t_open(nc->nc_device, O_RDWR, 0);

  if (*sock < 0) {
    plog(XLOG_ERROR, "t_open %s: %m", nc->nc_device);
    goto tryudp;
  }
  if (bind_resv_port(*sock, (u_short *) 0) < 0)
    plog(XLOG_ERROR, "couldn't bind mountd socket to privileged port");

  if ((client = clnt_vc_create(*sock, &nb, MOUNTPROG, mnt_version, 0, 0))
      == (CLIENT *) NULL) {
    plog(XLOG_ERROR, "clnt_vc_create failed");
    t_close(*sock);
    goto tryudp;
  }
  /* tcp succeeded */
  dlog("get_mount_client: using tcp, port %d", sin.sin_port);
  if (nc)
    freenetconfigent(nc);
  return client;

tryudp:
  /* first free possibly previously allocated netconfig entry */
  if (nc)
    freenetconfigent(nc);

  /*
   * TCP failed so try UDP
   */

  /*
   * Find mountd address on UDP
   */
  if ((nc = getnetconfigent(NC_UDP)) == NULL) {
    plog(XLOG_ERROR, "getnetconfig for udp failed: %s", nc_sperror());
    goto badout;
  }
  if (!rpcb_getaddr(MOUNTPROG, mnt_version, nc, &nb, host)) {
    plog(XLOG_ERROR, "%s",
	 clnt_spcreateerror("couldn't get mountd address on udp"));
    goto badout;
  }
  /*
   * Create privileged UDP socket
   */
  *sock = t_open(nc->nc_device, O_RDWR, 0);

  if (*sock < 0) {
    plog(XLOG_ERROR, "t_open %s: %m", nc->nc_device);
    goto badout;		/* neither tcp not udp succeeded */
  }
  if (bind_resv_port(*sock, (u_short *) 0) < 0)
    plog(XLOG_ERROR, "couldn't bind mountd socket to privileged port");

  if ((client = clnt_dg_create(*sock, &nb, MOUNTPROG, mnt_version, 0, 0))
      == (CLIENT *) NULL) {
    plog(XLOG_ERROR, "clnt_dg_create failed");
    t_close(*sock);
    goto badout;		/* neither tcp not udp succeeded */
  }
  if (clnt_control(client, CLSET_RETRY_TIMEOUT, (char *) tv) == FALSE) {
    plog(XLOG_ERROR, "clnt_control CLSET_RETRY_TIMEOUT for udp failed");
    clnt_destroy(client);
    goto badout;		/* neither tcp not udp succeeded */
  }
  /* udp succeeded */
  dlog("get_mount_client: using udp, port %d", sin.sin_port);
  return client;

badout:
  /* failed */
  if (nc)
    freenetconfigent(nc);
  return NULL;
}
Beispiel #10
0
/*
 * How to bind to reserved ports.
 * (port-only) version.
 */
int
bind_resv_port2(u_short *pp)
{
  int td, rc = -1, port;
  struct t_bind *treq, *tret;
  struct sockaddr_in *sin;
  extern char *t_errlist[];
  extern int t_errno;
  struct netconfig *nc = (struct netconfig *) NULL;
  voidp nc_handle;

  if ((nc_handle = setnetconfig()) == (voidp) NULL) {
    plog(XLOG_ERROR, "Cannot rewind netconfig: %s", nc_sperror());
    return -1;
  }
  /*
   * Search the netconfig table for INET/UDP.
   * This loop will terminate if there was an error in the /etc/netconfig
   * file or if you reached the end of the file without finding the udp
   * device.  Either way your machine has probably far more problems (for
   * example, you cannot have nfs v2 w/o UDP).
   */
  while (1) {
    if ((nc = getnetconfig(nc_handle)) == (struct netconfig *) NULL) {
      plog(XLOG_ERROR, "Error accessing getnetconfig: %s", nc_sperror());
      endnetconfig(nc_handle);
      return -1;
    }
    if (STREQ(nc->nc_protofmly, NC_INET) &&
	STREQ(nc->nc_proto, NC_UDP))
      break;
  }

  /*
   * This is the primary reason for the getnetconfig code above: to get the
   * correct device name to udp, and t_open a descriptor to be used in
   * t_bind below.
   */
  td = t_open(nc->nc_device, O_RDWR, (struct t_info *) 0);
  endnetconfig(nc_handle);

  if (td < 0) {
    plog(XLOG_ERROR, "t_open failed: %d: %s", t_errno, t_errlist[t_errno]);
    return -1;
  }
  treq = (struct t_bind *) t_alloc(td, T_BIND, T_ADDR);
  if (!treq) {
    plog(XLOG_ERROR, "t_alloc req");
    return -1;
  }
  tret = (struct t_bind *) t_alloc(td, T_BIND, T_ADDR);
  if (!tret) {
    t_free((char *) treq, T_BIND);
    plog(XLOG_ERROR, "t_alloc ret");
    return -1;
  }
  memset((char *) treq->addr.buf, 0, treq->addr.len);
  sin = (struct sockaddr_in *) treq->addr.buf;
  sin->sin_family = AF_INET;
  treq->qlen = 0;
  treq->addr.len = treq->addr.maxlen;
  errno = EADDRINUSE;
  port = IPPORT_RESERVED;

  do {
    --port;
    sin->sin_port = htons(port);
    rc = t_bind(td, treq, tret);
    if (rc < 0) {
      plog(XLOG_ERROR, "t_bind for port %d: %s", port, t_errlist[t_errno]);
    } else {
      if (memcmp(treq->addr.buf, tret->addr.buf, tret->addr.len) == 0)
	break;
      else
	t_unbind(td);
    }
  } while ((rc < 0 || errno == EADDRINUSE) && (int) port > IPPORT_RESERVED / 2);

  if (pp && rc == 0)
    *pp = port;
  t_free((char *) tret, T_BIND);
  t_free((char *) treq, T_BIND);
  return rc;
}
Beispiel #11
0
/*
 * We use our own private version of svc_create() which registers our services
 * only on loopback transports and enables an option whereby Solaris ucreds
 * are associated with each connection, permitting us to check privilege bits.
 */
static int
fmd_rpc_svc_create_local(void (*disp)(struct svc_req *, SVCXPRT *),
    rpcprog_t prog, rpcvers_t vers, uint_t ssz, uint_t rsz, int force)
{
	struct netconfig *ncp;
	struct netbuf buf;
	SVCXPRT *xprt;
	void *hdl;
	int fd, n = 0;

	char door[PATH_MAX];
	time_t tm;

	if ((hdl = setnetconfig()) == NULL) {
		fmd_error(EFMD_RPC_REG, "failed to iterate over "
		    "netconfig database: %s\n", nc_sperror());
		return (fmd_set_errno(EFMD_RPC_REG));
	}

	if (force)
		svc_unreg(prog, vers); /* clear stale rpcbind registrations */

	buf.buf = alloca(_SS_MAXSIZE);
	buf.maxlen = _SS_MAXSIZE;
	buf.len = 0;

	while ((ncp = getnetconfig(hdl)) != NULL) {
		if (strcmp(ncp->nc_protofmly, NC_LOOPBACK) != 0)
			continue;

		if (!force && rpcb_getaddr(prog, vers, ncp, &buf, HOST_SELF)) {
			(void) endnetconfig(hdl);
			return (fmd_set_errno(EFMD_RPC_BOUND));
		}

		if ((fd = t_open(ncp->nc_device, O_RDWR, NULL)) == -1) {
			fmd_error(EFMD_RPC_REG, "failed to open %s: %s\n",
			    ncp->nc_device, t_strerror(t_errno));
			continue;
		}

		svc_fd_negotiate_ucred(fd); /* enable ucred option on xprt */

		if ((xprt = svc_tli_create(fd, ncp, NULL, ssz, rsz)) == NULL) {
			(void) t_close(fd);
			continue;
		}

		if (svc_reg(xprt, prog, vers, disp, ncp) == FALSE) {
			fmd_error(EFMD_RPC_REG, "failed to register "
			    "rpc service on %s\n", ncp->nc_netid);
			svc_destroy(xprt);
			continue;
		}

		n++;
	}

	(void) endnetconfig(hdl);

	/*
	 * If we failed to register services (n == 0) because rpcbind is down,
	 * then check to see if the RPC door file exists before attempting an
	 * svc_door_create(), which cleverly destroys any existing door file.
	 * The RPC APIs have no stable errnos, so we use rpcb_gettime() as a
	 * hack to determine if rpcbind itself is down.
	 */
	if (!force && n == 0 && rpcb_gettime(HOST_SELF, &tm) == FALSE &&
	    snprintf(door, sizeof (door), RPC_DOOR_RENDEZVOUS,
	    prog, vers) > 0 && access(door, F_OK) == 0)
		return (fmd_set_errno(EFMD_RPC_BOUND));

	/*
	 * Attempt to create a door server for the RPC program as well.  Limit
	 * the maximum request size for the door transport to the receive size.
	 */
	if ((xprt = svc_door_create(disp, prog, vers, ssz)) == NULL) {
		fmd_error(EFMD_RPC_REG, "failed to create door for "
		    "rpc service 0x%lx/0x%lx\n", prog, vers);
	} else {
		(void) svc_control(xprt, SVCSET_CONNMAXREC, &rsz);
		n++;
	}

	return (n);
}