示例#1
0
char *
get_uaddr(int fd, struct netconfig *nconf, struct netbuf *nb)
{
	struct nfs_svc_args nsa;
	char *ua, *ua2, *mua = NULL;
	char me[MAXHOSTNAMELEN];
	struct nd_addrlist *nas;
	struct nd_hostserv hs;
	struct nd_mergearg ma;

	ua = taddr2uaddr(nconf, nb);

	if (ua == NULL) {
#ifdef	DEBUG
		fprintf(stderr, "taddr2uaddr failed for netid %s\n",
			nconf->nc_netid);
#endif
		return (NULL);
	}

	gethostname(me, MAXHOSTNAMELEN);

	hs.h_host = me;
	hs.h_serv = "nfs";
	if (netdir_getbyname(nconf, &hs, &nas)) {
#ifdef DEBUG
		netdir_perror("netdir_getbyname");
#endif
		return (NULL);
	}

	ua2 = taddr2uaddr(nconf, nas->n_addrs);

	if (ua2 == NULL) {
#ifdef	DEBUG
		fprintf(stderr, "taddr2uaddr failed for netid %s.\n",
			nconf->nc_netid);
#endif
		return (NULL);
	}

	ma.s_uaddr = ua;
	ma.c_uaddr = ua2;
	ma.m_uaddr = NULL;

	if (netdir_options(nconf, ND_MERGEADDR, 0, (char *)&ma)) {
#ifdef DEBUG
		netdir_perror("netdir_options");
#endif
		return (NULL);
	}

	mua = ma.m_uaddr;
	return (mua);
}
示例#2
0
/*
 * rpcb_log - log request for service
 */
void
rpcb_log(boolean_t verdict, SVCXPRT *transp, rpcproc_t proc, rpcprog_t prog,
         boolean_t pm)
{
    struct netconfig *conf;
    const char *client = "unknown";
    char *uaddr;
    char buf[BUFSIZ];

    /*
     * Transform the transport address into something printable.
     */
    if ((conf = rpcbind_get_conf(transp->xp_netid)) == 0) {
        syslog(LOG_WARNING,
               "unknown transport (rpcbind_get_conf failed)");
    } else if (strcmp(conf->nc_protofmly, "inet") == 0 ||
               strcmp(conf->nc_protofmly, "inet6") == 0) {
        client = sgen_toa(svc_getgencaller(transp));
    } else if ((uaddr = taddr2uaddr(conf, &(transp->xp_rtaddr))) == NULL) {
        syslog(LOG_WARNING, "unknown address (taddr2uaddr failed)");
    } else {
        (void) snprintf(buf, sizeof (buf), "%s(%s)",
                        conf->nc_protofmly, uaddr);
        free(uaddr);
        client = buf;
    }
    qsyslog(verdict ? allow_severity : deny_severity,
            "%sconnect from %s to %s(%s)", verdict ? "" : "refused ",
            client, find_procname(proc, pm), find_progname(prog));
}
示例#3
0
static void
rbllist_add(rpcprog_t prog, rpcvers_t vers, struct netconfig *nconf,
	    struct netbuf *addr)
{
	rpcblist_ptr rbl;

	rbl = malloc(sizeof (rpcblist));
	if (rbl == NULL) {
		syslog(LOG_ERR, "no memory!");
		exit(1);
	}
#ifdef RPCBIND_DEBUG	
	if (debugging){
	  fprintf(stderr,"FUNCTION rbllist_add");
	  fprintf(stderr,"Add the prog %lu vers %lu to the rpcbind list\n",
                  (ulong)prog, (ulong)vers);
	}
#endif	
        rbl->rpcb_map.r_prog = prog;
	rbl->rpcb_map.r_vers = vers;
	rbl->rpcb_map.r_netid = strdup(nconf->nc_netid);
	rbl->rpcb_map.r_addr = taddr2uaddr(nconf, addr);
	rbl->rpcb_map.r_owner = strdup(superuser);
	rbl->rpcb_next = list_rbl;	/* Attach to global list */
	list_rbl = rbl;
}
示例#4
0
/*
 * Returns NULL if there was some system error.
 * Returns "" if the address was not bound, i.e the server crashed.
 * Returns the merged address otherwise.
 */
