Commit | Line | Data |
---|---|---|
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 | ||
14 | 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) | |
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 | } |