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); }
/* * 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)); }
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; }
/* * 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); }
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); }
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; }
/* 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)); }
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; }
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; }
/* * 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; }
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; }
/* * 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); }
/* * 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); }
/* * 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 */ }
/* * 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); }
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; }