Пример #1
0
/*
 * find the IP address that can be used to connect autofs service to.
 */
static int
get_autofs_address(struct netconfig *ncp, struct t_bind *tbp)
{
  int ret;
  struct nd_addrlist *addrs = (struct nd_addrlist *) NULL;
  struct nd_hostserv service;

  service.h_host = HOST_SELF_CONNECT;
  service.h_serv = "autofs";

  ret = netdir_getbyname(ncp, &service, &addrs);

  if (ret) {
    plog(XLOG_FATAL, "get_autofs_address: cannot get local host address: %s", netdir_sperror());
    goto out;
  }

  /*
   * XXX: there may be more more than one address for this local
   * host.  Maybe something can be done with those.
   */
  tbp->addr.len = addrs->n_addrs->len;
  tbp->addr.maxlen = addrs->n_addrs->len;
  memcpy(tbp->addr.buf, addrs->n_addrs->buf, addrs->n_addrs->len);
  tbp->qlen = 8;		/* arbitrary? who cares really */

  /* all OK */
  netdir_free((voidp) addrs, ND_ADDRLIST);

out:
  return ret;
}
Пример #2
0
/*
 * find the IP address that can be used to connect to the local host
 */
void
amu_get_myaddress(struct in_addr *iap)
{
  int ret;
  voidp handlep;
  struct netconfig *ncp;
  struct nd_addrlist *addrs = (struct nd_addrlist *) NULL;
  struct nd_hostserv service;

  handlep = setnetconfig();
  ncp = getnetconfig(handlep);
  service.h_host = HOST_SELF_CONNECT;
  service.h_serv = (char *) NULL;

  ret = netdir_getbyname(ncp, &service, &addrs);

  if (ret || !addrs || addrs->n_cnt < 1) {
    plog(XLOG_FATAL, "cannot get local host address. using 127.0.0.1");
    iap->s_addr = 0x7f000001;
  } else {
    /*
     * XXX: there may be more more than one address for this local
     * host.  Maybe something can be done with those.
     */
    struct sockaddr_in *sinp = (struct sockaddr_in *) addrs->n_addrs[0].buf;
    iap->s_addr = htonl(sinp->sin_addr.s_addr);
  }

  endnetconfig(handlep);	/* free's up internal resources too */
  netdir_free((voidp) addrs, ND_ADDRLIST);
}
Пример #3
0
/*
 * find the IP address that can be used to connect to the local host
 */
void
amu_get_myaddress(struct in_addr *iap, const char *preferred_localhost)
{
  int ret;
  voidp handlep;
  struct netconfig *ncp;
  struct nd_addrlist *addrs = (struct nd_addrlist *) NULL;
  struct nd_hostserv service;

  handlep = setnetconfig();
  ncp = getnetconfig(handlep);
  service.h_host = (preferred_localhost ? (char *) preferred_localhost : HOST_SELF_CONNECT);
  service.h_serv = (char *) NULL;

  ret = netdir_getbyname(ncp, &service, &addrs);

  if (ret || !addrs || addrs->n_cnt < 1) {
    plog(XLOG_FATAL, "cannot get local host address. using 127.0.0.1");
    iap->s_addr = htonl(INADDR_LOOPBACK);
  } else {
    /*
     * XXX: there may be more more than one address for this local
     * host.  Maybe something can be done with those.
     */
    struct sockaddr_in *sinp = (struct sockaddr_in *) addrs->n_addrs[0].buf;
    char dq[20];
    if (preferred_localhost)
      plog(XLOG_INFO, "localhost_address \"%s\" requested, using %s",
	   preferred_localhost, inet_dquad(dq, sizeof(dq), iap->s_addr));
    iap->s_addr = sinp->sin_addr.s_addr; /* XXX: used to be htonl() */
  }

  endnetconfig(handlep);	/* free's up internal resources too */
  netdir_free((voidp) addrs, ND_ADDRLIST);
}
Пример #4
0
int
do_connect(const char *host, const char *serv)
{
	int					tfd, i;
	void				*handle;
	struct t_call		tcall;
	struct t_discon		tdiscon;
	struct netconfig	*ncp;
	struct nd_hostserv	hs;
	struct nd_addrlist	*alp;
	struct netbuf		*np;

	handle = Setnetpath();

	hs.h_host = (char *) host;
	hs.h_serv = (char *) serv;

	while ( (ncp = getnetpath(handle)) != NULL) {
		if (strcmp(ncp->nc_netid, "ticotsord") != 0)
			continue;

		if (netdir_getbyname(ncp, &hs, &alp) != 0)
			continue;

				/* try each server address */
		for (i = 0, np = alp->n_addrs; i < alp->n_cnt; i++, np++) {
			printf("device = %s\n", ncp->nc_device);
			if ( (tfd = t_open(ncp->nc_device, O_RDWR, NULL)) < 0)
				err_xti("t_open error for %s", ncp->nc_device);
		
			if (t_bind(tfd, NULL, NULL) < 0)
				err_xti("t_bind error");

			tcall.addr.len  = np->len;
			tcall.addr.buf  = np->buf;	/* pointer copy */
			printf("addr.len = %d\n", tcall.addr.len);
			printf("addr.buf = %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
					tcall.addr.buf[0], tcall.addr.buf[1],
					tcall.addr.buf[2], tcall.addr.buf[3],
					tcall.addr.buf[4], tcall.addr.buf[5],
					tcall.addr.buf[6], tcall.addr.buf[7],
					tcall.addr.buf[8], tcall.addr.buf[9],
					tcall.addr.buf[10]);
		}
		netdir_free(alp, ND_ADDRLIST);
	}
	endnetpath(handle);
	return(-1);
}
Пример #5
0
/*
 * Remove an entry from mounted list
 */