char *
mergeaddr(SVCXPRT *xprt, char *netid, char *uaddr, char *saddr)
{
	struct fdlist *fdl;
	char *c_uaddr, *s_uaddr, *m_uaddr, *allocated_uaddr = NULL;

	for (fdl = fdhead; fdl; fdl = fdl->next)
		if (strcmp(fdl->nconf->nc_netid, netid) == 0)
			break;
	if (fdl == NULL)
		return (NULL);
	if (check_bound(fdl, uaddr) == FALSE)
		/* that server died */
		return strdup(emptystring);
	/*
	 * If saddr is not NULL, the remote client may have included the
	 * address by which it contacted us.  Use that for the "client" uaddr,
	 * otherwise use the info from the SVCXPRT.
	 */
	if (saddr != NULL) {
		c_uaddr = saddr;
	} else {
		c_uaddr = taddr2uaddr(fdl->nconf, svc_getrpccaller(xprt));
		if (c_uaddr == NULL) {
			syslog(LOG_ERR, "taddr2uaddr failed for %s",
				fdl->nconf->nc_netid);
			return (NULL);
		}
		allocated_uaddr = c_uaddr;
	}

#ifdef RPCBIND_DEBUG
	if (debugging) {
		if (saddr == NULL) {
			fprintf(stderr, "mergeaddr: client uaddr = %s\n",
			    c_uaddr);
		} else {
			fprintf(stderr, "mergeaddr: contact uaddr = %s\n",
			    c_uaddr);
		}
	}
#endif
	s_uaddr = uaddr;
	/*
	 * This is all we should need for IP 4 and 6
	 */
	m_uaddr = addrmerge(svc_getrpccaller(xprt), s_uaddr, c_uaddr, netid);
#ifdef RPCBIND_DEBUG
	if (debugging)
		fprintf(stderr, "mergeaddr: uaddr = %s, merged uaddr = %s\n",
				uaddr, m_uaddr);
#endif
	if (allocated_uaddr != NULL)
		free(allocated_uaddr);
	return (m_uaddr);
}
示例#5
0
static char *
get_uaddr(struct netconfig *nconf, struct netbuf *nb)
{
	struct nfs_svc_args nsa;
	char *ua, *ua2, *mua = NULL;
	char me[MAXHOSTNAMELEN];
	struct nd_addrlist *nas;
	struct nd_hostserv hs;
	struct nd_mergearg ma;

	ua = taddr2uaddr(nconf, nb);

	if (ua == NULL) {
		return (NULL);
	}

	gethostname(me, MAXHOSTNAMELEN);

	hs.h_host = me;
	hs.h_serv = "nfs";
	if (netdir_getbyname(nconf, &hs, &nas)) {
		return (NULL);
	}

	ua2 = taddr2uaddr(nconf, nas->n_addrs);

	if (ua2 == NULL) {
		return (NULL);
	}

	ma.s_uaddr = ua;
	ma.c_uaddr = ua2;
	ma.m_uaddr = NULL;

	if (netdir_options(nconf, ND_MERGEADDR, 0, (char *)&ma)) {
		return (NULL);
	}

	mua = ma.m_uaddr;
	return (mua);
}
示例#6
0
static	int
TRANS(TLIAddrToNetbuf)(int tlifamily, char *host, char *port,
		       struct netbuf *netbufp)

{
    struct netconfig *netconfigp;
    struct nd_hostserv	nd_hostserv;
    struct nd_addrlist *nd_addrlistp = NULL;
    void *handlep;
    long lport;

    prmsg(3,"TLIAddrToNetbuf(%d,%s,%s)\n", tlifamily, host, port );

    if( (handlep=setnetconfig()) == NULL )
	return -1;

