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.
38 * This is the library routines that do the name to address
43 #include "rpc_mt.h" /* for MT declarations only */
45 #include <sys/types.h>
49 #include <netconfig.h>
56 #include <nss_netdir.h>
57 #include <netinet/in.h>
60 /* messaging stuff. */
62 extern const char __nsl_dom
[];
63 extern char *dgettext(const char *, const char *);
66 struct nd_addrlist
*(*gbn
)(); /* _netdir_getbyname */
67 struct nd_hostservlist
*(*gba
)(); /* _netdir_getbyaddr */
68 int (*opt
)(); /* _netdir_options */
69 char *(*t2u
)(); /* _taddr2uaddr */
70 struct netbuf
*(*u2t
)(); /* _uaddr2taddr */
71 void *tr_fd
; /* dyn library handle */
72 char *tr_name
; /* Full path */
73 struct translator
*next
;
77 * xlate_lock protects xlate_list during updates only. The xlate_list linked
78 * list is pre-pended when new entries are added, so threads that are already
79 * using the list will continue correctly to the end of the list.
81 static struct translator
*xlate_list
= NULL
;
82 static mutex_t xlate_lock
= DEFAULTMUTEX
;
84 static struct translator
*load_xlate(char *);
87 * This is the common data (global data) that is exported
88 * by public interfaces. It has been moved here from nd_comdata.c
89 * which no longer exists. This fixes the problem for applications
90 * that do not link directly with -lnsl but dlopen a shared object
91 * that has a NEEDED dependency on -lnsl and uses the netdir
102 static pthread_key_t nderror_key
= PTHREAD_ONCE_KEY_NP
;
107 ret
= thr_get_storage(&nderror_key
, sizeof (int), free
);
108 /* if thr_get_storage fails we return the address of _nderror */
109 return (ret
? ret
: &_nderror
);
112 #define _nderror (*(__nderror()))
115 * Adds a translator library to the xlate_list, but first check to see if
116 * it's already on the list. Must be called while holding xlate_lock.
117 * We have to be careful for the case of the same library being loaded
118 * with different names (e.g., straddr.so and /usr/lib/straddr.so).
119 * We check for this case by looking at the gbn and name fields.
120 * If the gbn address is the same, but the names are different, then we
121 * have accidentally reloaded the library. We dlclose the new version,
122 * and then update 'translate' with the old versions of the symbols.
125 add_to_xlate_list(struct translator
*translate
)
127 struct translator
*t
;
129 for (t
= xlate_list
; t
; t
= t
->next
) {
130 if (strcmp(translate
->tr_name
, t
->tr_name
) == 0) {
134 translate
->next
= xlate_list
;
135 xlate_list
= translate
;
139 * This routine is the main routine that resolves host/service/xprt triples
140 * into a bunch of netbufs that should connect you to that particular
141 * service. RPC uses it to contact the binder service (rpcbind).
143 * In the interest of consistency with the gethost/servbyYY() routines,
144 * this routine calls a common interface _get_hostserv_inetnetdir_byname
145 * if it's called with a netconfig with "inet" type transports and
146 * an empty list of nametoaddr libs (i.e. a "-" in /etc/netconfig),
147 * which indicates the use of the switch. For non-inet transports or
148 * inet transports with nametoaddr libs specified, it simply calls
149 * the SVr4-classic netdir_getbyname, which loops through the libs.
151 * After all, any problem can be solved by one more layer of abstraction..
153 * This routine when called with a netconfig with "inet6" type of transports
154 * returns pure IPv6 addresses only and if no IPv6 address is found it
155 * returns none - Bug Id. 4276329
158 netdir_getbyname(struct netconfig
*tp
, struct nd_hostserv
*serv
,
159 struct nd_addrlist
**addrs
)
162 _nderror
= ND_BADARG
;
165 if ((strcmp(tp
->nc_protofmly
, NC_INET
) == 0) &&
166 (tp
->nc_nlookups
== 0)) {
167 struct nss_netdirbyname_in nssin
;
168 union nss_netdirbyname_out nssout
;
170 nssin
.op_t
= NETDIR_BY
;
171 nssin
.arg
.nd_hs
= serv
;
173 * In code path of case NETDIR_BY,
174 * it also calls DOOR_GETIPNODEBYNAME_R.
175 * So af_family and flags are set to
176 * get V4 addresses only.
178 nssin
.arg
.nss
.host6
.af_family
= AF_INET
;
179 nssin
.arg
.nss
.host6
.flags
= 0;
180 nssout
.nd_alist
= addrs
;
181 return (_get_hostserv_inetnetdir_byname(tp
, &nssin
, &nssout
));
183 if ((strcmp(tp
->nc_protofmly
, NC_INET6
) == 0) &&
184 (tp
->nc_nlookups
== 0)) {
185 struct nss_netdirbyname_in nssin
;
186 union nss_netdirbyname_out nssout
;
188 nssin
.op_t
= NETDIR_BY6
;
189 nssin
.arg
.nd_hs
= serv
;
190 /* get both V4 & V6 addresses */
191 nssin
.arg
.nss
.host6
.af_family
= AF_INET6
;
192 nssin
.arg
.nss
.host6
.flags
= (AI_ALL
| AI_V4MAPPED
);
193 nssout
.nd_alist
= addrs
;
194 return (_get_hostserv_inetnetdir_byname(tp
, &nssin
, &nssout
));
196 return (__classic_netdir_getbyname(tp
, serv
, addrs
));
200 * This routine is the svr4_classic routine for resolving host/service/xprt
201 * triples into a bunch of netbufs that should connect you to that particular
202 * service. RPC uses it to contact the binder service (rpcbind).
204 * It's either called by the real netdir_getbyname() interface above
205 * or by gethost/servbyname when nametoaddr libs are specified in
206 * /etc/netconfig with an intent of bypassing the name service switch.
209 __classic_netdir_getbyname(struct netconfig
*tp
, struct nd_hostserv
*serv
,
210 struct nd_addrlist
**addrs
)
212 struct translator
*t
; /* pointer to translator list */
213 struct nd_addrlist
*nn
; /* the results */
214 char *lr
; /* routines to try */
215 int i
; /* counts the routines */
217 _nderror
= ND_SYSTEM
;
218 for (i
= 0; i
< tp
->nc_nlookups
; i
++) {
219 lr
= *((tp
->nc_lookups
) + i
);
220 for (t
= xlate_list
; t
; t
= t
->next
) {
221 if (strcmp(lr
, t
->tr_name
) == 0) {
222 nn
= (*(t
->gbn
))(tp
, serv
);
233 /* If we didn't find it try loading it */
235 if ((t
= load_xlate(lr
)) != NULL
) {
236 /* add it to the list */
237 (void) mutex_lock(&xlate_lock
);
238 add_to_xlate_list(t
);
239 (void) mutex_unlock(&xlate_lock
);
240 nn
= (*(t
->gbn
))(tp
, serv
);
249 if (_nderror
== ND_SYSTEM
) { /* retry cache */
257 return (_nderror
); /* No one works */
261 * This routine is similar to the one above except that it tries to resolve
262 * the name by the address passed.
265 netdir_getbyaddr(struct netconfig
*tp
, struct nd_hostservlist
**serv
,
269 _nderror
= ND_BADARG
;
272 if ((strcmp(tp
->nc_protofmly
, NC_INET
) == 0) &&
273 (tp
->nc_nlookups
== 0)) {
274 struct nss_netdirbyaddr_in nssin
;
275 union nss_netdirbyaddr_out nssout
;
277 nssin
.op_t
= NETDIR_BY
;
278 nssin
.arg
.nd_nbuf
= addr
;
279 nssout
.nd_hslist
= serv
;
280 return (_get_hostserv_inetnetdir_byaddr(tp
, &nssin
, &nssout
));
282 if ((strcmp(tp
->nc_protofmly
, NC_INET6
) == 0) &&
283 (tp
->nc_nlookups
== 0)) {
284 struct nss_netdirbyaddr_in nssin
;
285 union nss_netdirbyaddr_out nssout
;
287 nssin
.op_t
= NETDIR_BY6
;
288 nssin
.arg
.nd_nbuf
= addr
;
289 nssout
.nd_hslist
= serv
;
290 return (_get_hostserv_inetnetdir_byaddr(tp
, &nssin
, &nssout
));
292 return (__classic_netdir_getbyaddr(tp
, serv
, addr
));
295 * This routine is similar to the one above except that it instructs the
296 * _get_hostserv_inetnetdir_byaddr not to do a service lookup.
299 __netdir_getbyaddr_nosrv(struct netconfig
*tp
, struct nd_hostservlist
**serv
,
303 _nderror
= ND_BADARG
;
306 if ((strcmp(tp
->nc_protofmly
, NC_INET
) == 0) &&
307 (tp
->nc_nlookups
== 0)) {
308 struct nss_netdirbyaddr_in nssin
;
309 union nss_netdirbyaddr_out nssout
;
311 nssin
.op_t
= NETDIR_BY_NOSRV
;
312 nssin
.arg
.nd_nbuf
= addr
;
313 nssout
.nd_hslist
= serv
;
314 return (_get_hostserv_inetnetdir_byaddr(tp
, &nssin
, &nssout
));
316 if ((strcmp(tp
->nc_protofmly
, NC_INET6
) == 0) &&
317 (tp
->nc_nlookups
== 0)) {
318 struct nss_netdirbyaddr_in nssin
;
319 union nss_netdirbyaddr_out nssout
;
321 nssin
.op_t
= NETDIR_BY_NOSRV6
;
322 nssin
.arg
.nd_nbuf
= addr
;
323 nssout
.nd_hslist
= serv
;
324 return (_get_hostserv_inetnetdir_byaddr(tp
, &nssin
, &nssout
));
326 return (__classic_netdir_getbyaddr(tp
, serv
, addr
));
330 * This routine is the svr4_classic routine for resolving a netbuf struct
331 * into a bunch of host/service name pairs.
333 * It's either called by the real netdir_getbyaddr() interface above
334 * or by gethost/servbyaddr when nametoaddr libs are specified in
335 * /etc/netconfig with an intent of bypassing the name service switch.
338 __classic_netdir_getbyaddr(struct netconfig
*tp
, struct nd_hostservlist
**serv
,
341 struct translator
*t
; /* pointer to translator list */
342 struct nd_hostservlist
*hs
; /* the results */
343 char *lr
; /* routines to try */
344 int i
; /* counts the routines */
346 _nderror
= ND_SYSTEM
;
347 for (i
= 0; i
< tp
->nc_nlookups
; i
++) {
348 lr
= *((tp
->nc_lookups
) + i
);
349 for (t
= xlate_list
; t
; t
= t
->next
) {
350 if (strcmp(lr
, t
->tr_name
) == 0) {
351 hs
= (*(t
->gba
))(tp
, addr
);
361 /* If we didn't find it try loading it */
363 if ((t
= load_xlate(lr
)) != NULL
) {
364 /* add it to the list */
365 (void) mutex_lock(&xlate_lock
);
366 add_to_xlate_list(t
);
367 (void) mutex_unlock(&xlate_lock
);
368 hs
= (*(t
->gba
))(tp
, addr
);
376 if (_nderror
== ND_SYSTEM
) { /* retry cache */
384 return (_nderror
); /* No one works */
388 * This is the library routine to do transport specific stuff.
389 * The code is same as the other similar routines except that it does
390 * not bother to try whole bunch of routines since if the first
391 * libray cannot resolve the option, then no one can.
393 * If it gets a netconfig structure for inet transports with nametoddr libs,
394 * it simply calls the inet-specific built in implementation.
397 netdir_options(struct netconfig
*tp
, int option
, int fd
, char *par
)
399 struct translator
*t
; /* pointer to translator list */
400 char *lr
; /* routines to try */
401 int i
; /* counts the routines */
404 _nderror
= ND_BADARG
;
408 if ((strcmp(tp
->nc_protofmly
, NC_INET
) == 0 ||
409 strcmp(tp
->nc_protofmly
, NC_INET6
) == 0) &&
410 (tp
->nc_nlookups
== 0)) {
411 return (__inet_netdir_options(tp
, option
, fd
, par
));
415 for (i
= 0; i
< tp
->nc_nlookups
; i
++) {
416 lr
= *((tp
->nc_lookups
) + i
);
417 for (t
= xlate_list
; t
; t
= t
->next
) {
418 if (strcmp(lr
, t
->tr_name
) == 0)
419 return ((*(t
->opt
))(tp
, option
, fd
, par
));
421 /* If we didn't find it try loading it */
423 if ((t
= load_xlate(lr
)) != NULL
) {
424 /* add it to the list */
425 (void) mutex_lock(&xlate_lock
);
426 add_to_xlate_list(t
);
427 (void) mutex_unlock(&xlate_lock
);
428 return ((*(t
->opt
))(tp
, option
, fd
, par
));
430 if (_nderror
== ND_SYSTEM
) { /* retry cache */
437 return (_nderror
); /* No one works */
441 * This is the library routine for translating universal addresses to
442 * transport specific addresses. Again it uses the same code as above
443 * to search for the appropriate translation routine. Only it doesn't
444 * bother trying a whole bunch of routines since either the transport
445 * can translate it or it can't.
448 uaddr2taddr(struct netconfig
*tp
, char *addr
)
450 struct translator
*t
; /* pointer to translator list */
451 struct netbuf
*x
; /* the answer we want */
452 char *lr
; /* routines to try */
453 int i
; /* counts the routines */
456 _nderror
= ND_BADARG
;
459 if ((strcmp(tp
->nc_protofmly
, NC_INET
) == 0 ||
460 strcmp(tp
->nc_protofmly
, NC_INET6
) == 0) &&
461 (tp
->nc_nlookups
== 0)) {
462 return (__inet_uaddr2taddr(tp
, addr
));
464 for (i
= 0; i
< tp
->nc_nlookups
; i
++) {
465 lr
= *((tp
->nc_lookups
) + i
);
466 for (t
= xlate_list
; t
; t
= t
->next
) {
467 if (strcmp(lr
, t
->tr_name
) == 0) {
468 x
= (*(t
->u2t
))(tp
, addr
);
475 /* If we didn't find it try loading it */
477 if ((t
= load_xlate(lr
)) != NULL
) {
478 /* add it to the list */
479 (void) mutex_lock(&xlate_lock
);
480 add_to_xlate_list(t
);
481 (void) mutex_unlock(&xlate_lock
);
482 x
= (*(t
->u2t
))(tp
, addr
);
488 if (_nderror
== ND_SYSTEM
) { /* retry cache */
496 return (0); /* No one works */
500 * This is the library routine for translating transport specific
501 * addresses to universal addresses. Again it uses the same code as above
502 * to search for the appropriate translation routine. Only it doesn't
503 * bother trying a whole bunch of routines since either the transport
504 * can translate it or it can't.
507 taddr2uaddr(struct netconfig
*tp
, struct netbuf
*addr
)
509 struct translator
*t
; /* pointer to translator list */
510 char *lr
; /* routines to try */
511 char *x
; /* the answer */
512 int i
; /* counts the routines */
515 _nderror
= ND_BADARG
;
518 if ((strcmp(tp
->nc_protofmly
, NC_INET
) == 0 ||
519 strcmp(tp
->nc_protofmly
, NC_INET6
) == 0) &&
520 (tp
->nc_nlookups
== 0)) {
521 return (__inet_taddr2uaddr(tp
, addr
));
523 for (i
= 0; i
< tp
->nc_nlookups
; i
++) {
524 lr
= *((tp
->nc_lookups
) + i
);
525 for (t
= xlate_list
; t
; t
= t
->next
) {
526 if (strcmp(lr
, t
->tr_name
) == 0) {
527 x
= (*(t
->t2u
))(tp
, addr
);
534 /* If we didn't find it try loading it */
536 if ((t
= load_xlate(lr
)) != NULL
) {
537 /* add it to the list */
538 (void) mutex_lock(&xlate_lock
);
539 add_to_xlate_list(t
);
540 (void) mutex_unlock(&xlate_lock
);
541 x
= (*(t
->t2u
))(tp
, addr
);
547 if (_nderror
== ND_SYSTEM
) { /* retry cache */
555 return (0); /* No one works */
559 * This is the routine that frees the objects that these routines allocate.
562 netdir_free(void *ptr
, int type
)
565 struct nd_addrlist
*nas
;
566 struct nd_hostserv
*hs
;
567 struct nd_hostservlist
*hss
;
574 na
= (struct netbuf
*)ptr
;
580 nas
= (struct nd_addrlist
*)ptr
;
582 * XXX: We do NOT try to free all individual netbuf->buf
583 * pointers. Free only the first one since they are allocated
584 * using one calloc in
585 * libnsl/nss/netdir_inet.c:order_haddrlist().
586 * This potentially causes memory leaks if a nametoaddr
587 * implementation -- from a third party -- has a different
590 free(nas
->n_addrs
->buf
);
596 hs
= (struct nd_hostserv
*)ptr
;
602 case ND_HOSTSERVLIST
:
603 hss
= (struct nd_hostservlist
*)ptr
;
604 for (hs
= hss
->h_hostservs
, i
= 0; i
< hss
->h_cnt
; i
++, hs
++) {
608 free(hss
->h_hostservs
);
619 * load_xlate is a routine that will attempt to dynamically link in the
620 * file specified by the network configuration structure.
622 static struct translator
*
623 load_xlate(char *name
)
625 struct translator
*t
;
626 static struct xlate_list
{
628 struct xlate_list
*next
;
630 struct xlate_list
*xlp
, **xlastp
;
631 static mutex_t xlist_lock
= DEFAULTMUTEX
;
633 (void) mutex_lock(&xlist_lock
);
635 * We maintain a list of libraries we have loaded. Loading a library
636 * twice is double-plus ungood!
638 for (xlp
= xlistp
, xlastp
= &xlistp
; xlp
!= NULL
;
639 xlastp
= &xlp
->next
, xlp
= xlp
->next
) {
640 if (xlp
->library
!= NULL
) {
641 if (strcmp(xlp
->library
, name
) == 0) {
642 _nderror
= ND_SYSTEM
; /* seen this lib */
643 (void) mutex_unlock(&xlist_lock
);
648 t
= malloc(sizeof (struct translator
));
651 (void) mutex_unlock(&xlist_lock
);
654 t
->tr_name
= strdup(name
);
658 (void) mutex_unlock(&xlist_lock
);
662 t
->tr_fd
= dlopen(name
, RTLD_LAZY
);
663 if (t
->tr_fd
== NULL
) {
668 /* Resolve the getbyname symbol */
669 t
->gbn
= (struct nd_addrlist
*(*)())dlsym(t
->tr_fd
,
670 "_netdir_getbyname");
676 /* resolve the getbyaddr symbol */
677 t
->gba
= (struct nd_hostservlist
*(*)())dlsym(t
->tr_fd
,
678 "_netdir_getbyaddr");
684 /* resolve the taddr2uaddr symbol */
685 t
->t2u
= (char *(*)())dlsym(t
->tr_fd
, "_taddr2uaddr");
691 /* resolve the uaddr2taddr symbol */
692 t
->u2t
= (struct netbuf
*(*)())dlsym(t
->tr_fd
, "_uaddr2taddr");
698 /* resolve the netdir_options symbol */
699 t
->opt
= (int (*)())dlsym(t
->tr_fd
, "_netdir_options");
705 * Add this library to the list of loaded libraries.
707 *xlastp
= malloc(sizeof (struct xlate_list
));
708 if (*xlastp
== NULL
) {
712 (*xlastp
)->library
= strdup(name
);
713 if ((*xlastp
)->library
== NULL
) {
718 (*xlastp
)->next
= NULL
;
719 (void) mutex_unlock(&xlist_lock
);
722 if (t
->tr_fd
!= NULL
)
723 (void) dlclose(t
->tr_fd
);
726 (void) mutex_unlock(&xlist_lock
);
731 #define NDERR_BUFSZ 512
734 * This is a routine that returns a string related to the current
740 static pthread_key_t nderrbuf_key
= PTHREAD_ONCE_KEY_NP
;
741 static char buf_main
[NDERR_BUFSZ
];
747 thr_get_storage(&nderrbuf_key
, NDERR_BUFSZ
, free
);
750 dlerrstr
= dlerror();
753 (void) snprintf(str
, NDERR_BUFSZ
,
754 dgettext(__nsl_dom
, "n2a: memory allocation failed"));
757 (void) snprintf(str
, NDERR_BUFSZ
,
758 dgettext(__nsl_dom
, "n2a: successful completion"));
761 (void) snprintf(str
, NDERR_BUFSZ
,
762 dgettext(__nsl_dom
, "n2a: hostname not found"));
765 (void) snprintf(str
, NDERR_BUFSZ
,
766 dgettext(__nsl_dom
, "n2a: service name not found"));
769 (void) snprintf(str
, NDERR_BUFSZ
, "%s : %s ",
771 "n2a: symbol missing in shared object"),
772 dlerrstr
? dlerrstr
: " ");
775 (void) snprintf(str
, NDERR_BUFSZ
, "%s - %s ",
776 dgettext(__nsl_dom
, "n2a: couldn't open shared object"),
777 dlerrstr
? dlerrstr
: " ");
780 (void) snprintf(str
, NDERR_BUFSZ
,
782 "n2a: access denied for shared object"));
785 (void) snprintf(str
, NDERR_BUFSZ
,
787 "n2a: attempt to free unknown object"));
790 (void) snprintf(str
, NDERR_BUFSZ
,
792 "n2a: bad arguments passed to routine"));
795 (void) snprintf(str
, NDERR_BUFSZ
,
796 dgettext(__nsl_dom
, "n2a: unknown option passed"));
799 (void) snprintf(str
, NDERR_BUFSZ
,
800 dgettext(__nsl_dom
, "n2a: control operation failed"));
803 (void) snprintf(str
, NDERR_BUFSZ
, "%s: %s",
804 dgettext(__nsl_dom
, "n2a: system error"),
808 (void) snprintf(str
, NDERR_BUFSZ
, "%s#%d",
809 dgettext(__nsl_dom
, "n2a: unknown error "), _nderror
);
816 * This is a routine that prints out strings related to the current
817 * error in _nderror. Like perror() it takes a string to print with a
821 netdir_perror(char *s
)
825 err
= netdir_sperror();
826 (void) fprintf(stderr
, "%s: %s\n", s
, err
? err
: "n2a: error");