static void
umount(struct svc_req *rqstp)
{
	char *host, *path, *remove_path;
	char rpath[MAXPATHLEN];
	struct nd_hostservlist *clnames = NULL;
	SVCXPRT *transp;
	struct netbuf *nb;

	transp = rqstp->rq_xprt;
	path = NULL;
	if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) {
		svcerr_decode(transp);
		return;
	}
	errno = 0;
	if (!svc_sendreply(transp, xdr_void, (char *)NULL))
		log_cant_reply(transp);

	getclientsnames(transp, &nb, &clnames);
	if (clnames == NULL) {
		/*
		 * Without the hostname we can't do audit or delete
		 * this host from the mount entries.
		 */
		svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
		return;
	}
	host = clnames->h_hostservs[0].h_host;

	if (verbose)
		syslog(LOG_NOTICE, "UNMOUNT: %s unmounted %s", host, path);

	audit_mountd_umount(host, path);

	remove_path = rpath;	/* assume we will use the cannonical path */
	if (realpath(path, rpath) == NULL) {
		if (verbose)
			syslog(LOG_WARNING, "UNMOUNT: realpath: %s: %m ", path);
		remove_path = path;	/* use path provided instead */
	}

	mntlist_delete(host, remove_path);	/* remove from mount list */

	svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
	netdir_free(clnames, ND_HOSTSERVLIST);
}
Пример #6
0
/*
 * Create the client des authentication object. Obsoleted by
 * authdes_seccreate().
 */
AUTH *
authdes_create(char *servername, uint_t window, struct sockaddr_in *syncaddr,
	des_block *ckey)
{
	char *hostname = NULL;

	if (syncaddr) {
		/*
		 * Change addr to hostname, because that is the way
		 * new interface takes it.
		 */
		struct netconfig *nconf;
		struct netbuf nb_syncaddr;
		struct nd_hostservlist *hlist;
		AUTH *nauth;
		int fd;
		struct t_info tinfo;

		if ((nconf = __rpc_getconfip("udp")) == NULL &&
		    (nconf = __rpc_getconfip("tcp")) == NULL)
			goto fallback;

		/* Transform sockaddr_in to netbuf */
		if ((fd = t_open(nconf->nc_device, O_RDWR, &tinfo)) == -1) {
			(void) freenetconfigent(nconf);
			goto fallback;
		}
		(void) t_close(fd);
		nb_syncaddr.maxlen = nb_syncaddr.len =
			__rpc_get_a_size(tinfo.addr);
		nb_syncaddr.buf = (char *)syncaddr;
		if (netdir_getbyaddr(nconf, &hlist, &nb_syncaddr)) {
			(void) freenetconfigent(nconf);
			goto fallback;
		}
		if (hlist && hlist->h_cnt > 0 && hlist->h_hostservs)
			hostname = hlist->h_hostservs->h_host;
		nauth = authdes_seccreate(servername, window, hostname, ckey);
		(void) netdir_free((char *)hlist, ND_HOSTSERVLIST);
		(void) freenetconfigent(nconf);
		return (nauth);
	}
fallback:
	return (authdes_seccreate(servername, window, hostname, ckey));
}
Пример #7
0
int
udp_client(const char *host, const char *serv, void **vptr, socklen_t *lenp)
{
	int					tfd;
	void				*handle;
	struct netconfig	*ncp;
	struct nd_hostserv	hs;
	struct nd_addrlist	*alp;
	struct netbuf		*np;
	struct t_unitdata	*tudptr;

	handle = Setnetpath();

	hs.h_host = (char *) host;
	hs.h_serv = (char *) serv;

	while ( (ncp = getnetpath(handle)) != NULL) {
		if (strcmp(ncp->nc_proto, "udp") != 0)
			continue;

		if (netdir_getbyname(ncp, &hs, &alp) != 0)
			continue;

		tfd = T_open(ncp->nc_device, O_RDWR, NULL);
	
		T_bind(tfd, NULL, NULL);

		tudptr = T_alloc(tfd, T_UNITDATA, T_ADDR);

		np = alp->n_addrs;				/* use first server address */
		tudptr->addr.len = min(tudptr->addr.maxlen, np->len);
		memcpy(tudptr->addr.buf, np->buf, tudptr->addr.len);
	
		endnetpath(handle);
		netdir_free(alp, ND_ADDRLIST);

		*vptr = tudptr;				/* return pointer to t_unitdata{} */
		*lenp = tudptr->addr.maxlen;/* and size of addresses */
		return(tfd);
	}
	endnetpath(handle);
	return(-1);
}
Пример #8
0
int
udp_server(const char *host, const char *serv, socklen_t *addrlenp)
{
	int					tfd;
	void				*handle;
	struct t_bind		tbind;
	struct t_info		tinfo;
	struct netconfig	*ncp;
	struct nd_hostserv	hs;
	struct nd_addrlist	*alp;
	struct netbuf		*np;

	handle = Setnetconfig();

	hs.h_host = (host == NULL) ? HOST_SELF : (char *) host;
	hs.h_serv = (char *) serv;

	while ( (ncp = getnetconfig(handle)) != NULL &&
		   strcmp(ncp->nc_proto, "udp") != 0)
			;

	if (ncp == NULL)
		return(-1);

	if (netdir_getbyname(ncp, &hs, &alp) != 0)
		return(-2);
	np = alp->n_addrs;		/* use first address */

	tfd = T_open(ncp->nc_device, O_RDWR, &tinfo);

	tbind.addr = *np;		/* copy entire netbuf{} */
	tbind.qlen = 0;			/* not used for connectionless server */
	T_bind(tfd, &tbind, NULL);

	endnetconfig(handle);
	netdir_free(alp, ND_ADDRLIST);

	if (addrlenp)
		*addrlenp = tinfo.addr;	/* size of protocol addresses */
	return(tfd);
}
Пример #9
0
void
log_cant_reply(SVCXPRT *transp)
{
	int saverrno;
	struct nd_hostservlist *clnames = NULL;
	register char *host;
	struct netbuf *nb;

	saverrno = errno;	/* save error code */
	getclientsnames(transp, &nb, &clnames);
	if (clnames == NULL)
		return;
	host = clnames->h_hostservs->h_host;

	errno = saverrno;
	if (errno == 0)
		syslog(LOG_ERR, "couldn't send reply to %s", host);
	else
		syslog(LOG_ERR, "couldn't send reply to %s: %m", host);

	netdir_free(clnames, ND_HOSTSERVLIST);
}
Пример #10
0
/*
 * Remove all entries for one machine from mounted list
 */