    lport = strtol (port, (char**)NULL, 10);
    if (lport < 1024 || lport > USHRT_MAX)
	return -1;

    nd_hostserv.h_host = host;
    if( port && *port ) {
	nd_hostserv.h_serv = port;
    } else {
	nd_hostserv.h_serv = NULL;
    }

    while( (netconfigp=getnetconfig(handlep)) != NULL )
    {
	if( strcmp(netconfigp->nc_protofmly,
		   TLItrans2devtab[tlifamily].protofamily) != 0 )
	    continue;
	prmsg(5,"TLIAddrToNetbuf: Trying to resolve %s.%s for %s\n",
	      host, port, TLItrans2devtab[tlifamily].protofamily );
	if( netdir_getbyname(netconfigp,&nd_hostserv, &nd_addrlistp) == 0 )
	{
	    /* we have at least one address to use */

	    prmsg(5, "TLIAddrToNetbuf: found address for %s.%s\n", host, port);
	    prmsg(5, "TLIAddrToNetbuf: %s\n",taddr2uaddr(netconfigp,nd_addrlistp->n_addrs));

	    memcpy(netbufp->buf,nd_addrlistp->n_addrs->buf,
		   nd_addrlistp->n_addrs->len);
	    netbufp->len=nd_addrlistp->n_addrs->len;
	    endnetconfig(handlep);
	    return 0;
	}
    }
    endnetconfig(handlep);

    return -1;
}
示例#7
0
/* ARGSUSED */
static void *
rpcbproc_getaddr_4_local(void *arg, struct svc_req *rqstp, SVCXPRT *transp,
			 rpcvers_t rpcbversnum /*__unused*/)
{
	RPCB *regp = (RPCB *)arg;
#ifdef RPCBIND_DEBUG
	if (debugging) {
		char *uaddr;

		uaddr =	taddr2uaddr(rpcbind_get_conf(transp->xp_netid),
			    svc_getrpccaller(transp));
		fprintf(stderr, "RPCB_GETADDR req for (%lu, %lu, %s) from %s: ",
		    (unsigned long)regp->r_prog, (unsigned long)regp->r_vers,
		    regp->r_netid, uaddr);
		free(uaddr);
	}
#endif
	return (rpcbproc_getaddr_com(regp, rqstp, transp, RPCBVERS4,
					RPCB_ALLVERS));
}
示例#8
0
static void
rbllist_add(rpcprog_t prog, rpcvers_t vers, struct netconfig *nconf,
            struct netbuf *addr)
{
    rpcblist_ptr rbl;

    rbl = malloc(sizeof (rpcblist));
    if (rbl == NULL) {
        syslog(LOG_ERR, "no memory!");
        exit(1);
    }

    rbl->rpcb_map.r_prog = prog;
    rbl->rpcb_map.r_vers = vers;
    rbl->rpcb_map.r_netid = strdup(nconf->nc_netid);
    rbl->rpcb_map.r_addr = taddr2uaddr(nconf, addr);
    rbl->rpcb_map.r_owner = strdup(superuser);
    rbl->rpcb_next = list_rbl;	/* Attach to global list */
    list_rbl = rbl;
}
示例#9
0
文件: rpcbind.c 项目: ryo/netbsd-src
static void
rbllist_add(rpcprog_t prog, rpcvers_t vers, struct netconfig *nconf,
	    struct netbuf *addr)
{
	rpcblist_ptr rbl;

	rbl = malloc(sizeof(rpcblist));
	if (rbl == NULL) {
		warn("Out of memory");
		return;
	}

