Small cleanups.
[icmp-dn.git] / nss-icmp.c
CommitLineData
2dec74ab
DC
1#include <stdlib.h>
2#include <stdio.h>
3#include <unistd.h>
4#include <string.h>
5#include <errno.h>
6#include <sys/socket.h>
7#include <netinet/in.h>
8#include <netdb.h>
9#include <arpa/inet.h>
10#include <nss.h>
11#include <sys/types.h>
12#include <fcntl.h>
13
14enum 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)
15{
16 int ret;
17 struct retstruct {
18 char *aliaslist[16];
19 char *addrlist[2];
20 char retaddr[16];
21 } *retbuf;
22 char addrbuf[1024];
03511d7b 23 int an, thislen;
2dec74ab
DC
24 char *p, *p2, *p3;
25 u_int8_t *ap;
26 pid_t child;
27 int pfd[2];
28 int rl;
29
30 retbuf = (struct retstruct *)buffer;
31 if((buflen < sizeof(*retbuf)) || (len > sizeof(retbuf->retaddr))) {
32 *errnop = ENOMEM;
33 *h_errnop = NETDB_INTERNAL;
34 return(NSS_STATUS_UNAVAIL);
35 }
36
37 ap = (u_int8_t *)addr;
38 if(inet_ntop(af, addr, addrbuf, sizeof(addrbuf)) == NULL) {
39 *errnop = errno;
40 *h_errnop = NETDB_INTERNAL;
41 return(NSS_STATUS_UNAVAIL);
42 }
43
44 if(pipe(pfd)) {
45 *errnop = errno;
46 *h_errnop = NETDB_INTERNAL;
47 return(NSS_STATUS_UNAVAIL);
48 }
49 /* I honestly don't know if it is considered OK to fork in other
50 * people's programs. We need a SUID worker, though, so there's
51 * little choice that I can see. */
52 if((child = fork()) < 0) {
53 *errnop = errno;
54 *h_errnop = NETDB_INTERNAL;
55 return(NSS_STATUS_UNAVAIL);
56 }
57
58 if(child == 0) {
59 int i, fd;
60
61 if((fd = open("/dev/null", O_WRONLY)) < 0)
62 exit(127);
63 close(pfd[0]);
64 dup2(pfd[1], 1);
65 dup2(fd, 2);
66 for(i = 3; i < FD_SETSIZE; i++)
67 close(i);
68
69 execlp("idnlookup", "idnlookup", addrbuf, NULL);
70 exit(127);
71 }
72
73 close(pfd[1]);
74
75 rl = 0;
76 do {
77 ret = read(pfd[0], addrbuf + rl, sizeof(addrbuf) - rl);
78 if(ret < 0) {
79 *errnop = errno;
80 *h_errnop = NETDB_INTERNAL;
81 close(pfd[0]);
82 return(NSS_STATUS_UNAVAIL);
83 }
84 rl += ret;
85 if(rl >= sizeof(addrbuf) - 1) {
86 *errnop = ENOMEM;
87 *h_errnop = NETDB_INTERNAL;
88 close(pfd[0]);
89 return(NSS_STATUS_UNAVAIL);
90 }
91 } while(ret != 0);
92 addrbuf[rl] = 0;
93 close(pfd[0]);
94
95 an = 0;
96 p = addrbuf;
97 p3 = buffer + sizeof(*retbuf);
98 while((p2 = strchr(p, '\n')) != NULL) {
99 *p2 = 0;
03511d7b
DC
100 thislen = p2 - p;
101 if(thislen == 0)
102 continue;
103 if((p3 - buffer) + thislen + 1 > buflen) {
2dec74ab
DC
104 *errnop = ENOMEM;
105 *h_errnop = NETDB_INTERNAL;
106 return(NSS_STATUS_UNAVAIL);
107 }
03511d7b 108 memcpy(p3, p, thislen + 1);
2dec74ab 109 retbuf->aliaslist[an] = p3;
03511d7b 110 p3 += thislen + 1;
2dec74ab
DC
111 p = p2 + 1;
112 if(++an == 16) {
113 *errnop = ENOMEM;
114 *h_errnop = NETDB_INTERNAL;
115 return(NSS_STATUS_UNAVAIL);
116 }
117 }
118 if(an == 0) {
03511d7b 119 *h_errnop = TRY_AGAIN; /* XXX: Is this correct? */
2dec74ab
DC
120 return(NSS_STATUS_NOTFOUND);
121 }
122 retbuf->aliaslist[an] = NULL;
123
124 memcpy(retbuf->retaddr, addr, len);
125 retbuf->addrlist[0] = retbuf->retaddr;
126 retbuf->addrlist[1] = NULL;
127 result->h_name = retbuf->aliaslist[0];
128 result->h_aliases = retbuf->aliaslist;
129 result->h_addr_list = retbuf->addrlist;
130 result->h_addrtype = af;
131 result->h_length = len;
132
133 *h_errnop = NETDB_SUCCESS;
134 return(NSS_STATUS_SUCCESS);
135}