First should-be-working version.
authorfredrik@DOLDA2000.COM <fredrik@DOLDA2000.COM@959494ce-11ee-0310-bf91-de5d638817bd>
Fri, 29 Apr 2005 02:12:34 +0000 (02:12 +0000)
committerfredrik@DOLDA2000.COM <fredrik@DOLDA2000.COM@959494ce-11ee-0310-bf91-de5d638817bd>
Fri, 29 Apr 2005 02:12:34 +0000 (02:12 +0000)
git-svn-id: svn+ssh://svn.dolda2000.com/srv/svn/repos/src/icmp-dn@216 959494ce-11ee-0310-bf91-de5d638817bd

nss-icmp.c [new file with mode: 0644]

diff --git a/nss-icmp.c b/nss-icmp.c
new file mode 100644 (file)
index 0000000..1e3d8cd
--- /dev/null
@@ -0,0 +1,132 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <nss.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+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);
+}