From: fredrik@DOLDA2000.COM Date: Fri, 29 Apr 2005 02:12:34 +0000 (+0000) Subject: First should-be-working version. X-Git-Url: http://git.dolda2000.com/gitweb/?a=commitdiff_plain;h=2dec74ab7bfd55e30467636c869a360445185b1f;p=icmp-dn.git First should-be-working version. git-svn-id: svn+ssh://svn.dolda2000.com/srv/svn/repos/src/icmp-dn@216 959494ce-11ee-0310-bf91-de5d638817bd --- diff --git a/nss-icmp.c b/nss-icmp.c new file mode 100644 index 0000000..1e3d8cd --- /dev/null +++ b/nss-icmp.c @@ -0,0 +1,132 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum nss_status _nss_icmp_gethostbyaddr_r(const void *addr, socklen_t len, int af, struct hostent *result, char *buffer, size_t buflen, int *errnop, int *h_errnop) +{ + int ret; + struct retstruct { + char *aliaslist[16]; + char *addrlist[2]; + char retaddr[16]; + } *retbuf; + char addrbuf[1024]; + int an; + char *p, *p2, *p3; + u_int8_t *ap; + pid_t child; + int pfd[2]; + int rl; + + retbuf = (struct retstruct *)buffer; + if((buflen < sizeof(*retbuf)) || (len > sizeof(retbuf->retaddr))) { + *errnop = ENOMEM; + *h_errnop = NETDB_INTERNAL; + return(NSS_STATUS_UNAVAIL); + } + + ap = (u_int8_t *)addr; + if(inet_ntop(af, addr, addrbuf, sizeof(addrbuf)) == NULL) { + *errnop = errno; + *h_errnop = NETDB_INTERNAL; + return(NSS_STATUS_UNAVAIL); + } + + if(pipe(pfd)) { + *errnop = errno; + *h_errnop = NETDB_INTERNAL; + return(NSS_STATUS_UNAVAIL); + } + /* I honestly don't know if it is considered OK to fork in other + * people's programs. We need a SUID worker, though, so there's + * little choice that I can see. */ + if((child = fork()) < 0) { + *errnop = errno; + *h_errnop = NETDB_INTERNAL; + return(NSS_STATUS_UNAVAIL); + } + + if(child == 0) { + int i, fd; + + if((fd = open("/dev/null", O_WRONLY)) < 0) + exit(127); + close(pfd[0]); + dup2(pfd[1], 1); + dup2(fd, 2); + for(i = 3; i < FD_SETSIZE; i++) + close(i); + + execlp("idnlookup", "idnlookup", addrbuf, NULL); + exit(127); + } + + close(pfd[1]); + + rl = 0; + do { + ret = read(pfd[0], addrbuf + rl, sizeof(addrbuf) - rl); + if(ret < 0) { + *errnop = errno; + *h_errnop = NETDB_INTERNAL; + close(pfd[0]); + return(NSS_STATUS_UNAVAIL); + } + rl += ret; + if(rl >= sizeof(addrbuf) - 1) { + *errnop = ENOMEM; + *h_errnop = NETDB_INTERNAL; + close(pfd[0]); + return(NSS_STATUS_UNAVAIL); + } + } while(ret != 0); + addrbuf[rl] = 0; + close(pfd[0]); + + an = 0; + p = addrbuf; + p3 = buffer + sizeof(*retbuf); + while((p2 = strchr(p, '\n')) != NULL) { + *p2 = 0; + if((p3 - buffer) + (p2 - p) + 1 > buflen) { + *errnop = ENOMEM; + *h_errnop = NETDB_INTERNAL; + return(NSS_STATUS_UNAVAIL); + } + memcpy(p3, p, (p2 - p) + 1); + retbuf->aliaslist[an] = p3; + p3 += (p2 - p) + 1; + p = p2 + 1; + if(++an == 16) { + *errnop = ENOMEM; + *h_errnop = NETDB_INTERNAL; + return(NSS_STATUS_UNAVAIL); + } + } + if(an == 0) { + *h_errnop = TRY_AGAIN; /* Is this correct? */ + return(NSS_STATUS_NOTFOUND); + } + retbuf->aliaslist[an] = NULL; + + memcpy(retbuf->retaddr, addr, len); + retbuf->addrlist[0] = retbuf->retaddr; + retbuf->addrlist[1] = NULL; + result->h_name = retbuf->aliaslist[0]; + result->h_aliases = retbuf->aliaslist; + result->h_addr_list = retbuf->addrlist; + result->h_addrtype = af; + result->h_length = len; + + *h_errnop = NETDB_SUCCESS; + return(NSS_STATUS_SUCCESS); +}