xref: /titanic_54/usr/src/lib/libnsl/netdir/netdir.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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