	rbl->rpcb_map.r_prog = prog;
	rbl->rpcb_map.r_vers = vers;
	rbl->rpcb_map.r_netid = strdup(nconf->nc_netid);
	rbl->rpcb_map.r_addr = taddr2uaddr(nconf, addr);
	rbl->rpcb_map.r_owner = strdup(rpcbind_superuser);
	rbl->rpcb_next = list_rbl;	/* Attach to global list */
	list_rbl = rbl;
}
示例#10
0
/*
 * Find a server address that can be used by `caller' to contact
 * the local service specified by `serv_uaddr'. If `clnt_uaddr' is
 * non-NULL, it is used instead of `caller' as a hint suggesting
 * the best address (e.g. the `r_addr' field of an rpc, which
 * contains the rpcbind server address that the caller used).
 *
 * Returns the best server address as a malloc'd "universal address"
 * string which should be freed by the caller. On error, returns NULL.
 */
char *
addrmerge(struct netbuf *caller, const char *serv_uaddr, const char *clnt_uaddr,
	  const char *netid)
{
	struct ifaddrs *ifap, *ifp = NULL, *bestif;
	struct netbuf *serv_nbp = NULL, *hint_nbp = NULL, tbuf;
	struct sockaddr *caller_sa, *hint_sa, *ifsa, *ifmasksa, *serv_sa;
	struct sockaddr_storage ss;
	struct netconfig *nconf;
	char *caller_uaddr = NULL;
	const char *hint_uaddr = NULL;
	char *ret = NULL;
	int bestif_goodness;

#ifdef ND_DEBUG
	if (debugging)
		fprintf(stderr, "addrmerge(caller, %s, %s, %s\n", serv_uaddr,
		    clnt_uaddr == NULL ? "NULL" : clnt_uaddr, netid);
#endif
	caller_sa = caller->buf;
	if ((nconf = rpcbind_get_conf(netid)) == NULL)
		goto freeit;
	if ((caller_uaddr = taddr2uaddr(nconf, caller)) == NULL)
		goto freeit;

	/*
	 * Use `clnt_uaddr' as the hint if non-NULL, but ignore it if its
	 * address family is different from that of the caller.
	 */
	hint_sa = NULL;
	if (clnt_uaddr != NULL) {
		hint_uaddr = clnt_uaddr;
		if ((hint_nbp = uaddr2taddr(nconf, clnt_uaddr)) == NULL)
			goto freeit;
		hint_sa = hint_nbp->buf;
	}
	if (hint_sa == NULL || hint_sa->sa_family != caller_sa->sa_family) {
		hint_uaddr = caller_uaddr;
		hint_sa = caller->buf;
	}

#ifdef ND_DEBUG
	if (debugging)
		fprintf(stderr, "addrmerge: hint %s\n", hint_uaddr);
#endif
	/* Local caller, just return the server address. */
	if (strncmp(caller_uaddr, "0.0.0.0.", 8) == 0 ||
	    strncmp(caller_uaddr, "::.", 3) == 0 || caller_uaddr[0] == '/') {
		ret = strdup(serv_uaddr);
		goto freeit;
	}

	if (getifaddrs(&ifp) < 0)
		goto freeit;

	/*
	 * Loop through all interface addresses.  We are listening to an address
	 * if any of the following are true:
	 * a) It's a loopback address
	 * b) It was specified with the -h command line option
	 * c) There were no -h command line options.
	 *
	 * Among addresses on which we are listening, choose in order of
	 * preference an address that is:
	 *
	 * a) Equal to the hint
	 * b) A link local address with the same scope ID as the client's
	 *    address, if the client's address is also link local
	 * c) An address on the same subnet as the client's address
	 * d) A non-localhost, non-p2p address
	 * e) Any usable address
	 */
	bestif = NULL;
	bestif_goodness = 0;
	for (ifap = ifp; ifap != NULL; ifap = ifap->ifa_next) {
		ifsa = ifap->ifa_addr;
		ifmasksa = ifap->ifa_netmask;

		/* Skip addresses where we don't listen */
		if (ifsa == NULL || ifsa->sa_family != hint_sa->sa_family ||
		    !(ifap->ifa_flags & IFF_UP))
			continue;

		if (!(ifap->ifa_flags & IFF_LOOPBACK) && !listen_addr(ifsa))
			continue;

		if ((hint_sa->sa_family == AF_INET) &&
		    ((((struct sockaddr_in*)hint_sa)->sin_addr.s_addr == 
		      ((struct sockaddr_in*)ifsa)->sin_addr.s_addr))) {
			const int goodness = 4;

			bestif_goodness = goodness;
			bestif = ifap;
			goto found;
		}
#ifdef INET6
		if ((hint_sa->sa_family == AF_INET6) &&
		    (0 == memcmp(&((struct sockaddr_in6*)hint_sa)->sin6_addr,
				 &((struct sockaddr_in6*)ifsa)->sin6_addr,
				 sizeof(struct in6_addr))) &&
		    (((struct sockaddr_in6*)hint_sa)->sin6_scope_id ==
		    (((struct sockaddr_in6*)ifsa)->sin6_scope_id))) {
			const int goodness = 4;

			bestif_goodness = goodness;
			bestif = ifap;
			goto found;
		}
		if (hint_sa->sa_family == AF_INET6) {
			/*
			 * For v6 link local addresses, if the caller is on
			 * a link-local address then use the scope id to see
			 * which one.
			 */
			if (IN6_IS_ADDR_LINKLOCAL(&SA2SIN6ADDR(ifsa)) &&
			    IN6_IS_ADDR_LINKLOCAL(&SA2SIN6ADDR(caller_sa)) &&
			    IN6_IS_ADDR_LINKLOCAL(&SA2SIN6ADDR(hint_sa))) {
				if (SA2SIN6(ifsa)->sin6_scope_id ==
				    SA2SIN6(caller_sa)->sin6_scope_id) {
					const int goodness = 3;

					if (bestif_goodness < goodness) {
						bestif = ifap;
						bestif_goodness = goodness;
					}
				}
			}
		}
#endif /* INET6 */
		if (0 == bitmaskcmp(hint_sa, ifsa, ifmasksa)) {
			const int goodness = 2;

			if (bestif_goodness < goodness) {
				bestif = ifap;
				bestif_goodness = goodness;
			}
		}
		if (!(ifap->ifa_flags & (IFF_LOOPBACK | IFF_POINTOPOINT))) {
			const int goodness = 1;

			if (bestif_goodness < goodness) {
				bestif = ifap;
				bestif_goodness = goodness;
			}
		}
		if (bestif == NULL)
			bestif = ifap;
	}
	if (bestif == NULL)
		goto freeit;

found:
	/*
	 * Construct the new address using the address from
	 * `bestif', and the port number from `serv_uaddr'.
	 */
	serv_nbp = uaddr2taddr(nconf, serv_uaddr);
	if (serv_nbp == NULL)
		goto freeit;
	serv_sa = serv_nbp->buf;

	memcpy(&ss, bestif->ifa_addr, bestif->ifa_addr->sa_len);
	switch (ss.ss_family) {
	case AF_INET:
		SA2SIN(&ss)->sin_port = SA2SIN(serv_sa)->sin_port;
		break;
#ifdef INET6
	case AF_INET6:
		SA2SIN6(&ss)->sin6_port = SA2SIN6(serv_sa)->sin6_port;
		break;
#endif
	}
	tbuf.len = ss.ss_len;
	tbuf.maxlen = sizeof(ss);
	tbuf.buf = &ss;
	ret = taddr2uaddr(nconf, &tbuf);

freeit:
	if (caller_uaddr != NULL)
		free(caller_uaddr);
	if (hint_nbp != NULL) {
		free(hint_nbp->buf);
		free(hint_nbp);
	}
	if (serv_nbp != NULL) {
		free(serv_nbp->buf);
		free(serv_nbp);
	}
	if (ifp != NULL)
		freeifaddrs(ifp);

#ifdef ND_DEBUG
	if (debugging)
		fprintf(stderr, "addrmerge: returning %s\n", ret);
#endif
	return ret;
}
示例#11
0
int nfs41_server_resolve(
    IN const char *hostname,
    IN unsigned short port,
    OUT multi_addr4 *addrs)
{
    int status = ERROR_BAD_NET_NAME;
    char service[16];
    struct addrinfo hints = { 0 }, *res, *info;
    struct netconfig *nconf;
    struct netbuf addr;
    char *netid, *uaddr;

    dprintf(SRVLVL, "--> nfs41_server_resolve(%s:%u)\n",
        hostname, port);

    addrs->count = 0;

    StringCchPrintfA(service, 16, "%u", port);

    /* request a list of tcp addrs for the given hostname,port */
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    if (getaddrinfo(hostname, service, &hints, &res) != 0)
        goto out;

    for (info = res; info != NULL; info = info->ai_next) {
        /* find the appropriate entry in /etc/netconfig */
        switch (info->ai_family) {
        case AF_INET:  netid = "tcp";  break;
        case AF_INET6: netid = "tcp6"; break;
        default: continue;
        }

        nconf = getnetconfigent(netid);
        if (nconf == NULL)
            continue;

        /* convert to a transport-independent universal address */
        addr.buf = info->ai_addr;
        addr.maxlen = addr.len = (unsigned int)info->ai_addrlen;

        uaddr = taddr2uaddr(nconf, &addr);
        freenetconfigent(nconf);

        if (uaddr == NULL)
            continue;

        StringCchCopyA(addrs->arr[addrs->count].netid,
            NFS41_NETWORK_ID_LEN+1, netid);
        StringCchCopyA(addrs->arr[addrs->count].uaddr,
            NFS41_UNIVERSAL_ADDR_LEN+1, uaddr);
        freeuaddr(uaddr);

        status = NO_ERROR;
        if (++addrs->count >= NFS41_ADDRS_PER_SERVER)
            break;
    }
    freeaddrinfo(res);
out:
    if (status)
        dprintf(SRVLVL, "<-- nfs41_server_resolve(%s:%u) returning "
            "error %d\n", hostname, port, status);
    else
        dprintf(SRVLVL, "<-- nfs41_server_resolve(%s:%u) returning "
            "%s\n", hostname, port, addrs->arr[0].uaddr);
    return status;
}
示例#12
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);
}
示例#13
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);
}
示例#14
0
/*
 * Look up addresses for the kernel to create transports for.
 */
