Exemplo n.º 1
0
/*
 * Returns 1 if the given address is bound for the given addr & transport
 * For all error cases, we assume that the address is bound
 * Returns 0 for success.
 */
static bool_t
check_bound(struct fdlist *fdl, char *uaddr)
{
	int fd;
	struct netbuf *na;
	int ans;

	if (fdl->check_binding == FALSE)
		return (TRUE);

	na = uaddr2taddr(fdl->nconf, uaddr);
	if (!na)
		return (TRUE); /* punt, should never happen */

	fd = __rpc_nconf2fd(fdl->nconf);
	if (fd < 0) {
		free(na->buf);
		free(na);
		return (TRUE);
	}

	ans = bind(fd, (struct sockaddr *)na->buf, na->len);

	close(fd);
	free(na->buf);
	free(na);

	return (ans == 0 ? FALSE : TRUE);
}
Exemplo n.º 2
0
/*
 * A common server create routine
 */
static SVCXPRT *
svc_com_create(int fd, u_int sendsize, u_int recvsize, const char *netid)
{
	struct netconfig *nconf;
	SVCXPRT *svc;
	int madefd = FALSE;
	int port;
	struct sockaddr_in sccsin;

	_DIAGASSERT(netid != NULL);

	if ((nconf = __rpc_getconfip(netid)) == NULL) {
		(void) syslog(LOG_ERR, "Could not get %s transport", netid);
		return (NULL);
	}
	if (fd == RPC_ANYSOCK) {
		fd = __rpc_nconf2fd(nconf);
		if (fd == -1) {
			(void) freenetconfigent(nconf);
			(void) syslog(LOG_ERR,
			"svc%s_create: could not open connection", netid);
			return (NULL);
		}
		madefd = TRUE;
	}

	memset(&sccsin, 0, sizeof sccsin);
	sccsin.sin_family = AF_INET;
	(void)bindresvport(fd, &sccsin);

	switch (nconf->nc_semantics) {
	case NC_TPI_COTS:
	case NC_TPI_COTS_ORD:
		if (listen(fd, SOMAXCONN) == -1) {
			(void) syslog(LOG_ERR,
			    "svc%s_create: listen(2) failed: %s",
			    netid, strerror(errno));
			(void) freenetconfigent(nconf);
			goto out;
		}
		break;
	default:
		break;
	}

	svc = svc_tli_create(fd, nconf, NULL, sendsize, recvsize);
	(void) freenetconfigent(nconf);
	if (svc == NULL)
		goto out;
	port = (((struct sockaddr_in *)svc->xp_ltaddr.buf)->sin_port);
	svc->xp_port = ntohs(port);
	return svc;
out:
	if (madefd)
		(void) close(fd);
	return NULL;
}
Exemplo n.º 3
0
/*
 * Creates, registers, and returns a (rpc) unix based transporter.
 * Obsoleted by svc_vc_create().
 */
SVCXPRT *
svcunix_create(int sock, u_int sendsize, u_int recvsize, char *path)
{
	struct netconfig *nconf;
	void *localhandle;
	struct sockaddr_un sun;
	struct sockaddr *sa;
	struct t_bind taddr;
	SVCXPRT *xprt;
	int addrlen;

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

	if ((sock = __rpc_nconf2fd(nconf)) < 0)
		goto done;

	memset(&sun, 0, sizeof sun);
	sun.sun_family = AF_LOCAL;
	if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >=
	    sizeof(sun.sun_path))
		goto done;
	sun.sun_len = SUN_LEN(&sun);
	addrlen = sizeof (struct sockaddr_un);
	sa = (struct sockaddr *)&sun;

	if (_bind(sock, sa, addrlen) < 0)
		goto done;

	taddr.addr.len = taddr.addr.maxlen = addrlen;
	taddr.addr.buf = malloc(addrlen);
	if (taddr.addr.buf == NULL)
		goto done;
	memcpy(taddr.addr.buf, sa, addrlen);

	if (nconf->nc_semantics != NC_TPI_CLTS) {
		if (_listen(sock, SOMAXCONN) < 0) {
			free(taddr.addr.buf);
			goto done;
		}
	}

	xprt = (SVCXPRT *)svc_tli_create(sock, nconf, &taddr, sendsize, recvsize);

done:
	endnetconfig(localhandle);
	return(xprt);
}
Exemplo n.º 4
0
/*
 * A common server create routine
 */
static SVCXPRT *
svc_com_create(int fd, u_int sendsize, u_int recvsize, char *netid)
{
	struct netconfig *nconf;
	SVCXPRT *svc;
	int madefd = FALSE;
	int port;
	struct sockaddr_in sin;

	if ((nconf = __rpc_getconfip(netid)) == NULL) {
		(void) syslog(LOG_ERR, "Could not get %s transport", netid);
		return (NULL);
	}
	if (fd == RPC_ANYSOCK) {
		fd = __rpc_nconf2fd(nconf);
		if (fd == -1) {
			(void) freenetconfigent(nconf);
			(void) syslog(LOG_ERR,
			"svc%s_create: could not open connection", netid);
			return (NULL);
		}
		madefd = TRUE;
	}

	memset(&sin, 0, sizeof sin);
	sin.sin_family = AF_INET;
	bindresvport(fd, &sin);
	_listen(fd, SOMAXCONN);
	svc = svc_tli_create(fd, nconf, NULL, sendsize, recvsize);
	(void) freenetconfigent(nconf);
	if (svc == NULL) {
		if (madefd)
			(void)_close(fd);
		return (NULL);
	}
	port = (((struct sockaddr_in *)svc->xp_ltaddr.buf)->sin_port);
	svc->xp_port = ntohs(port);
	return (svc);
}
Exemplo n.º 5
0
/*
 * A common clnt create routine
 */
