static int gaih_inet(const char *name, const struct gaih_service *service, const struct addrinfo *req, struct addrinfo **pai) { struct gaih_servtuple nullserv; const struct gaih_typeproto *tp = gaih_inet_typeproto; struct gaih_servtuple *st = &nullserv; struct gaih_addrtuple *at = NULL; int rc; int v4mapped = (req->ai_family == PF_UNSPEC || req->ai_family == PF_INET6) && (req->ai_flags & AI_V4MAPPED); unsigned seen = __check_pf(); memset(&nullserv, 0, sizeof(nullserv)); if (req->ai_protocol || req->ai_socktype) { ++tp; while (tp->name[0] && ((req->ai_socktype != 0 && req->ai_socktype != tp->socktype) || (req->ai_protocol != 0 && !(tp->protoflag & GAI_PROTO_PROTOANY) && req->ai_protocol != tp->protocol) ) ) { ++tp; } if (! tp->name[0]) { if (req->ai_socktype) return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE); return (GAIH_OKIFUNSPEC | -EAI_SERVICE); } } if (service != NULL) { if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0) return (GAIH_OKIFUNSPEC | -EAI_SERVICE); if (service->num < 0) { if (tp->name[0]) { st = alloca(sizeof(struct gaih_servtuple)); rc = gaih_inet_serv(service->name, tp, req, st); if (rc) return rc; } else { struct gaih_servtuple **pst = &st; for (tp++; tp->name[0]; tp++) { struct gaih_servtuple *newp; if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0) continue; if (req->ai_socktype != 0 && req->ai_socktype != tp->socktype) continue; if (req->ai_protocol != 0 && !(tp->protoflag & GAI_PROTO_PROTOANY) && req->ai_protocol != tp->protocol) continue; newp = alloca(sizeof(struct gaih_servtuple)); rc = gaih_inet_serv(service->name, tp, req, newp); if (rc) { if (rc & GAIH_OKIFUNSPEC) continue; return rc; } *pst = newp; pst = &(newp->next); } if (st == &nullserv) return (GAIH_OKIFUNSPEC | -EAI_SERVICE); } } else { st = alloca(sizeof(struct gaih_servtuple)); st->next = NULL; st->socktype = tp->socktype; st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY) ? req->ai_protocol : tp->protocol); st->port = htons(service->num); } } else if (req->ai_socktype || req->ai_protocol) { st = alloca(sizeof(struct gaih_servtuple)); st->next = NULL; st->socktype = tp->socktype; st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY) ? req->ai_protocol : tp->protocol); st->port = 0; } else { /* * Neither socket type nor protocol is set. Return all socket types * we know about. */ struct gaih_servtuple **lastp = &st; for (++tp; tp->name[0]; ++tp) { struct gaih_servtuple *newp; newp = alloca(sizeof(struct gaih_servtuple)); newp->next = NULL; newp->socktype = tp->socktype; newp->protocol = tp->protocol; newp->port = 0; *lastp = newp; lastp = &newp->next; } } if (name != NULL) { at = alloca(sizeof(struct gaih_addrtuple)); at->family = AF_UNSPEC; at->scopeid = 0; at->next = NULL; if (inet_pton(AF_INET, name, at->addr) > 0) { if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET || v4mapped) at->family = AF_INET; else return -EAI_FAMILY; } #if defined __UCLIBC_HAS_IPV6__ if (at->family == AF_UNSPEC) { char *namebuf = strdupa(name); char *scope_delim; scope_delim = strchr(namebuf, SCOPE_DELIMITER); if (scope_delim != NULL) *scope_delim = '\0'; if (inet_pton(AF_INET6, namebuf, at->addr) > 0) { if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6) at->family = AF_INET6; else return -EAI_FAMILY; if (scope_delim != NULL) { int try_numericscope = 0; if (IN6_IS_ADDR_LINKLOCAL(at->addr) || IN6_IS_ADDR_MC_LINKLOCAL(at->addr)) { at->scopeid = if_nametoindex(scope_delim + 1); if (at->scopeid == 0) try_numericscope = 1; } else try_numericscope = 1; if (try_numericscope != 0) { char *end; assert(sizeof(uint32_t) <= sizeof(unsigned long)); at->scopeid = (uint32_t)strtoul(scope_delim + 1, &end, 10); if (*end != '\0') return (GAIH_OKIFUNSPEC | -EAI_NONAME); } } } } #endif if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0) { struct hostent *h; struct gaih_addrtuple **pat = &at; int no_data = 0; int no_inet6_data; /* * If we are looking for both IPv4 and IPv6 address we don't want * the lookup functions to automatically promote IPv4 addresses to * IPv6 addresses. */ #if defined __UCLIBC_HAS_IPV6__ if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6) if (!(req->ai_flags & AI_ADDRCONFIG) || (seen & SEEN_IPV6)) gethosts(AF_INET6, struct in6_addr); #endif no_inet6_data = no_data; if (req->ai_family == AF_INET || (!v4mapped && req->ai_family == AF_UNSPEC) || (v4mapped && (no_inet6_data != 0 || (req->ai_flags & AI_ALL))) ) { if (!(req->ai_flags & AI_ADDRCONFIG) || (seen & SEEN_IPV4)) gethosts(AF_INET, struct in_addr); } if (no_data != 0 && no_inet6_data != 0) { /* If both requests timed out report this. */ if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN) return -EAI_AGAIN; /* * We made requests but they turned out no data. * The name is known, though. */ return (GAIH_OKIFUNSPEC | -EAI_AGAIN); } } if (at->family == AF_UNSPEC) return (GAIH_OKIFUNSPEC | -EAI_NONAME); } else { struct gaih_addrtuple *atr; atr = at = alloca(sizeof(struct gaih_addrtuple)); memset(at, '\0', sizeof(struct gaih_addrtuple)); if (req->ai_family == 0) { at->next = alloca(sizeof(struct gaih_addrtuple)); memset(at->next, '\0', sizeof(struct gaih_addrtuple)); } #if defined __UCLIBC_HAS_IPV6__ if (req->ai_family == 0 || req->ai_family == AF_INET6) { at->family = AF_INET6; if ((req->ai_flags & AI_PASSIVE) == 0) memcpy(at->addr, &in6addr_loopback, sizeof(struct in6_addr)); atr = at->next; } #endif if (req->ai_family == 0 || req->ai_family == AF_INET) { atr->family = AF_INET; if ((req->ai_flags & AI_PASSIVE) == 0) *(uint32_t*)atr->addr = htonl(INADDR_LOOPBACK); } } if (pai == NULL) return 0; { const char *c = NULL; struct gaih_servtuple *st2; struct gaih_addrtuple *at2 = at; size_t socklen, namelen; sa_family_t family; /* * buffer is the size of an unformatted IPv6 address in * printable format. */ char buffer[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; while (at2 != NULL) { if (req->ai_flags & AI_CANONNAME) { struct hostent *h = NULL; int herrno; struct hostent th; size_t tmpbuflen = 512; char *tmpbuf; do { tmpbuflen *= 2; tmpbuf = alloca(tmpbuflen); //if (tmpbuf == NULL) // return -EAI_MEMORY; rc = gethostbyaddr_r(at2->addr, ((at2->family == AF_INET6) ? sizeof(struct in6_addr) : sizeof(struct in_addr)), at2->family, &th, tmpbuf, tmpbuflen, &h, &herrno); } while (rc == errno && herrno == NETDB_INTERNAL); if (rc != 0 && herrno == NETDB_INTERNAL) { __set_h_errno(herrno); return -EAI_SYSTEM; } if (h == NULL) c = inet_ntop(at2->family, at2->addr, buffer, sizeof(buffer)); else c = h->h_name; if (c == NULL) return (GAIH_OKIFUNSPEC | -EAI_NONAME); namelen = strlen(c) + 1; } else namelen = 0; #if defined __UCLIBC_HAS_IPV6__ if (at2->family == AF_INET6 || v4mapped) { family = AF_INET6; socklen = sizeof(struct sockaddr_in6); } #endif #if defined __UCLIBC_HAS_IPV4__ && defined __UCLIBC_HAS_IPV6__ else #endif #if defined __UCLIBC_HAS_IPV4__ { family = AF_INET; socklen = sizeof(struct sockaddr_in); } #endif for (st2 = st; st2 != NULL; st2 = st2->next) { if (req->ai_flags & AI_ADDRCONFIG) { if (family == AF_INET && !(seen & SEEN_IPV4)) break; #if defined __UCLIBC_HAS_IPV6__ else if (family == AF_INET6 && !(seen & SEEN_IPV6)) break; #endif } *pai = malloc(sizeof(struct addrinfo) + socklen + namelen); if (*pai == NULL) return -EAI_MEMORY; (*pai)->ai_flags = req->ai_flags; (*pai)->ai_family = family; (*pai)->ai_socktype = st2->socktype; (*pai)->ai_protocol = st2->protocol; (*pai)->ai_addrlen = socklen; (*pai)->ai_addr = (void *) (*pai) + sizeof(struct addrinfo); #if SALEN (*pai)->ai_addr->sa_len = socklen; #endif /* SALEN */ (*pai)->ai_addr->sa_family = family; #if defined __UCLIBC_HAS_IPV6__ if (family == AF_INET6) { struct sockaddr_in6 *sin6p = (struct sockaddr_in6 *) (*pai)->ai_addr; sin6p->sin6_flowinfo = 0; if (at2->family == AF_INET6) { memcpy(&sin6p->sin6_addr, at2->addr, sizeof(struct in6_addr)); } else { sin6p->sin6_addr.s6_addr32[0] = 0; sin6p->sin6_addr.s6_addr32[1] = 0; sin6p->sin6_addr.s6_addr32[2] = htonl(0x0000ffff); memcpy(&sin6p->sin6_addr.s6_addr32[3], at2->addr, sizeof(sin6p->sin6_addr.s6_addr32[3])); } sin6p->sin6_port = st2->port; sin6p->sin6_scope_id = at2->scopeid; } #endif #if defined __UCLIBC_HAS_IPV4__ && defined __UCLIBC_HAS_IPV6__ else #endif #if defined __UCLIBC_HAS_IPV4__ { struct sockaddr_in *sinp = (struct sockaddr_in *) (*pai)->ai_addr; memcpy(&sinp->sin_addr, at2->addr, sizeof(struct in_addr)); sinp->sin_port = st2->port; memset(sinp->sin_zero, '\0', sizeof(sinp->sin_zero)); } #endif if (c) { (*pai)->ai_canonname = ((void *) (*pai) + sizeof(struct addrinfo) + socklen); strcpy((*pai)->ai_canonname, c); } else { (*pai)->ai_canonname = NULL; } (*pai)->ai_next = NULL; pai = &((*pai)->ai_next); } at2 = at2->next; } } return 0; }
LOOKUP_TYPE * FUNCTION_NAME (ADD_PARAMS) { static size_t buffer_size; static LOOKUP_TYPE resbuf; LOOKUP_TYPE *result; #ifdef NEED_H_ERRNO int h_errno_tmp = 0; #endif /* Get lock. */ __libc_lock_lock (lock); if (buffer == NULL) { buffer_size = BUFLEN; buffer = (char *) malloc (buffer_size); } #ifdef HANDLE_DIGITS_DOTS if (buffer != NULL) { if (__nss_hostname_digits_dots (name, &resbuf, &buffer, &buffer_size, 0, &result, NULL, AF_VAL, H_ERRNO_VAR_P)) goto done; } #endif while (buffer != NULL && (INTERNAL (REENTRANT_NAME) (ADD_VARIABLES, &resbuf, buffer, buffer_size, &result H_ERRNO_VAR) == ERANGE) #ifdef NEED_H_ERRNO && h_errno_tmp == NETDB_INTERNAL #endif ) { char *new_buf; buffer_size *= 2; new_buf = (char *) realloc (buffer, buffer_size); if (new_buf == NULL) { /* We are out of memory. Free the current buffer so that the process gets a chance for a normal termination. */ free (buffer); __set_errno (ENOMEM); } buffer = new_buf; } if (buffer == NULL) result = NULL; #ifdef HANDLE_DIGITS_DOTS done: #endif /* Release lock. */ __libc_lock_unlock (lock); #ifdef NEED_H_ERRNO if (h_errno_tmp != 0) __set_h_errno (h_errno_tmp); #endif return result; }
int rcmd(char **ahost, u_short rport, const char *locuser, const char *remuser, const char *cmd, int *fd2p) { #ifdef __UCLIBC_HAS_REENTRANT_RPC__ int herr; struct hostent hostbuf; size_t hstbuflen; char *tmphstbuf; #endif struct hostent *hp; struct sockaddr_in sin, from; struct pollfd pfd[2]; int32_t oldmask; pid_t pid; int s, lport, timo; char c; pid = getpid(); #ifdef __UCLIBC_HAS_REENTRANT_RPC__ hstbuflen = 1024; tmphstbuf = stack_heap_alloc(hstbuflen); while (gethostbyname_r (*ahost, &hostbuf, tmphstbuf, hstbuflen, &hp, &herr) != 0 || hp == NULL) { if (herr != NETDB_INTERNAL || errno != ERANGE) { __set_h_errno (herr); stack_heap_free(tmphstbuf); herror(*ahost); return -1; } else { /* Enlarge the buffer. */ hstbuflen *= 2; stack_heap_free(tmphstbuf); tmphstbuf = stack_heap_alloc(hstbuflen); } } stack_heap_free(tmphstbuf); #else /* call the non-reentrant version */ if ((hp = gethostbyname(*ahost)) == NULL) { return -1; } #endif pfd[0].events = POLLIN; pfd[1].events = POLLIN; *ahost = hp->h_name; oldmask = sigblock(sigmask(SIGURG)); /* __sigblock */ for (timo = 1, lport = IPPORT_RESERVED - 1;;) { s = rresvport(&lport); if (s < 0) { if (errno == EAGAIN) (void)fprintf(stderr, "rcmd: socket: All ports in use\n"); else (void)fprintf(stderr, "rcmd: socket: %m\n"); sigsetmask(oldmask); /* sigsetmask */ return -1; } fcntl(s, F_SETOWN, pid); sin.sin_family = hp->h_addrtype; memmove(&sin.sin_addr, hp->h_addr_list[0], MIN (sizeof (sin.sin_addr), hp->h_length)); sin.sin_port = rport; if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0) /* __connect */ break; (void)close(s); if (errno == EADDRINUSE) { lport--; continue; } if (errno == ECONNREFUSED && timo <= 16) { (void)sleep(timo); /* __sleep */ timo *= 2; continue; } if (hp->h_addr_list[1] != NULL) { int oerrno = errno; (void)fprintf(stderr, "connect to address %s: ", inet_ntoa(sin.sin_addr)); __set_errno (oerrno); perror(0); hp->h_addr_list++; memmove(&sin.sin_addr, hp->h_addr_list[0], MIN (sizeof (sin.sin_addr), hp->h_length)); (void)fprintf(stderr, "Trying %s...\n", inet_ntoa(sin.sin_addr)); continue; } (void)fprintf(stderr, "%s: %m\n", hp->h_name); sigsetmask(oldmask); /* __sigsetmask */ return -1; } lport--; if (fd2p == 0) { write(s, "", 1); lport = 0; } else { char num[8]; int s2 = rresvport(&lport), s3; socklen_t len = sizeof(from); if (s2 < 0) goto bad; listen(s2, 1); (void)snprintf(num, sizeof(num), "%d", lport); /* __snprintf */ if (write(s, num, strlen(num)+1) != strlen(num)+1) { (void)fprintf(stderr, "rcmd: write (setting up stderr): %m\n"); (void)close(s2); goto bad; } pfd[0].fd = s; pfd[1].fd = s2; __set_errno (0); if (poll (pfd, 2, -1) < 1 || (pfd[1].revents & POLLIN) == 0) { if (errno != 0) (void)fprintf(stderr, "rcmd: poll (setting up stderr): %m\n"); else (void)fprintf(stderr, "poll: protocol failure in circuit setup\n"); (void)close(s2); goto bad; } s3 = accept(s2, (struct sockaddr *)&from, &len); (void)close(s2); if (s3 < 0) { (void)fprintf(stderr, "rcmd: accept: %m\n"); lport = 0; goto bad; } *fd2p = s3; from.sin_port = ntohs((u_short)from.sin_port); if (from.sin_family != AF_INET || from.sin_port >= IPPORT_RESERVED || from.sin_port < IPPORT_RESERVED / 2) { (void)fprintf(stderr, "socket: protocol failure in circuit setup\n"); goto bad2; } } (void)write(s, locuser, strlen(locuser)+1); (void)write(s, remuser, strlen(remuser)+1); (void)write(s, cmd, strlen(cmd)+1); if (read(s, &c, 1) != 1) { (void)fprintf(stderr, "rcmd: %s: %m\n", *ahost); goto bad2; } if (c != 0) { while (read(s, &c, 1) == 1) { (void)write(STDERR_FILENO, &c, 1); if (c == '\n') break; } goto bad2; } sigsetmask(oldmask); return s; bad2: if (lport) (void)close(*fd2p); bad: (void)close(s); sigsetmask(oldmask); return -1; }