4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 * Portions of this source code were derived from Berkeley 4.3 BSD
32 * under license from the Regents of the University of California.
35 #pragma ident "%Z%%M% %I% %E% SMI"
40 * This is the library routines that do the name to address
45 #include "../rpc/rpc_mt.h" /* for MT declarations only */
47 #include <sys/types.h>
51 #include <netconfig.h>
58 #include <nss_netdir.h>
59 #include <netinet/in.h>
62 /* messaging stuff. */
64 extern const char __nsl_dom
[];
65 extern char *dgettext(const char *, const char *);
68 struct nd_addrlist
*(*gbn
)(); /* _netdir_getbyname */
69 struct nd_hostservlist
*(*gba
)(); /* _netdir_getbyaddr */
70 int (*opt
)(); /* _netdir_options */
71 char *(*t2u
)(); /* _taddr2uaddr */
72 struct netbuf
*(*u2t
)(); /* _uaddr2taddr */
73 void *tr_fd
; /* dyn library handle */
74 char *tr_name
; /* Full path */
75 struct translator
*next
;
79 * xlate_lock protects xlate_list during updates only. The xlate_list linked
80 * list is pre-pended when new entries are added, so threads that are already
81 * using the list will continue correctly to the end of the list.
83 static struct translator
*xlate_list
= NULL
;
84 static mutex_t xlate_lock
= DEFAULTMUTEX
;
86 static struct translator
*load_xlate(char *);
89 * This is the common data (global data) that is exported
90 * by public interfaces. It has been moved here from nd_comdata.c
91 * which no longer exists. This fixes the problem for applications
92 * that do not link directly with -lnsl but dlopen a shared object
93 * that has a NEEDED dependency on -lnsl and uses the netdir
104 static pthread_key_t nderror_key
= PTHREAD_ONCE_KEY_NP
;
109 ret
= thr_get_storage(&nderror_key
, sizeof (int), free
);
110 /* if thr_get_storage fails we return the address of _nderror */
111 return (ret
? ret
: &_nderror
);
114 #define _nderror (*(__nderror()))
117 * Adds a translator library to the xlate_list, but first check to see if
118 * it's already on the list. Must be called while holding xlate_lock.
119 * We have to be careful for the case of the same library being loaded
120 * with different names (e.g., straddr.so and /usr/lib/straddr.so).
121 * We check for this case by looking at the gbn and name fields.
122 * If the gbn address is the same, but the names are different, then we
123 * have accidentally reloaded the library. We dlclose the new version,
124 * and then update 'translate' with the old versions of the symbols.
127 add_to_xlate_list(struct translator
*translate
)
129 struct translator
*t
;
131 for (t
= xlate_list
; t
; t
= t
->next
) {
132 if (strcmp(translate
->tr_name
, t
->tr_name
) == 0) {
136 translate
->next
= xlate_list
;
137 xlate_list
= translate
;
141 * This routine is the main routine that resolves host/service/xprt triples
142 * into a bunch of netbufs that should connect you to that particular
143 * service. RPC uses it to contact the binder service (rpcbind).
145 * In the interest of consistency with the gethost/servbyYY() routines,
146 * this routine calls a common interface _get_hostserv_inetnetdir_byname
147 * if it's called with a netconfig with "inet" type transports and
148 * an empty list of nametoaddr libs (i.e. a "-" in /etc/netconfig),
149 * which indicates the use of the switch. For non-inet transports or
150 * inet transports with nametoaddr libs specified, it simply calls
151 * the SVr4-classic netdir_getbyname, which loops through the libs.
153 * After all, any problem can be solved by one more layer of abstraction..
155 * This routine when called with a netconfig with "inet6" type of transports
156 * returns pure IPv6 addresses only and if no IPv6 address is found it
157 * returns none - Bug Id. 4276329
160 netdir_getbyname(struct netconfig
*tp
, struct nd_hostserv
*serv
,
161 struct nd_addrlist
**addrs
)
164 _nderror
= ND_BADARG
;
167 if ((strcmp(tp
->nc_protofmly
, NC_INET
) == 0) &&
168 (tp
->nc_nlookups
== 0)) {
169 struct nss_netdirbyname_in nssin
;
170 union nss_netdirbyname_out nssout
;
172 nssin
.op_t
= NETDIR_BY
;
173 nssin
.arg
.nd_hs
= serv
;
175 * In code path of case NETDIR_BY,
176 * it also calls DOOR_GETIPNODEBYNAME_R.
177 * So af_family and flags are set to
178 * get V4 addresses only.
180 nssin
.arg
.nss
.host6
.af_family
= AF_INET
;
181 nssin
.arg
.nss
.host6
.flags
= 0;
182 nssout
.nd_alist
= addrs
;
183 return (_get_hostserv_inetnetdir_byname(tp
, &nssin
, &nssout
));
185 if ((strcmp(tp
->nc_protofmly
, NC_INET6
) == 0) &&
186 (tp
->nc_nlookups
== 0)) {
187 struct nss_netdirbyname_in nssin
;
188 union nss_netdirbyname_out nssout
;
190 nssin
.op_t
= NETDIR_BY6
;
191 nssin
.arg
.nd_hs
= serv
;
192 /* get both V4 & V6 addresses */
193 nssin
.arg
.nss
.host6
.af_family
= AF_INET6
;
194 nssin
.arg
.nss
.host6
.flags
= (AI_ALL
| AI_V4MAPPED
);
195 nssout
.nd_alist
= addrs
;
196 return (_get_hostserv_inetnetdir_byname(tp
, &nssin
, &nssout
));
198 return (__classic_netdir_getbyname(tp
, serv
, addrs
));
202 * This routine is the svr4_classic routine for resolving host/service/xprt
203 * triples into a bunch of netbufs that should connect you to that particular
204 * service. RPC uses it to contact the binder service (rpcbind).
206 * It's either called by the real netdir_getbyname() interface above
207 * or by gethost/servbyname when nametoaddr libs are specified in
208 * /etc/netconfig with an intent of bypassing the name service switch.
211 __classic_netdir_getbyname(struct netconfig
*tp
, struct nd_hostserv
*serv
,
212 struct nd_addrlist
**addrs
)
214 struct translator
*t
; /* pointer to translator list */
215 struct nd_addrlist
*nn
; /* the results */
216 char *lr
; /* routines to try */
217 int i
; /* counts the routines */
219 _nderror
= ND_SYSTEM
;
220 for (i
= 0; i
< tp
->nc_nlookups
; i
++) {
221 lr
= *((tp
->nc_lookups
) + i
);
222 for (t
= xlate_list
; t
; t
= t
->next
) {
223 if (strcmp(lr
, t
->tr_name
) == 0) {
224 nn
= (*(t
->gbn
))(tp
, serv
);
235 /* If we didn't find it try loading it */
237 if ((t
= load_xlate(lr
)) != NULL
) {
238 /* add it to the list */
239 (void) mutex_lock(&xlate_lock
);
240 add_to_xlate_list(t
);
241 (void) mutex_unlock(&xlate_lock
);
242 nn
= (*(t
->gbn
))(tp
, serv
);
251 if (_nderror
== ND_SYSTEM
) { /* retry cache */
259 return (_nderror
); /* No one works */
263 * This routine is similar to the one above except that it tries to resolve
264 * the name by the address passed.
267 netdir_getbyaddr(struct netconfig
*tp
, struct nd_hostservlist
**serv
,
271 _nderror
= ND_BADARG
;
274 if ((strcmp(tp
->nc_protofmly
, NC_INET
) == 0) &&
275 (tp
->nc_nlookups
== 0)) {
276 struct nss_netdirbyaddr_in nssin
;
277 union nss_netdirbyaddr_out nssout
;
279 nssin
.op_t
= NETDIR_BY
;
280 nssin
.arg
.nd_nbuf
= addr
;
281 nssout
.nd_hslist
= serv
;
282 return (_get_hostserv_inetnetdir_byaddr(tp
, &nssin
, &nssout
));
284 if ((strcmp(tp
->nc_protofmly
, NC_INET6
) == 0) &&
285 (tp
->nc_nlookups
== 0)) {
286 struct nss_netdirbyaddr_in nssin
;
287 union nss_netdirbyaddr_out nssout
;
289 nssin
.op_t
= NETDIR_BY6
;
290 nssin
.arg
.nd_nbuf
= addr
;
291 nssout
.nd_hslist
= serv
;
292 return (_get_hostserv_inetnetdir_byaddr(tp
, &nssin
, &nssout
));
294 return (__classic_netdir_getbyaddr(tp
, serv
, addr
));
297 * This routine is similar to the one above except that it instructs the
298 * _get_hostserv_inetnetdir_byaddr not to do a service lookup.
301 __netdir_getbyaddr_nosrv(struct netconfig
*tp
, struct nd_hostservlist
**serv
,
305 _nderror
= ND_BADARG
;
308 if ((strcmp(tp
->nc_protofmly
, NC_INET
) == 0) &&
309 (tp
->nc_nlookups
== 0)) {
310 struct nss_netdirbyaddr_in nssin
;
311 union nss_netdirbyaddr_out nssout
;
313 nssin
.op_t
= NETDIR_BY_NOSRV
;
314 nssin
.arg
.nd_nbuf
= addr
;
315 nssout
.nd_hslist
= serv
;
316 return (_get_hostserv_inetnetdir_byaddr(tp
, &nssin
, &nssout
));
318 if ((strcmp(tp
->nc_protofmly
, NC_INET6
) == 0) &&
319 (tp
->nc_nlookups
== 0)) {
320 struct nss_netdirbyaddr_in nssin
;
321 union nss_netdirbyaddr_out nssout
;
323 nssin
.op_t
= NETDIR_BY_NOSRV6
;
324 nssin
.arg
.nd_nbuf
= addr
;
325 nssout
.nd_hslist
= serv
;
326 return (_get_hostserv_inetnetdir_byaddr(tp
, &nssin
, &nssout
));
328 return (__classic_netdir_getbyaddr(tp
, serv
, addr
));
332 * This routine is the svr4_classic routine for resolving a netbuf struct
333 * into a bunch of host/service name pairs.
335 * It's either called by the real netdir_getbyaddr() interface above
336 * or by gethost/servbyaddr when nametoaddr libs are specified in
337 * /etc/netconfig with an intent of bypassing the name service switch.
340 __classic_netdir_getbyaddr(struct netconfig
*tp
, struct nd_hostservlist
**serv
,
343 struct translator
*t
; /* pointer to translator list */
344 struct nd_hostservlist
*hs
; /* the results */
345 char *lr
; /* routines to try */
346 int i
; /* counts the routines */
348 _nderror
= ND_SYSTEM
;
349 for (i
= 0; i
< tp
->nc_nlookups
; i
++) {
350 lr
= *((tp
->nc_lookups
) + i
);
351 for (t
= xlate_list
; t
; t
= t
->next
) {
352 if (strcmp(lr
, t
->tr_name
) == 0) {
353 hs
= (*(t
->gba
))(tp
, addr
);
363 /* If we didn't find it try loading it */
365 if ((t
= load_xlate(lr
)) != NULL
) {
366 /* add it to the list */
367 (void) mutex_lock(&xlate_lock
);
368 add_to_xlate_list(t
);
369 (void) mutex_unlock(&xlate_lock
);
370 hs
= (*(t
->gba
))(tp
, addr
);
378 if (_nderror
== ND_SYSTEM
) { /* retry cache */
386 return (_nderror
); /* No one works */
390 * This is the library routine to do transport specific stuff.
391 * The code is same as the other similar routines except that it does
392 * not bother to try whole bunch of routines since if the first
393 * libray cannot resolve the option, then no one can.
395 * If it gets a netconfig structure for inet transports with nametoddr libs,
396 * it simply calls the inet-specific built in implementation.
399 netdir_options(struct netconfig
*tp
, int option
, int fd
, char *par
)
401 struct translator
*t
; /* pointer to translator list */
402 char *lr
; /* routines to try */
403 int i
; /* counts the routines */
406 _nderror
= ND_BADARG
;
410 if ((strcmp(tp
->nc_protofmly
, NC_INET
) == 0 ||
411 strcmp(tp
->nc_protofmly
, NC_INET6
) == 0) &&
412 (tp
->nc_nlookups
== 0)) {
413 return (__inet_netdir_options(tp
, option
, fd
, par
));
417 for (i
= 0; i
< tp
->nc_nlookups
; i
++) {
418 lr
= *((tp
->nc_lookups
) + i
);
419 for (t
= xlate_list
; t
; t
= t
->next
) {
420 if (strcmp(lr
, t
->tr_name
) == 0)
421 return ((*(t
->opt
))(tp
, option
, fd
, par
));
423 /* If we didn't find it try loading it */
425 if ((t
= load_xlate(lr
)) != NULL
) {
426 /* add it to the list */
427 (void) mutex_lock(&xlate_lock
);
428 add_to_xlate_list(t
);
429 (void) mutex_unlock(&xlate_lock
);
430 return ((*(t
->opt
))(tp
, option
, fd
, par
));
432 if (_nderror
== ND_SYSTEM
) { /* retry cache */
439 return (_nderror
); /* No one works */
443 * This is the library routine for translating universal addresses to
444 * transport specific addresses. Again it uses the same code as above
445 * to search for the appropriate translation routine. Only it doesn't
446 * bother trying a whole bunch of routines since either the transport
447 * can translate it or it can't.
450 uaddr2taddr(struct netconfig
*tp
, char *addr
)
452 struct translator
*t
; /* pointer to translator list */
453 struct netbuf
*x
; /* the answer we want */
454 char *lr
; /* routines to try */
455 int i
; /* counts the routines */
458 _nderror
= ND_BADARG
;
461 if ((strcmp(tp
->nc_protofmly
, NC_INET
) == 0 ||
462 strcmp(tp
->nc_protofmly
, NC_INET6
) == 0) &&
463 (tp
->nc_nlookups
== 0)) {
464 return (__inet_uaddr2taddr(tp
, addr
));
466 for (i
= 0; i
< tp
->nc_nlookups
; i
++) {
467 lr
= *((tp
->nc_lookups
) + i
);
468 for (t
= xlate_list
; t
; t
= t
->next
) {
469 if (strcmp(lr
, t
->tr_name
) == 0) {
470 x
= (*(t
->u2t
))(tp
, addr
);
477 /* If we didn't find it try loading it */
479 if ((t
= load_xlate(lr
)) != NULL
) {
480 /* add it to the list */
481 (void) mutex_lock(&xlate_lock
);
482 add_to_xlate_list(t
);
483 (void) mutex_unlock(&xlate_lock
);
484 x
= (*(t
->u2t
))(tp
, addr
);
490 if (_nderror
== ND_SYSTEM
) { /* retry cache */
498 return (0); /* No one works */
502 * This is the library routine for translating transport specific
503 * addresses to universal addresses. Again it uses the same code as above
504 * to search for the appropriate translation routine. Only it doesn't
505 * bother trying a whole bunch of routines since either the transport
506 * can translate it or it can't.
509 taddr2uaddr(struct netconfig
*tp
, struct netbuf
*addr
)
511 struct translator
*t
; /* pointer to translator list */
512 char *lr
; /* routines to try */
513 char *x
; /* the answer */
514 int i
; /* counts the routines */
517 _nderror
= ND_BADARG
;
520 if ((strcmp(tp
->nc_protofmly
, NC_INET
) == 0 ||
521 strcmp(tp
->nc_protofmly
, NC_INET6
) == 0) &&
522 (tp
->nc_nlookups
== 0)) {
523 return (__inet_taddr2uaddr(tp
, addr
));
525 for (i
= 0; i
< tp
->nc_nlookups
; i
++) {
526 lr
= *((tp
->nc_lookups
) + i
);
527 for (t
= xlate_list
; t
; t
= t
->next
) {
528 if (strcmp(lr
, t
->tr_name
) == 0) {
529 x
= (*(t
->t2u
))(tp
, addr
);
536 /* If we didn't find it try loading it */
538 if ((t
= load_xlate(lr
)) != NULL
) {
539 /* add it to the list */
540 (void) mutex_lock(&xlate_lock
);
541 add_to_xlate_list(t
);
542 (void) mutex_unlock(&xlate_lock
);
543 x
= (*(t
->t2u
))(tp
, addr
);
549 if (_nderror
== ND_SYSTEM
) { /* retry cache */
557 return (0); /* No one works */
561 * This is the routine that frees the objects that these routines allocate.
564 netdir_free(void *ptr
, int type
)
567 struct nd_addrlist
*nas
;
568 struct nd_hostserv
*hs
;
569 struct nd_hostservlist
*hss
;
576 na
= (struct netbuf
*)ptr
;
583 nas
= (struct nd_addrlist
*)ptr
;
585 * XXX: We do NOT try to free all individual netbuf->buf
586 * pointers. Free only the first one since they are allocated
587 * using one calloc in
588 * libnsl/nss/netdir_inet.c:order_haddrlist().
589 * This potentially causes memory leaks if a nametoaddr
590 * implementation -- from a third party -- has a different
593 if (nas
->n_addrs
->buf
)
594 free(nas
->n_addrs
->buf
);
600 hs
= (struct nd_hostserv
*)ptr
;
608 case ND_HOSTSERVLIST
:
609 hss
= (struct nd_hostservlist
*)ptr
;
610 for (hs
= hss
->h_hostservs
, i
= 0; i
< hss
->h_cnt
; i
++, hs
++) {
616 free(hss
->h_hostservs
);
627 * load_xlate is a routine that will attempt to dynamically link in the
628 * file specified by the network configuration structure.
630 static struct translator
*
631 load_xlate(char *name
)
633 struct translator
*t
;
634 static struct xlate_list
{
636 struct xlate_list
*next
;
638 struct xlate_list
*xlp
, **xlastp
;
639 static mutex_t xlist_lock
= DEFAULTMUTEX
;
641 (void) mutex_lock(&xlist_lock
);
643 * We maintain a list of libraries we have loaded. Loading a library
644 * twice is double-plus ungood!
646 for (xlp
= xlistp
, xlastp
= &xlistp
; xlp
!= NULL
;
647 xlastp
= &xlp
->next
, xlp
= xlp
->next
) {
648 if (xlp
->library
!= NULL
) {
649 if (strcmp(xlp
->library
, name
) == 0) {
650 _nderror
= ND_SYSTEM
; /* seen this lib */
651 (void) mutex_unlock(&xlist_lock
);
656 t
= malloc(sizeof (struct translator
));
659 (void) mutex_unlock(&xlist_lock
);
662 t
->tr_name
= strdup(name
);
666 (void) mutex_unlock(&xlist_lock
);
670 t
->tr_fd
= dlopen(name
, RTLD_LAZY
);
671 if (t
->tr_fd
== NULL
) {
676 /* Resolve the getbyname symbol */
677 t
->gbn
= (struct nd_addrlist
*(*)())dlsym(t
->tr_fd
,
678 "_netdir_getbyname");
684 /* resolve the getbyaddr symbol */
685 t
->gba
= (struct nd_hostservlist
*(*)())dlsym(t
->tr_fd
,
686 "_netdir_getbyaddr");
692 /* resolve the taddr2uaddr symbol */
693 t
->t2u
= (char *(*)())dlsym(t
->tr_fd
, "_taddr2uaddr");
699 /* resolve the uaddr2taddr symbol */
700 t
->u2t
= (struct netbuf
*(*)())dlsym(t
->tr_fd
, "_uaddr2taddr");
706 /* resolve the netdir_options symbol */
707 t
->opt
= (int (*)())dlsym(t
->tr_fd
, "_netdir_options");
713 * Add this library to the list of loaded libraries.
715 *xlastp
= malloc(sizeof (struct xlate_list
));
716 if (*xlastp
== NULL
) {
720 (*xlastp
)->library
= strdup(name
);
721 if ((*xlastp
)->library
== NULL
) {
726 (*xlastp
)->next
= NULL
;
727 (void) mutex_unlock(&xlist_lock
);
730 if (t
->tr_fd
!= NULL
)
731 (void) dlclose(t
->tr_fd
);
734 (void) mutex_unlock(&xlist_lock
);
739 #define NDERR_BUFSZ 512
742 * This is a routine that returns a string related to the current
748 static pthread_key_t nderrbuf_key
= PTHREAD_ONCE_KEY_NP
;
749 static char buf_main
[NDERR_BUFSZ
];
755 thr_get_storage(&nderrbuf_key
, NDERR_BUFSZ
, free
);
758 dlerrstr
= dlerror();
761 (void) snprintf(str
, NDERR_BUFSZ
,
762 dgettext(__nsl_dom
, "n2a: memory allocation failed"));
765 (void) snprintf(str
, NDERR_BUFSZ
,
766 dgettext(__nsl_dom
, "n2a: successful completion"));
769 (void) snprintf(str
, NDERR_BUFSZ
,
770 dgettext(__nsl_dom
, "n2a: hostname not found"));
773 (void) snprintf(str
, NDERR_BUFSZ
,
774 dgettext(__nsl_dom
, "n2a: service name not found"));
777 (void) snprintf(str
, NDERR_BUFSZ
, "%s : %s ",
779 "n2a: symbol missing in shared object"),
780 dlerrstr
? dlerrstr
: " ");
783 (void) snprintf(str
, NDERR_BUFSZ
, "%s - %s ",
784 dgettext(__nsl_dom
, "n2a: couldn't open shared object"),
785 dlerrstr
? dlerrstr
: " ");
788 (void) snprintf(str
, NDERR_BUFSZ
,
790 "n2a: access denied for shared object"));
793 (void) snprintf(str
, NDERR_BUFSZ
,
795 "n2a: attempt to free unknown object"));
798 (void) snprintf(str
, NDERR_BUFSZ
,
800 "n2a: bad arguments passed to routine"));
803 (void) snprintf(str
, NDERR_BUFSZ
,
804 dgettext(__nsl_dom
, "n2a: unknown option passed"));
807 (void) snprintf(str
, NDERR_BUFSZ
,
808 dgettext(__nsl_dom
, "n2a: control operation failed"));
811 (void) snprintf(str
, NDERR_BUFSZ
, "%s: %s",
812 dgettext(__nsl_dom
, "n2a: system error"),
816 (void) snprintf(str
, NDERR_BUFSZ
, "%s#%d",
817 dgettext(__nsl_dom
, "n2a: unknown error "), _nderror
);
824 * This is a routine that prints out strings related to the current
825 * error in _nderror. Like perror() it takes a string to print with a
829 netdir_perror(char *s
)
833 err
= netdir_sperror();
834 (void) fprintf(stderr
, "%s: %s\n", s
, err
? err
: "n2a: error");