static CLIENT *
clnt_com_create(struct sockaddr_in *raddr, rpcprog_t prog, rpcvers_t vers,
	int *sockp, u_int sendsz, u_int recvsz, const char *tp)
{
	CLIENT *cl;
	int madefd = FALSE;
	int fd;
	struct netconfig *nconf;
	struct netbuf bindaddr;

	_DIAGASSERT(raddr != NULL);
	_DIAGASSERT(sockp != NULL);
	_DIAGASSERT(tp != NULL);

	fd = *sockp;

	mutex_lock(&rpcsoc_lock);
	if ((nconf = __rpc_getconfip(tp)) == NULL) {
		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
		mutex_unlock(&rpcsoc_lock);
		return (NULL);
	}
	if (fd == RPC_ANYSOCK) {
		fd = __rpc_nconf2fd(nconf);
		if (fd == -1)
			goto syserror;
		madefd = TRUE;
	}

	if (raddr->sin_port == 0) {
		u_int proto;
		u_short sport;

		mutex_unlock(&rpcsoc_lock);	/* pmap_getport is recursive */
		proto = strcmp(tp, "udp") == 0 ? IPPROTO_UDP : IPPROTO_TCP;
		sport = pmap_getport(raddr, (u_long)prog, (u_long)vers,
		    proto);
		if (sport == 0) {
			goto err;
		}
		raddr->sin_port = htons(sport);
		mutex_lock(&rpcsoc_lock);	/* pmap_getport is recursive */
	}

	/* Transform sockaddr_in to netbuf */
	bindaddr.maxlen = bindaddr.len =  sizeof (struct sockaddr_in);
	bindaddr.buf = raddr;

	(void)bindresvport(fd, NULL);
	cl = clnt_tli_create(fd, nconf, &bindaddr, prog, vers,
				sendsz, recvsz);
	if (cl) {
		if (madefd == TRUE) {
			/*
			 * The fd should be closed while destroying the handle.
			 */
			(void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL);
			*sockp = fd;
		}
		(void) freenetconfigent(nconf);
		mutex_unlock(&rpcsoc_lock);
		return (cl);
	}
	goto err;

syserror:
	rpc_createerr.cf_stat = RPC_SYSTEMERROR;
	rpc_createerr.cf_error.re_errno = errno;

err:	if (madefd == TRUE)
		(void) close(fd);
	(void) freenetconfigent(nconf);
	mutex_unlock(&rpcsoc_lock);
	return (NULL);
}
Exemplo n.º 6
0
/*
 * Generic client creation:  returns client handle.
 * Default options are set, which the user can
 * change using the rpc equivalent of _ioctl()'s : clnt_control().
 * If fd is RPC_ANYFD, it will be opened using nconf.
 * It will be bound if not so.
 * If sizes are 0; appropriate defaults will be chosen.
 */
CLIENT *
clnt_tli_create(int fd, const struct netconfig *nconf,
	struct netbuf *svcaddr, rpcprog_t prog, rpcvers_t vers,
	uint sendsz, uint recvsz)
{
	CLIENT *cl;			/* client handle */
	bool_t madefd = FALSE;		/* whether fd opened here */
	long servtype;
	int one = 1;
	struct __rpc_sockinfo si;
	extern int __rpc_minfd;

	if (fd == RPC_ANYFD) {
		if (nconf == NULL) {
			rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
			return (NULL);
		}

		fd = __rpc_nconf2fd(nconf);

		if (fd == -1)
			goto err;
		if (fd < __rpc_minfd)
			fd = __rpc_raise_fd(fd);
		madefd = TRUE;
		servtype = nconf->nc_semantics;
		if (!__rpc_fd2sockinfo(fd, &si))
			goto err;
		bindresvport(fd, NULL);
	} else {
		if (!__rpc_fd2sockinfo(fd, &si))
			goto err;
		servtype = __rpc_socktype2seman(si.si_socktype);
		if (servtype == -1) {
			rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
			return (NULL);
		}
	}

	if (si.si_af != ((struct sockaddr *)svcaddr->buf)->sa_family) {
		rpc_createerr.cf_stat = RPC_UNKNOWNHOST;	/* XXX */
		goto err1;
	}

	switch (servtype) {
	case NC_TPI_COTS:
		cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz);
		break;
	case NC_TPI_COTS_ORD:
		if (nconf &&
		    ((strcmp(nconf->nc_protofmly, "inet") == 0) ||
		     (strcmp(nconf->nc_protofmly, "inet6") == 0))) {
			setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one,
			    sizeof (one));
		}
		cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz);
		break;
	case NC_TPI_CLTS:
		cl = clnt_dg_create(fd, svcaddr, prog, vers, sendsz, recvsz);
		break;
	default:
		goto err;
	}

	if (cl == NULL)
		goto err1; /* borrow errors from clnt_dg/vc creates */
	if (nconf) {
		cl->cl_netid = strdup(nconf->nc_netid);
		cl->cl_tp = strdup(nconf->nc_device);
	} else {
		cl->cl_netid = "";
		cl->cl_tp = "";
	}
	if (madefd) {
		(void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL);
/*		(void) CLNT_CONTROL(cl, CLSET_POP_TIMOD, NULL);  */
	};

	return (cl);

err:
	rpc_createerr.cf_stat = RPC_SYSTEMERROR;
	rpc_createerr.cf_error.re_errno = errno;
err1:	if (madefd)
		(void)close(fd);
	return (NULL);
}
Exemplo n.º 7
0
/*
 * This routine creates and binds sockets on the appropriate
 * addresses. It gets called one time for each transport.
 * It returns 0 upon success, 1 for ingore the call and -1 to indicate
 * bind failed with EADDRINUSE.
 * Any file descriptors that have been created are stored in sock_fd and
 * the total count of them is maintained in sock_fdcnt.
 */