void
lookup_addresses(struct netconfig *nconf)
{
	struct addrinfo hints, *res = NULL;
	struct sockaddr_in *sin;
	struct sockaddr_in6 *sin6;
	struct __rpc_sockinfo si;
	struct netbuf servaddr;
	int aicode;
	int nhostsbak;
	u_int32_t host_addr[4];  /* IPv4 or IPv6 */
	char *uaddr;

	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
	    (nconf->nc_semantics != NC_TPI_COTS) &&
	    (nconf->nc_semantics != NC_TPI_COTS_ORD))
		return;	/* 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;
	}

	/* Get rpc.statd'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;

	/*
	 * Bind to specific IPs if asked to
	 */
	nhostsbak = nhosts;
	while (nhostsbak > 0) {
		--nhostsbak;

		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) {
						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) {
						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();
				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(res->ai_addr);
						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(res->ai_addr);
						break;
					default:
						break;
				}
			} 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));
					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));
				continue;
			}
		}

		servaddr.len = servaddr.maxlen = res->ai_addr->sa_len;
		servaddr.buf = res->ai_addr;
		uaddr = taddr2uaddr(nconf, &servaddr);

		addrs = realloc(addrs, 2 * (naddrs + 1) * sizeof(char *));
		if (!addrs)
			out_of_mem();
		addrs[2 * naddrs] = strdup(nconf->nc_netid);
		addrs[2 * naddrs + 1] = uaddr;
		naddrs++;
	} /* end while */
}
示例#15
0
文件: rpcbind.c 项目: ryo/netbsd-src
/*
 * 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);
}
示例#16
0
文件: util.c 项目: 2asoft/freebsd
char *
addrmerge(struct netbuf *caller, char *serv_uaddr, char *clnt_uaddr,
	  char *netid)
{
	struct ifaddrs *ifap, *ifp, *bestif;
#ifdef INET6
	struct sockaddr_in6 *servsin6, *sin6mask, *clntsin6, *ifsin6, *realsin6;
	struct sockaddr_in6 *newsin6;
#endif
	struct sockaddr_in *servsin, *sinmask, *clntsin, *newsin, *ifsin;
	struct netbuf *serv_nbp, *clnt_nbp = NULL, tbuf;
	struct sockaddr *serv_sa;
	struct sockaddr *clnt_sa;
	struct sockaddr_storage ss;
	struct netconfig *nconf;
	struct sockaddr *clnt = caller->buf;
	char *ret = NULL;

#ifdef INET6
	servsin6 = ifsin6 = newsin6 = NULL;	/* XXXGCC -Wuninitialized */