static void
umountall(struct svc_req *rqstp)
{
	struct nd_hostservlist *clnames = NULL;
	SVCXPRT *transp;
	char *host;
	struct netbuf *nb;

	transp = rqstp->rq_xprt;
	if (!svc_getargs(transp, xdr_void, NULL)) {
		svcerr_decode(transp);
		return;
	}
	/*
	 * We assume that this call is asynchronous and made via rpcbind
	 * callit routine.  Therefore return control immediately. The error
	 * causes rpcbind to remain silent, as opposed to every machine
	 * on the net blasting the requester with a response.
	 */
	svcerr_systemerr(transp);
	getclientsnames(transp, &nb, &clnames);
	if (clnames == NULL) {
		/* Can't do anything without the name of the client */
		return;
	}

	host = clnames->h_hostservs[0].h_host;

	/*
	 * Remove all hosts entries from mount list
	 */
	mntlist_delete_all(host);

	if (verbose)
		syslog(LOG_NOTICE, "UNMOUNTALL: from %s", host);

	netdir_free(clnames, ND_HOSTSERVLIST);
}
Пример #11
0
/*
 * __yp_all_cflookup() is a variant of the yp_all() code,
 * which adds a 'hardlookup' parameter. This parameter is passed
 * to __yp_dobind_cflookup(), and determines whether the server
 * binding attempt is hard (try forever) of soft (retry a compiled-
 * in number of times).
 */