static int
create_service(struct netconfig *nconf)
{
	struct addrinfo hints, *res = NULL;
	struct sockaddr_in *sin;
	struct sockaddr_in6 *sin6;
	struct __rpc_sockinfo si;
	int aicode;
	int fd;
	int nhostsbak;
	int r;
	u_int32_t host_addr[4];  /* IPv4 or IPv6 */
	int mallocd_res;

	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
	    (nconf->nc_semantics != NC_TPI_COTS) &&
	    (nconf->nc_semantics != NC_TPI_COTS_ORD))
		return (1);	/* not my type */

	/*
	 * XXX - using RPC library internal functions.
	 */
	if (!__rpc_nconf2sockinfo(nconf, &si)) {
		syslog(LOG_ERR, "cannot get information for %s",
		    nconf->nc_netid);
		return (1);
	}

	/* Get rpc.statd's address on this transport */
	memset(&hints, 0, sizeof hints);
	hints.ai_family = si.si_af;
	hints.ai_socktype = si.si_socktype;
	hints.ai_protocol = si.si_proto;

	/*
	 * Bind to specific IPs if asked to
	 */
	nhostsbak = nhosts;
	while (nhostsbak > 0) {
		--nhostsbak;
		sock_fd = realloc(sock_fd, (sock_fdcnt + 1) * sizeof(int));
		if (sock_fd == NULL)
			out_of_mem();
		sock_fd[sock_fdcnt++] = -1;	/* Set invalid for now. */
		mallocd_res = 0;
		hints.ai_flags = AI_PASSIVE;

		/*	
		 * XXX - using RPC library internal functions.
		 */
		if ((fd = __rpc_nconf2fd(nconf)) < 0) {
			syslog(LOG_ERR, "cannot create socket for %s",
			    nconf->nc_netid);
			continue;
		}
		switch (hints.ai_family) {
		case AF_INET:
			if (inet_pton(AF_INET, hosts[nhostsbak],
			    host_addr) == 1) {
				hints.ai_flags |= AI_NUMERICHOST;
			} else {
				/*
				 * Skip if we have an AF_INET6 address.
				 */
				if (inet_pton(AF_INET6, hosts[nhostsbak],
				    host_addr) == 1) {
					close(fd);
					continue;
				}
			}
			break;
		case AF_INET6:
			if (inet_pton(AF_INET6, hosts[nhostsbak],
			    host_addr) == 1) {
				hints.ai_flags |= AI_NUMERICHOST;
			} else {
				/*
				 * Skip if we have an AF_INET address.
				 */
				if (inet_pton(AF_INET, hosts[nhostsbak],
				    host_addr) == 1) {
					close(fd);
					continue;
				}
			}
			break;
		default:
			break;
		}

		/*
		 * If no hosts were specified, just bind to INADDR_ANY
		 */
		if (strcmp("*", hosts[nhostsbak]) == 0) {
			if (svcport_str == NULL) {
				res = malloc(sizeof(struct addrinfo));
				if (res == NULL) 
					out_of_mem();
				mallocd_res = 1;
				res->ai_flags = hints.ai_flags;
				res->ai_family = hints.ai_family;
				res->ai_protocol = hints.ai_protocol;
				switch (res->ai_family) {
				case AF_INET:
					sin = malloc(sizeof(struct sockaddr_in));
					if (sin == NULL) 
						out_of_mem();
					sin->sin_family = AF_INET;
					sin->sin_port = htons(0);
					sin->sin_addr.s_addr = htonl(INADDR_ANY);
					res->ai_addr = (struct sockaddr*) sin;
					res->ai_addrlen = (socklen_t)
					    sizeof(struct sockaddr_in);
					break;
				case AF_INET6:
					sin6 = malloc(sizeof(struct sockaddr_in6));
					if (sin6 == NULL)
						out_of_mem();
					sin6->sin6_family = AF_INET6;
					sin6->sin6_port = htons(0);
					sin6->sin6_addr = in6addr_any;
					res->ai_addr = (struct sockaddr*) sin6;
					res->ai_addrlen = (socklen_t)
					    sizeof(struct sockaddr_in6);
					break;
				default:
					syslog(LOG_ERR, "bad addr fam %d",
					    res->ai_family);
					exit(1);
				}
			} else { 
				if ((aicode = getaddrinfo(NULL, svcport_str,
				    &hints, &res)) != 0) {
					syslog(LOG_ERR,
					    "cannot get local address for %s: %s",
					    nconf->nc_netid,
					    gai_strerror(aicode));
					close(fd);
					continue;
				}
			}
		} else {
			if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str,
			    &hints, &res)) != 0) {
				syslog(LOG_ERR,
				    "cannot get local address for %s: %s",
				    nconf->nc_netid, gai_strerror(aicode));
				close(fd);
				continue;
			}
		}

		/* Store the fd. */
		sock_fd[sock_fdcnt - 1] = fd;

		/* Now, attempt the bind. */
		r = bindresvport_sa(fd, res->ai_addr);
		if (r != 0) {
			if (errno == EADDRINUSE && mallocd_svcport != 0) {
				if (mallocd_res != 0) {
					free(res->ai_addr);
					free(res);
				} else
					freeaddrinfo(res);
				return (-1);
			}
			syslog(LOG_ERR, "bindresvport_sa: %m");
			exit(1);
		}

		if (svcport_str == NULL) {
			svcport_str = malloc(NI_MAXSERV * sizeof(char));
			if (svcport_str == NULL)
				out_of_mem();
			mallocd_svcport = 1;

			if (getnameinfo(res->ai_addr,
			    res->ai_addr->sa_len, NULL, NI_MAXHOST,
			    svcport_str, NI_MAXSERV * sizeof(char),
			    NI_NUMERICHOST | NI_NUMERICSERV))
				errx(1, "Cannot get port number");
		}
		if (mallocd_res != 0) {
			free(res->ai_addr);
			free(res);
		} else
			freeaddrinfo(res);
		res = NULL;
	}
	return (0);
}
Exemplo n.º 8
0
/*
 * Adds the entry into the rpcbind database.
 * If PORTMAP, then for UDP and TCP, it adds the entries for version 2 also
 * Returns 0 if succeeds, else fails
 */
static int
init_transport(struct netconfig *nconf)
{
	int fd = -1;
	struct t_bind taddr;
	struct addrinfo hints, *res;
	struct __rpc_sockinfo si;
	SVCXPRT	*my_xprt = NULL;
	int status;	/* bound checking ? */
	int aicode;
	int addrlen = 0;
	int nhostsbak;
	int checkbind;
	struct sockaddr *sa = NULL;
	u_int32_t host_addr[4];  /* IPv4 or IPv6 */
	struct sockaddr_un sun;
	mode_t oldmask;
        res = NULL;

	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
		(nconf->nc_semantics != NC_TPI_COTS) &&
		(nconf->nc_semantics != NC_TPI_COTS_ORD))
		return (1);	/* not my type */
#ifdef RPCBIND_DEBUG
	if (debugging) {
		int i;
		char **s;

		(void) fprintf(stderr, "%s: %ld lookup routines :\n",
			nconf->nc_netid, nconf->nc_nlookups);
		for (i = 0, s = nconf->nc_lookups; i < nconf->nc_nlookups;
		     i++, s++)
			fprintf(stderr, "[%d] - %s\n", i, *s);
	}
