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