1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30 /*
31 * Portions of this source code were derived from Berkeley 4.3 BSD
32 * under license from the Regents of the University of California.
33 */
34
35 #pragma ident "%Z%%M% %I% %E% SMI"
36
37 /*
38 * netdir.c
39 *
40 * This is the library routines that do the name to address
41 * translation.
42 */
43
44 #include "mt.h"
45 #include "../rpc/rpc_mt.h" /* for MT declarations only */
46 #include <stdio.h>
47 #include <sys/types.h>
48 #include <errno.h>
49 #include <tiuser.h>
50 #include <netdir.h>
51 #include <netconfig.h>
52 #include <string.h>
53 #include <sys/file.h>
54 #include <dlfcn.h>
55 #include <stdlib.h>
56 #include <malloc.h>
57 #include <syslog.h>
58 #include <nss_netdir.h>
59 #include <netinet/in.h>
60 #include <netdb.h>
61
62 /* messaging stuff. */
63
64 extern const char __nsl_dom[];
65 extern char *dgettext(const char *, const char *);
66
67 struct translator {
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;
76 };
77
78 /*
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.
82 */
83 static struct translator *xlate_list = NULL;
84 static mutex_t xlate_lock = DEFAULTMUTEX;
85
86 static struct translator *load_xlate(char *);
87
88 /*
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
94 * interface.
95 */
96
97 #undef _nderror
98
99 int _nderror;
100
101 int *
__nderror(void)102 __nderror(void)
103 {
104 static pthread_key_t nderror_key = PTHREAD_ONCE_KEY_NP;
105 int *ret;
106
107 if (thr_main())
108 return (&_nderror);
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);
112 }
113
114 #define _nderror (*(__nderror()))
115
116 /*
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.
125 */
126 void
add_to_xlate_list(struct translator * translate)127 add_to_xlate_list(struct translator *translate)
128 {
129 struct translator *t;
130
131 for (t = xlate_list; t; t = t->next) {
132 if (strcmp(translate->tr_name, t->tr_name) == 0) {
133 return;
134 }
135 }
136 translate->next = xlate_list;
137 xlate_list = translate;
138 }
139
140 /*
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).
144 *
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.
152 *
153 * After all, any problem can be solved by one more layer of abstraction..
154 *
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
158 */
159 int
netdir_getbyname(struct netconfig * tp,struct nd_hostserv * serv,struct nd_addrlist ** addrs)160 netdir_getbyname(struct netconfig *tp, struct nd_hostserv *serv,
161 struct nd_addrlist **addrs)
162 {
163 if (tp == 0) {
164 _nderror = ND_BADARG;
165 return (_nderror);
166 }
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;
171
172 nssin.op_t = NETDIR_BY;
173 nssin.arg.nd_hs = serv;
174 /*
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.
179 */
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));
184 }
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;
189
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));
197 }
198 return (__classic_netdir_getbyname(tp, serv, addrs));
199 }
200
201 /*
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).
205 *
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.
209 */
210 int
__classic_netdir_getbyname(struct netconfig * tp,struct nd_hostserv * serv,struct nd_addrlist ** addrs)211 __classic_netdir_getbyname(struct netconfig *tp, struct nd_hostserv *serv,
212 struct nd_addrlist **addrs)
213 {
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 */
218
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);
225 if (nn) {
226 *addrs = nn;
227 return (0);
228 }
229 if (_nderror < 0) {
230 return (_nderror);
231 }
232 break;
233 }
234 }
235 /* If we didn't find it try loading it */
236 if (!t) {
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);
243 if (nn) {
244 *addrs = nn;
245 return (0);
246 }
247 if (_nderror < 0) {
248 return (_nderror);
249 }
250 } else {
251 if (_nderror == ND_SYSTEM) { /* retry cache */
252 _nderror = ND_OK;
253 i--;
254 continue;
255 }
256 }
257 }
258 }
259 return (_nderror); /* No one works */
260 }
261
262 /*
263 * This routine is similar to the one above except that it tries to resolve
264 * the name by the address passed.
265 */
266 int
netdir_getbyaddr(struct netconfig * tp,struct nd_hostservlist ** serv,struct netbuf * addr)267 netdir_getbyaddr(struct netconfig *tp, struct nd_hostservlist **serv,
268 struct netbuf *addr)
269 {
270 if (tp == 0) {
271 _nderror = ND_BADARG;
272 return (_nderror);
273 }
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;
278
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));
283 }
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;
288
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));
293 }
294 return (__classic_netdir_getbyaddr(tp, serv, addr));
295 }
296 /*
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.
299 */
300 int
__netdir_getbyaddr_nosrv(struct netconfig * tp,struct nd_hostservlist ** serv,struct netbuf * addr)301 __netdir_getbyaddr_nosrv(struct netconfig *tp, struct nd_hostservlist **serv,
302 struct netbuf *addr)
303 {
304 if (tp == 0) {
305 _nderror = ND_BADARG;
306 return (_nderror);
307 }
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;
312
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));
317 }
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;
322
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));
327 }
328 return (__classic_netdir_getbyaddr(tp, serv, addr));
329 }
330
331 /*
332 * This routine is the svr4_classic routine for resolving a netbuf struct
333 * into a bunch of host/service name pairs.
334 *
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.
338 */
339 int
__classic_netdir_getbyaddr(struct netconfig * tp,struct nd_hostservlist ** serv,struct netbuf * addr)340 __classic_netdir_getbyaddr(struct netconfig *tp, struct nd_hostservlist **serv,
341 struct netbuf *addr)
342 {
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 */
347
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);
354 if (hs) {
355 *serv = hs;
356 return (0);
357 }
358 if (_nderror < 0)
359 return (_nderror);
360 break;
361 }
362 }
363 /* If we didn't find it try loading it */
364 if (!t) {
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);
371 if (hs) {
372 *serv = hs;
373 return (0);
374 }
375 if (_nderror < 0)
376 return (_nderror);
377 } else {
378 if (_nderror == ND_SYSTEM) { /* retry cache */
379 _nderror = ND_OK;
380 i--;
381 continue;
382 }
383 }
384 }
385 }
386 return (_nderror); /* No one works */
387 }
388
389 /*
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.
394 *
395 * If it gets a netconfig structure for inet transports with nametoddr libs,
396 * it simply calls the inet-specific built in implementation.
397 */
398 int
netdir_options(struct netconfig * tp,int option,int fd,char * par)399 netdir_options(struct netconfig *tp, int option, int fd, char *par)
400 {
401 struct translator *t; /* pointer to translator list */
402 char *lr; /* routines to try */
403 int i; /* counts the routines */
404
405 if (tp == 0) {
406 _nderror = ND_BADARG;
407 return (_nderror);
408 }
409
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));
414 }
415
416
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));
422 }
423 /* If we didn't find it try loading it */
424 if (!t) {
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));
431 }
432 if (_nderror == ND_SYSTEM) { /* retry cache */
433 _nderror = ND_OK;
434 i--;
435 continue;
436 }
437 }
438 }
439 return (_nderror); /* No one works */
440 }
441
442 /*
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.
448 */
449 struct netbuf *
uaddr2taddr(struct netconfig * tp,char * addr)450 uaddr2taddr(struct netconfig *tp, char *addr)
451 {
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 */
456
457 if (tp == 0) {
458 _nderror = ND_BADARG;
459 return (0);
460 }
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));
465 }
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);
471 if (x)
472 return (x);
473 if (_nderror < 0)
474 return (0);
475 }
476 }
477 /* If we didn't find it try loading it */
478 if (!t) {
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);
485 if (x)
486 return (x);
487 if (_nderror < 0)
488 return (0);
489 } else {
490 if (_nderror == ND_SYSTEM) { /* retry cache */
491 _nderror = ND_OK;
492 i--;
493 continue;
494 }
495 }
496 }
497 }
498 return (0); /* No one works */
499 }
500
501 /*
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.
507 */
508 char *
taddr2uaddr(struct netconfig * tp,struct netbuf * addr)509 taddr2uaddr(struct netconfig *tp, struct netbuf *addr)
510 {
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 */
515
516 if (tp == 0) {
517 _nderror = ND_BADARG;
518 return (0);
519 }
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));
524 }
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);
530 if (x)
531 return (x);
532 if (_nderror < 0)
533 return (0);
534 }
535 }
536 /* If we didn't find it try loading it */
537 if (!t) {
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);
544 if (x)
545 return (x);
546 if (_nderror < 0)
547 return (0);
548 } else {
549 if (_nderror == ND_SYSTEM) { /* retry cache */
550 _nderror = ND_OK;
551 i--;
552 continue;
553 }
554 }
555 }
556 }
557 return (0); /* No one works */
558 }
559
560 /*
561 * This is the routine that frees the objects that these routines allocate.
562 */
563 void
netdir_free(void * ptr,int type)564 netdir_free(void *ptr, int type)
565 {
566 struct netbuf *na;
567 struct nd_addrlist *nas;
568 struct nd_hostserv *hs;
569 struct nd_hostservlist *hss;
570 int i;
571
572 if (ptr == NULL)
573 return;
574 switch (type) {
575 case ND_ADDR :
576 na = (struct netbuf *)ptr;
577 if (na->buf)
578 free(na->buf);
579 free(na);
580 break;
581
582 case ND_ADDRLIST :
583 nas = (struct nd_addrlist *)ptr;
584 /*
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
591 * allocation scheme.
592 */
593 if (nas->n_addrs->buf)
594 free(nas->n_addrs->buf);
595 free(nas->n_addrs);
596 free(nas);
597 break;
598
599 case ND_HOSTSERV :
600 hs = (struct nd_hostserv *)ptr;
601 if (hs->h_host)
602 free(hs->h_host);
603 if (hs->h_serv)
604 free(hs->h_serv);
605 free(hs);
606 break;
607
608 case ND_HOSTSERVLIST :
609 hss = (struct nd_hostservlist *)ptr;
610 for (hs = hss->h_hostservs, i = 0; i < hss->h_cnt; i++, hs++) {
611 if (hs->h_host)
612 free(hs->h_host);
613 if (hs->h_serv)
614 free(hs->h_serv);
615 }
616 free(hss->h_hostservs);
617 free(hss);
618 break;
619
620 default :
621 _nderror = ND_UKNWN;
622 break;
623 }
624 }
625
626 /*
627 * load_xlate is a routine that will attempt to dynamically link in the
628 * file specified by the network configuration structure.
629 */
630 static struct translator *
load_xlate(char * name)631 load_xlate(char *name)
632 {
633 struct translator *t;
634 static struct xlate_list {
635 char *library;
636 struct xlate_list *next;
637 } *xlistp = NULL;
638 struct xlate_list *xlp, **xlastp;
639 static mutex_t xlist_lock = DEFAULTMUTEX;
640
641 (void) mutex_lock(&xlist_lock);
642 /*
643 * We maintain a list of libraries we have loaded. Loading a library
644 * twice is double-plus ungood!
645 */
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);
652 return (0);
653 }
654 }
655 }
656 t = malloc(sizeof (struct translator));
657 if (!t) {
658 _nderror = ND_NOMEM;
659 (void) mutex_unlock(&xlist_lock);
660 return (0);
661 }
662 t->tr_name = strdup(name);
663 if (!t->tr_name) {
664 _nderror = ND_NOMEM;
665 free(t);
666 (void) mutex_unlock(&xlist_lock);
667 return (NULL);
668 }
669
670 t->tr_fd = dlopen(name, RTLD_LAZY);
671 if (t->tr_fd == NULL) {
672 _nderror = ND_OPEN;
673 goto error;
674 }
675
676 /* Resolve the getbyname symbol */
677 t->gbn = (struct nd_addrlist *(*)())dlsym(t->tr_fd,
678 "_netdir_getbyname");
679 if (!(t->gbn)) {
680 _nderror = ND_NOSYM;
681 goto error;
682 }
683
684 /* resolve the getbyaddr symbol */
685 t->gba = (struct nd_hostservlist *(*)())dlsym(t->tr_fd,
686 "_netdir_getbyaddr");
687 if (!(t->gba)) {
688 _nderror = ND_NOSYM;
689 goto error;
690 }
691
692 /* resolve the taddr2uaddr symbol */
693 t->t2u = (char *(*)())dlsym(t->tr_fd, "_taddr2uaddr");
694 if (!(t->t2u)) {
695 _nderror = ND_NOSYM;
696 goto error;
697 }
698
699 /* resolve the uaddr2taddr symbol */
700 t->u2t = (struct netbuf *(*)())dlsym(t->tr_fd, "_uaddr2taddr");
701 if (!(t->u2t)) {
702 _nderror = ND_NOSYM;
703 goto error;
704 }
705
706 /* resolve the netdir_options symbol */
707 t->opt = (int (*)())dlsym(t->tr_fd, "_netdir_options");
708 if (!(t->opt)) {
709 _nderror = ND_NOSYM;
710 goto error;
711 }
712 /*
713 * Add this library to the list of loaded libraries.
714 */
715 *xlastp = malloc(sizeof (struct xlate_list));
716 if (*xlastp == NULL) {
717 _nderror = ND_NOMEM;
718 goto error;
719 }
720 (*xlastp)->library = strdup(name);
721 if ((*xlastp)->library == NULL) {
722 _nderror = ND_NOMEM;
723 free(*xlastp);
724 goto error;
725 }
726 (*xlastp)->next = NULL;
727 (void) mutex_unlock(&xlist_lock);
728 return (t);
729 error:
730 if (t->tr_fd != NULL)
731 (void) dlclose(t->tr_fd);
732 free(t->tr_name);
733 free(t);
734 (void) mutex_unlock(&xlist_lock);
735 return (NULL);
736 }
737
738
739 #define NDERR_BUFSZ 512
740
741 /*
742 * This is a routine that returns a string related to the current
743 * error in _nderror.
744 */
745 char *
netdir_sperror(void)746 netdir_sperror(void)
747 {
748 static pthread_key_t nderrbuf_key = PTHREAD_ONCE_KEY_NP;
749 static char buf_main[NDERR_BUFSZ];
750 char *str;
751 char *dlerrstr;
752
753 str = thr_main()?
754 buf_main :
755 thr_get_storage(&nderrbuf_key, NDERR_BUFSZ, free);
756 if (str == NULL)
757 return (NULL);
758 dlerrstr = dlerror();
759 switch (_nderror) {
760 case ND_NOMEM :
761 (void) snprintf(str, NDERR_BUFSZ,
762 dgettext(__nsl_dom, "n2a: memory allocation failed"));
763 break;
764 case ND_OK :
765 (void) snprintf(str, NDERR_BUFSZ,
766 dgettext(__nsl_dom, "n2a: successful completion"));
767 break;
768 case ND_NOHOST :
769 (void) snprintf(str, NDERR_BUFSZ,
770 dgettext(__nsl_dom, "n2a: hostname not found"));
771 break;
772 case ND_NOSERV :
773 (void) snprintf(str, NDERR_BUFSZ,
774 dgettext(__nsl_dom, "n2a: service name not found"));
775 break;
776 case ND_NOSYM :
777 (void) snprintf(str, NDERR_BUFSZ, "%s : %s ",
778 dgettext(__nsl_dom,
779 "n2a: symbol missing in shared object"),
780 dlerrstr ? dlerrstr : " ");
781 break;
782 case ND_OPEN :
783 (void) snprintf(str, NDERR_BUFSZ, "%s - %s ",
784 dgettext(__nsl_dom, "n2a: couldn't open shared object"),
785 dlerrstr ? dlerrstr : " ");
786 break;
787 case ND_ACCESS :
788 (void) snprintf(str, NDERR_BUFSZ,
789 dgettext(__nsl_dom,
790 "n2a: access denied for shared object"));
791 break;
792 case ND_UKNWN :
793 (void) snprintf(str, NDERR_BUFSZ,
794 dgettext(__nsl_dom,
795 "n2a: attempt to free unknown object"));
796 break;
797 case ND_BADARG :
798 (void) snprintf(str, NDERR_BUFSZ,
799 dgettext(__nsl_dom,
800 "n2a: bad arguments passed to routine"));
801 break;
802 case ND_NOCTRL:
803 (void) snprintf(str, NDERR_BUFSZ,
804 dgettext(__nsl_dom, "n2a: unknown option passed"));
805 break;
806 case ND_FAILCTRL:
807 (void) snprintf(str, NDERR_BUFSZ,
808 dgettext(__nsl_dom, "n2a: control operation failed"));
809 break;
810 case ND_SYSTEM:
811 (void) snprintf(str, NDERR_BUFSZ, "%s: %s",
812 dgettext(__nsl_dom, "n2a: system error"),
813 strerror(errno));
814 break;
815 default :
816 (void) snprintf(str, NDERR_BUFSZ, "%s#%d",
817 dgettext(__nsl_dom, "n2a: unknown error "), _nderror);
818 break;
819 }
820 return (str);
821 }
822
823 /*
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
826 * colon first.
827 */
828 void
netdir_perror(char * s)829 netdir_perror(char *s)
830 {
831 char *err;
832
833 err = netdir_sperror();
834 (void) fprintf(stderr, "%s: %s\n", s, err ? err : "n2a: error");
835 }
836