#endif

	/*
	 * XXX - using RPC library internal functions. For NC_TPI_CLTS
	 * we call this later, for each socket we like to bind.
	 */
	if (nconf->nc_semantics != NC_TPI_CLTS) {
		if ((fd = __rpc_nconf2fd(nconf)) < 0) {
			syslog(LOG_ERR, "cannot create socket for %s",
			    nconf->nc_netid);
			return (1);
		}
	}

	if (!__rpc_nconf2sockinfo(nconf, &si)) {
		syslog(LOG_ERR, "cannot get information for %s",
		    nconf->nc_netid);
		return (1);
	}

	if ((strcmp(nconf->nc_netid, "local") == 0) ||
	    (strcmp(nconf->nc_netid, "unix") == 0)) {
		memset(&sun, 0, sizeof sun);
		sun.sun_family = AF_LOCAL;
		unlink(_PATH_RPCBINDSOCK);
		strcpy(sun.sun_path, _PATH_RPCBINDSOCK);
		addrlen = SUN_LEN(&sun);
		sa = (struct sockaddr *)&sun;
	} else {
		/* Get rpcbind's address on this transport */

		memset(&hints, 0, sizeof hints);
		hints.ai_flags = AI_PASSIVE;
		hints.ai_family = si.si_af;
		hints.ai_socktype = si.si_socktype;
		hints.ai_protocol = si.si_proto;
	}
	if (nconf->nc_semantics == NC_TPI_CLTS) {
		/*
		 * If no hosts were specified, just bind to INADDR_ANY.  Otherwise
		 * make sure 127.0.0.1 is added to the list.
		 */
		nhostsbak = nhosts;
		nhostsbak++;
		hosts = realloc(hosts, nhostsbak * sizeof(char *));
		if (nhostsbak == 1)
			hosts[0] = "*";
		else {
			if (hints.ai_family == AF_INET) {
				hosts[nhostsbak - 1] = "127.0.0.1";
			} else if (hints.ai_family == AF_INET6) {
				hosts[nhostsbak - 1] = "::1";
			} else
				return 1;
		}

	       /*
		* Bind to specific IPs if asked to
		*/
		checkbind = 0;
		while (nhostsbak > 0) {
			--nhostsbak;
			/*
			 * XXX - using RPC library internal functions.
			 */
			if ((fd = __rpc_nconf2fd(nconf)) < 0) {
				syslog(LOG_ERR, "cannot create socket for %s",
				    nconf->nc_netid);
				return (1);
			}
			switch (hints.ai_family) {
			case AF_INET:
				if (inet_pton(AF_INET, hosts[nhostsbak],
				    host_addr) == 1) {
					hints.ai_flags &= AI_NUMERICHOST;
				} else {
					/*
					 * Skip if we have an AF_INET6 adress.
					 */
					if (inet_pton(AF_INET6,
					    hosts[nhostsbak], host_addr) == 1)
						continue;
				}
				break;
			case AF_INET6:
				if (inet_pton(AF_INET6, hosts[nhostsbak],
				    host_addr) == 1) {
					hints.ai_flags &= AI_NUMERICHOST;
				} else {
					/*
					 * Skip if we have an AF_INET adress.
					 */
					if (inet_pton(AF_INET, hosts[nhostsbak],
					    host_addr) == 1)
						continue;
				}
	        		break;
			default:
				break;
			}

			/*
			 * If no hosts were specified, just bind to INADDR_ANY
			 */
			if (strcmp("*", hosts[nhostsbak]) == 0)
				hosts[nhostsbak] = NULL;

			if ((aicode = getaddrinfo(hosts[nhostsbak],
			    servname, &hints, &res)) != 0) {
			  if ((aicode = getaddrinfo(hosts[nhostsbak],
						    "portmapper", &hints, &res)) != 0) {
				syslog(LOG_ERR,
				    "cannot get local address for %s: %s",
				    nconf->nc_netid, gai_strerror(aicode));
				continue;
			  }
			}
			addrlen = res->ai_addrlen;
			sa = (struct sockaddr *)res->ai_addr;
			oldmask = umask(S_IXUSR|S_IXGRP|S_IXOTH);
                        if (bind(fd, sa, addrlen) != 0) {
				syslog(LOG_ERR, "cannot bind %s on %s: %m",
					(hosts[nhostsbak] == NULL) ? "*" :
					hosts[nhostsbak], nconf->nc_netid);
				if (res != NULL)
					freeaddrinfo(res);
				continue;
			} else
				checkbind++;
			(void) umask(oldmask);

			/* Copy the address */
			taddr.addr.maxlen = taddr.addr.len = addrlen;
			taddr.addr.buf = malloc(addrlen);
			if (taddr.addr.buf == NULL) {
				syslog(LOG_ERR,
				    "cannot allocate memory for %s address",
				    nconf->nc_netid);
				if (res != NULL)
					freeaddrinfo(res);
				return 1;
			}
			memcpy(taddr.addr.buf, sa, addrlen);
#ifdef RPCBIND_DEBUG
			if (debugging) {
				/*
				 * for debugging print out our universal
				 * address
				 */
				char *uaddr;
				struct netbuf nb;
				int sa_size = 0;

				nb.buf = sa;
				switch( sa->sa_family){
				case AF_INET:
				  sa_size = sizeof (struct sockaddr_in);
				  break;
				case AF_INET6:
				  sa_size = sizeof (struct sockaddr_in6);				 
				  break;
				}
				nb.len = nb.maxlen = sa_size;
				uaddr = taddr2uaddr(nconf, &nb);
				(void) fprintf(stderr,
				    "rpcbind : my address is %s\n", uaddr);
				(void) free(uaddr);
			}
#endif
			my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr, 
                                RPC_MAXDATASIZE, RPC_MAXDATASIZE);
			if (my_xprt == (SVCXPRT *)NULL) {
				syslog(LOG_ERR, "%s: could not create service", 
                                        nconf->nc_netid);
				goto error;
			}
		}
		if (!checkbind)
			return 1;
	} else {	/* NC_TPI_COTS */
		if ((strcmp(nconf->nc_netid, "local") != 0) &&
		    (strcmp(nconf->nc_netid, "unix") != 0)) {
			if ((aicode = getaddrinfo(NULL, servname, &hints, &res))!= 0) {
			  if ((aicode = getaddrinfo(NULL, "portmapper", &hints, &res))!= 0) {
			  printf("cannot get local address for %s: %s",  nconf->nc_netid, gai_strerror(aicode));
			  syslog(LOG_ERR,
				    "cannot get local address for %s: %s",
				    nconf->nc_netid, gai_strerror(aicode));
				return 1;
			  }
			}
			addrlen = res->ai_addrlen;
			sa = (struct sockaddr *)res->ai_addr;
		}
		oldmask = umask(S_IXUSR|S_IXGRP|S_IXOTH);
		__rpc_fd2sockinfo(fd, &si);
		if (bind(fd, sa, addrlen) < 0) {
			syslog(LOG_ERR, "cannot bind %s: %m", nconf->nc_netid);
			if (res != NULL)
				freeaddrinfo(res);
			return 1;
		}
		(void) umask(oldmask);

		/* Copy the address */
		taddr.addr.len = taddr.addr.maxlen = addrlen;
		taddr.addr.buf = malloc(addrlen);
		if (taddr.addr.buf == NULL) {
			syslog(LOG_ERR, "cannot allocate memory for %s address",
			    nconf->nc_netid);
			if (res != NULL)
				freeaddrinfo(res);
			return 1;
		}
		memcpy(taddr.addr.buf, sa, addrlen);
#ifdef RPCBIND_DEBUG
		if (debugging) {
			/* for debugging print out our universal address */
			char *uaddr;
			struct netbuf nb;
		        int sa_size2 = 0;

			nb.buf = sa;
			switch( sa->sa_family){
			case AF_INET:
			  sa_size2 = sizeof (struct sockaddr_in);
			  break;
			case AF_INET6:
			  sa_size2 = sizeof (struct sockaddr_in6);				 
			  break;
			}
			nb.len = nb.maxlen = sa_size2;
			uaddr = taddr2uaddr(nconf, &nb);
			(void) fprintf(stderr, "rpcbind : my address is %s\n",
			    uaddr);
			(void) free(uaddr);
		}
#endif

		listen(fd, SOMAXCONN);

		my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr, RPC_MAXDATASIZE, RPC_MAXDATASIZE);
		if (my_xprt == (SVCXPRT *)NULL) {
			syslog(LOG_ERR, "%s: could not create service",
					nconf->nc_netid);
			goto error;
		}
	}