#endif
	servsin = newsin = NULL;		/* XXXGCC -Wuninitialized */

#ifdef RPCBIND_DEBUG
	if (debugging)
		fprintf(stderr, "addrmerge(caller, %s, %s, %s\n", serv_uaddr,
		    clnt_uaddr, netid);
#endif
	nconf = getnetconfigent(netid);
	if (nconf == NULL)
		return NULL;

	/*
	 * Local merge, just return a duplicate.
	 */
	if (clnt_uaddr != NULL && strncmp(clnt_uaddr, "0.0.0.0.", 8) == 0)
		return strdup(clnt_uaddr);

	serv_nbp = uaddr2taddr(nconf, serv_uaddr);
	if (serv_nbp == NULL)
		return NULL;

	serv_sa = (struct sockaddr *)serv_nbp->buf;
	if (clnt_uaddr != NULL) {
		clnt_nbp = uaddr2taddr(nconf, clnt_uaddr);
		if (clnt_nbp == NULL) {
			free(serv_nbp);
			return NULL;
		}
		clnt_sa = (struct sockaddr *)clnt_nbp->buf;
		if (clnt_sa->sa_family == AF_LOCAL) {
			free(serv_nbp);
			free(clnt_nbp);
			free(clnt_sa);
			return strdup(serv_uaddr);
		}
	} else {
		clnt_sa = (struct sockaddr *)
		    malloc(sizeof (struct sockaddr_storage));
		memcpy(clnt_sa, clnt, clnt->sa_len);
	}

	if (getifaddrs(&ifp) < 0) {
		free(serv_nbp);
		free(clnt_sa);
		if (clnt_nbp != NULL)
			free(clnt_nbp);
		return 0;
	}

	/*
	 * Loop through all interfaces. For each interface, see if the
	 * network portion of its address is equal to that of the client.
	 * If so, we have found the interface that we want to use.
	 */
	for (ifap = ifp; ifap != NULL; ifap = ifap->ifa_next) {
		if (ifap->ifa_addr->sa_family != clnt->sa_family ||
		    !(ifap->ifa_flags & IFF_UP))
			continue;

		switch (clnt->sa_family) {
		case AF_INET:
			/*
			 * realsin: address that recvfrom gave us.
			 * ifsin: address of interface being examined.
			 * clntsin: address that client want us to contact
			 *           it on
			 * servsin: local address of RPC service.
			 * sinmask: netmask of this interface
			 * newsin: initially a copy of clntsin, eventually
			 *         the merged address
			 */
			servsin = (struct sockaddr_in *)serv_sa;
			clntsin = (struct sockaddr_in *)clnt_sa;
			sinmask = (struct sockaddr_in *)ifap->ifa_netmask;
			newsin = (struct sockaddr_in *)&ss;
			ifsin = (struct sockaddr_in *)ifap->ifa_addr;
			if (!bitmaskcmp(&ifsin->sin_addr, &clntsin->sin_addr,
			    &sinmask->sin_addr, sizeof (struct in_addr))) {
				goto found;
			}
			break;
#ifdef INET6
		case AF_INET6:
			/*
			 * realsin6: address that recvfrom gave us.
			 * ifsin6: address of interface being examined.
			 * clntsin6: address that client want us to contact
			 *           it on
			 * servsin6: local address of RPC service.
			 * sin6mask: netmask of this interface
			 * newsin6: initially a copy of clntsin, eventually
			 *          the merged address
			 *
			 * For v6 link local addresses, if the client contacted
			 * us via a link-local address, and wants us to reply
			 * to one, use the scope id to see which one.
			 */
			realsin6 = (struct sockaddr_in6 *)clnt;
			ifsin6 = (struct sockaddr_in6 *)ifap->ifa_addr;
			in6_fillscopeid(ifsin6);
			clntsin6 = (struct sockaddr_in6 *)clnt_sa;
			servsin6 = (struct sockaddr_in6 *)serv_sa;
			sin6mask = (struct sockaddr_in6 *)ifap->ifa_netmask;
			newsin6 = (struct sockaddr_in6 *)&ss;
			if (IN6_IS_ADDR_LINKLOCAL(&ifsin6->sin6_addr) &&
			    IN6_IS_ADDR_LINKLOCAL(&realsin6->sin6_addr) &&
			    IN6_IS_ADDR_LINKLOCAL(&clntsin6->sin6_addr)) {
				if (ifsin6->sin6_scope_id !=
				    realsin6->sin6_scope_id)
					continue;
				goto found;
			}
			if (!bitmaskcmp(&ifsin6->sin6_addr,
			    &clntsin6->sin6_addr, &sin6mask->sin6_addr,
			    sizeof (struct in6_addr)))
				goto found;
			break;
#endif
		default:
			goto freeit;
		}
	}
	/*
	 * Didn't find anything. Get the first possibly useful interface,
	 * preferring "normal" interfaces to point-to-point and loopback
	 * ones.
	 */
	bestif = NULL;
	for (ifap = ifp; ifap != NULL; ifap = ifap->ifa_next) {
		if (ifap->ifa_addr->sa_family != clnt->sa_family ||
		    !(ifap->ifa_flags & IFF_UP))
			continue;
		if (!(ifap->ifa_flags & IFF_LOOPBACK) &&
		    !(ifap->ifa_flags & IFF_POINTOPOINT)) {
			bestif = ifap;
			break;
		}
		if (bestif == NULL)
			bestif = ifap;
		else if ((bestif->ifa_flags & IFF_LOOPBACK) &&
		    !(ifap->ifa_flags & IFF_LOOPBACK))
			bestif = ifap;
	}
	ifap = bestif;
