6 #include <sys/socket.h>
7 #include <netinet/in.h>
11 #include <sys/types.h>
14 #define CONFIGFILE "/etc/nss-icmp.conf"
17 struct cache *next, *prev;
25 static int inited = 0;
26 static int timeout = -1;
27 static int usecache = 1;
28 static struct cache *cache = NULL;
30 static void readconfig(void)
36 if((f = fopen(CONFIGFILE, "r")) == NULL)
39 while(fgets(linebuf, sizeof(linebuf), f) != NULL) {
42 if((p = strchr(linebuf, '\n')) != NULL)
44 if((p = strchr(linebuf, ' ')) != NULL) {
48 if(!strcmp(linebuf, "timeout")) {
53 if(!strcmp(linebuf, "nocache")) {
61 static void freecache(struct cache *cc)
66 cc->next->prev = cc->prev;
68 cc->prev->next = cc->next;
73 if(cc->names != NULL) {
74 for(i = 0; cc->names[i] != NULL; i++)
81 static void cachenotfound(const void *addr, socklen_t len, int af)
85 for(cc = cache; cc != NULL; cc = cc->next) {
86 if((cc->af == af) && (cc->addrlen == len) && !memcmp(cc->addr, addr, len))
90 if((cc = malloc(sizeof(*cc))) == NULL)
92 memset(cc, 0, sizeof(*cc));
93 if((cc->addr = malloc(len)) == NULL) {
97 memcpy(cc->addr, addr, len);
110 static void updatecache(struct hostent *he)
115 for(cc = cache; cc != NULL; cc = cc->next) {
116 if((cc->af == he->h_addrtype) && (cc->addrlen == he->h_length) && !memcmp(cc->addr, he->h_addr_list[0], he->h_length))
120 if((cc = malloc(sizeof(*cc))) == NULL)
122 memset(cc, 0, sizeof(*cc));
123 if((cc->addr = malloc(he->h_length)) == NULL) {
127 memcpy(cc->addr, he->h_addr_list[0], he->h_length);
128 cc->addrlen = he->h_length;
129 cc->af = he->h_addrtype;
131 for(i = 0; he->h_aliases[i] != NULL; i++);
132 if((cc->names = malloc(sizeof(*(cc->names)) * (i + 1))) == NULL) {
136 memset(cc->names, 0, sizeof(*(cc->names)) * (i + 1));
137 for(i = 0; he->h_aliases[i] != NULL; i++) {
138 if((cc->names[i] = malloc(strlen(he->h_aliases[i]) + 1)) == NULL) {
142 strcpy(cc->names[i], he->h_aliases[i]);
152 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)
174 retbuf = (struct retstruct *)buffer;
175 if((buflen < sizeof(*retbuf)) || (len > sizeof(retbuf->retaddr))) {
177 *h_errnop = NETDB_INTERNAL;
178 return(NSS_STATUS_UNAVAIL);
182 for(cc = cache; cc != NULL; cc = cc->next) {
183 if((cc->af == af) && (cc->addrlen == len) && !memcmp(cc->addr, addr, len))
191 ap = (u_int8_t *)addr;
192 if(inet_ntop(af, addr, addrbuf, sizeof(addrbuf)) == NULL) {
194 *h_errnop = NETDB_INTERNAL;
195 return(NSS_STATUS_UNAVAIL);
200 *h_errnop = NETDB_INTERNAL;
201 return(NSS_STATUS_UNAVAIL);
203 /* I honestly don't know if it is considered OK to fork in other
204 * people's programs. We need a SUID worker, though, so there's
205 * little choice that I can see. */
206 if((child = fork()) < 0) {
208 *h_errnop = NETDB_INTERNAL;
209 return(NSS_STATUS_UNAVAIL);
214 char timeoutbuf[128];
216 if((fd = open("/dev/null", O_WRONLY)) < 0)
221 for(i = 3; i < FD_SETSIZE; i++)
225 snprintf(timeoutbuf, sizeof(timeoutbuf), "%i", timeout);
226 execlp("idnlookup", "idnlookup", "-t", timeoutbuf, addrbuf, NULL);
228 execlp("idnlookup", "idnlookup", addrbuf, NULL);
237 ret = read(pfd[0], addrbuf + rl, sizeof(addrbuf) - rl);
240 *h_errnop = NETDB_INTERNAL;
242 return(NSS_STATUS_UNAVAIL);
245 if(rl >= sizeof(addrbuf) - 1) {
247 *h_errnop = NETDB_INTERNAL;
249 return(NSS_STATUS_UNAVAIL);
257 p3 = buffer + sizeof(*retbuf);
258 while((p2 = strchr(p, '\n')) != NULL) {
263 if((p3 - buffer) + thislen + 1 > buflen) {
265 *h_errnop = NETDB_INTERNAL;
266 return(NSS_STATUS_UNAVAIL);
268 memcpy(p3, p, thislen + 1);
269 retbuf->aliaslist[an] = p3;
274 *h_errnop = NETDB_INTERNAL;
275 return(NSS_STATUS_UNAVAIL);
280 cachenotfound(addr, len, af);
281 *h_errnop = TRY_AGAIN; /* XXX: Is this correct? */
282 return(NSS_STATUS_NOTFOUND);
284 retbuf->aliaslist[an] = NULL;
287 *h_errnop = TRY_AGAIN; /* XXX: Is this correct? */
288 return(NSS_STATUS_NOTFOUND);
291 p3 = buffer + sizeof(*retbuf);
292 for(i = 0; cc->names[i] != NULL; i++) {
293 thislen = strlen(cc->names[i]);
294 if((p3 - buffer) + thislen + 1 > buflen) {
296 *h_errnop = NETDB_INTERNAL;
297 return(NSS_STATUS_UNAVAIL);
299 memcpy(p3, cc->names[i], thislen + 1);
300 retbuf->aliaslist[an] = p3;
304 *h_errnop = NETDB_INTERNAL;
305 return(NSS_STATUS_UNAVAIL);
310 memcpy(retbuf->retaddr, addr, len);
311 retbuf->addrlist[0] = retbuf->retaddr;
312 retbuf->addrlist[1] = NULL;
313 result->h_name = retbuf->aliaslist[0];
314 result->h_aliases = retbuf->aliaslist;
315 result->h_addr_list = retbuf->addrlist;
316 result->h_addrtype = af;
317 result->h_length = len;
319 if((cc == NULL) && usecache)
322 *h_errnop = NETDB_SUCCESS;
323 return(NSS_STATUS_SUCCESS);