int
__yp_all_cflookup(char *domain, char *map, struct ypall_callback *callback,
								int hardlookup)
{
	size_t domlen;
	size_t maplen;
	struct ypreq_nokey req;
	int reason;
	struct dom_binding *pdomb;
	enum clnt_stat s;
	CLIENT *allc;
	char server_name[MAXHOSTNAMELEN];
	char errbuf[BUFSIZ];

	if ((map == NULL) || (domain == NULL))
		return (YPERR_BADARGS);

	domlen = strlen(domain);
	maplen = strlen(map);

	if ((domlen == 0) || (domlen > YPMAXDOMAIN) ||
	    (maplen == 0) || (maplen > YPMAXMAP) ||
	    (callback == NULL))
		return (YPERR_BADARGS);

	if (reason = __yp_dobind_cflookup(domain, &pdomb, hardlookup))
		return (reason);

	if (pdomb->dom_binding->ypbind_hi_vers < YPVERS) {
		__yp_rel_binding(pdomb);
		return (YPERR_VERS);
	}
	(void) mutex_lock(&pdomb->server_name_lock);
	if (!pdomb->dom_binding->ypbind_servername) {
		(void) mutex_unlock(&pdomb->server_name_lock);
		__yp_rel_binding(pdomb);
		syslog(LOG_ERR, "yp_all: failed to get server's name\n");
		return (YPERR_RPC);
	}
	(void) strcpy(server_name, pdomb->dom_binding->ypbind_servername);
	(void) mutex_unlock(&pdomb->server_name_lock);
	if (strcmp(server_name, nullstring) == 0) {
		/*
		 * This is the case where ypbind is running in broadcast mode,
		 * we have to do the jugglery to get the
		 * ypserv's address on COTS transport based
		 * on the CLTS address ypbind gave us !
		 */

		struct nd_hostservlist *nhs;

		if (netdir_getbyaddr(pdomb->dom_binding->ypbind_nconf,
			&nhs, pdomb->dom_binding->ypbind_svcaddr) != ND_OK) {
			syslog(LOG_ERR,
				"yp_all: failed to get server's name\n");
			__yp_rel_binding(pdomb);
			return (YPERR_RPC);
		}
		/* check server name again, some other thread may have set it */
		(void) mutex_lock(&pdomb->server_name_lock);
		if (strcmp(pdomb->dom_binding->ypbind_servername,
					nullstring) == 0) {
			pdomb->dom_binding->ypbind_servername =
				(char *)strdup(nhs->h_hostservs->h_host);
		}
		(void) strcpy(server_name,
		    pdomb->dom_binding->ypbind_servername);
		(void) mutex_unlock(&pdomb->server_name_lock);
		netdir_free((char *)nhs, ND_HOSTSERVLIST);
	}
	__yp_rel_binding(pdomb);
	if ((allc = clnt_create(server_name, YPPROG,
		YPVERS, "circuit_n")) == NULL) {
			(void) snprintf(errbuf, BUFSIZ, "yp_all \
- transport level create failure for domain %s / map %s", domain, map);
			syslog(LOG_ERR, "%s", clnt_spcreateerror(errbuf));
			return (YPERR_RPC);
	}
Пример #12
0
/*
 * Called to read and interpret the event on a connectionless descriptor.
 * Returns 0 if successful, or a UNIX error code if failure.
 */
static int
do_poll_clts_action(int fd, int conn_index)
{
	int error;
	int ret;
	int flags;
	struct netconfig *nconf = &conn_polled[conn_index].nc;
	static struct t_unitdata *unitdata = NULL;
	static struct t_uderr *uderr = NULL;
	static int oldfd = -1;
	struct nd_hostservlist *host = NULL;
	struct strbuf ctl[1], data[1];
	/*
	 * We just need to have some space to consume the
	 * message in the event we can't use the TLI interface to do the
	 * job.
	 *
	 * We flush the message using getmsg(). For the control part
	 * we allocate enough for any TPI header plus 32 bytes for address
	 * and options. For the data part, there is nothing magic about
	 * the size of the array, but 256 bytes is probably better than
	 * 1 byte, and we don't expect any data portion anyway.
	 *
	 * If the array sizes are too small, we handle this because getmsg()
	 * (called to consume the message) will return MOREDATA|MORECTL.
	 * Thus we just call getmsg() until it's read the message.
	 */
	char ctlbuf[sizeof (union T_primitives) + 32];
	char databuf[256];

	/*
	 * If this is the same descriptor as the last time
	 * do_poll_clts_action was called, we can save some
	 * de-allocation and allocation.
	 */
	if (oldfd != fd) {
		oldfd = fd;

		if (unitdata) {
			(void) t_free((char *)unitdata, T_UNITDATA);
			unitdata = NULL;
		}
		if (uderr) {
			(void) t_free((char *)uderr, T_UDERROR);
			uderr = NULL;
		}
	}

	/*
	 * Allocate a unitdata structure for receiving the event.
	 */
	if (unitdata == NULL) {
		/* LINTED pointer alignment */
		unitdata = (struct t_unitdata *)t_alloc(fd, T_UNITDATA, T_ALL);
		if (unitdata == NULL) {
			if (t_errno == TSYSERR) {
				/*
				 * Save the error code across
				 * syslog(), just in case
				 * syslog() gets its own error
				 * and therefore overwrites errno.
				 */
				error = errno;
				(void) syslog(LOG_ERR,
	"t_alloc(file descriptor %d/transport %s, T_UNITDATA) failed: %m",
				    fd, nconf->nc_proto);
				return (error);
			}
			(void) syslog(LOG_ERR,
"t_alloc(file descriptor %d/transport %s, T_UNITDATA) failed TLI error %d",
			    fd, nconf->nc_proto, t_errno);
			goto flush_it;
		}
	}

try_again:
	flags = 0;

	/*
	 * The idea is we wait for T_UNITDATA_IND's. Of course,
	 * we don't get any, because rpcmod filters them out.
	 * However, we need to call t_rcvudata() to let TLI
	 * tell us we have a T_UDERROR_IND.
	 *
	 * algorithm is:
	 * 	t_rcvudata(), expecting TLOOK.
	 * 	t_look(), expecting T_UDERR.
	 * 	t_rcvuderr(), expecting success (0).
	 * 	expand destination address into ASCII,
	 *	and dump it.
	 */

	ret = t_rcvudata(fd, unitdata, &flags);
	if (ret == 0 || t_errno == TBUFOVFLW) {
		(void) syslog(LOG_WARNING,
"t_rcvudata(file descriptor %d/transport %s) got unexpected data, %d bytes",
		    fd, nconf->nc_proto, unitdata->udata.len);

		/*
		 * Even though we don't expect any data, in case we do,
		 * keep reading until there is no more.
		 */
		if (flags & T_MORE)
			goto try_again;

		return (0);
	}

	switch (t_errno) {
	case TNODATA:
		return (0);
	case TSYSERR:
		/*
		 * System errors are returned to caller.
		 * Save the error code across
		 * syslog(), just in case
		 * syslog() gets its own error
		 * and therefore overwrites errno.
		 */
		error = errno;
		(void) syslog(LOG_ERR,
		    "t_rcvudata(file descriptor %d/transport %s) %m",
		    fd, nconf->nc_proto);
		return (error);
	case TLOOK:
		break;
	default:
		(void) syslog(LOG_ERR,
		"t_rcvudata(file descriptor %d/transport %s) TLI error %d",
		    fd, nconf->nc_proto, t_errno);
		goto flush_it;
	}

	ret = t_look(fd);
	switch (ret) {
	case 0:
		return (0);
	case -1:
		/*
		 * System errors are returned to caller.
		 */
		if (t_errno == TSYSERR) {
			/*
			 * Save the error code across
			 * syslog(), just in case
			 * syslog() gets its own error
			 * and therefore overwrites errno.
			 */
			error = errno;
			(void) syslog(LOG_ERR,
			    "t_look(file descriptor %d/transport %s) %m",
			    fd, nconf->nc_proto);
			return (error);
		}
		(void) syslog(LOG_ERR,
		    "t_look(file descriptor %d/transport %s) TLI error %d",
		    fd, nconf->nc_proto, t_errno);
		goto flush_it;
	case T_UDERR:
		break;
	default:
		(void) syslog(LOG_WARNING,
	"t_look(file descriptor %d/transport %s) returned %d not T_UDERR (%d)",
		    fd, nconf->nc_proto, ret, T_UDERR);
	}

	if (uderr == NULL) {
		/* LINTED pointer alignment */
		uderr = (struct t_uderr *)t_alloc(fd, T_UDERROR, T_ALL);
		if (uderr == NULL) {
			if (t_errno == TSYSERR) {
				/*
				 * Save the error code across
				 * syslog(), just in case
				 * syslog() gets its own error
				 * and therefore overwrites errno.
				 */
				error = errno;
				(void) syslog(LOG_ERR,
	"t_alloc(file descriptor %d/transport %s, T_UDERROR) failed: %m",
				    fd, nconf->nc_proto);
				return (error);
			}
			(void) syslog(LOG_ERR,
"t_alloc(file descriptor %d/transport %s, T_UDERROR) failed TLI error: %d",
			    fd, nconf->nc_proto, t_errno);
			goto flush_it;
		}
	}

	ret = t_rcvuderr(fd, uderr);
	if (ret == 0) {

		/*
		 * Save the datagram error in errno, so that the
		 * %m argument to syslog picks up the error string.
		 */
		errno = uderr->error;

		/*
		 * Log the datagram error, then log the host that
		 * probably triggerred. Cannot log both in the
		 * same transaction because of packet size limitations
		 * in /dev/log.
		 */
		(void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING,
"NFS response over <file descriptor %d/transport %s> generated error: %m",
		    fd, nconf->nc_proto);

		/*
		 * Try to map the client's address back to a
		 * name.
		 */
		ret = netdir_getbyaddr(nconf, &host, &uderr->addr);
		if (ret != -1 && host && host->h_cnt > 0 &&
		    host->h_hostservs) {
		(void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING,
"Bad NFS response was sent to client with host name: %s; service port: %s",
		    host->h_hostservs->h_host,
		    host->h_hostservs->h_serv);
		} else {
			int i, j;
			char *buf;
			char *hex = "0123456789abcdef";

			/*
			 * Mapping failed, print the whole thing
			 * in ASCII hex.
			 */
			buf = (char *)malloc(uderr->addr.len * 2 + 1);
			for (i = 0, j = 0; i < uderr->addr.len; i++, j += 2) {
				buf[j] = hex[((uderr->addr.buf[i]) >> 4) & 0xf];
				buf[j+1] = hex[uderr->addr.buf[i] & 0xf];
			}
			buf[j] = '\0';
		(void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING,
	"Bad NFS response was sent to client with transport address: 0x%s",
		    buf);
			free((void *)buf);
		}

		if (ret == 0 && host != NULL)
			netdir_free((void *)host, ND_HOSTSERVLIST);
		return (0);
	}
Пример #13
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);
}
Пример #14
0
struct nd_hostservlist *
_netdir_getbyaddr(struct netconfig *netconfigp, struct netbuf *netbufp)
{
	char   fulladdr[BUFSIZ];	  /* a copy of the address string   */
	char   servbuf[BUFSIZ];		  /* a buffer for service string    */
	char   hostbuf[BUFSIZ];		  /* points to list of host names   */
	char   *hostname;		  /* the "first" path of the string */
	char   *servname;		  /* the "second" part of string    */
	struct nd_hostservlist *retp;	  /* the return structure	    */
	char   *serv;			  /* resultant service name obtained */
	int    nhost;			  /* the number of hosts in hostpp  */
	struct nd_hostserv *nd_hostservp; /* traverses the host structures  */
	char   *nexttok;		  /* next token to process	    */

	/*
	 *	Separate the two parts of the address string.
	 */

	(void) strlcpy(fulladdr, netbufp->buf, sizeof (fulladdr));
	hostname = strtok_r(fulladdr, ".", &nexttok);
	if (hostname == NULL) {
		_nderror = ND_NOHOST;
		return (NULL);
	}
	servname = strtok_r(NULL, " \n\t", &nexttok);

	/*
	 *	Search for all the hosts associated with the
	 *	first part of the address string.
	 */

	nhost = searchhost(netconfigp, hostname, FIELD1, hostbuf);
	if (nhost == 0) {
		_nderror = ND_NOHOST;
		return (NULL);
	}

	/*
	 *	Search for the service associated with the second
	 *	path of the address string.
	 */

	if (servname == NULL) {
		_nderror = ND_NOSERV;
		return (NULL);
	}

	servbuf[0] = '\0';
	serv = servbuf;
	if (searchserv(netconfigp, servname, FIELD2, servbuf) == 0) {
		serv = _taddr2uaddr(netconfigp, netbufp);
		(void) strcpy(servbuf, serv);
		free(serv);
		serv = servbuf;
		while (*serv != '.')
			serv++;
	}

	/*
	 *	Allocate space to hold the return structure, set the number
	 *	of hosts, and allocate space to hold them.
	 */

	if ((retp = malloc(sizeof (struct nd_hostservlist))) == NULL) {
		_nderror = ND_NOMEM;
		return (NULL);
	}

	retp->h_cnt = nhost;
	retp->h_hostservs = calloc(nhost, sizeof (struct nd_hostserv));
	if (retp->h_hostservs == NULL) {
		free(retp);
		_nderror = ND_NOMEM;
		return (NULL);
	}

	/*
	 *	Loop through the host structues and fill them in with
	 *	each host name (and service name).
	 */

	nd_hostservp = retp->h_hostservs;
	hostname = strtok_r(hostbuf, ",", &nexttok);
	while (hostname && nhost--) {
		if (((nd_hostservp->h_host = strdup(hostname)) == NULL) ||
		    ((nd_hostservp->h_serv = strdup(serv)) == NULL)) {
			netdir_free(retp, ND_HOSTSERVLIST);
			_nderror = ND_NOMEM;
			return (NULL);
		}
		nd_hostservp++;
		hostname = strtok_r(NULL, ",", &nexttok);
	}

	_nderror = ND_OK;
	return (retp);
}
Пример #15
0
static void
nfsauth_access(auth_req *argp, auth_res *result)
{
	struct netconfig *nconf;
	struct nd_hostservlist *clnames = NULL;
	struct netbuf nbuf;
	struct share *sh;
	char tmp[MAXIPADDRLEN];
	char *host = NULL;

	result->auth_perm = NFSAUTH_DENIED;

	/*
	 * Convert the client's address to a hostname
	 */
	nconf = getnetconfigent(argp->req_netid);
	if (nconf == NULL) {
		syslog(LOG_ERR, "No netconfig entry for %s", argp->req_netid);
		return;
	}

	nbuf.len = argp->req_client.n_len;
	nbuf.buf = argp->req_client.n_bytes;

	if (netdir_getbyaddr(nconf, &clnames, &nbuf)) {
		host = &tmp[0];
		if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
			struct sockaddr_in *sa;

			/* LINTED pointer alignment */
			sa = (struct sockaddr_in *)nbuf.buf;
			(void) inet_ntoa_r(sa->sin_addr, tmp);
		} else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) {
			struct sockaddr_in6 *sa;
			/* LINTED pointer */
			sa = (struct sockaddr_in6 *)nbuf.buf;
			(void) inet_ntop(AF_INET6, sa->sin6_addr.s6_addr,
				    tmp, INET6_ADDRSTRLEN);
		}
		clnames = anon_client(host);
	}

	/*
	 * Now find the export
	 */
	sh = findentry(argp->req_path);
	if (sh == NULL) {
		syslog(LOG_ERR, "%s not exported", argp->req_path);
		goto done;
	}

	result->auth_perm = check_client(sh, &nbuf, clnames, argp->req_flavor);

	sharefree(sh);

	if (result->auth_perm == NFSAUTH_DENIED) {
		syslog(LOG_ERR, "%s denied access to %s",
			clnames->h_hostservs[0].h_host, argp->req_path);
	}

