1 /*        $NetBSD: nis_ho.c,v 1.1.1.2 2012/09/09 16:07:56 christos Exp $        */
2 
3 /*
4  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5  * Copyright (c) 1996,1999 by Internet Software Consortium.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #if defined(LIBC_SCCS) && !defined(lint)
21 static const char rcsid[] = "Id: nis_ho.c,v 1.5 2005/04/27 04:56:32 sra Exp ";
22 #endif /* LIBC_SCCS and not lint */
23 
24 /* Imports */
25 
26 #include "port_before.h"
27 
28 #ifndef WANT_IRS_NIS
29 static int __bind_irs_nis_unneeded;
30 #else
31 
32 #include <sys/types.h>
33 #include <sys/param.h>
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
37 #include <arpa/nameser.h>
38 #ifdef T_NULL
39 #undef T_NULL                           /* Silence re-definition warning of T_NULL. */
40 #endif
41 #include <rpc/rpc.h>
42 #include <rpc/xdr.h>
43 #include <rpcsvc/yp_prot.h>
44 #include <rpcsvc/ypclnt.h>
45 
46 #include <ctype.h>
47 #include <errno.h>
48 #include <stdlib.h>
49 #include <netdb.h>
50 #include <resolv.h>
51 #include <stdio.h>
52 #include <string.h>
53 
54 #include <isc/memcluster.h>
55 #include <irs.h>
56 
57 #include "port_after.h"
58 
59 #include "irs_p.h"
60 #include "nis_p.h"
61 
62 /* Definitions */
63 
64 #define   MAXALIASES          35
65 #define   MAXADDRS  35
66 
67 #if PACKETSZ > 1024
68 #define   MAXPACKET PACKETSZ
69 #else
70 #define   MAXPACKET 1024
71 #endif
72 
73 struct pvt {
74           int                 needrewind;
75           char *              nis_domain;
76           char *              curkey_data;
77           int                 curkey_len;
78           char *              curval_data;
79           int                 curval_len;
80           struct hostent      host;
81           char *              h_addr_ptrs[MAXADDRS + 1];
82           char *              host_aliases[MAXALIASES + 1];
83           char                hostbuf[8*1024];
84           u_char              host_addr[16];      /*%< IPv4 or IPv6 */
85           struct __res_state  *res;
86           void                (*free_res)(void *);
87 };
88 
89 enum do_what { do_none = 0x0, do_key = 0x1, do_val = 0x2, do_all = 0x3 };
90 
91 static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
92 static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
93 static /*const*/ char hosts_byname[] = "hosts.byname";
94 static /*const*/ char hosts_byaddr[] = "hosts.byaddr";
95 static /*const*/ char ipnode_byname[] = "ipnode.byname";
96 static /*const*/ char ipnode_byaddr[] = "ipnode.byaddr";
97 static /*const*/ char yp_multi[] = "YP_MULTI_";
98 
99 /* Forwards */
100 
101 static void                   ho_close(struct irs_ho *this);
102 static struct hostent *       ho_byname(struct irs_ho *this, const char *name);
103 static struct hostent *       ho_byname2(struct irs_ho *this, const char *name,
104                                                   int af);
105 static struct hostent *       ho_byaddr(struct irs_ho *this, const void *addr,
106                                                int len, int af);
107 static struct hostent *       ho_next(struct irs_ho *this);
108 static void                   ho_rewind(struct irs_ho *this);
109 static void                   ho_minimize(struct irs_ho *this);
110 static struct __res_state * ho_res_get(struct irs_ho *this);
111 static void                   ho_res_set(struct irs_ho *this,
112                                            struct __res_state *res,
113                                            void (*free_res)(void *));
114 static struct addrinfo * ho_addrinfo(struct irs_ho *this, const char *name,
115                                              const struct addrinfo *pai);
116 
117 static struct hostent *       makehostent(struct irs_ho *this);
118 static void                   nisfree(struct pvt *, enum do_what);
119 static int                    init(struct irs_ho *this);
120 
121 /* Public */
122 
123 struct irs_ho *
irs_nis_ho(struct irs_acc * this)124 irs_nis_ho(struct irs_acc *this) {
125           struct irs_ho *ho;
126           struct pvt *pvt;
127 
128           if (!(pvt = memget(sizeof *pvt))) {
129                     errno = ENOMEM;
130                     return (NULL);
131           }
132           memset(pvt, 0, sizeof *pvt);
133           if (!(ho = memget(sizeof *ho))) {
134                     memput(pvt, sizeof *pvt);
135                     errno = ENOMEM;
136                     return (NULL);
137           }
138           memset(ho, 0x5e, sizeof *ho);
139           pvt->needrewind = 1;
140           pvt->nis_domain = ((struct nis_p *)this->private)->domain;
141           ho->private = pvt;
142           ho->close = ho_close;
143           ho->byname = ho_byname;
144           ho->byname2 = ho_byname2;
145           ho->byaddr = ho_byaddr;
146           ho->next = ho_next;
147           ho->rewind = ho_rewind;
148           ho->minimize = ho_minimize;
149           ho->res_set = ho_res_set;
150           ho->res_get = ho_res_get;
151           ho->addrinfo = ho_addrinfo;
152           return (ho);
153 }
154 
155 /* Methods */
156 
157 static void
ho_close(struct irs_ho * this)158 ho_close(struct irs_ho *this) {
159           struct pvt *pvt = (struct pvt *)this->private;
160 
161           ho_minimize(this);
162           nisfree(pvt, do_all);
163           if (pvt->res && pvt->free_res)
164                     (*pvt->free_res)(pvt->res);
165           memput(pvt, sizeof *pvt);
166           memput(this, sizeof *this);
167 }
168 
169 static struct hostent *
ho_byname(struct irs_ho * this,const char * name)170 ho_byname(struct irs_ho *this, const char *name) {
171           struct pvt *pvt = (struct pvt *)this->private;
172           struct hostent *hp;
173 
174           if (init(this) == -1)
175                     return (NULL);
176 
177           if (pvt->res->options & RES_USE_INET6) {
178                     hp = ho_byname2(this, name, AF_INET6);
179                     if (hp)
180                               return (hp);
181           }
182           return (ho_byname2(this, name, AF_INET));
183 }
184 
185 static struct hostent *
ho_byname2(struct irs_ho * this,const char * name,int af)186 ho_byname2(struct irs_ho *this, const char *name, int af) {
187           struct pvt *pvt = (struct pvt *)this->private;
188           int r;
189           char *tmp;
190 
191           UNUSED(af);
192 
193           if (init(this) == -1)
194                     return (NULL);
195 
196           nisfree(pvt, do_val);
197 
198           strcpy(pvt->hostbuf, yp_multi);
199           strncat(pvt->hostbuf, name, sizeof(pvt->hostbuf) - sizeof(yp_multi));
200           pvt->hostbuf[sizeof(pvt->hostbuf) - 1] = '\0';
201           for (r = sizeof(yp_multi) - 1; pvt->hostbuf[r] != '\0'; r++)
202                     if (isupper((unsigned char)pvt->hostbuf[r]))
203                               tolower(pvt->hostbuf[r]);
204 
205           tmp = pvt->hostbuf;
206           r = yp_match(pvt->nis_domain, ipnode_byname, tmp,
207                          strlen(tmp), &pvt->curval_data, &pvt->curval_len);
208           if (r != 0) {
209                     tmp = pvt->hostbuf + sizeof(yp_multi) - 1;
210                     r = yp_match(pvt->nis_domain, ipnode_byname, tmp,
211                                    strlen(tmp), &pvt->curval_data, &pvt->curval_len);
212           }
213           if (r != 0) {
214                     tmp = pvt->hostbuf;
215                     r = yp_match(pvt->nis_domain, hosts_byname, tmp,
216                                    strlen(tmp), &pvt->curval_data, &pvt->curval_len);
217           }
218           if (r != 0) {
219                     tmp = pvt->hostbuf + sizeof(yp_multi) - 1;
220                     r = yp_match(pvt->nis_domain, hosts_byname, tmp,
221                                    strlen(tmp), &pvt->curval_data, &pvt->curval_len);
222           }
223           if (r != 0) {
224                     RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
225                     return (NULL);
226           }
227           return (makehostent(this));
228 }
229 
230 static struct hostent *
ho_byaddr(struct irs_ho * this,const void * addr,int len,int af)231 ho_byaddr(struct irs_ho *this, const void *addr, int len, int af) {
232           struct pvt *pvt = (struct pvt *)this->private;
233           char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
234           const u_char *uaddr = addr;
235           int r;
236 
237           if (init(this) == -1)
238                     return (NULL);
239 
240           if (af == AF_INET6 && len == IN6ADDRSZ &&
241               (!memcmp(uaddr, mapped, sizeof mapped) ||
242                !memcmp(uaddr, tunnelled, sizeof tunnelled))) {
243                     /* Unmap. */
244                     addr = (const u_char *)addr + sizeof mapped;
245                     uaddr += sizeof mapped;
246                     af = AF_INET;
247                     len = INADDRSZ;
248           }
249           if (inet_ntop(af, uaddr, tmp, sizeof tmp) == NULL) {
250                     RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
251                     return (NULL);
252           }
253           nisfree(pvt, do_val);
254           r = yp_match(pvt->nis_domain, ipnode_byaddr, tmp, strlen(tmp),
255                          &pvt->curval_data, &pvt->curval_len);
256           if (r != 0)
257                     r = yp_match(pvt->nis_domain, hosts_byaddr, tmp, strlen(tmp),
258                                    &pvt->curval_data, &pvt->curval_len);
259           if (r != 0) {
260                     RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
261                     return (NULL);
262           }
263           return (makehostent(this));
264 }
265 
266 static struct hostent *
ho_next(struct irs_ho * this)267 ho_next(struct irs_ho *this) {
268           struct pvt *pvt = (struct pvt *)this->private;
269           struct hostent *rval;
270           int r;
271 
272           if (init(this) == -1)
273                     return (NULL);
274 
275           do {
276                     if (pvt->needrewind) {
277                               nisfree(pvt, do_all);
278                               r = yp_first(pvt->nis_domain, hosts_byaddr,
279                                              &pvt->curkey_data, &pvt->curkey_len,
280                                              &pvt->curval_data, &pvt->curval_len);
281                               pvt->needrewind = 0;
282                     } else {
283                               char *newkey_data;
284                               int newkey_len;
285 
286                               nisfree(pvt, do_val);
287                               r = yp_next(pvt->nis_domain, hosts_byaddr,
288                                             pvt->curkey_data, pvt->curkey_len,
289                                             &newkey_data, &newkey_len,
290                                             &pvt->curval_data, &pvt->curval_len);
291                               nisfree(pvt, do_key);
292                               pvt->curkey_data = newkey_data;
293                               pvt->curkey_len = newkey_len;
294                     }
295                     if (r != 0) {
296                               RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
297                               return (NULL);
298                     }
299                     rval = makehostent(this);
300           } while (rval == NULL);
301           return (rval);
302 }
303 
304 static void
ho_rewind(struct irs_ho * this)305 ho_rewind(struct irs_ho *this) {
306           struct pvt *pvt = (struct pvt *)this->private;
307 
308           pvt->needrewind = 1;
309 }
310 
311 static void
ho_minimize(struct irs_ho * this)312 ho_minimize(struct irs_ho *this) {
313           struct pvt *pvt = (struct pvt *)this->private;
314 
315           if (pvt->res)
316                     res_nclose(pvt->res);
317 }
318 
319 static struct __res_state *
ho_res_get(struct irs_ho * this)320 ho_res_get(struct irs_ho *this) {
321           struct pvt *pvt = (struct pvt *)this->private;
322 
323           if (!pvt->res) {
324                     struct __res_state *res;
325                     res = (struct __res_state *)malloc(sizeof *res);
326                     if (!res) {
327                               errno = ENOMEM;
328                               return (NULL);
329                     }
330                     memset(res, 0, sizeof *res);
331                     ho_res_set(this, res, free);
332           }
333 
334           return (pvt->res);
335 }
336 
337 static void
ho_res_set(struct irs_ho * this,struct __res_state * res,void (* free_res)(void *))338 ho_res_set(struct irs_ho *this, struct __res_state *res,
339                     void (*free_res)(void *)) {
340           struct pvt *pvt = (struct pvt *)this->private;
341 
342           if (pvt->res && pvt->free_res) {
343                     res_nclose(pvt->res);
344                     (*pvt->free_res)(pvt->res);
345           }
346 
347           pvt->res = res;
348           pvt->free_res = free_res;
349 }
350 
351 struct nis_res_target {
352           struct nis_res_target *next;
353           int family;
354 };
355 
356 /* XXX */
357 extern struct addrinfo *hostent2addrinfo __P((struct hostent *,
358                                                         const struct addrinfo *pai));
359 
360 static struct addrinfo *
ho_addrinfo(struct irs_ho * this,const char * name,const struct addrinfo * pai)361 ho_addrinfo(struct irs_ho *this, const char *name, const struct addrinfo *pai)
362 {
363           struct pvt *pvt = (struct pvt *)this->private;
364           struct hostent *hp;
365           struct nis_res_target q, q2, *p;
366           struct addrinfo sentinel, *cur;
367 
368           memset(&q, 0, sizeof(q2));
369           memset(&q2, 0, sizeof(q2));
370           memset(&sentinel, 0, sizeof(sentinel));
371           cur = &sentinel;
372 
373           switch(pai->ai_family) {
374           case AF_UNSPEC:               /*%< INET6 then INET4 */
375                     q.family = AF_INET6;
376                     q.next = &q2;
377                     q2.family = AF_INET;
378                     break;
379           case AF_INET6:
380                     q.family = AF_INET6;
381                     break;
382           case AF_INET:
383                     q.family = AF_INET;
384                     break;
385           default:
386                     RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); /*%< ??? */
387                     return(NULL);
388           }
389 
390           for (p = &q; p; p = p->next) {
391                     struct addrinfo *ai;
392 
393                     hp = (*this->byname2)(this, name, p->family);
394                     if (hp == NULL) {
395                               /* byname2 should've set an appropriate error */
396                               continue;
397                     }
398                     if ((hp->h_name == NULL) || (hp->h_name[0] == 0) ||
399                         (hp->h_addr_list[0] == NULL)) {
400                               RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
401                               continue;
402                     }
403                     ai = hostent2addrinfo(hp, pai);
404                     if (ai) {
405                               cur->ai_next = ai;
406                               while (cur && cur->ai_next)
407                                         cur = cur->ai_next;
408                     }
409           }
410 
411           if (sentinel.ai_next == NULL)
412                     RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
413 
414           return(sentinel.ai_next);
415 }
416 
417 /* Private */
418 
419 /*%
420 ipnodes:
421 ::1             localhost
422 127.0.0.1       localhost
423 1.2.3.4         FOO bar
424 1.2.6.4         FOO bar
425 1.2.6.5         host
426 
427 ipnodes.byname:
428 YP_MULTI_localhost ::1,127.0.0.1        localhost
429 YP_MULTI_foo 1.2.3.4,1.2.6.4    FOO bar
430 YP_MULTI_bar 1.2.3.4,1.2.6.4    FOO bar
431 host 1.2.6.5    host
432 
433 hosts.byname:
434 localhost 127.0.0.1     localhost
435 host 1.2.6.5    host
436 YP_MULTI_foo 1.2.3.4,1.2.6.4    FOO bar
437 YP_MULTI_bar 1.2.3.4,1.2.6.4    FOO bar
438 */
439 
440 static struct hostent *
makehostent(struct irs_ho * this)441 makehostent(struct irs_ho *this) {
442           struct pvt *pvt = (struct pvt *)this->private;
443           static const char spaces[] = " \t";
444           char *cp, **q, *p, *comma, *ap;
445           int af = 0, len = 0;
446           int multi = 0;
447           int addr = 0;
448 
449           p = pvt->curval_data;
450           if ((cp = strpbrk(p, "#\n")) != NULL)
451                     *cp = '\0';
452           if (!(cp = strpbrk(p, spaces)))
453                     return (NULL);
454           *cp++ = '\0';
455           ap = pvt->hostbuf;
456           do {
457                     if ((comma = strchr(p, ',')) != NULL) {
458                               *comma++ = '\0';
459                               multi = 1;
460                     }
461                     if ((ap + IN6ADDRSZ) > (pvt->hostbuf + sizeof(pvt->hostbuf)))
462                               break;
463                     if ((pvt->res->options & RES_USE_INET6) &&
464                         inet_pton(AF_INET6, p, ap) > 0) {
465                               af = AF_INET6;
466                               len = IN6ADDRSZ;
467                     } else if (inet_pton(AF_INET, p, pvt->host_addr) > 0) {
468                               if (pvt->res->options & RES_USE_INET6) {
469                                         map_v4v6_address((char*)pvt->host_addr, ap);
470                                         af = AF_INET6;
471                                         len = IN6ADDRSZ;
472                               } else {
473                                         af = AF_INET;
474                                         len = INADDRSZ;
475                               }
476                     } else {
477                               if (!multi)
478                                         return (NULL);
479                               continue;
480                     }
481                     if (addr < MAXADDRS) {
482                               pvt->h_addr_ptrs[addr++] = ap;
483                               pvt->h_addr_ptrs[addr] = NULL;
484                               ap += len;
485                     }
486           } while ((p = comma) != NULL);
487           if (ap == pvt->hostbuf)
488                     return (NULL);
489           pvt->host.h_addr_list = pvt->h_addr_ptrs;
490           pvt->host.h_length = len;
491           pvt->host.h_addrtype = af;
492           cp += strspn(cp, spaces);
493           pvt->host.h_name = cp;
494           q = pvt->host.h_aliases = pvt->host_aliases;
495           if ((cp = strpbrk(cp, spaces)) != NULL)
496                     *cp++ = '\0';
497           while (cp && *cp) {
498                     if (*cp == ' ' || *cp == '\t') {
499                               cp++;
500                               continue;
501                     }
502                     if (q < &pvt->host_aliases[MAXALIASES])
503                               *q++ = cp;
504                     if ((cp = strpbrk(cp, spaces)) != NULL)
505                               *cp++ = '\0';
506           }
507           *q = NULL;
508           RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS);
509           return (&pvt->host);
510 }
511 
512 static void
nisfree(struct pvt * pvt,enum do_what do_what)513 nisfree(struct pvt *pvt, enum do_what do_what) {
514           if ((do_what & do_key) && pvt->curkey_data) {
515                     free(pvt->curkey_data);
516                     pvt->curkey_data = NULL;
517           }
518           if ((do_what & do_val) && pvt->curval_data) {
519                     free(pvt->curval_data);
520                     pvt->curval_data = NULL;
521           }
522 }
523 
524 static int
init(struct irs_ho * this)525 init(struct irs_ho *this) {
526           struct pvt *pvt = (struct pvt *)this->private;
527 
528           if (!pvt->res && !ho_res_get(this))
529                     return (-1);
530           if (((pvt->res->options & RES_INIT) == 0) &&
531               res_ninit(pvt->res) == -1)
532                     return (-1);
533           return (0);
534 }
535 #endif /*WANT_IRS_NIS*/
536 
537 /*! \file */
538