found:
	switch (clnt->sa_family) {
	case AF_INET:
		memcpy(newsin, ifap->ifa_addr, clnt_sa->sa_len);
		newsin->sin_port = servsin->sin_port;
		tbuf.len = clnt_sa->sa_len;
		tbuf.maxlen = sizeof (struct sockaddr_storage);
		tbuf.buf = newsin;
		break;				
#ifdef INET6
	case AF_INET6:
		assert(newsin6);
		memcpy(newsin6, ifsin6, clnt_sa->sa_len);
		newsin6->sin6_port = servsin6->sin6_port;
		tbuf.maxlen = sizeof (struct sockaddr_storage);
		tbuf.len = clnt_sa->sa_len;
		tbuf.buf = newsin6;
		break;
#endif
	default:
		goto freeit;
	}
	if (ifap != NULL)
		ret = taddr2uaddr(nconf, &tbuf);
freeit:
	freenetconfigent(nconf);
	free(serv_sa);
	free(serv_nbp);
	if (clnt_sa != NULL)
		free(clnt_sa);
	if (clnt_nbp != NULL)
		free(clnt_nbp);
	freeifaddrs(ifp);

#ifdef RPCBIND_DEBUG
	if (debugging)
		fprintf(stderr, "addrmerge: returning %s\n", ret);
#endif
	return ret;
}