done:
	freenetconfigent(nconf);
	if (clnames)
		netdir_free(clnames, ND_HOSTSERVLIST);
}
Пример #16
0
int
tcp_connect(const char *host, const char *serv)
{
	int					tfd, i;
	void				*handle;
	struct t_call		tcall;
	struct t_discon		tdiscon;
	struct netconfig	*ncp;
	struct nd_hostserv	hs;
	struct nd_addrlist	*alp;
	struct netbuf		*np;
	struct t_opthdr		*topt;

	handle = Setnetpath();

	hs.h_host = (char *) host;
	hs.h_serv = (char *) serv;

	while ( (ncp = getnetpath(handle)) != NULL) {
		if (strcmp(ncp->nc_proto, "tcp") != 0)
			continue;

		if (netdir_getbyname(ncp, &hs, &alp) != 0)
			continue;

				/* try each server address */
		for (i = 0, np = alp->n_addrs; i < alp->n_cnt; i++, np++) {
			tfd = T_open(ncp->nc_device, O_RDWR, NULL);
		
			T_bind(tfd, NULL, NULL);

			tcall.addr.len  = np->len;
			tcall.addr.buf  = np->buf;	/* pointer copy */
			tcall.opt.len   = 0;		/* no options */
			tcall.udata.len = 0;		/* no user data with connect */
		
			if (t_connect(tfd, &tcall, NULL) == 0) {
				endnetpath(handle);		/* success, connected to server */
				netdir_free(alp, ND_ADDRLIST);

				req = T_alloc(fd, T_OPTMGMT, T_ALL);
				ret = T_alloc(fd, T_OPTMGMT, T_ALL);

				topt = (struct t_opthdr *) req->opt.buf;
				topt->level = T_INET_TCP;
				topt->name = T_TCP_MAXSEG;
				topt->len = sizeof(struct t_opthdr) + sizeof(u_long);
				req->opt.len = topt->len;

				topt = OPT_NEXTHDR(req->opt.buf, req->opt.maxlen, topt);
				topt->level = XTI_GENERIC;
				topt->name = XTI_SNDBUF;
				topt->len = sizeof(struct t_opthdr) + sizeof(u_long);
				req->opt.len += topt->len;

				return(tfd);
			}

			if (t_errno == TLOOK && t_look(tfd) == T_DISCONNECT) {
				t_rcvdis(tfd, &tdiscon);
				errno = tdiscon.reason;
			}
			t_close(tfd);
		}
		netdir_free(alp, ND_ADDRLIST);
	}
	endnetpath(handle);
	return(-1);
}
Пример #17
0
/*
 * Check mount requests, add to mounted list if ok
 */