#ifdef PORTMAP
	/*
	 * Register both the versions for tcp/ip, udp/ip.
	 */
	if (si.si_af == AF_INET &&
	    (si.si_proto == IPPROTO_TCP || si.si_proto == IPPROTO_UDP)) {
		struct pmaplist *pml;

		pml = malloc(sizeof (struct pmaplist));
		if (pml == NULL) {
			syslog(LOG_ERR, "no memory!");
			exit(1);
		}
		pml->pml_map.pm_prog = PMAPPROG;
		pml->pml_map.pm_vers = PMAPVERS;
		pml->pml_map.pm_port = PMAPPORT;
		pml->pml_map.pm_prot = si.si_proto;

		switch (si.si_proto) {
		case IPPROTO_TCP:
			tcptrans = strdup(nconf->nc_netid);
			break;
		case IPPROTO_UDP:
			udptrans = strdup(nconf->nc_netid);
			break;
		} 
		pml->pml_next = list_pml;
		list_pml = pml;

		/* Add version 3 information */
		pml = malloc(sizeof (struct pmaplist));
		if (pml == NULL) {
			syslog(LOG_ERR, "no memory!");
			exit(1);
		}
		pml->pml_map = list_pml->pml_map;
		pml->pml_map.pm_vers = RPCBVERS;
		pml->pml_next = list_pml;
		list_pml = pml;

		/* Add version 4 information */
		pml = malloc (sizeof (struct pmaplist));
		if (pml == NULL) {
			syslog(LOG_ERR, "no memory!");
			exit(1);
		}
		pml->pml_map = list_pml->pml_map;
		pml->pml_map.pm_vers = RPCBVERS4;
		pml->pml_next = list_pml;
		list_pml = pml;

		/* Also add version 2 stuff to rpcbind list */
		rbllist_add(PMAPPROG, PMAPVERS, nconf, &taddr.addr);
	}

	/* We need to support portmap over IPv4. It makes sense to
	 * support it over AF_LOCAL as well, because that allows
	 * rpcbind to identify the owner of a socket much better
	 * than by relying on privileged ports to tell root from
	 * non-root users. */
	if (si.si_af == AF_INET || si.si_af == AF_LOCAL) {
		if (!svc_register(my_xprt, PMAPPROG, PMAPVERS, pmap_service, 0)) {
			syslog(LOG_ERR, "could not register on %s",
					nconf->nc_netid);
			goto error;
		}
	}
#endif

	/* version 3 registration */
	if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS, rpcb_service_3, NULL)) {
		syslog(LOG_ERR, "could not register %s version 3",
				nconf->nc_netid);
		goto error;
	}
	rbllist_add(RPCBPROG, RPCBVERS, nconf, &taddr.addr);

	/* version 4 registration */
	if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS4, rpcb_service_4, NULL)) {
		syslog(LOG_ERR, "could not register %s version 4",
				nconf->nc_netid);
		goto error;
	}
	rbllist_add(RPCBPROG, RPCBVERS4, nconf, &taddr.addr);

	/* decide if bound checking works for this transport */
	status = add_bndlist(nconf, &taddr.addr);
#ifdef RPCBIND_DEBUG
	if (debugging) {
		if (status < 0) {
			fprintf(stderr, "Error in finding bind status for %s\n",
				nconf->nc_netid);
		} else if (status == 0) {
			fprintf(stderr, "check binding for %s\n",
				nconf->nc_netid);
		} else if (status > 0) {
			fprintf(stderr, "No check binding for %s\n",
				nconf->nc_netid);
		}
	}
#endif
	/*
	 * rmtcall only supported on CLTS transports for now.
	 */
	if (nconf->nc_semantics == NC_TPI_CLTS) {
		status = create_rmtcall_fd(nconf);

#ifdef RPCBIND_DEBUG
		if (debugging) {
			if (status < 0) {
				fprintf(stderr,
				    "Could not create rmtcall fd for %s\n",
					nconf->nc_netid);
			} else {
				fprintf(stderr, "rmtcall fd for %s is %d\n",
					nconf->nc_netid, status);
			}
		}
#endif
	}
	return (0);
error:
	close(fd);
	return (1);
}
Exemplo n.º 9
0
/*
 * Adds the entry into the rpcbind database.
 * If PORTMAP, then for UDP and TCP, it adds the entries for version 2 also
 * Returns 0 if succeeds, else fails
 */
