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 * 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 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 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 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 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 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 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 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 * 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 * 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 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 * 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 * 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 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