static void
mount(struct svc_req *rqstp)
{
	SVCXPRT *transp;
	int version, vers;
	struct fhstatus fhs;
	struct mountres3 mountres3;
	char fh[FHSIZE3];
	int len = FHSIZE3;
	char *path, rpath[MAXPATHLEN];
	struct share *sh = NULL;
	struct nd_hostservlist *clnames = NULL;
	char *host = NULL;
	int error = 0, lofs_tried = 0;
	int flavor_list[MAX_FLAVORS];
	int flavor_count;
	struct netbuf *nb;

	transp = rqstp->rq_xprt;
	version = rqstp->rq_vers;
	path = NULL;

	if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) {
		svcerr_decode(transp);
		return;
	}

	getclientsnames(transp, &nb, &clnames);
	if (clnames == NULL || nb == NULL) {
		/*
		 * We failed to get a name for the client, even 'anon',
		 * probably because we ran out of memory. In this situation
		 * it doesn't make sense to allow the mount to succeed.
		 */
		error = EACCES;
		goto reply;
	}
	host = clnames->h_hostservs[0].h_host;

	/*
	 * If the version being used is less than the minimum version,
	 * the filehandle translation should not be provided to the
	 * client.
	 */
	if (rejecting || version < mount_vers_min) {
		if (verbose)
			syslog(LOG_NOTICE, "Rejected mount: %s for %s",
				host, path);
		error = EACCES;
		goto reply;
	}

	/*
	 * Trusted Extension doesn't support older versions of nfs(v2, v3).
	 * To prevent circumventing TX label policy via using an older
	 * version of nfs client, reject the mount request and log an
	 * error.
	 */
	if (is_system_labeled()) {
		syslog(LOG_ERR,
		    "mount rejected: Solaris TX only supports nfs4 clients");
		error = EACCES;
		goto reply;
	}

	/*
	 * Get the real path (no symbolic links in it)
	 */
	if (realpath(path, rpath) == NULL) {
		error = errno;
		if (verbose)
			syslog(LOG_ERR,
				"mount request: realpath: %s: %m", path);
		if (error == ENOENT)
			error = mount_enoent_error(path, rpath, clnames, nb,
					flavor_list);
		goto reply;
	}

	if ((sh = findentry(rpath)) == NULL &&
		(sh = find_lofsentry(rpath, &lofs_tried)) == NULL) {
		error = EACCES;
		goto reply;
	}

	/*
	 * Check if this is a "nosub" only export, in which case, mounting
	 * subdirectories isn't allowed. Bug 1184573.
	 */
	if (checkrootmount(sh, rpath) == 0) {
		error = EACCES;
		goto reply;
	}

	if (newopts(sh->sh_opts))
		flavor_count = getclientsflavors_new(sh, nb, clnames,
					flavor_list);
	else
		flavor_count = getclientsflavors_old(sh, nb, clnames,
					flavor_list);

	if (flavor_count == 0) {
		error = EACCES;
		goto reply;
	}

	/*
	 * Now get the filehandle.
	 *
	 * NFS V2 clients get a 32 byte filehandle.
	 * NFS V3 clients get a 32 or 64 byte filehandle, depending on
	 * the embedded FIDs.
	 */
	vers = (version == MOUNTVERS3) ? NFS_V3 : NFS_VERSION;

	/* LINTED pointer alignment */
	while (nfs_getfh(rpath, vers, &len, fh) < 0) {
		if (errno == EINVAL &&
			(sh = find_lofsentry(rpath, &lofs_tried)) != NULL) {
			errno = 0;
			continue;
		}
		error = errno == EINVAL ? EACCES : errno;
		syslog(LOG_DEBUG, "mount request: getfh failed on %s: %m",
			path);
		break;
	}

	if (version == MOUNTVERS3) {
		mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len = len;
		mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val = fh;
	} else {
		bcopy(fh, &fhs.fhstatus_u.fhs_fhandle, NFS_FHSIZE);
	}

