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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 29 /* All Rights Reserved */ 30 31 /* 32 * Portions of this source code were derived from Berkeley 4.3 BSD 33 * under license from the Regents of the University of California. 34 */ 35 36 #pragma ident "%Z%%M% %I% %E% SMI" 37 38 /* 39 * netdir.c 40 * 41 * This is the library routines that do the name to address 42 * translation. 43 */ 44 45 #include "mt.h" 46 #include "../rpc/rpc_mt.h" /* for MT declarations only */ 47 #include <stdio.h> 48 #include <sys/types.h> 49 #include <errno.h> 50 #include <tiuser.h> 51 #include <netdir.h> 52 #include <netconfig.h> 53 #include <string.h> 54 #include <sys/file.h> 55 #include <dlfcn.h> 56 #include <stdlib.h> 57 #include <malloc.h> 58 #include <syslog.h> 59 #include <nss_netdir.h> 60 #include <netinet/in.h> 61 #include <netdb.h> 62 63 /* messaging stuff. */ 64 65 extern const char __nsl_dom[]; 66 extern char *dgettext(const char *, const char *); 67 68 struct translator { 69 struct nd_addrlist *(*gbn)(); /* _netdir_getbyname */ 70 struct nd_hostservlist *(*gba)(); /* _netdir_getbyaddr */ 71 int (*opt)(); /* _netdir_options */ 72 char *(*t2u)(); /* _taddr2uaddr */ 73 struct netbuf *(*u2t)(); /* _uaddr2taddr */ 74 void *tr_fd; /* dyn library handle */ 75 char *tr_name; /* Full path */ 76 struct translator *next; 77 }; 78 79 /* 80 * xlate_lock protects xlate_list during updates only. The xlate_list linked 81 * list is pre-pended when new entries are added, so threads that are already 82 * using the list will continue correctly to the end of the list. 83 */ 84 static struct translator *xlate_list = NULL; 85 static mutex_t xlate_lock = DEFAULTMUTEX; 86 87 static struct translator *load_xlate(char *); 88 89 /* 90 * This is the common data (global data) that is exported 91 * by public interfaces. It has been moved here from nd_comdata.c 92 * which no longer exists. This fixes the problem for applications 93 * that do not link directly with -lnsl but dlopen a shared object 94 * that has a NEEDED dependency on -lnsl and uses the netdir 95 * interface. 96 */ 97 98 #undef _nderror 99 100 int _nderror; 101 102 int * 103 __nderror(void) 104 { 105 static pthread_key_t nderror_key = 0; 106 int *ret; 107 108 if (thr_main()) 109 return (&_nderror); 110 ret = thr_get_storage(&nderror_key, sizeof (int), free); 111 /* if thr_get_storage fails we return the address of _nderror */ 112 return (ret ? ret : &_nderror); 113 } 114 115 #define _nderror (*(__nderror())) 116 117 /* 118 * Adds a translator library to the xlate_list, but first check to see if 119 * it's already on the list. Must be called while holding xlate_lock. 120 * We have to be careful for the case of the same library being loaded 121 * with different names (e.g., straddr.so and /usr/lib/straddr.so). 122 * We check for this case by looking at the gbn and name fields. 123 * If the gbn address is the same, but the names are different, then we 124 * have accidentally reloaded the library. We dlclose the new version, 125 * and then update 'translate' with the old versions of the symbols. 126 */ 127 void 128 add_to_xlate_list(struct translator *translate) 129 { 130 struct translator *t; 131 132 for (t = xlate_list; t; t = t->next) { 133 if (strcmp(translate->tr_name, t->tr_name) == 0) { 134 return; 135 } 136 } 137 translate->next = xlate_list; 138 xlate_list = translate; 139 } 140 141 /* 142 * This routine is the main routine that resolves host/service/xprt triples 143 * into a bunch of netbufs that should connect you to that particular 144 * service. RPC uses it to contact the binder service (rpcbind). 145 * 146 * In the interest of consistency with the gethost/servbyYY() routines, 147 * this routine calls a common interface _get_hostserv_inetnetdir_byname 148 * if it's called with a netconfig with "inet" type transports and 149 * an empty list of nametoaddr libs (i.e. a "-" in /etc/netconfig), 150 * which indicates the use of the switch. For non-inet transports or 151 * inet transports with nametoaddr libs specified, it simply calls 152 * the SVr4-classic netdir_getbyname, which loops through the libs. 153 * 154 * After all, any problem can be solved by one more layer of abstraction.. 155 * 156 * This routine when called with a netconfig with "inet6" type of transports 157 * returns pure IPv6 addresses only and if no IPv6 address is found it 158 * returns none - Bug Id. 4276329 159 */ 160 int 161 netdir_getbyname(struct netconfig *tp, struct nd_hostserv *serv, 162 struct nd_addrlist **addrs) 163 { 164 if (tp == 0) { 165 _nderror = ND_BADARG; 166 return (_nderror); 167 } 168 if ((strcmp(tp->nc_protofmly, NC_INET) == 0) && 169 (tp->nc_nlookups == 0)) { 170 struct nss_netdirbyname_in nssin; 171 union nss_netdirbyname_out nssout; 172 173 nssin.op_t = NETDIR_BY; 174 nssin.arg.nd_hs = serv; 175 /* 176 * In code path of case NETDIR_BY, 177 * it also calls DOOR_GETIPNODEBYNAME_R. 178 * So af_family and flags are set to 179 * get V4 addresses only. 180 */ 181 nssin.arg.nss.host6.af_family = AF_INET; 182 nssin.arg.nss.host6.flags = 0; 183 nssout.nd_alist = addrs; 184 return (_get_hostserv_inetnetdir_byname(tp, &nssin, &nssout)); 185 } 186 if ((strcmp(tp->nc_protofmly, NC_INET6) == 0) && 187 (tp->nc_nlookups == 0)) { 188 struct nss_netdirbyname_in nssin; 189 union nss_netdirbyname_out nssout; 190 191 nssin.op_t = NETDIR_BY6; 192 nssin.arg.nd_hs = serv; 193 /* get both V4 & V6 addresses */ 194 nssin.arg.nss.host6.af_family = AF_INET6; 195 nssin.arg.nss.host6.flags = (AI_ALL | AI_V4MAPPED); 196 nssout.nd_alist = addrs; 197 return (_get_hostserv_inetnetdir_byname(tp, &nssin, &nssout)); 198 } 199 return (__classic_netdir_getbyname(tp, serv, addrs)); 200 } 201 202 /* 203 * This routine is the svr4_classic routine for resolving host/service/xprt 204 * triples into a bunch of netbufs that should connect you to that particular 205 * service. RPC uses it to contact the binder service (rpcbind). 206 * 207 * It's either called by the real netdir_getbyname() interface above 208 * or by gethost/servbyname when nametoaddr libs are specified in 209 * /etc/netconfig with an intent of bypassing the name service switch. 210 */ 211 int 212 __classic_netdir_getbyname(struct netconfig *tp, struct nd_hostserv *serv, 213 struct nd_addrlist **addrs) 214 { 215 struct translator *t; /* pointer to translator list */ 216 struct nd_addrlist *nn; /* the results */ 217 char *lr; /* routines to try */ 218 int i; /* counts the routines */ 219 220 _nderror = ND_SYSTEM; 221 for (i = 0; i < tp->nc_nlookups; i++) { 222 lr = *((tp->nc_lookups) + i); 223 for (t = xlate_list; t; t = t->next) { 224 if (strcmp(lr, t->tr_name) == 0) { 225 nn = (*(t->gbn))(tp, serv); 226 if (nn) { 227 *addrs = nn; 228 return (0); 229 } 230 if (_nderror < 0) { 231 return (_nderror); 232 } 233 break; 234 } 235 } 236 /* If we didn't find it try loading it */ 237 if (!t) { 238 if ((t = load_xlate(lr)) != NULL) { 239 /* add it to the list */ 240 (void) mutex_lock(&xlate_lock); 241 add_to_xlate_list(t); 242 (void) mutex_unlock(&xlate_lock); 243 nn = (*(t->gbn))(tp, serv); 244 if (nn) { 245 *addrs = nn; 246 return (0); 247 } 248 if (_nderror < 0) { 249 return (_nderror); 250 } 251 } else { 252 if (_nderror == ND_SYSTEM) { /* retry cache */ 253 _nderror = ND_OK; 254 i--; 255 continue; 256 } 257 } 258 } 259 } 260 return (_nderror); /* No one works */ 261 } 262 263 /* 264 * This routine is similar to the one above except that it tries to resolve 265 * the name by the address passed. 266 */ 267 int 268 netdir_getbyaddr(struct netconfig *tp, struct nd_hostservlist **serv, 269 struct netbuf *addr) 270 { 271 if (tp == 0) { 272 _nderror = ND_BADARG; 273 return (_nderror); 274 } 275 if ((strcmp(tp->nc_protofmly, NC_INET) == 0) && 276 (tp->nc_nlookups == 0)) { 277 struct nss_netdirbyaddr_in nssin; 278 union nss_netdirbyaddr_out nssout; 279 280 nssin.op_t = NETDIR_BY; 281 nssin.arg.nd_nbuf = addr; 282 nssout.nd_hslist = serv; 283 return (_get_hostserv_inetnetdir_byaddr(tp, &nssin, &nssout)); 284 } 285 if ((strcmp(tp->nc_protofmly, NC_INET6) == 0) && 286 (tp->nc_nlookups == 0)) { 287 struct nss_netdirbyaddr_in nssin; 288 union nss_netdirbyaddr_out nssout; 289 290 nssin.op_t = NETDIR_BY6; 291 nssin.arg.nd_nbuf = addr; 292 nssout.nd_hslist = serv; 293 return (_get_hostserv_inetnetdir_byaddr(tp, &nssin, &nssout)); 294 } 295 return (__classic_netdir_getbyaddr(tp, serv, addr)); 296 } 297 /* 298 * This routine is similar to the one above except that it instructs the 299 * _get_hostserv_inetnetdir_byaddr not to do a service lookup. 300 */ 301 int 302 __netdir_getbyaddr_nosrv(struct netconfig *tp, struct nd_hostservlist **serv, 303 struct netbuf *addr) 304 { 305 if (tp == 0) { 306 _nderror = ND_BADARG; 307 return (_nderror); 308 } 309 if ((strcmp(tp->nc_protofmly, NC_INET) == 0) && 310 (tp->nc_nlookups == 0)) { 311 struct nss_netdirbyaddr_in nssin; 312 union nss_netdirbyaddr_out nssout; 313 314 nssin.op_t = NETDIR_BY_NOSRV; 315 nssin.arg.nd_nbuf = addr; 316 nssout.nd_hslist = serv; 317 return (_get_hostserv_inetnetdir_byaddr(tp, &nssin, &nssout)); 318 } 319 if ((strcmp(tp->nc_protofmly, NC_INET6) == 0) && 320 (tp->nc_nlookups == 0)) { 321 struct nss_netdirbyaddr_in nssin; 322 union nss_netdirbyaddr_out nssout; 323 324 nssin.op_t = NETDIR_BY_NOSRV6; 325 nssin.arg.nd_nbuf = addr; 326 nssout.nd_hslist = serv; 327 return (_get_hostserv_inetnetdir_byaddr(tp, &nssin, &nssout)); 328 } 329 return (__classic_netdir_getbyaddr(tp, serv, addr)); 330 } 331 332 /* 333 * This routine is the svr4_classic routine for resolving a netbuf struct 334 * into a bunch of host/service name pairs. 335 * 336 * It's either called by the real netdir_getbyaddr() interface above 337 * or by gethost/servbyaddr when nametoaddr libs are specified in 338 * /etc/netconfig with an intent of bypassing the name service switch. 339 */ 340 int 341 __classic_netdir_getbyaddr(struct netconfig *tp, struct nd_hostservlist **serv, 342 struct netbuf *addr) 343 { 344 struct translator *t; /* pointer to translator list */ 345 struct nd_hostservlist *hs; /* the results */ 346 char *lr; /* routines to try */ 347 int i; /* counts the routines */ 348 349 _nderror = ND_SYSTEM; 350 for (i = 0; i < tp->nc_nlookups; i++) { 351 lr = *((tp->nc_lookups) + i); 352 for (t = xlate_list; t; t = t->next) { 353 if (strcmp(lr, t->tr_name) == 0) { 354 hs = (*(t->gba))(tp, addr); 355 if (hs) { 356 *serv = hs; 357 return (0); 358 } 359 if (_nderror < 0) 360 return (_nderror); 361 break; 362 } 363 } 364 /* If we didn't find it try loading it */ 365 if (!t) { 366 if ((t = load_xlate(lr)) != NULL) { 367 /* add it to the list */ 368 (void) mutex_lock(&xlate_lock); 369 add_to_xlate_list(t); 370 (void) mutex_unlock(&xlate_lock); 371 hs = (*(t->gba))(tp, addr); 372 if (hs) { 373 *serv = hs; 374 return (0); 375 } 376 if (_nderror < 0) 377 return (_nderror); 378 } else { 379 if (_nderror == ND_SYSTEM) { /* retry cache */ 380 _nderror = ND_OK; 381 i--; 382 continue; 383 } 384 } 385 } 386 } 387 return (_nderror); /* No one works */ 388 } 389 390 /* 391 * This is the library routine to do transport specific stuff. 392 * The code is same as the other similar routines except that it does 393 * not bother to try whole bunch of routines since if the first 394 * libray cannot resolve the option, then no one can. 395 * 396 * If it gets a netconfig structure for inet transports with nametoddr libs, 397 * it simply calls the inet-specific built in implementation. 398 */ 399 int 400 netdir_options(struct netconfig *tp, int option, int fd, char *par) 401 { 402 struct translator *t; /* pointer to translator list */ 403 char *lr; /* routines to try */ 404 int i; /* counts the routines */ 405 406 if (tp == 0) { 407 _nderror = ND_BADARG; 408 return (_nderror); 409 } 410 411 if ((strcmp(tp->nc_protofmly, NC_INET) == 0 || 412 strcmp(tp->nc_protofmly, NC_INET6) == 0) && 413 (tp->nc_nlookups == 0)) { 414 return (__inet_netdir_options(tp, option, fd, par)); 415 } 416 417 418 for (i = 0; i < tp->nc_nlookups; i++) { 419 lr = *((tp->nc_lookups) + i); 420 for (t = xlate_list; t; t = t->next) { 421 if (strcmp(lr, t->tr_name) == 0) 422 return ((*(t->opt))(tp, option, fd, par)); 423 } 424 /* If we didn't find it try loading it */ 425 if (!t) { 426 if ((t = load_xlate(lr)) != NULL) { 427 /* add it to the list */ 428 (void) mutex_lock(&xlate_lock); 429 add_to_xlate_list(t); 430 (void) mutex_unlock(&xlate_lock); 431 return ((*(t->opt))(tp, option, fd, par)); 432 } 433 if (_nderror == ND_SYSTEM) { /* retry cache */ 434 _nderror = ND_OK; 435 i--; 436 continue; 437 } 438 } 439 } 440 return (_nderror); /* No one works */ 441 } 442 443 /* 444 * This is the library routine for translating universal addresses to 445 * transport specific addresses. Again it uses the same code as above 446 * to search for the appropriate translation routine. Only it doesn't 447 * bother trying a whole bunch of routines since either the transport 448 * can translate it or it can't. 449 */ 450 struct netbuf * 451 uaddr2taddr(struct netconfig *tp, char *addr) 452 { 453 struct translator *t; /* pointer to translator list */ 454 struct netbuf *x; /* the answer we want */ 455 char *lr; /* routines to try */ 456 int i; /* counts the routines */ 457 458 if (tp == 0) { 459 _nderror = ND_BADARG; 460 return (0); 461 } 462 if ((strcmp(tp->nc_protofmly, NC_INET) == 0 || 463 strcmp(tp->nc_protofmly, NC_INET6) == 0) && 464 (tp->nc_nlookups == 0)) { 465 return (__inet_uaddr2taddr(tp, addr)); 466 } 467 for (i = 0; i < tp->nc_nlookups; i++) { 468 lr = *((tp->nc_lookups) + i); 469 for (t = xlate_list; t; t = t->next) { 470 if (strcmp(lr, t->tr_name) == 0) { 471 x = (*(t->u2t))(tp, addr); 472 if (x) 473 return (x); 474 if (_nderror < 0) 475 return (0); 476 } 477 } 478 /* If we didn't find it try loading it */ 479 if (!t) { 480 if ((t = load_xlate(lr)) != NULL) { 481 /* add it to the list */ 482 (void) mutex_lock(&xlate_lock); 483 add_to_xlate_list(t); 484 (void) mutex_unlock(&xlate_lock); 485 x = (*(t->u2t))(tp, addr); 486 if (x) 487 return (x); 488 if (_nderror < 0) 489 return (0); 490 } else { 491 if (_nderror == ND_SYSTEM) { /* retry cache */ 492 _nderror = ND_OK; 493 i--; 494 continue; 495 } 496 } 497 } 498 } 499 return (0); /* No one works */ 500 } 501 502 /* 503 * This is the library routine for translating transport specific 504 * addresses to universal addresses. Again it uses the same code as above 505 * to search for the appropriate translation routine. Only it doesn't 506 * bother trying a whole bunch of routines since either the transport 507 * can translate it or it can't. 508 */ 509 char * 510 taddr2uaddr(struct netconfig *tp, struct netbuf *addr) 511 { 512 struct translator *t; /* pointer to translator list */ 513 char *lr; /* routines to try */ 514 char *x; /* the answer */ 515 int i; /* counts the routines */ 516 517 if (tp == 0) { 518 _nderror = ND_BADARG; 519 return (0); 520 } 521 if ((strcmp(tp->nc_protofmly, NC_INET) == 0 || 522 strcmp(tp->nc_protofmly, NC_INET6) == 0) && 523 (tp->nc_nlookups == 0)) { 524 return (__inet_taddr2uaddr(tp, addr)); 525 } 526 for (i = 0; i < tp->nc_nlookups; i++) { 527 lr = *((tp->nc_lookups) + i); 528 for (t = xlate_list; t; t = t->next) { 529 if (strcmp(lr, t->tr_name) == 0) { 530 x = (*(t->t2u))(tp, addr); 531 if (x) 532 return (x); 533 if (_nderror < 0) 534 return (0); 535 } 536 } 537 /* If we didn't find it try loading it */ 538 if (!t) { 539 if ((t = load_xlate(lr)) != NULL) { 540 /* add it to the list */ 541 (void) mutex_lock(&xlate_lock); 542 add_to_xlate_list(t); 543 (void) mutex_unlock(&xlate_lock); 544 x = (*(t->t2u))(tp, addr); 545 if (x) 546 return (x); 547 if (_nderror < 0) 548 return (0); 549 } else { 550 if (_nderror == ND_SYSTEM) { /* retry cache */ 551 _nderror = ND_OK; 552 i--; 553 continue; 554 } 555 } 556 } 557 } 558 return (0); /* No one works */ 559 } 560 561 /* 562 * This is the routine that frees the objects that these routines allocate. 563 */ 564 void 565 netdir_free(void *ptr, int type) 566 { 567 struct netbuf *na; 568 struct nd_addrlist *nas; 569 struct nd_hostserv *hs; 570 struct nd_hostservlist *hss; 571 int i; 572 573 if (ptr == NULL) 574 return; 575 switch (type) { 576 case ND_ADDR : 577 na = (struct netbuf *)ptr; 578 if (na->buf) 579 free(na->buf); 580 free(na); 581 break; 582 583 case ND_ADDRLIST : 584 nas = (struct nd_addrlist *)ptr; 585 /* 586 * XXX: We do NOT try to free all individual netbuf->buf 587 * pointers. Free only the first one since they are allocated 588 * using one calloc in 589 * libnsl/nss/netdir_inet.c:order_haddrlist(). 590 * This potentially causes memory leaks if a nametoaddr 591 * implementation -- from a third party -- has a different 592 * allocation scheme. 593 */ 594 if (nas->n_addrs->buf) 595 free(nas->n_addrs->buf); 596 free(nas->n_addrs); 597 free(nas); 598 break; 599 600 case ND_HOSTSERV : 601 hs = (struct nd_hostserv *)ptr; 602 if (hs->h_host) 603 free(hs->h_host); 604 if (hs->h_serv) 605 free(hs->h_serv); 606 free(hs); 607 break; 608 609 case ND_HOSTSERVLIST : 610 hss = (struct nd_hostservlist *)ptr; 611 for (hs = hss->h_hostservs, i = 0; i < hss->h_cnt; i++, hs++) { 612 if (hs->h_host) 613 free(hs->h_host); 614 if (hs->h_serv) 615 free(hs->h_serv); 616 } 617 free(hss->h_hostservs); 618 free(hss); 619 break; 620 621 default : 622 _nderror = ND_UKNWN; 623 break; 624 } 625 } 626 627 /* 628 * load_xlate is a routine that will attempt to dynamically link in the 629 * file specified by the network configuration structure. 630 */ 631 static struct translator * 632 load_xlate(char *name) 633 { 634 struct translator *t; 635 static struct xlate_list { 636 char *library; 637 struct xlate_list *next; 638 } *xlistp = NULL; 639 struct xlate_list *xlp, **xlastp; 640 static mutex_t xlist_lock = DEFAULTMUTEX; 641 642 (void) mutex_lock(&xlist_lock); 643 /* 644 * We maintain a list of libraries we have loaded. Loading a library 645 * twice is double-plus ungood! 646 */ 647 for (xlp = xlistp, xlastp = &xlistp; xlp != NULL; 648 xlastp = &xlp->next, xlp = xlp->next) { 649 if (xlp->library != NULL) { 650 if (strcmp(xlp->library, name) == 0) { 651 _nderror = ND_SYSTEM; /* seen this lib */ 652 (void) mutex_unlock(&xlist_lock); 653 return (0); 654 } 655 } 656 } 657 t = malloc(sizeof (struct translator)); 658 if (!t) { 659 _nderror = ND_NOMEM; 660 (void) mutex_unlock(&xlist_lock); 661 return (0); 662 } 663 t->tr_name = strdup(name); 664 if (!t->tr_name) { 665 _nderror = ND_NOMEM; 666 free(t); 667 (void) mutex_unlock(&xlist_lock); 668 return (NULL); 669 } 670 671 t->tr_fd = dlopen(name, RTLD_LAZY); 672 if (t->tr_fd == NULL) { 673 _nderror = ND_OPEN; 674 goto error; 675 } 676 677 /* Resolve the getbyname symbol */ 678 t->gbn = (struct nd_addrlist *(*)())dlsym(t->tr_fd, 679 "_netdir_getbyname"); 680 if (!(t->gbn)) { 681 _nderror = ND_NOSYM; 682 goto error; 683 } 684 685 /* resolve the getbyaddr symbol */ 686 t->gba = (struct nd_hostservlist *(*)())dlsym(t->tr_fd, 687 "_netdir_getbyaddr"); 688 if (!(t->gba)) { 689 _nderror = ND_NOSYM; 690 goto error; 691 } 692 693 /* resolve the taddr2uaddr symbol */ 694 t->t2u = (char *(*)())dlsym(t->tr_fd, "_taddr2uaddr"); 695 if (!(t->t2u)) { 696 _nderror = ND_NOSYM; 697 goto error; 698 } 699 700 /* resolve the uaddr2taddr symbol */ 701 t->u2t = (struct netbuf *(*)())dlsym(t->tr_fd, "_uaddr2taddr"); 702 if (!(t->u2t)) { 703 _nderror = ND_NOSYM; 704 goto error; 705 } 706 707 /* resolve the netdir_options symbol */ 708 t->opt = (int (*)())dlsym(t->tr_fd, "_netdir_options"); 709 if (!(t->opt)) { 710 _nderror = ND_NOSYM; 711 goto error; 712 } 713 /* 714 * Add this library to the list of loaded libraries. 715 */ 716 *xlastp = malloc(sizeof (struct xlate_list)); 717 if (*xlastp == NULL) { 718 _nderror = ND_NOMEM; 719 goto error; 720 } 721 (*xlastp)->library = strdup(name); 722 if ((*xlastp)->library == NULL) { 723 _nderror = ND_NOMEM; 724 free(*xlastp); 725 goto error; 726 } 727 (*xlastp)->next = NULL; 728 (void) mutex_unlock(&xlist_lock); 729 return (t); 730 error: 731 if (t->tr_fd != NULL) 732 (void) dlclose(t->tr_fd); 733 free(t->tr_name); 734 free(t); 735 (void) mutex_unlock(&xlist_lock); 736 return (NULL); 737 } 738 739 740 #define NDERR_BUFSZ 512 741 742 /* 743 * This is a routine that returns a string related to the current 744 * error in _nderror. 745 */ 746 char * 747 netdir_sperror(void) 748 { 749 static pthread_key_t nderrbuf_key = 0; 750 static char buf_main[NDERR_BUFSZ]; 751 char *str; 752 char *dlerrstr; 753 754 str = thr_main()? 755 buf_main : 756 thr_get_storage(&nderrbuf_key, NDERR_BUFSZ, free); 757 if (str == NULL) 758 return (NULL); 759 dlerrstr = dlerror(); 760 switch (_nderror) { 761 case ND_NOMEM : 762 (void) snprintf(str, NDERR_BUFSZ, 763 dgettext(__nsl_dom, "n2a: memory allocation failed")); 764 break; 765 case ND_OK : 766 (void) snprintf(str, NDERR_BUFSZ, 767 dgettext(__nsl_dom, "n2a: successful completion")); 768 break; 769 case ND_NOHOST : 770 (void) snprintf(str, NDERR_BUFSZ, 771 dgettext(__nsl_dom, "n2a: hostname not found")); 772 break; 773 case ND_NOSERV : 774 (void) snprintf(str, NDERR_BUFSZ, 775 dgettext(__nsl_dom, "n2a: service name not found")); 776 break; 777 case ND_NOSYM : 778 (void) snprintf(str, NDERR_BUFSZ, "%s : %s ", 779 dgettext(__nsl_dom, 780 "n2a: symbol missing in shared object"), 781 dlerrstr ? dlerrstr : " "); 782 break; 783 case ND_OPEN : 784 (void) snprintf(str, NDERR_BUFSZ, "%s - %s ", 785 dgettext(__nsl_dom, "n2a: couldn't open shared object"), 786 dlerrstr ? dlerrstr : " "); 787 break; 788 case ND_ACCESS : 789 (void) snprintf(str, NDERR_BUFSZ, 790 dgettext(__nsl_dom, 791 "n2a: access denied for shared object")); 792 break; 793 case ND_UKNWN : 794 (void) snprintf(str, NDERR_BUFSZ, 795 dgettext(__nsl_dom, 796 "n2a: attempt to free unknown object")); 797 break; 798 case ND_BADARG : 799 (void) snprintf(str, NDERR_BUFSZ, 800 dgettext(__nsl_dom, 801 "n2a: bad arguments passed to routine")); 802 break; 803 case ND_NOCTRL: 804 (void) snprintf(str, NDERR_BUFSZ, 805 dgettext(__nsl_dom, "n2a: unknown option passed")); 806 break; 807 case ND_FAILCTRL: 808 (void) snprintf(str, NDERR_BUFSZ, 809 dgettext(__nsl_dom, "n2a: control operation failed")); 810 break; 811 case ND_SYSTEM: 812 (void) snprintf(str, NDERR_BUFSZ, "%s: %s", 813 dgettext(__nsl_dom, "n2a: system error"), 814 strerror(errno)); 815 break; 816 default : 817 (void) snprintf(str, NDERR_BUFSZ, "%s#%d", 818 dgettext(__nsl_dom, "n2a: unknown error "), _nderror); 819 break; 820 } 821 return (str); 822 } 823 824 /* 825 * This is a routine that prints out strings related to the current 826 * error in _nderror. Like perror() it takes a string to print with a 827 * colon first. 828 */ 829 void 830 netdir_perror(char *s) 831 { 832 char *err; 833 834 err = netdir_sperror(); 835 (void) fprintf(stderr, "%s: %s\n", s, err ? err : "n2a: error"); 836 } 837