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