reply:
	switch (version) {
	case MOUNTVERS:
	case MOUNTVERS_POSIX:
		if (error == EINVAL)
			fhs.fhs_status = NFSERR_ACCES;
		else if (error == EREMOTE)
			fhs.fhs_status = NFSERR_REMOTE;
		else
			fhs.fhs_status = error;
		if (!svc_sendreply(transp, xdr_fhstatus, (char *)&fhs))
			log_cant_reply(transp);
		audit_mountd_mount(host, path, fhs.fhs_status); /* BSM */
		break;

	case MOUNTVERS3:
		if (!error) {
		mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_val =
			flavor_list;
		mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_len =
			flavor_count;

		} else if (error == ENAMETOOLONG)
			error = MNT3ERR_NAMETOOLONG;

		mountres3.fhs_status = error;
		if (!svc_sendreply(transp, xdr_mountres3, (char *)&mountres3))
			log_cant_reply(transp);
		audit_mountd_mount(host, path, mountres3.fhs_status); /* BSM */

		break;
	}

	if (verbose)
		syslog(LOG_NOTICE, "MOUNT: %s %s %s",
			(host == NULL) ? "unknown host" : host,
			error ? "denied" : "mounted", path);

	if (path != NULL)
		svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);

	if (!error)
		mntlist_new(host, rpath); /* add entry to mount list */
done:
	if (sh)
		sharefree(sh);
	netdir_free(clnames, ND_HOSTSERVLIST);
}
Пример #18
0
CreateWellKnownSockets ()
{
    struct t_bind bind_addr;
    struct netconfig *nconf;
    struct nd_hostserv service;
    struct nd_addrlist *servaddrs;
    char *name, *localHostname();
    char bindbuf[15];
    int it;

    if (request_port == 0)
	return;
    Debug ("creating UDP stream %d\n", request_port);

    nconf = getnetconfigent("udp");
    if (!nconf) {
	t_error("getnetconfigent udp");
	return;
    }

    xdmcpFd = t_open(nconf->nc_device, O_RDWR, NULL);
    if (xdmcpFd == -1) {
	LogError ("XDMCP stream creation failed\n");
	t_error ("t_open");
	return;
    }
    name = localHostname ();
    registerHostname (name, strlen (name));
    RegisterCloseOnFork (xdmcpFd);

    service.h_host = HOST_SELF;
    sprintf(bindbuf, "%d", request_port);
    service.h_serv = bindbuf;
    netdir_getbyname(nconf, &service, &servaddrs);
    freenetconfigent(nconf);

    bind_addr.qlen = 5;
    bind_addr.addr.buf = servaddrs->n_addrs[0].buf;
    bind_addr.addr.len = servaddrs->n_addrs[0].len;
    it = t_bind(xdmcpFd, &bind_addr, &bind_addr);
    netdir_free(servaddrs, ND_ADDRLIST);
    if (it < 0)
    {
	LogError ("error binding STREAMS address %d\n", request_port);
	t_error("t_bind");	/* also goes to log file */
	t_close (xdmcpFd);
	xdmcpFd = -1;
	return;
    }
    WellKnownSocketsMax = xdmcpFd;
    FD_SET (xdmcpFd, &WellKnownSocketsMask);

    chooserFd = t_open ("/dev/tcp", O_RDWR, NULL);
    Debug ("Created chooser fd %d\n", chooserFd);
    if (chooserFd == -1)
    {
	LogError ("chooser stream creation failed\n");
	t_error("t_open chooser");
	return;
    }
    if (chooserFd > WellKnownSocketsMax)
	WellKnownSocketsMax = chooserFd;
    FD_SET (chooserFd, &WellKnownSocketsMask);
}
Пример #19
0
int
nfslib_bindit(struct netconfig *nconf, struct netbuf **addr,
	struct nd_hostserv *hs, int backlog)
{
	int fd;
	struct t_bind  *ntb;
	struct t_bind tb;
	struct nd_addrlist *addrlist;
	struct t_optmgmt req, resp;
	struct opthdr *opt;
	char reqbuf[128];
	bool_t use_any = FALSE;
	bool_t gzone = TRUE;

	if ((fd = nfslib_transport_open(nconf)) == -1) {
		syslog(LOG_ERR, "cannot establish transport service over %s",
		    nconf->nc_device);
		return (-1);
	}

	addrlist = (struct nd_addrlist *)NULL;

	/* nfs4_callback service does not used a fieed port number */

	if (strcmp(hs->h_serv, "nfs4_callback") == 0) {
		tb.addr.maxlen = 0;
		tb.addr.len = 0;
		tb.addr.buf = 0;
		use_any = TRUE;
		gzone = (getzoneid() == GLOBAL_ZONEID);
	} else if (netdir_getbyname(nconf, hs, &addrlist) != 0) {

		syslog(LOG_ERR,
		"Cannot get address for transport %s host %s service %s",
		    nconf->nc_netid, hs->h_host, hs->h_serv);
		(void) t_close(fd);
		return (-1);
	}

	if (strcmp(nconf->nc_proto, "tcp") == 0) {
		/*
		 * If we're running over TCP, then set the
		 * SO_REUSEADDR option so that we can bind
		 * to our preferred address even if previously
		 * left connections exist in FIN_WAIT states.
		 * This is somewhat bogus, but otherwise you have
		 * to wait 2 minutes to restart after killing it.
		 */
		if (reuseaddr(fd) == -1) {
			syslog(LOG_WARNING,
			"couldn't set SO_REUSEADDR option on transport");
		}
	} else if (strcmp(nconf->nc_proto, "udp") == 0) {
		/*
		 * In order to run MLP on UDP, we need to handle creds.
		 */
		if (recvucred(fd) == -1) {
			syslog(LOG_WARNING,
			    "couldn't set SO_RECVUCRED option on transport");
		}
	}

	/*
	 * Make non global zone nfs4_callback port MLP
	 */
	if (use_any && is_system_labeled() && !gzone) {
		if (anonmlp(fd) == -1) {
			/*
			 * failing to set this option means nfs4_callback
			 * could fail silently later. So fail it with
			 * with an error message now.
			 */
			syslog(LOG_ERR,
			    "couldn't set SO_ANON_MLP option on transport");
			(void) t_close(fd);
			return (-1);
		}
	}

