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 /*
36 * netdir.c
37 *
38 * This is the library routines that do the name to address
39 * translation.
40 */
41
42 #include "mt.h"
43 #include "../rpc/rpc_mt.h" /* for MT declarations only */
44 #include <stdio.h>
45 #include <sys/types.h>
46 #include <errno.h>
47 #include <tiuser.h>
48 #include <netdir.h>
49 #include <netconfig.h>
50 #include <string.h>
51 #include <sys/file.h>
52 #include <dlfcn.h>
53 #include <stdlib.h>
54 #include <malloc.h>
55 #include <syslog.h>
56 #include <nss_netdir.h>
57 #include <netinet/in.h>
58 #include <netdb.h>
59
60 /* messaging stuff. */
61
62 extern const char __nsl_dom[];
63 extern char *dgettext(const char *, const char *);
64
65 struct translator {
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;
74 };
75
76 /*
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.
80 */
81 static struct translator *xlate_list = NULL;
82 static mutex_t xlate_lock = DEFAULTMUTEX;
83
84 static struct translator *load_xlate(char *);
85
86 /*
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
92 * interface.
93 */
94
95 #undef _nderror
96
97 int _nderror;
98
99 int *
__nderror(void)100 __nderror(void)
101 {
102 static pthread_key_t nderror_key = PTHREAD_ONCE_KEY_NP;
103 int *ret;
104
105 if (thr_main())
106 return (&_nderror);
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);
110 }
111
112 #define _nderror (*(__nderror()))
113
114 /*
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.
123 */
124 void
add_to_xlate_list(struct translator * translate)125 add_to_xlate_list(struct translator *translate)
126 {
127 struct translator *t;
128
129 for (t = xlate_list; t; t = t->next) {
130 if (strcmp(translate->tr_name, t->tr_name) == 0) {
131 return;
132 }
133 }
134 translate->next = xlate_list;
135 xlate_list = translate;
136 }
137
138 /*
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).
142 *
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.
150 *
151 * After all, any problem can be solved by one more layer of abstraction..
152 *
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
156 */
157 int
netdir_getbyname(struct netconfig * tp,struct nd_hostserv * serv,struct nd_addrlist ** addrs)158 netdir_getbyname(struct netconfig *tp, struct nd_hostserv *serv,
159 struct nd_addrlist **addrs)
160 {
161 if (tp == 0) {
162 _nderror = ND_BADARG;
163 return (_nderror);
164 }
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;
169
170 nssin.op_t = NETDIR_BY;
171 nssin.arg.nd_hs = serv;
172 /*
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.
177 */
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));
182 }
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;
187
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));
195 }
196 return (__classic_netdir_getbyname(tp, serv, addrs));
197 }
198
199 /*
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).
203 *
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.
207 */
208 int
__classic_netdir_getbyname(struct netconfig * tp,struct nd_hostserv * serv,struct nd_addrlist ** addrs)209 __classic_netdir_getbyname(struct netconfig *tp, struct nd_hostserv *serv,
210 struct nd_addrlist **addrs)
211 {
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 */
216
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);
223 if (nn) {
224 *addrs = nn;
225 return (0);
226 }
227 if (_nderror < 0) {
228 return (_nderror);
229 }
230 break;
231 }
232 }
233 /* If we didn't find it try loading it */
234 if (!t) {
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);
241 if (nn) {
242 *addrs = nn;
243 return (0);
244 }
245 if (_nderror < 0) {
246 return (_nderror);
247 }
248 } else {
249 if (_nderror == ND_SYSTEM) { /* retry cache */
250 _nderror = ND_OK;
251 i--;
252 continue;
253 }
254 }
255 }
256 }
257 return (_nderror); /* No one works */
258 }
259
260 /*
261 * This routine is similar to the one above except that it tries to resolve
262 * the name by the address passed.
263 */
264 int
netdir_getbyaddr(struct netconfig * tp,struct nd_hostservlist ** serv,struct netbuf * addr)265 netdir_getbyaddr(struct netconfig *tp, struct nd_hostservlist **serv,
266 struct netbuf *addr)
267 {
268 if (tp == 0) {
269 _nderror = ND_BADARG;
270 return (_nderror);
271 }
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;
276
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));
281 }
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;
286
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));
291 }
292 return (__classic_netdir_getbyaddr(tp, serv, addr));
293 }
294 /*
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.
297 */
298 int
__netdir_getbyaddr_nosrv(struct netconfig * tp,struct nd_hostservlist ** serv,struct netbuf * addr)299 __netdir_getbyaddr_nosrv(struct netconfig *tp, struct nd_hostservlist **serv,
300 struct netbuf *addr)
301 {
302 if (tp == 0) {
303 _nderror = ND_BADARG;
304 return (_nderror);
305 }
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;
310
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));
315 }
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;
320
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));
325 }
326 return (__classic_netdir_getbyaddr(tp, serv, addr));
327 }
328
329 /*
330 * This routine is the svr4_classic routine for resolving a netbuf struct
331 * into a bunch of host/service name pairs.
332 *
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.
336 */
337 int
__classic_netdir_getbyaddr(struct netconfig * tp,struct nd_hostservlist ** serv,struct netbuf * addr)338 __classic_netdir_getbyaddr(struct netconfig *tp, struct nd_hostservlist **serv,
339 struct netbuf *addr)
340 {
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 */
345
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);
352 if (hs) {
353 *serv = hs;
354 return (0);
355 }
356 if (_nderror < 0)
357 return (_nderror);
358 break;
359 }
360 }
361 /* If we didn't find it try loading it */
362 if (!t) {
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);
369 if (hs) {
370 *serv = hs;
371 return (0);
372 }
373 if (_nderror < 0)
374 return (_nderror);
375 } else {
376 if (_nderror == ND_SYSTEM) { /* retry cache */
377 _nderror = ND_OK;
378 i--;
379 continue;
380 }
381 }
382 }
383 }
384 return (_nderror); /* No one works */
385 }
386
387 /*
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.
392 *
393 * If it gets a netconfig structure for inet transports with nametoddr libs,
394 * it simply calls the inet-specific built in implementation.
395 */
396 int
netdir_options(struct netconfig * tp,int option,int fd,char * par)397 netdir_options(struct netconfig *tp, int option, int fd, char *par)
398 {
399 struct translator *t; /* pointer to translator list */
400 char *lr; /* routines to try */
401 int i; /* counts the routines */
402
403 if (tp == 0) {
404 _nderror = ND_BADARG;
405 return (_nderror);
406 }
407
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));
412 }
413
414
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));
420 }
421 /* If we didn't find it try loading it */
422 if (!t) {
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));
429 }
430 if (_nderror == ND_SYSTEM) { /* retry cache */
431 _nderror = ND_OK;
432 i--;
433 continue;
434 }
435 }
436 }
437 return (_nderror); /* No one works */
438 }
439
440 /*
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.
446 */
447 struct netbuf *
uaddr2taddr(struct netconfig * tp,char * addr)448 uaddr2taddr(struct netconfig *tp, char *addr)
449 {
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 */
454
455 if (tp == 0) {
456 _nderror = ND_BADARG;
457 return (0);
458 }
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));
463 }
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);
469 if (x)
470 return (x);
471 if (_nderror < 0)
472 return (0);
473 }
474 }
475 /* If we didn't find it try loading it */
476 if (!t) {
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);
483 if (x)
484 return (x);
485 if (_nderror < 0)
486 return (0);
487 } else {
488 if (_nderror == ND_SYSTEM) { /* retry cache */
489 _nderror = ND_OK;
490 i--;
491 continue;
492 }
493 }
494 }
495 }
496 return (0); /* No one works */
497 }
498
499 /*
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.
505 */
506 char *
taddr2uaddr(struct netconfig * tp,struct netbuf * addr)507 taddr2uaddr(struct netconfig *tp, struct netbuf *addr)
508 {
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 */
513
514 if (tp == 0) {
515 _nderror = ND_BADARG;
516 return (0);
517 }
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));
522 }
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);
528 if (x)
529 return (x);
530 if (_nderror < 0)
531 return (0);
532 }
533 }
534 /* If we didn't find it try loading it */
535 if (!t) {
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);
542 if (x)
543 return (x);
544 if (_nderror < 0)
545 return (0);
546 } else {
547 if (_nderror == ND_SYSTEM) { /* retry cache */
548 _nderror = ND_OK;
549 i--;
550 continue;
551 }
552 }
553 }
554 }
555 return (0); /* No one works */
556 }
557
558 /*
559 * This is the routine that frees the objects that these routines allocate.
560 */
561 void
netdir_free(void * ptr,int type)562 netdir_free(void *ptr, int type)
563 {
564 struct netbuf *na;
565 struct nd_addrlist *nas;
566 struct nd_hostserv *hs;
567 struct nd_hostservlist *hss;
568 int i;
569
570 if (ptr == NULL)
571 return;
572 switch (type) {
573 case ND_ADDR :
574 na = (struct netbuf *)ptr;
575 if (na->buf)
576 free(na->buf);
577 free(na);
578 break;
579
580 case ND_ADDRLIST :
581 nas = (struct nd_addrlist *)ptr;
582 /*
583 * XXX: We do NOT try to free all individual netbuf->buf
584 * pointers. Free only the first one since they are allocated
585 * using one calloc in
586 * libnsl/nss/netdir_inet.c:order_haddrlist().
587 * This potentially causes memory leaks if a nametoaddr
588 * implementation -- from a third party -- has a different
589 * allocation scheme.
590 */
591 if (nas->n_addrs->buf)
592 free(nas->n_addrs->buf);
593 free(nas->n_addrs);
594 free(nas);
595 break;
596
597 case ND_HOSTSERV :
598 hs = (struct nd_hostserv *)ptr;
599 if (hs->h_host)
600 free(hs->h_host);
601 if (hs->h_serv)
602 free(hs->h_serv);
603 free(hs);
604 break;
605
606 case ND_HOSTSERVLIST :
607 hss = (struct nd_hostservlist *)ptr;
608 for (hs = hss->h_hostservs, i = 0; i < hss->h_cnt; i++, hs++) {
609 if (hs->h_host)
610 free(hs->h_host);
611 if (hs->h_serv)
612 free(hs->h_serv);
613 }
614 free(hss->h_hostservs);
615 free(hss);
616 break;
617
618 default :
619 _nderror = ND_UKNWN;
620 break;
621 }
622 }
623
624 /*
625 * load_xlate is a routine that will attempt to dynamically link in the
626 * file specified by the network configuration structure.
627 */
628 static struct translator *
load_xlate(char * name)629 load_xlate(char *name)
630 {
631 struct translator *t;
632 static struct xlate_list {
633 char *library;
634 struct xlate_list *next;
635 } *xlistp = NULL;
636 struct xlate_list *xlp, **xlastp;
637 static mutex_t xlist_lock = DEFAULTMUTEX;
638
639 (void) mutex_lock(&xlist_lock);
640 /*
641 * We maintain a list of libraries we have loaded. Loading a library
642 * twice is double-plus ungood!
643 */
644 for (xlp = xlistp, xlastp = &xlistp; xlp != NULL;
645 xlastp = &xlp->next, xlp = xlp->next) {
646 if (xlp->library != NULL) {
647 if (strcmp(xlp->library, name) == 0) {
648 _nderror = ND_SYSTEM; /* seen this lib */
649 (void) mutex_unlock(&xlist_lock);
650 return (0);
651 }
652 }
653 }
654 t = malloc(sizeof (struct translator));
655 if (!t) {
656 _nderror = ND_NOMEM;
657 (void) mutex_unlock(&xlist_lock);
658 return (0);
659 }
660 t->tr_name = strdup(name);
661 if (!t->tr_name) {
662 _nderror = ND_NOMEM;
663 free(t);
664 (void) mutex_unlock(&xlist_lock);
665 return (NULL);
666 }
667
668 t->tr_fd = dlopen(name, RTLD_LAZY);
669 if (t->tr_fd == NULL) {
670 _nderror = ND_OPEN;
671 goto error;
672 }
673
674 /* Resolve the getbyname symbol */
675 t->gbn = (struct nd_addrlist *(*)())dlsym(t->tr_fd,
676 "_netdir_getbyname");
677 if (!(t->gbn)) {
678 _nderror = ND_NOSYM;
679 goto error;
680 }
681
682 /* resolve the getbyaddr symbol */
683 t->gba = (struct nd_hostservlist *(*)())dlsym(t->tr_fd,
684 "_netdir_getbyaddr");
685 if (!(t->gba)) {
686 _nderror = ND_NOSYM;
687 goto error;
688 }
689
690 /* resolve the taddr2uaddr symbol */
691 t->t2u = (char *(*)())dlsym(t->tr_fd, "_taddr2uaddr");
692 if (!(t->t2u)) {
693 _nderror = ND_NOSYM;
694 goto error;
695 }
696
697 /* resolve the uaddr2taddr symbol */
698 t->u2t = (struct netbuf *(*)())dlsym(t->tr_fd, "_uaddr2taddr");
699 if (!(t->u2t)) {
700 _nderror = ND_NOSYM;
701 goto error;
702 }
703
704 /* resolve the netdir_options symbol */
705 t->opt = (int (*)())dlsym(t->tr_fd, "_netdir_options");
706 if (!(t->opt)) {
707 _nderror = ND_NOSYM;
708 goto error;
709 }
710 /*
711 * Add this library to the list of loaded libraries.
712 */
713 *xlastp = malloc(sizeof (struct xlate_list));
714 if (*xlastp == NULL) {
715 _nderror = ND_NOMEM;
716 goto error;
717 }
718 (*xlastp)->library = strdup(name);
719 if ((*xlastp)->library == NULL) {
720 _nderror = ND_NOMEM;
721 free(*xlastp);
722 goto error;
723 }
724 (*xlastp)->next = NULL;
725 (void) mutex_unlock(&xlist_lock);
726 return (t);
727 error:
728 if (t->tr_fd != NULL)
729 (void) dlclose(t->tr_fd);
730 free(t->tr_name);
731 free(t);
732 (void) mutex_unlock(&xlist_lock);
733 return (NULL);
734 }
735
736
737 #define NDERR_BUFSZ 512
738
739 /*
740 * This is a routine that returns a string related to the current
741 * error in _nderror.
742 */
743 char *
netdir_sperror(void)744 netdir_sperror(void)
745 {
746 static pthread_key_t nderrbuf_key = PTHREAD_ONCE_KEY_NP;
747 static char buf_main[NDERR_BUFSZ];
748 char *str;
749 char *dlerrstr;
750
751 str = thr_main()?
752 buf_main :
753 thr_get_storage(&nderrbuf_key, NDERR_BUFSZ, free);
754 if (str == NULL)
755 return (NULL);
756 dlerrstr = dlerror();
757 switch (_nderror) {
758 case ND_NOMEM :
759 (void) snprintf(str, NDERR_BUFSZ,
760 dgettext(__nsl_dom, "n2a: memory allocation failed"));
761 break;
762 case ND_OK :
763 (void) snprintf(str, NDERR_BUFSZ,
764 dgettext(__nsl_dom, "n2a: successful completion"));
765 break;
766 case ND_NOHOST :
767 (void) snprintf(str, NDERR_BUFSZ,
768 dgettext(__nsl_dom, "n2a: hostname not found"));
769 break;
770 case ND_NOSERV :
771 (void) snprintf(str, NDERR_BUFSZ,
772 dgettext(__nsl_dom, "n2a: service name not found"));
773 break;
774 case ND_NOSYM :
775 (void) snprintf(str, NDERR_BUFSZ, "%s : %s ",
776 dgettext(__nsl_dom,
777 "n2a: symbol missing in shared object"),
778 dlerrstr ? dlerrstr : " ");
779 break;
780 case ND_OPEN :
781 (void) snprintf(str, NDERR_BUFSZ, "%s - %s ",
782 dgettext(__nsl_dom, "n2a: couldn't open shared object"),
783 dlerrstr ? dlerrstr : " ");
784 break;
785 case ND_ACCESS :
786 (void) snprintf(str, NDERR_BUFSZ,
787 dgettext(__nsl_dom,
788 "n2a: access denied for shared object"));
789 break;
790 case ND_UKNWN :
791 (void) snprintf(str, NDERR_BUFSZ,
792 dgettext(__nsl_dom,
793 "n2a: attempt to free unknown object"));
794 break;
795 case ND_BADARG :
796 (void) snprintf(str, NDERR_BUFSZ,
797 dgettext(__nsl_dom,
798 "n2a: bad arguments passed to routine"));
799 break;
800 case ND_NOCTRL:
801 (void) snprintf(str, NDERR_BUFSZ,
802 dgettext(__nsl_dom, "n2a: unknown option passed"));
803 break;
804 case ND_FAILCTRL:
805 (void) snprintf(str, NDERR_BUFSZ,
806 dgettext(__nsl_dom, "n2a: control operation failed"));
807 break;
808 case ND_SYSTEM:
809 (void) snprintf(str, NDERR_BUFSZ, "%s: %s",
810 dgettext(__nsl_dom, "n2a: system error"),
811 strerror(errno));
812 break;
813 default :
814 (void) snprintf(str, NDERR_BUFSZ, "%s#%d",
815 dgettext(__nsl_dom, "n2a: unknown error "), _nderror);
816 break;
817 }
818 return (str);
819 }
820
821 /*
822 * This is a routine that prints out strings related to the current
823 * error in _nderror. Like perror() it takes a string to print with a
824 * colon first.
825 */
826 void
netdir_perror(char * s)827 netdir_perror(char *s)
828 {
829 char *err;
830
831 err = netdir_sperror();
832 (void) fprintf(stderr, "%s: %s\n", s, err ? err : "n2a: error");
833 }
834