static int
init_transport(struct netconfig *nconf)
{
    int fd;
    struct t_bind taddr;
    struct addrinfo hints, *res = NULL;
    struct __rpc_sockinfo si;
    SVCXPRT	*my_xprt;
    int status;	/* bound checking ? */
    int aicode;
    int addrlen;
    int nhostsbak;
    int bound;
    struct sockaddr *sa;
    u_int32_t host_addr[4];  /* IPv4 or IPv6 */
    struct sockaddr_un sun;
    mode_t oldmask;

    if ((nconf->nc_semantics != NC_TPI_CLTS) &&
            (nconf->nc_semantics != NC_TPI_COTS) &&
            (nconf->nc_semantics != NC_TPI_COTS_ORD))
        return (1);	/* not my type */
#ifdef ND_DEBUG
    if (debugging) {
        int i;
        char **s;

        (void)fprintf(stderr, "%s: %ld lookup routines :\n",
                      nconf->nc_netid, nconf->nc_nlookups);
        for (i = 0, s = nconf->nc_lookups; i < nconf->nc_nlookups;
                i++, s++)
            fprintf(stderr, "[%d] - %s\n", i, *s);
    }
#endif

    /*
     * XXX - using RPC library internal functions.
     */
    if ((strcmp(nconf->nc_netid, "local") == 0) ||
            (strcmp(nconf->nc_netid, "unix") == 0)) {
        /*
         * For other transports we call this later, for each socket we
         * like to bind.
         */
        if ((fd = __rpc_nconf2fd(nconf)) < 0) {
            int non_fatal = 0;
            if (errno == EAFNOSUPPORT)
                non_fatal = 1;
            syslog(non_fatal?LOG_DEBUG:LOG_ERR, "cannot create socket for %s",
                   nconf->nc_netid);
            return (1);
        }
    }

    if (!__rpc_nconf2sockinfo(nconf, &si)) {
        syslog(LOG_ERR, "cannot get information for %s",
               nconf->nc_netid);
        return (1);
    }

    if ((strcmp(nconf->nc_netid, "local") == 0) ||
            (strcmp(nconf->nc_netid, "unix") == 0)) {
        memset(&sun, 0, sizeof sun);
        sun.sun_family = AF_LOCAL;
        unlink(_PATH_RPCBINDSOCK);
        strcpy(sun.sun_path, _PATH_RPCBINDSOCK);
        sun.sun_len = SUN_LEN(&sun);
        addrlen = sizeof (struct sockaddr_un);
        sa = (struct sockaddr *)&sun;
    } else {
        /* Get rpcbind's address on this transport */

        memset(&hints, 0, sizeof hints);
        hints.ai_flags = AI_PASSIVE;
        hints.ai_family = si.si_af;
        hints.ai_socktype = si.si_socktype;
        hints.ai_protocol = si.si_proto;
    }

    if ((strcmp(nconf->nc_netid, "local") != 0) &&
            (strcmp(nconf->nc_netid, "unix") != 0)) {
        /*
         * If no hosts were specified, just bind to INADDR_ANY.
         * Otherwise  make sure 127.0.0.1 is added to the list.
         */
        nhostsbak = nhosts + 1;
        hosts = realloc(hosts, nhostsbak * sizeof(char *));
        if (nhostsbak == 1)
            hosts[0] = "*";
        else {
            if (hints.ai_family == AF_INET) {
                hosts[nhostsbak - 1] = "127.0.0.1";
            } else if (hints.ai_family == AF_INET6) {
                hosts[nhostsbak - 1] = "::1";
            } else
                return 1;
        }

        /*
         * Bind to specific IPs if asked to
         */
        bound = 0;
        while (nhostsbak > 0) {
            --nhostsbak;
            /*
             * XXX - using RPC library internal functions.
             */
            if ((fd = __rpc_nconf2fd(nconf)) < 0) {
                int non_fatal = 0;
                if (errno == EAFNOSUPPORT &&
                        nconf->nc_semantics != NC_TPI_CLTS)
                    non_fatal = 1;
                syslog(non_fatal ? LOG_DEBUG : LOG_ERR,
                       "cannot create socket for %s", nconf->nc_netid);
                return (1);
            }
            switch (hints.ai_family) {
            case AF_INET:
                if (inet_pton(AF_INET, hosts[nhostsbak],
                              host_addr) == 1) {
                    hints.ai_flags &= AI_NUMERICHOST;
                } else {
                    /*
                     * Skip if we have an AF_INET6 address.
                     */
                    if (inet_pton(AF_INET6,
                                  hosts[nhostsbak], host_addr) == 1) {
                        close(fd);
                        continue;
                    }
                }
                break;
            case AF_INET6:
                if (inet_pton(AF_INET6, hosts[nhostsbak],
                              host_addr) == 1) {
                    hints.ai_flags &= AI_NUMERICHOST;
                } else {
                    /*
                     * Skip if we have an AF_INET address.
                     */
                    if (inet_pton(AF_INET, hosts[nhostsbak],
                                  host_addr) == 1) {
                        close(fd);
                        continue;
                    }
                }
                if (setsockopt(fd, IPPROTO_IPV6,
                               IPV6_V6ONLY, &on, sizeof on) < 0) {
                    syslog(LOG_ERR,
                           "can't set v6-only binding for "
                           "ipv6 socket: %m");
                    continue;
                }
                break;
            default:
                break;
            }

            /*
             * If no hosts were specified, just bind to INADDR_ANY
             */
            if (strcmp("*", hosts[nhostsbak]) == 0)
                hosts[nhostsbak] = NULL;
            if ((strcmp(nconf->nc_netid, "local") != 0) &&
                    (strcmp(nconf->nc_netid, "unix") != 0)) {
                if ((aicode = getaddrinfo(hosts[nhostsbak],
                                          servname, &hints, &res)) != 0) {
                    syslog(LOG_ERR,
                           "cannot get local address for %s: %s",
                           nconf->nc_netid, gai_strerror(aicode));
                    continue;
                }
                addrlen = res->ai_addrlen;
                sa = (struct sockaddr *)res->ai_addr;
            }
            oldmask = umask(S_IXUSR|S_IXGRP|S_IXOTH);
            if (bind(fd, sa, addrlen) != 0) {
                syslog(LOG_ERR, "cannot bind %s on %s: %m",
                       (hosts[nhostsbak] == NULL) ? "*" :
                       hosts[nhostsbak], nconf->nc_netid);
                if (res != NULL)
                    freeaddrinfo(res);
                continue;
            } else
                bound = 1;
            (void)umask(oldmask);

            /* Copy the address */
            taddr.addr.len = taddr.addr.maxlen = addrlen;
            taddr.addr.buf = malloc(addrlen);
            if (taddr.addr.buf == NULL) {
                syslog(LOG_ERR,
                       "cannot allocate memory for %s address",
                       nconf->nc_netid);
                if (res != NULL)
                    freeaddrinfo(res);
                return 1;
            }
            memcpy(taddr.addr.buf, sa, addrlen);
#ifdef ND_DEBUG
            if (debugging) {
                /*
                 * for debugging print out our universal
                 * address
                 */
                char *uaddr;
                struct netbuf nb;

                nb.buf = sa;
                nb.len = nb.maxlen = sa->sa_len;
                uaddr = taddr2uaddr(nconf, &nb);
                (void)fprintf(stderr,
                              "rpcbind : my address is %s\n", uaddr);
                (void)free(uaddr);
            }
#endif

            if (nconf->nc_semantics != NC_TPI_CLTS)
                listen(fd, SOMAXCONN);

            my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr,
                                                RPC_MAXDATASIZE, RPC_MAXDATASIZE);
            if (my_xprt == (SVCXPRT *)NULL) {
                syslog(LOG_ERR, "%s: could not create service",
                       nconf->nc_netid);
                goto error;
            }
        }
        if (!bound)
            return 1;
    } else {
        oldmask = umask(S_IXUSR|S_IXGRP|S_IXOTH);
        if (bind(fd, sa, addrlen) < 0) {
            syslog(LOG_ERR, "cannot bind %s: %m", nconf->nc_netid);
            if (res != NULL)
                freeaddrinfo(res);
            return 1;
        }
        (void) umask(oldmask);

        /* Copy the address */
        taddr.addr.len = taddr.addr.maxlen = addrlen;
        taddr.addr.buf = malloc(addrlen);
        if (taddr.addr.buf == NULL) {
            syslog(LOG_ERR, "cannot allocate memory for %s address",
                   nconf->nc_netid);
            if (res != NULL)
                freeaddrinfo(res);
            return 1;
        }
        memcpy(taddr.addr.buf, sa, addrlen);
#ifdef ND_DEBUG
        if (debugging) {
            /* for debugging print out our universal address */
            char *uaddr;
            struct netbuf nb;

            nb.buf = sa;
            nb.len = nb.maxlen = sa->sa_len;
            uaddr = taddr2uaddr(nconf, &nb);
            (void) fprintf(stderr, "rpcbind : my address is %s\n",
                           uaddr);
            (void) free(uaddr);
        }
#endif

        if (nconf->nc_semantics != NC_TPI_CLTS)
            listen(fd, SOMAXCONN);

        my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr,
                                            RPC_MAXDATASIZE, RPC_MAXDATASIZE);
        if (my_xprt == (SVCXPRT *)NULL) {
            syslog(LOG_ERR, "%s: could not create service",
                   nconf->nc_netid);
            goto error;
        }
    }