	if (nconf->nc_semantics == NC_TPI_CLTS)
		tb.qlen = 0;
	else
		tb.qlen = backlog;

	/* LINTED pointer alignment */
	ntb = (struct t_bind *)t_alloc(fd, T_BIND, T_ALL);
	if (ntb == (struct t_bind *)NULL) {
		syslog(LOG_ERR, "t_alloc failed:  t_errno %d, %m", t_errno);
		(void) t_close(fd);
		netdir_free((void *)addrlist, ND_ADDRLIST);
		return (-1);
	}

	/*
	 * XXX - what about the space tb->addr.buf points to? This should
	 * be either a memcpy() to/from the buf fields, or t_alloc(fd,T_BIND,)
	 * should't be called with T_ALL.
	 */
	if (addrlist)
		tb.addr = *(addrlist->n_addrs);		/* structure copy */

	if (t_bind(fd, &tb, ntb) == -1) {
		syslog(LOG_ERR, "t_bind failed:  t_errno %d, %m", t_errno);
		(void) t_free((char *)ntb, T_BIND);
		netdir_free((void *)addrlist, ND_ADDRLIST);
		(void) t_close(fd);
		return (-1);
	}

	/* make sure we bound to the right address */
	if (use_any == FALSE &&
	    (tb.addr.len != ntb->addr.len ||
	    memcmp(tb.addr.buf, ntb->addr.buf, tb.addr.len) != 0)) {
		syslog(LOG_ERR, "t_bind to wrong address");
		(void) t_free((char *)ntb, T_BIND);
		netdir_free((void *)addrlist, ND_ADDRLIST);
		(void) t_close(fd);
		return (-1);
	}

	/*
	 * Call nfs4svc_setport so that the kernel can be
	 * informed what port number the daemon is listing
	 * for incoming connection requests.
	 */

	if ((nconf->nc_semantics == NC_TPI_COTS ||
	    nconf->nc_semantics == NC_TPI_COTS_ORD) && Mysvc4 != NULL)
		(*Mysvc4)(fd, NULL, nconf, NFS4_SETPORT, &ntb->addr);

	*addr = &ntb->addr;
	netdir_free((void *)addrlist, ND_ADDRLIST);

	if (strcmp(nconf->nc_proto, "tcp") == 0) {
		/*
		 * Disable the Nagle algorithm on TCP connections.
		 * Connections accepted from this listener will
		 * inherit the listener options.
		 */

		/* LINTED pointer alignment */
		opt = (struct opthdr *)reqbuf;
		opt->level = IPPROTO_TCP;
		opt->name = TCP_NODELAY;
		opt->len = sizeof (int);

		/* LINTED pointer alignment */
		*(int *)((char *)opt + sizeof (*opt)) = 1;

		req.flags = T_NEGOTIATE;
		req.opt.len = sizeof (*opt) + opt->len;
		req.opt.buf = (char *)opt;
		resp.flags = 0;
		resp.opt.buf = reqbuf;
		resp.opt.maxlen = sizeof (reqbuf);

		if (t_optmgmt(fd, &req, &resp) < 0 ||
		    resp.flags != T_SUCCESS) {
			syslog(LOG_ERR,
	"couldn't set NODELAY option for proto %s: t_errno = %d, %m",
			    nconf->nc_proto, t_errno);
		}

		nfslib_set_sockbuf(fd);
	}

	return (fd);
}
Пример #20
0
/*
 * check for trusted host and user
 */
static int
check_host(
	struct svc_req		*rqstp		/* RPC stuff */
)
{
	struct authsys_parms	*sys_credp;
	SVCXPRT			*transp = rqstp->rq_xprt;
	struct netconfig	*nconfp = NULL;
	struct nd_hostservlist	*hservlistp = NULL;
	int			i;
	int			rval = -1;
	char			*inplace = NULL;

	/* check for root */
	/*LINTED*/
	sys_credp = (struct authsys_parms *)rqstp->rq_clntcred;
	assert(sys_credp != NULL);
	if (sys_credp->aup_uid != 0)
		goto out;

	/* get hostnames */
	if (transp->xp_netid == NULL) {
		md_eprintf("transp->xp_netid == NULL\n");
		goto out;
	}
	if ((nconfp = getnetconfigent(transp->xp_netid)) == NULL) {
#ifdef	DEBUG
		nc_perror("getnetconfigent(transp->xp_netid)");
#endif
		goto out;
	}
	if ((__netdir_getbyaddr_nosrv(nconfp, &hservlistp, &transp->xp_rtaddr)
	    != 0) || (hservlistp == NULL)) {
#ifdef	DEBUG
		netdir_perror("netdir_getbyaddr(transp->xp_rtaddr)");
#endif
		goto out;
	}

	/* check hostnames */
	for (i = 0; (i < hservlistp->h_cnt); ++i) {
		struct nd_hostserv	*hservp = &hservlistp->h_hostservs[i];
		char			*hostname = hservp->h_host;

		inplace = strdup(hostname);

		/* localhost is OK */
		if (strcmp(hostname, mynode()) == 0) {
			rval = 0;
			goto out;
		}

		/* check for remote root access */
		if (ruserok(hostname, 1, "root", "root") == 0) {
			rval = 0;
			goto out;
		}

		sdssc_cm_nm2nid(inplace);
		if (strcmp(inplace, hostname)) {

			/*
			 * If the names are now different it indicates
			 * that hostname was converted to a nodeid. This
			 * will only occur if hostname is part of the same
			 * cluster that the current node is in.
			 * If the machine is not running in a cluster than
			 * sdssc_cm_nm2nid is a noop which leaves inplace
			 * alone.
			 */
			rval = 0;
			goto out;
		}
	}

	/* cleanup, return success */
out:
	if (inplace)
		free(inplace);
	if (hservlistp != NULL)
		netdir_free(hservlistp, ND_HOSTSERVLIST);
	if (nconfp != NULL)
		Free(nconfp);
	return (rval);
}