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 * Copyright 2004 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 <rpc/trace.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() 103 { 104 static pthread_key_t nderror_key = 0; 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(translate) 128 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(tp, serv, addrs) 162 struct netconfig *tp; /* The network config entry */ 163 struct nd_hostserv *serv; /* the service, host pair */ 164 struct nd_addrlist **addrs; /* the answer */ 165 { 166 trace1(TR_netdir_getbyname, 0); 167 if (tp == 0) { 168 _nderror = ND_BADARG; 169 trace1(TR_netdir_getbyname, 1); 170 return (_nderror); 171 } 172 if ((strcmp(tp->nc_protofmly, NC_INET) == 0) && 173 (tp->nc_nlookups == 0)) { 174 struct nss_netdirbyname_in nssin; 175 union nss_netdirbyname_out nssout; 176 177 nssin.op_t = NETDIR_BY; 178 nssin.arg.nd_hs = serv; 179 /* 180 * In code path of case NETDIR_BY, 181 * it also calls DOOR_GETIPNODEBYNAME_R. 182 * So af_family and flags are set to 183 * get V4 addresses only. 184 */ 185 nssin.arg.nss.host6.af_family = AF_INET; 186 nssin.arg.nss.host6.flags = 0; 187 nssout.nd_alist = addrs; 188 return (_get_hostserv_inetnetdir_byname(tp, &nssin, &nssout)); 189 } else if ((strcmp(tp->nc_protofmly, NC_INET6) == 0) && 190 (tp->nc_nlookups == 0)) { 191 struct nss_netdirbyname_in nssin; 192 union nss_netdirbyname_out nssout; 193 194 nssin.op_t = NETDIR_BY6; 195 nssin.arg.nd_hs = serv; 196 /* get both V4 & V6 addresses */ 197 nssin.arg.nss.host6.af_family = AF_INET6; 198 nssin.arg.nss.host6.flags = (AI_ALL | AI_V4MAPPED); 199 nssout.nd_alist = addrs; 200 return (_get_hostserv_inetnetdir_byname(tp, &nssin, &nssout)); 201 } else { 202 trace1(TR_netdir_getbyname, 1); 203 return (__classic_netdir_getbyname(tp, serv, addrs)); 204 } 205 } 206 207 /* 208 * This routine is the svr4_classic routine for resolving host/service/xprt 209 * triples into a bunch of netbufs that should connect you to that particular 210 * service. RPC uses it to contact the binder service (rpcbind). 211 * 212 * It's either called by the real netdir_getbyname() interface above 213 * or by gethost/servbyname when nametoaddr libs are specified in 214 * /etc/netconfig with an intent of bypassing the name service switch. 215 */ 216 int 217 __classic_netdir_getbyname(tp, serv, addrs) 218 struct netconfig *tp; /* The network config entry */ 219 struct nd_hostserv *serv; /* the service, host pair */ 220 struct nd_addrlist **addrs; /* the answer */ 221 { 222 struct translator *t; /* pointer to translator list */ 223 struct nd_addrlist *nn; /* the results */ 224 char *lr; /* routines to try */ 225 int i; /* counts the routines */ 226 227 trace1(TR_netdir_getbyname, 0); 228 _nderror = ND_SYSTEM; 229 for (i = 0; i < tp->nc_nlookups; i++) { 230 lr = *((tp->nc_lookups) + i); 231 for (t = xlate_list; t; t = t->next) { 232 if (strcmp(lr, t->tr_name) == 0) { 233 nn = (*(t->gbn))(tp, serv); 234 if (nn) { 235 *addrs = nn; 236 trace1(TR_netdir_getbyname, 1); 237 return (0); 238 } else { 239 if (_nderror < 0) { 240 trace1(TR_netdir_getbyname, 1); 241 return (_nderror); 242 } 243 break; 244 } 245 } 246 } 247 /* If we didn't find it try loading it */ 248 if (!t) { 249 if ((t = load_xlate(lr)) != NULL) { 250 /* add it to the list */ 251 mutex_lock(&xlate_lock); 252 add_to_xlate_list(t); 253 mutex_unlock(&xlate_lock); 254 nn = (*(t->gbn))(tp, serv); 255 if (nn) { 256 *addrs = nn; 257 trace1(TR_netdir_getbyname, 1); 258 return (0); 259 } else { 260 if (_nderror < 0) { 261 trace1(TR_netdir_getbyname, 1); 262 return (_nderror); 263 } 264 } 265 } else { 266 if (_nderror == ND_SYSTEM) { /* retry cache */ 267 _nderror = ND_OK; 268 i--; 269 continue; 270 } 271 } 272 } 273 } 274 trace1(TR_netdir_getbyname, 1); 275 return (_nderror); /* No one works */ 276 } 277 278 /* 279 * This routine is similar to the one above except that it tries to resolve 280 * the name by the address passed. 281 */ 282 int 283 netdir_getbyaddr(tp, serv, addr) 284 struct netconfig *tp; /* The netconfig entry */ 285 struct nd_hostservlist **serv; /* the answer(s) */ 286 struct netbuf *addr; /* the address we have */ 287 { 288 trace1(TR_netdir_getbyaddr, 0); 289 if (tp == 0) { 290 _nderror = ND_BADARG; 291 trace1(TR_netdir_getbyaddr, 1); 292 return (_nderror); 293 } 294 if ((strcmp(tp->nc_protofmly, NC_INET) == 0) && 295 (tp->nc_nlookups == 0)) { 296 struct nss_netdirbyaddr_in nssin; 297 union nss_netdirbyaddr_out nssout; 298 299 nssin.op_t = NETDIR_BY; 300 nssin.arg.nd_nbuf = addr; 301 nssout.nd_hslist = serv; 302 trace1(TR_netdir_getbyaddr, 1); 303 return (_get_hostserv_inetnetdir_byaddr(tp, &nssin, &nssout)); 304 } else if ((strcmp(tp->nc_protofmly, NC_INET6) == 0) && 305 (tp->nc_nlookups == 0)) { 306 struct nss_netdirbyaddr_in nssin; 307 union nss_netdirbyaddr_out nssout; 308 309 nssin.op_t = NETDIR_BY6; 310 nssin.arg.nd_nbuf = addr; 311 nssout.nd_hslist = serv; 312 trace1(TR_netdir_getbyaddr, 1); 313 return (_get_hostserv_inetnetdir_byaddr(tp, &nssin, &nssout)); 314 } else { 315 trace1(TR_netdir_getbyaddr, 1); 316 return (__classic_netdir_getbyaddr(tp, serv, addr)); 317 } 318 } 319 /* 320 * This routine is similar to the one above except that it instructs the 321 * _get_hostserv_inetnetdir_byaddr not to do a service lookup. 322 */ 323 int 324 __netdir_getbyaddr_nosrv(tp, serv, addr) 325 struct netconfig *tp; /* The netconfig entry */ 326 struct nd_hostservlist **serv; /* the answer(s) */ 327 struct netbuf *addr; /* the address we have */ 328 { 329 trace1(TR_netdir_getbyaddr, 0); 330 if (tp == 0) { 331 _nderror = ND_BADARG; 332 trace1(TR_netdir_getbyaddr, 1); 333 return (_nderror); 334 } 335 if ((strcmp(tp->nc_protofmly, NC_INET) == 0) && 336 (tp->nc_nlookups == 0)) { 337 struct nss_netdirbyaddr_in nssin; 338 union nss_netdirbyaddr_out nssout; 339 340 nssin.op_t = NETDIR_BY_NOSRV; 341 nssin.arg.nd_nbuf = addr; 342 nssout.nd_hslist = serv; 343 trace1(TR_netdir_getbyaddr, 1); 344 return (_get_hostserv_inetnetdir_byaddr(tp, &nssin, &nssout)); 345 } else if ((strcmp(tp->nc_protofmly, NC_INET6) == 0) && 346 (tp->nc_nlookups == 0)) { 347 struct nss_netdirbyaddr_in nssin; 348 union nss_netdirbyaddr_out nssout; 349 350 nssin.op_t = NETDIR_BY_NOSRV6; 351 nssin.arg.nd_nbuf = addr; 352 nssout.nd_hslist = serv; 353 trace1(TR_netdir_getbyaddr, 1); 354 return (_get_hostserv_inetnetdir_byaddr(tp, &nssin, &nssout)); 355 } else { 356 trace1(TR_netdir_getbyaddr, 1); 357 return (__classic_netdir_getbyaddr(tp, serv, addr)); 358 } 359 } 360 361 /* 362 * This routine is the svr4_classic routine for resolving a netbuf struct 363 * into a bunch of host/service name pairs. 364 * 365 * It's either called by the real netdir_getbyaddr() interface above 366 * or by gethost/servbyaddr when nametoaddr libs are specified in 367 * /etc/netconfig with an intent of bypassing the name service switch. 368 */ 369 int 370 __classic_netdir_getbyaddr(tp, serv, addr) 371 struct netconfig *tp; /* The netconfig entry */ 372 struct nd_hostservlist **serv; /* the answer(s) */ 373 struct netbuf *addr; /* the address we have */ 374 { 375 struct translator *t; /* pointer to translator list */ 376 struct nd_hostservlist *hs; /* the results */ 377 char *lr; /* routines to try */ 378 int i; /* counts the routines */ 379 380 trace1(TR_netdir_getbyaddr, 0); 381 _nderror = ND_SYSTEM; 382 for (i = 0; i < tp->nc_nlookups; i++) { 383 lr = *((tp->nc_lookups) + i); 384 for (t = xlate_list; t; t = t->next) { 385 if (strcmp(lr, t->tr_name) == 0) { 386 hs = (*(t->gba))(tp, addr); 387 if (hs) { 388 *serv = hs; 389 trace1(TR_netdir_getbyaddr, 1); 390 return (0); 391 } else { 392 if (_nderror < 0) { 393 trace1(TR_netdir_getbyaddr, 1); 394 return (_nderror); 395 } 396 break; 397 } 398 } 399 } 400 /* If we didn't find it try loading it */ 401 if (!t) { 402 if ((t = load_xlate(lr)) != NULL) { 403 /* add it to the list */ 404 mutex_lock(&xlate_lock); 405 add_to_xlate_list(t); 406 mutex_unlock(&xlate_lock); 407 hs = (*(t->gba))(tp, addr); 408 if (hs) { 409 *serv = hs; 410 trace1(TR_netdir_getbyaddr, 1); 411 return (0); 412 } else { 413 if (_nderror < 0) { 414 trace1(TR_netdir_getbyaddr, 1); 415 return (_nderror); 416 } 417 } 418 } else { 419 if (_nderror == ND_SYSTEM) { /* retry cache */ 420 _nderror = ND_OK; 421 i--; 422 continue; 423 } 424 } 425 } 426 } 427 trace1(TR_netdir_getbyaddr, 1); 428 return (_nderror); /* No one works */ 429 } 430 431 /* 432 * This is the library routine to do transport specific stuff. 433 * The code is same as the other similar routines except that it does 434 * not bother to try whole bunch of routines since if the first 435 * libray cannot resolve the option, then no one can. 436 * 437 * If it gets a netconfig structure for inet transports with nametoddr libs, 438 * it simply calls the inet-specific built in implementation. 439 */ 440 int 441 netdir_options(tp, option, fd, par) 442 struct netconfig *tp; /* the netconfig entry */ 443 int option; /* option number */ 444 int fd; /* open file descriptor */ 445 char *par; /* parameters if any */ 446 { 447 struct translator *t; /* pointer to translator list */ 448 char *lr; /* routines to try */ 449 int i; /* counts the routines */ 450 451 trace3(TR_netdir_options, 0, option, fd); 452 if (tp == 0) { 453 _nderror = ND_BADARG; 454 trace3(TR_netdir_options, 1, option, fd); 455 return (_nderror); 456 } 457 458 if ((strcmp(tp->nc_protofmly, NC_INET) == 0 || 459 strcmp(tp->nc_protofmly, NC_INET6) == 0) && 460 (tp->nc_nlookups == 0)) { 461 trace3(TR_netdir_options, 1, option, fd); 462 return (__inet_netdir_options(tp, option, fd, par)); 463 } 464 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 trace3(TR_netdir_options, 1, option, fd); 471 return ((*(t->opt))(tp, option, fd, par)); 472 } 473 } 474 /* If we didn't find it try loading it */ 475 if (!t) { 476 if ((t = load_xlate(lr)) != NULL) { 477 /* add it to the list */ 478 mutex_lock(&xlate_lock); 479 add_to_xlate_list(t); 480 mutex_unlock(&xlate_lock); 481 trace3(TR_netdir_options, 1, option, fd); 482 return ((*(t->opt))(tp, option, fd, par)); 483 } else { 484 if (_nderror == ND_SYSTEM) { /* retry cache */ 485 _nderror = ND_OK; 486 i--; 487 continue; 488 } 489 } 490 } 491 } 492 trace3(TR_netdir_options, 1, option, fd); 493 return (_nderror); /* No one works */ 494 } 495 496 /* 497 * This is the library routine for translating universal addresses to 498 * transport specific addresses. Again it uses the same code as above 499 * to search for the appropriate translation routine. Only it doesn't 500 * bother trying a whole bunch of routines since either the transport 501 * can translate it or it can't. 502 */ 503 struct netbuf * 504 uaddr2taddr(tp, addr) 505 struct netconfig *tp; /* the netconfig entry */ 506 char *addr; /* The address in question */ 507 { 508 struct translator *t; /* pointer to translator list */ 509 struct netbuf *x; /* the answer we want */ 510 char *lr; /* routines to try */ 511 int i; /* counts the routines */ 512 513 trace1(TR_uaddr2taddr, 0); 514 if (tp == 0) { 515 _nderror = ND_BADARG; 516 trace1(TR_uaddr2taddr, 1); 517 return (0); 518 } 519 if ((strcmp(tp->nc_protofmly, NC_INET) == 0 || 520 strcmp(tp->nc_protofmly, NC_INET6) == 0) && 521 (tp->nc_nlookups == 0)) { 522 trace1(TR_uaddr2taddr, 1); 523 return (__inet_uaddr2taddr(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->u2t))(tp, addr); 530 if (x) { 531 trace1(TR_uaddr2taddr, 1); 532 return (x); 533 } 534 if (_nderror < 0) { 535 trace1(TR_uaddr2taddr, 1); 536 return (0); 537 } 538 } 539 } 540 /* If we didn't find it try loading it */ 541 if (!t) { 542 if ((t = load_xlate(lr)) != NULL) { 543 /* add it to the list */ 544 mutex_lock(&xlate_lock); 545 add_to_xlate_list(t); 546 mutex_unlock(&xlate_lock); 547 x = (*(t->u2t))(tp, addr); 548 if (x) { 549 trace1(TR_uaddr2taddr, 1); 550 return (x); 551 } 552 if (_nderror < 0) { 553 trace1(TR_uaddr2taddr, 1); 554 return (0); 555 } 556 } else { 557 if (_nderror == ND_SYSTEM) { /* retry cache */ 558 _nderror = ND_OK; 559 i--; 560 continue; 561 } 562 } 563 } 564 } 565 trace1(TR_uaddr2taddr, 1); 566 return (0); /* No one works */ 567 } 568 569 /* 570 * This is the library routine for translating transport specific 571 * addresses to universal addresses. Again it uses the same code as above 572 * to search for the appropriate translation routine. Only it doesn't 573 * bother trying a whole bunch of routines since either the transport 574 * can translate it or it can't. 575 */ 576 char * 577 taddr2uaddr(tp, addr) 578 struct netconfig *tp; /* the netconfig entry */ 579 struct netbuf *addr; /* The address in question */ 580 { 581 struct translator *t; /* pointer to translator list */ 582 char *lr; /* routines to try */ 583 char *x; /* the answer */ 584 int i; /* counts the routines */ 585 586 trace1(TR_taddr2uaddr, 0); 587 if (tp == 0) { 588 _nderror = ND_BADARG; 589 trace1(TR_taddr2uaddr, 1); 590 return (0); 591 } 592 if ((strcmp(tp->nc_protofmly, NC_INET) == 0 || 593 strcmp(tp->nc_protofmly, NC_INET6) == 0) && 594 (tp->nc_nlookups == 0)) { 595 trace1(TR_taddr2uaddr, 1); 596 return (__inet_taddr2uaddr(tp, addr)); 597 } 598 for (i = 0; i < tp->nc_nlookups; i++) { 599 lr = *((tp->nc_lookups) + i); 600 for (t = xlate_list; t; t = t->next) { 601 if (strcmp(lr, t->tr_name) == 0) { 602 x = (*(t->t2u))(tp, addr); 603 if (x) { 604 trace1(TR_taddr2uaddr, 1); 605 return (x); 606 } 607 if (_nderror < 0) { 608 trace1(TR_taddr2uaddr, 1); 609 return (0); 610 } 611 } 612 } 613 /* If we didn't find it try loading it */ 614 if (!t) { 615 if ((t = load_xlate(lr)) != NULL) { 616 /* add it to the list */ 617 mutex_lock(&xlate_lock); 618 add_to_xlate_list(t); 619 mutex_unlock(&xlate_lock); 620 x = (*(t->t2u))(tp, addr); 621 if (x) { 622 trace1(TR_taddr2uaddr, 1); 623 return (x); 624 } 625 if (_nderror < 0) { 626 trace1(TR_taddr2uaddr, 1); 627 return (0); 628 } 629 } else { 630 if (_nderror == ND_SYSTEM) { /* retry cache */ 631 _nderror = ND_OK; 632 i--; 633 continue; 634 } 635 } 636 } 637 } 638 trace1(TR_taddr2uaddr, 1); 639 return (0); /* No one works */ 640 } 641 642 /* 643 * This is the routine that frees the objects that these routines allocate. 644 */ 645 void 646 netdir_free(ptr, type) 647 void *ptr; /* generic pointer */ 648 int type; /* thing we are freeing */ 649 { 650 struct netbuf *na; 651 struct nd_addrlist *nas; 652 struct nd_hostserv *hs; 653 struct nd_hostservlist *hss; 654 int i; 655 656 trace2(TR_netdir_free, 0, type); 657 if (ptr == NULL) { 658 trace2(TR_netdir_free, 1, type); 659 return; 660 } 661 switch (type) { 662 case ND_ADDR : 663 na = (struct netbuf *)ptr; 664 if (na->buf) 665 free(na->buf); 666 free((char *)na); 667 break; 668 669 case ND_ADDRLIST : 670 nas = (struct nd_addrlist *)ptr; 671 /* 672 * XXX: We do NOT try to free all individual netbuf->buf 673 * pointers. Free only the first one since they are allocated 674 * using one calloc in 675 * libnsl/nss/netdir_inet.c:order_haddrlist(). 676 * This potentially causes memory leaks if a nametoaddr 677 * implementation -- from a third party -- has a different 678 * allocation scheme. 679 */ 680 if (nas->n_addrs->buf) 681 free(nas->n_addrs->buf); 682 free((char *)nas->n_addrs); 683 free((char *)nas); 684 break; 685 686 case ND_HOSTSERV : 687 hs = (struct nd_hostserv *)ptr; 688 if (hs->h_host) 689 free(hs->h_host); 690 if (hs->h_serv) 691 free(hs->h_serv); 692 free((char *)hs); 693 break; 694 695 case ND_HOSTSERVLIST : 696 hss = (struct nd_hostservlist *)ptr; 697 for (hs = hss->h_hostservs, i = 0; i < hss->h_cnt; i++, hs++) { 698 if (hs->h_host) 699 free(hs->h_host); 700 if (hs->h_serv) 701 free(hs->h_serv); 702 } 703 free((char *)hss->h_hostservs); 704 free((char *)hss); 705 break; 706 707 default : 708 _nderror = ND_UKNWN; 709 break; 710 } 711 trace2(TR_netdir_free, 1, type); 712 } 713 714 /* 715 * load_xlate is a routine that will attempt to dynamically link in the 716 * file specified by the network configuration structure. 717 */ 718 static struct translator * 719 load_xlate(name) 720 char *name; /* file name to load */ 721 { 722 struct translator *t; 723 static struct xlate_list { 724 char *library; 725 struct xlate_list *next; 726 } *xlistp = NULL; 727 struct xlate_list *xlp, **xlastp; 728 static mutex_t xlist_lock = DEFAULTMUTEX; 729 730 trace1(TR_load_xlate, 0); 731 mutex_lock(&xlist_lock); 732 /* 733 * We maintain a list of libraries we have loaded. Loading a library 734 * twice is double-plus ungood! 735 */ 736 for (xlp = xlistp, xlastp = &xlistp; xlp != NULL; 737 xlastp = &xlp->next, xlp = xlp->next) { 738 if (xlp->library != NULL) { 739 if (strcmp(xlp->library, name) == 0) { 740 _nderror = ND_SYSTEM; /* seen this lib */ 741 mutex_unlock(&xlist_lock); 742 trace1(TR_load_xlate, 1); 743 return (0); 744 } 745 } 746 } 747 t = (struct translator *)malloc(sizeof (struct translator)); 748 if (!t) { 749 _nderror = ND_NOMEM; 750 mutex_unlock(&xlist_lock); 751 trace1(TR_load_xlate, 1); 752 return (0); 753 } 754 t->tr_name = strdup(name); 755 if (!t->tr_name) { 756 _nderror = ND_NOMEM; 757 free((char *)t); 758 mutex_unlock(&xlist_lock); 759 trace1(TR_load_xlate, 1); 760 return (NULL); 761 } 762 763 t->tr_fd = dlopen(name, RTLD_LAZY); 764 if (t->tr_fd == NULL) { 765 _nderror = ND_OPEN; 766 goto error; 767 } 768 769 /* Resolve the getbyname symbol */ 770 t->gbn = (struct nd_addrlist *(*)())dlsym(t->tr_fd, 771 "_netdir_getbyname"); 772 if (!(t->gbn)) { 773 _nderror = ND_NOSYM; 774 goto error; 775 } 776 777 /* resolve the getbyaddr symbol */ 778 t->gba = (struct nd_hostservlist *(*)())dlsym(t->tr_fd, 779 "_netdir_getbyaddr"); 780 if (!(t->gba)) { 781 _nderror = ND_NOSYM; 782 goto error; 783 } 784 785 /* resolve the taddr2uaddr symbol */ 786 t->t2u = (char *(*)())dlsym(t->tr_fd, "_taddr2uaddr"); 787 if (!(t->t2u)) { 788 _nderror = ND_NOSYM; 789 goto error; 790 } 791 792 /* resolve the uaddr2taddr symbol */ 793 t->u2t = (struct netbuf *(*)())dlsym(t->tr_fd, "_uaddr2taddr"); 794 if (!(t->u2t)) { 795 _nderror = ND_NOSYM; 796 goto error; 797 } 798 799 /* resolve the netdir_options symbol */ 800 t->opt = (int (*)())dlsym(t->tr_fd, "_netdir_options"); 801 if (!(t->opt)) { 802 _nderror = ND_NOSYM; 803 goto error; 804 } 805 /* 806 * Add this library to the list of loaded libraries. 807 */ 808 *xlastp = (struct xlate_list *)malloc(sizeof (struct xlate_list)); 809 if (*xlastp == NULL) { 810 _nderror = ND_NOMEM; 811 goto error; 812 } 813 (*xlastp)->library = strdup(name); 814 if ((*xlastp)->library == NULL) { 815 _nderror = ND_NOMEM; 816 free(*xlastp); 817 goto error; 818 } 819 (*xlastp)->next = NULL; 820 mutex_unlock(&xlist_lock); 821 trace1(TR_load_xlate, 1); 822 return (t); 823 error: 824 if (t->tr_fd != NULL) 825 (void) dlclose(t->tr_fd); 826 free(t->tr_name); 827 free((char *)t); 828 mutex_unlock(&xlist_lock); 829 trace1(TR_load_xlate, 1); 830 return (NULL); 831 } 832 833 834 #define NDERR_BUFSZ 512 835 836 /* 837 * This is a routine that returns a string related to the current 838 * error in _nderror. 839 */ 840 char * 841 netdir_sperror() 842 { 843 static pthread_key_t nderrbuf_key = 0; 844 static char buf_main[NDERR_BUFSZ]; 845 char *str; 846 char *dlerrstr; 847 848 trace1(TR_netdir_sperror, 0); 849 str = thr_main()? 850 buf_main : 851 thr_get_storage(&nderrbuf_key, NDERR_BUFSZ, free); 852 if (str == NULL) { 853 trace1(TR_netdir_sperror, 1); 854 return (NULL); 855 } 856 dlerrstr = dlerror(); 857 switch (_nderror) { 858 case ND_NOMEM : 859 (void) snprintf(str, NDERR_BUFSZ, 860 dgettext(__nsl_dom, "n2a: memory allocation failed")); 861 break; 862 case ND_OK : 863 (void) snprintf(str, NDERR_BUFSZ, 864 dgettext(__nsl_dom, "n2a: successful completion")); 865 break; 866 case ND_NOHOST : 867 (void) snprintf(str, NDERR_BUFSZ, 868 dgettext(__nsl_dom, "n2a: hostname not found")); 869 break; 870 case ND_NOSERV : 871 (void) snprintf(str, NDERR_BUFSZ, 872 dgettext(__nsl_dom, "n2a: service name not found")); 873 break; 874 case ND_NOSYM : 875 (void) snprintf(str, NDERR_BUFSZ, "%s : %s ", 876 dgettext(__nsl_dom, 877 "n2a: symbol missing in shared object"), 878 dlerrstr ? dlerrstr : " "); 879 break; 880 case ND_OPEN : 881 (void) snprintf(str, NDERR_BUFSZ, "%s - %s ", 882 dgettext(__nsl_dom, "n2a: couldn't open shared object"), 883 dlerrstr ? dlerrstr : " "); 884 break; 885 case ND_ACCESS : 886 (void) snprintf(str, NDERR_BUFSZ, 887 dgettext(__nsl_dom, 888 "n2a: access denied for shared object")); 889 break; 890 case ND_UKNWN : 891 (void) snprintf(str, NDERR_BUFSZ, 892 dgettext(__nsl_dom, 893 "n2a: attempt to free unknown object")); 894 break; 895 case ND_BADARG : 896 (void) snprintf(str, NDERR_BUFSZ, 897 dgettext(__nsl_dom, 898 "n2a: bad arguments passed to routine")); 899 break; 900 case ND_NOCTRL: 901 (void) snprintf(str, NDERR_BUFSZ, 902 dgettext(__nsl_dom, "n2a: unknown option passed")); 903 break; 904 case ND_FAILCTRL: 905 (void) snprintf(str, NDERR_BUFSZ, 906 dgettext(__nsl_dom, "n2a: control operation failed")); 907 break; 908 case ND_SYSTEM: 909 (void) snprintf(str, NDERR_BUFSZ, "%s: %s", 910 dgettext(__nsl_dom, "n2a: system error"), 911 strerror(errno)); 912 break; 913 default : 914 (void) snprintf(str, NDERR_BUFSZ, "%s#%d", 915 dgettext(__nsl_dom, "n2a: unknown error "), _nderror); 916 break; 917 } 918 trace1(TR_netdir_sperror, 1); 919 return (str); 920 } 921 922 /* 923 * This is a routine that prints out strings related to the current 924 * error in _nderror. Like perror() it takes a string to print with a 925 * colon first. 926 */ 927 void 928 netdir_perror(s) 929 char *s; 930 { 931 char *err; 932 933 trace1(TR_netdir_perror, 0); 934 err = netdir_sperror(); 935 (void) fprintf(stderr, "%s: %s\n", s, err ? err : "n2a: error"); 936 trace1(TR_netdir_perror, 1); 937 } 938