#ifdef PORTMAP
    /*
     * Register both the versions for tcp/ip, udp/ip and local.
     */
    if ((strcmp(nconf->nc_protofmly, NC_INET) == 0 &&
            (strcmp(nconf->nc_proto, NC_TCP) == 0 ||
             strcmp(nconf->nc_proto, NC_UDP) == 0)) ||
            (strcmp(nconf->nc_netid, "unix") == 0) ||
            (strcmp(nconf->nc_netid, "local") == 0)) {
        struct pmaplist *pml;

        if (!svc_register(my_xprt, PMAPPROG, PMAPVERS,
                          pmap_service, 0)) {
            syslog(LOG_ERR, "could not register on %s",
                   nconf->nc_netid);
            goto error;
        }
        pml = malloc(sizeof (struct pmaplist));
        if (pml == NULL) {
            syslog(LOG_ERR, "no memory!");
            exit(1);
        }
        pml->pml_map.pm_prog = PMAPPROG;
        pml->pml_map.pm_vers = PMAPVERS;
        pml->pml_map.pm_port = PMAPPORT;
        if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
            if (tcptrans[0]) {
                syslog(LOG_ERR,
                       "cannot have more than one TCP transport");
                goto error;
            }
            tcptrans = strdup(nconf->nc_netid);
            pml->pml_map.pm_prot = IPPROTO_TCP;

            /* Let's snarf the universal address */
            /* "h1.h2.h3.h4.p1.p2" */
            tcp_uaddr = taddr2uaddr(nconf, &taddr.addr);
        } else if (strcmp(nconf->nc_proto, NC_UDP) == 0) {
            if (udptrans[0]) {
                syslog(LOG_ERR,
                       "cannot have more than one UDP transport");
                goto error;
            }
            udptrans = strdup(nconf->nc_netid);
            pml->pml_map.pm_prot = IPPROTO_UDP;

            /* Let's snarf the universal address */
            /* "h1.h2.h3.h4.p1.p2" */
            udp_uaddr = taddr2uaddr(nconf, &taddr.addr);
        } else if (strcmp(nconf->nc_netid, "local") == 0)
            pml->pml_map.pm_prot = IPPROTO_ST;
        else if (strcmp(nconf->nc_netid, "unix") == 0)
            pml->pml_map.pm_prot = IPPROTO_ST;
        pml->pml_next = list_pml;
        list_pml = pml;

        /* Add version 3 information */
        pml = malloc(sizeof (struct pmaplist));
        if (pml == NULL) {
            syslog(LOG_ERR, "no memory!");
            exit(1);
        }
        pml->pml_map = list_pml->pml_map;
        pml->pml_map.pm_vers = RPCBVERS;
        pml->pml_next = list_pml;
        list_pml = pml;

        /* Add version 4 information */
        pml = malloc (sizeof (struct pmaplist));
        if (pml == NULL) {
            syslog(LOG_ERR, "no memory!");
            exit(1);
        }
        pml->pml_map = list_pml->pml_map;
        pml->pml_map.pm_vers = RPCBVERS4;
        pml->pml_next = list_pml;
        list_pml = pml;

        /* Also add version 2 stuff to rpcbind list */
        rbllist_add(PMAPPROG, PMAPVERS, nconf, &taddr.addr);
    }
#endif

    /* version 3 registration */
    if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS, rpcb_service_3, NULL)) {
        syslog(LOG_ERR, "could not register %s version 3",
               nconf->nc_netid);
        goto error;
    }
    rbllist_add(RPCBPROG, RPCBVERS, nconf, &taddr.addr);

    /* version 4 registration */
    if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS4, rpcb_service_4, NULL)) {
        syslog(LOG_ERR, "could not register %s version 4",
               nconf->nc_netid);
        goto error;
    }
    rbllist_add(RPCBPROG, RPCBVERS4, nconf, &taddr.addr);

    /* decide if bound checking works for this transport */
    status = add_bndlist(nconf, &taddr.addr);
#ifdef BIND_DEBUG
    if (debugging) {
        if (status < 0) {
            fprintf(stderr, "Error in finding bind status for %s\n",
                    nconf->nc_netid);
        } else if (status == 0) {
            fprintf(stderr, "check binding for %s\n",
                    nconf->nc_netid);
        } else if (status > 0) {
            fprintf(stderr, "No check binding for %s\n",
                    nconf->nc_netid);
        }
    }
#endif
    /*
     * rmtcall only supported on CLTS transports for now.
     */
    if (nconf->nc_semantics == NC_TPI_CLTS) {
        status = create_rmtcall_fd(nconf);

#ifdef BIND_DEBUG
        if (debugging) {
            if (status < 0) {
                fprintf(stderr,
                        "Could not create rmtcall fd for %s\n",
                        nconf->nc_netid);
            } else {
                fprintf(stderr, "rmtcall fd for %s is %d\n",
                        nconf->nc_netid, status);
            }
        }
#endif
    }
    return (0);
error:
    close(fd);
    return (1);
}
Exemplo n.º 10
0
/*
 * Adds the entry into the rpcbind database.
 * If PORTMAP, then for UDP and TCP, it adds the entries for version 2 also
 * Returns 0 if succeeds, else fails
 */
static int
init_transport(struct netconfig *nconf)
{
	int fd;
	struct t_bind taddr;
	struct addrinfo hints, *res = NULL;
	struct __rpc_sockinfo si;
	SVCXPRT	*my_xprt;
	int status;	/* bound checking ? */
	int aicode;
	int addrlen;
	struct sockaddr *sa;
	struct sockaddr_un sun;
	const int one = 1;

	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
		(nconf->nc_semantics != NC_TPI_COTS) &&
		(nconf->nc_semantics != NC_TPI_COTS_ORD))
		return 1;	/* not my type */
#ifdef RPCBIND_DEBUG
	if (debugging) {
		int i;
		char **s;

		(void)fprintf(stderr, "%s: %ld lookup routines :\n",
		    nconf->nc_netid, nconf->nc_nlookups);
		for (i = 0, s = nconf->nc_lookups; i < nconf->nc_nlookups;
		     i++, s++)
			(void)fprintf(stderr, "[%d] - %s\n", i, *s);
	}
#endif

	/*
	 * XXX - using RPC library internal functions.
	 */
	if ((fd = __rpc_nconf2fd(nconf)) < 0) {
		if (errno == EAFNOSUPPORT)
			return 1;
		warn("Cannot create socket for `%s'", nconf->nc_netid);
		return 1;
	}

	if (!__rpc_nconf2sockinfo(nconf, &si)) {
		warnx("Cannot get information for `%s'", nconf->nc_netid);
		return 1;
	}

	if (si.si_af == AF_INET6) {
		/*
		 * We're doing host-based access checks here, so don't allow
		 * v4-in-v6 to confuse things.
		 */
		if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one,
		    sizeof one) < 0) {
			warn("Can't make socket ipv6 only");
			return 1;
		}
	}


	if (!strcmp(nconf->nc_netid, "local")) {
		(void)memset(&sun, 0, sizeof sun);
		sun.sun_family = AF_LOCAL;
#ifdef RPCBIND_RUMP
		(void)rump_sys_unlink(_PATH_RPCBINDSOCK);
#else
		(void)unlink(_PATH_RPCBINDSOCK);
#endif
		(void)strlcpy(sun.sun_path, _PATH_RPCBINDSOCK,
		    sizeof(sun.sun_path));
		sun.sun_len = SUN_LEN(&sun);
		addrlen = sizeof(struct sockaddr_un);
		sa = (struct sockaddr *)&sun;
	} else {
		/* Get rpcbind's address on this transport */

		(void)memset(&hints, 0, sizeof hints);
		hints.ai_flags = AI_PASSIVE;
		hints.ai_family = si.si_af;
		hints.ai_socktype = si.si_socktype;
		hints.ai_protocol = si.si_proto;
		if ((aicode = getaddrinfo(NULL, servname, &hints, &res)) != 0) {
			warnx("Cannot get local address for `%s' (%s)",
			    nconf->nc_netid, gai_strerror(aicode));
			return 1;
		}
		addrlen = res->ai_addrlen;
		sa = (struct sockaddr *)res->ai_addr;
	}

	if (bind(fd, sa, addrlen) < 0) {
		warn("Cannot bind `%s'", nconf->nc_netid);
		if (res != NULL)
			freeaddrinfo(res);
		return 1;
	}
#ifndef RPCBIND_RUMP
	if (sa->sa_family == AF_LOCAL)
		if (chmod(sun.sun_path, S_IRWXU|S_IRWXG|S_IRWXO) == -1)
			warn("Cannot chmod `%s'", sun.sun_path);
#endif

	/* Copy the address */
	taddr.addr.len = taddr.addr.maxlen = addrlen;
	taddr.addr.buf = malloc(addrlen);
	if (taddr.addr.buf == NULL) {
		warn("Cannot allocate memory for `%s' address",
		    nconf->nc_netid);
		if (res != NULL)
			freeaddrinfo(res);
		return 1;
	}
	(void)memcpy(taddr.addr.buf, sa, addrlen);
#ifdef RPCBIND_DEBUG
	if (debugging) {
		/* for debugging print out our universal address */
		char *uaddr;
		struct netbuf nb;

		nb.buf = sa;
		nb.len = nb.maxlen = sa->sa_len;
		uaddr = taddr2uaddr(nconf, &nb);
		(void)fprintf(stderr, "rpcbind: my address is %s fd=%d\n",
		    uaddr, fd);
		(void)free(uaddr);
	}
#endif

	if (res != NULL)
		freeaddrinfo(res);

	if (nconf->nc_semantics != NC_TPI_CLTS)
		listen(fd, SOMAXCONN);
		
	my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr, RPC_MAXDATASIZE,
	    RPC_MAXDATASIZE);
	if (my_xprt == NULL) {
		warnx("Could not create service for `%s'", nconf->nc_netid);
		goto error;
	}

#ifdef PORTMAP
	/*
	 * Register both the versions for tcp/ip, udp/ip and local.
	 */
	if ((strcmp(nconf->nc_protofmly, NC_INET) == 0 &&
		(strcmp(nconf->nc_proto, NC_TCP) == 0 ||
		strcmp(nconf->nc_proto, NC_UDP) == 0)) ||
		strcmp(nconf->nc_netid, "local") == 0) {
		struct pmaplist *pml;

		if (!svc_register(my_xprt, PMAPPROG, PMAPVERS,
			pmap_service, 0)) {
			warn("Could not register on `%s'", nconf->nc_netid);
			goto error;
		}
		pml = malloc(sizeof (struct pmaplist));
		if (pml == NULL) {
			warn("Cannot allocate memory");
			goto error;
		}
		pml->pml_map.pm_prog = PMAPPROG;
		pml->pml_map.pm_vers = PMAPVERS;
		pml->pml_map.pm_port = PMAPPORT;
		if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
			if (tcptrans[0]) {
				warnx(
				    "Cannot have more than one TCP transport");
				free(pml);
				goto error;
			}
			tcptrans = strdup(nconf->nc_netid);
			if (tcptrans == NULL) {
				free(pml);
				warn("Cannot allocate memory");
				goto error;
			}
			pml->pml_map.pm_prot = IPPROTO_TCP;

			/* Let's snarf the universal address */
			/* "h1.h2.h3.h4.p1.p2" */
			tcp_uaddr = taddr2uaddr(nconf, &taddr.addr);
		} else if (strcmp(nconf->nc_proto, NC_UDP) == 0) {
			if (udptrans[0]) {
				free(pml);
				warnx(
				"Cannot have more than one UDP transport");
				goto error;
			}
			udptrans = strdup(nconf->nc_netid);
			if (udptrans == NULL) {
				free(pml);
				warn("Cannot allocate memory");
				goto error;
			}
			pml->pml_map.pm_prot = IPPROTO_UDP;

			/* Let's snarf the universal address */
			/* "h1.h2.h3.h4.p1.p2" */
			udp_uaddr = taddr2uaddr(nconf, &taddr.addr);
		}
		pml->pml_next = list_pml;
		list_pml = pml;

		/* Add version 3 information */
		pml = malloc(sizeof (struct pmaplist));
		if (pml == NULL) {
			warn("Cannot allocate memory");
			goto error;
		}
		pml->pml_map = list_pml->pml_map;
		pml->pml_map.pm_vers = RPCBVERS;
		pml->pml_next = list_pml;
		list_pml = pml;

		/* Add version 4 information */
		pml = malloc(sizeof (struct pmaplist));
		if (pml == NULL) {
			warn("Cannot allocate memory");
			goto error;
		}
		pml->pml_map = list_pml->pml_map;
		pml->pml_map.pm_vers = RPCBVERS4;
		pml->pml_next = list_pml;
		list_pml = pml;

		/* Also add version 2 stuff to rpcbind list */
		rbllist_add(PMAPPROG, PMAPVERS, nconf, &taddr.addr);
	}
#endif

	/* version 3 registration */
	if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS, rpcb_service_3, NULL)) {
		warn("Could not register %s version 3", nconf->nc_netid);
		goto error;
	}
	rbllist_add(RPCBPROG, RPCBVERS, nconf, &taddr.addr);

	/* version 4 registration */
	if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS4, rpcb_service_4, NULL)) {
		warn("Could not register %s version 4", nconf->nc_netid);
		goto error;
	}
	rbllist_add(RPCBPROG, RPCBVERS4, nconf, &taddr.addr);

	/* decide if bound checking works for this transport */
	status = add_bndlist(nconf, &taddr.addr);
#ifdef RPCBIND_DEBUG
	if (debugging) {
		if (status < 0) {
			fprintf(stderr, "Error in finding bind status for %s\n",
				nconf->nc_netid);
		} else if (status == 0) {
			fprintf(stderr, "check binding for %s\n",
				nconf->nc_netid);
		} else if (status > 0) {
			fprintf(stderr, "No check binding for %s\n",
				nconf->nc_netid);
		}
	}
#else
	__USE(status);
#endif
	/*
	 * rmtcall only supported on CLTS transports for now.
	 */
	if (nconf->nc_semantics == NC_TPI_CLTS) {
		status = create_rmtcall_fd(nconf);

#ifdef RPCBIND_DEBUG
		if (debugging) {
			if (status < 0) {
				fprintf(stderr,
				    "Could not create rmtcall fd for %s\n",
					nconf->nc_netid);
			} else {
				fprintf(stderr, "rmtcall fd for %s is %d\n",
					nconf->nc_netid, status);
			}
		}
#endif
	}
	return (0);
error:
#ifdef RPCBIND_RUMP
	(void)rump_sys_close(fd);
#else
	(void)close(fd);
#endif
	return (1);
}