2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
2N/A/* All Rights Reserved */
2N/A
2N/A/*
2N/A * Portions of this source code were derived from Berkeley 4.3 BSD
2N/A * under license from the Regents of the University of California.
2N/A */
2N/A
2N/A#pragma ident "%Z%%M% %I% %E% SMI"
2N/A
2N/A/*
2N/A * netdir.c
2N/A *
2N/A * This is the library routines that do the name to address
2N/A * translation.
2N/A */
2N/A
2N/A#include "mt.h"
2N/A#include "../rpc/rpc_mt.h" /* for MT declarations only */
2N/A#include <stdio.h>
2N/A#include <sys/types.h>
2N/A#include <errno.h>
2N/A#include <tiuser.h>
2N/A#include <netdir.h>
2N/A#include <netconfig.h>
2N/A#include <string.h>
2N/A#include <sys/file.h>
2N/A#include <dlfcn.h>
2N/A#include <stdlib.h>
2N/A#include <malloc.h>
2N/A#include <syslog.h>
2N/A#include <nss_netdir.h>
2N/A#include <netinet/in.h>
2N/A#include <netdb.h>
2N/A
2N/A/* messaging stuff. */
2N/A
2N/Aextern const char __nsl_dom[];
2N/Aextern char *dgettext(const char *, const char *);
2N/A
2N/Astruct translator {
2N/A struct nd_addrlist *(*gbn)(); /* _netdir_getbyname */
2N/A struct nd_hostservlist *(*gba)(); /* _netdir_getbyaddr */
2N/A int (*opt)(); /* _netdir_options */
2N/A char *(*t2u)(); /* _taddr2uaddr */
2N/A struct netbuf *(*u2t)(); /* _uaddr2taddr */
2N/A void *tr_fd; /* dyn library handle */
2N/A char *tr_name; /* Full path */
2N/A struct translator *next;
2N/A};
2N/A
2N/A/*
2N/A * xlate_lock protects xlate_list during updates only. The xlate_list linked
2N/A * list is pre-pended when new entries are added, so threads that are already
2N/A * using the list will continue correctly to the end of the list.
2N/A */
2N/Astatic struct translator *xlate_list = NULL;
2N/Astatic mutex_t xlate_lock = DEFAULTMUTEX;
2N/A
2N/Astatic struct translator *load_xlate(char *);
2N/A
2N/A/*
2N/A * This is the common data (global data) that is exported
2N/A * by public interfaces. It has been moved here from nd_comdata.c
2N/A * which no longer exists. This fixes the problem for applications
2N/A * that do not link directly with -lnsl but dlopen a shared object
2N/A * that has a NEEDED dependency on -lnsl and uses the netdir
2N/A * interface.
2N/A */
2N/A
2N/A#undef _nderror
2N/A
2N/Aint _nderror;
2N/A
2N/Aint *
2N/A__nderror(void)
2N/A{
2N/A static pthread_key_t nderror_key = PTHREAD_ONCE_KEY_NP;
2N/A int *ret;
2N/A
2N/A if (thr_main())
2N/A return (&_nderror);
2N/A ret = thr_get_storage(&nderror_key, sizeof (int), free);
2N/A /* if thr_get_storage fails we return the address of _nderror */
2N/A return (ret ? ret : &_nderror);
2N/A}
2N/A
2N/A#define _nderror (*(__nderror()))
2N/A
2N/A/*
2N/A * Adds a translator library to the xlate_list, but first check to see if
2N/A * it's already on the list. Must be called while holding xlate_lock.
2N/A * We have to be careful for the case of the same library being loaded
2N/A * with different names (e.g., straddr.so and /usr/lib/straddr.so).
2N/A * We check for this case by looking at the gbn and name fields.
2N/A * If the gbn address is the same, but the names are different, then we
2N/A * have accidentally reloaded the library. We dlclose the new version,
2N/A * and then update 'translate' with the old versions of the symbols.
2N/A */
2N/Avoid
2N/Aadd_to_xlate_list(struct translator *translate)
2N/A{
2N/A struct translator *t;
2N/A
2N/A for (t = xlate_list; t; t = t->next) {
2N/A if (strcmp(translate->tr_name, t->tr_name) == 0) {
2N/A return;
2N/A }
2N/A }
2N/A translate->next = xlate_list;
2N/A xlate_list = translate;
2N/A}
2N/A
2N/A/*
2N/A * This routine is the main routine that resolves host/service/xprt triples
2N/A * into a bunch of netbufs that should connect you to that particular
2N/A * service. RPC uses it to contact the binder service (rpcbind).
2N/A *
2N/A * In the interest of consistency with the gethost/servbyYY() routines,
2N/A * this routine calls a common interface _get_hostserv_inetnetdir_byname
2N/A * if it's called with a netconfig with "inet" type transports and
2N/A * an empty list of nametoaddr libs (i.e. a "-" in /etc/netconfig),
2N/A * which indicates the use of the switch. For non-inet transports or
2N/A * inet transports with nametoaddr libs specified, it simply calls
2N/A * the SVr4-classic netdir_getbyname, which loops through the libs.
2N/A *
2N/A * After all, any problem can be solved by one more layer of abstraction..
2N/A *
2N/A * This routine when called with a netconfig with "inet6" type of transports
2N/A * returns pure IPv6 addresses only and if no IPv6 address is found it
2N/A * returns none - Bug Id. 4276329
2N/A */
2N/Aint
2N/Anetdir_getbyname(struct netconfig *tp, struct nd_hostserv *serv,
2N/A struct nd_addrlist **addrs)
2N/A{
2N/A if (tp == 0) {
2N/A _nderror = ND_BADARG;
2N/A return (_nderror);
2N/A }
2N/A if ((strcmp(tp->nc_protofmly, NC_INET) == 0) &&
2N/A (tp->nc_nlookups == 0)) {
2N/A struct nss_netdirbyname_in nssin;
2N/A union nss_netdirbyname_out nssout;
2N/A
2N/A nssin.op_t = NETDIR_BY;
2N/A nssin.arg.nd_hs = serv;
2N/A /*
2N/A * In code path of case NETDIR_BY,
2N/A * it also calls DOOR_GETIPNODEBYNAME_R.
2N/A * So af_family and flags are set to
2N/A * get V4 addresses only.
2N/A */
2N/A nssin.arg.nss.host6.af_family = AF_INET;
2N/A nssin.arg.nss.host6.flags = 0;
2N/A nssout.nd_alist = addrs;
2N/A return (_get_hostserv_inetnetdir_byname(tp, &nssin, &nssout));
2N/A }
2N/A if ((strcmp(tp->nc_protofmly, NC_INET6) == 0) &&
2N/A (tp->nc_nlookups == 0)) {
2N/A struct nss_netdirbyname_in nssin;
2N/A union nss_netdirbyname_out nssout;
2N/A
2N/A nssin.op_t = NETDIR_BY6;
2N/A nssin.arg.nd_hs = serv;
2N/A /* get both V4 & V6 addresses */
2N/A nssin.arg.nss.host6.af_family = AF_INET6;
2N/A nssin.arg.nss.host6.flags = (AI_ALL | AI_V4MAPPED);
2N/A nssout.nd_alist = addrs;
2N/A return (_get_hostserv_inetnetdir_byname(tp, &nssin, &nssout));
2N/A }
2N/A return (__classic_netdir_getbyname(tp, serv, addrs));
2N/A}
2N/A
2N/A/*
2N/A * This routine is the svr4_classic routine for resolving host/service/xprt
2N/A * triples into a bunch of netbufs that should connect you to that particular
2N/A * service. RPC uses it to contact the binder service (rpcbind).
2N/A *
2N/A * It's either called by the real netdir_getbyname() interface above
2N/A * or by gethost/servbyname when nametoaddr libs are specified in
2N/A * /etc/netconfig with an intent of bypassing the name service switch.
2N/A */
2N/Aint
2N/A__classic_netdir_getbyname(struct netconfig *tp, struct nd_hostserv *serv,
2N/A struct nd_addrlist **addrs)
2N/A{
2N/A struct translator *t; /* pointer to translator list */
2N/A struct nd_addrlist *nn; /* the results */
2N/A char *lr; /* routines to try */
2N/A int i; /* counts the routines */
2N/A
2N/A _nderror = ND_SYSTEM;
2N/A for (i = 0; i < tp->nc_nlookups; i++) {
2N/A lr = *((tp->nc_lookups) + i);
2N/A for (t = xlate_list; t; t = t->next) {
2N/A if (strcmp(lr, t->tr_name) == 0) {
2N/A nn = (*(t->gbn))(tp, serv);
2N/A if (nn) {
2N/A *addrs = nn;
2N/A return (0);
2N/A }
2N/A if (_nderror < 0) {
2N/A return (_nderror);
2N/A }
2N/A break;
2N/A }
2N/A }
2N/A /* If we didn't find it try loading it */
2N/A if (!t) {
2N/A if ((t = load_xlate(lr)) != NULL) {
2N/A /* add it to the list */
2N/A (void) mutex_lock(&xlate_lock);
2N/A add_to_xlate_list(t);
2N/A (void) mutex_unlock(&xlate_lock);
2N/A nn = (*(t->gbn))(tp, serv);
2N/A if (nn) {
2N/A *addrs = nn;
2N/A return (0);
2N/A }
2N/A if (_nderror < 0) {
2N/A return (_nderror);
2N/A }
2N/A } else {
2N/A if (_nderror == ND_SYSTEM) { /* retry cache */
2N/A _nderror = ND_OK;
2N/A i--;
2N/A continue;
2N/A }
2N/A }
2N/A }
2N/A }
2N/A return (_nderror); /* No one works */
2N/A}
2N/A
2N/A/*
2N/A * This routine is similar to the one above except that it tries to resolve
2N/A * the name by the address passed.
2N/A */
2N/Aint
2N/Anetdir_getbyaddr(struct netconfig *tp, struct nd_hostservlist **serv,
2N/A struct netbuf *addr)
2N/A{
2N/A if (tp == 0) {
2N/A _nderror = ND_BADARG;
2N/A return (_nderror);
2N/A }
2N/A if ((strcmp(tp->nc_protofmly, NC_INET) == 0) &&
2N/A (tp->nc_nlookups == 0)) {
2N/A struct nss_netdirbyaddr_in nssin;
2N/A union nss_netdirbyaddr_out nssout;
2N/A
2N/A nssin.op_t = NETDIR_BY;
2N/A nssin.arg.nd_nbuf = addr;
2N/A nssout.nd_hslist = serv;
2N/A return (_get_hostserv_inetnetdir_byaddr(tp, &nssin, &nssout));
2N/A }
2N/A if ((strcmp(tp->nc_protofmly, NC_INET6) == 0) &&
2N/A (tp->nc_nlookups == 0)) {
2N/A struct nss_netdirbyaddr_in nssin;
2N/A union nss_netdirbyaddr_out nssout;
2N/A
2N/A nssin.op_t = NETDIR_BY6;
2N/A nssin.arg.nd_nbuf = addr;
2N/A nssout.nd_hslist = serv;
2N/A return (_get_hostserv_inetnetdir_byaddr(tp, &nssin, &nssout));
2N/A }
2N/A return (__classic_netdir_getbyaddr(tp, serv, addr));
2N/A}
2N/A/*
2N/A * This routine is similar to the one above except that it instructs the
2N/A * _get_hostserv_inetnetdir_byaddr not to do a service lookup.
2N/A */
2N/Aint
2N/A__netdir_getbyaddr_nosrv(struct netconfig *tp, struct nd_hostservlist **serv,
2N/A struct netbuf *addr)
2N/A{
2N/A if (tp == 0) {
2N/A _nderror = ND_BADARG;
2N/A return (_nderror);
2N/A }
2N/A if ((strcmp(tp->nc_protofmly, NC_INET) == 0) &&
2N/A (tp->nc_nlookups == 0)) {
2N/A struct nss_netdirbyaddr_in nssin;
2N/A union nss_netdirbyaddr_out nssout;
2N/A
2N/A nssin.op_t = NETDIR_BY_NOSRV;
2N/A nssin.arg.nd_nbuf = addr;
2N/A nssout.nd_hslist = serv;
2N/A return (_get_hostserv_inetnetdir_byaddr(tp, &nssin, &nssout));
2N/A }
2N/A if ((strcmp(tp->nc_protofmly, NC_INET6) == 0) &&
2N/A (tp->nc_nlookups == 0)) {
2N/A struct nss_netdirbyaddr_in nssin;
2N/A union nss_netdirbyaddr_out nssout;
2N/A
2N/A nssin.op_t = NETDIR_BY_NOSRV6;
2N/A nssin.arg.nd_nbuf = addr;
2N/A nssout.nd_hslist = serv;
2N/A return (_get_hostserv_inetnetdir_byaddr(tp, &nssin, &nssout));
2N/A }
2N/A return (__classic_netdir_getbyaddr(tp, serv, addr));
2N/A}
2N/A
2N/A/*
2N/A * This routine is the svr4_classic routine for resolving a netbuf struct
2N/A * into a bunch of host/service name pairs.
2N/A *
2N/A * It's either called by the real netdir_getbyaddr() interface above
2N/A * or by gethost/servbyaddr when nametoaddr libs are specified in
2N/A * /etc/netconfig with an intent of bypassing the name service switch.
2N/A */
2N/Aint
2N/A__classic_netdir_getbyaddr(struct netconfig *tp, struct nd_hostservlist **serv,
2N/A struct netbuf *addr)
2N/A{
2N/A struct translator *t; /* pointer to translator list */
2N/A struct nd_hostservlist *hs; /* the results */
2N/A char *lr; /* routines to try */
2N/A int i; /* counts the routines */
2N/A
2N/A _nderror = ND_SYSTEM;
2N/A for (i = 0; i < tp->nc_nlookups; i++) {
2N/A lr = *((tp->nc_lookups) + i);
2N/A for (t = xlate_list; t; t = t->next) {
2N/A if (strcmp(lr, t->tr_name) == 0) {
2N/A hs = (*(t->gba))(tp, addr);
2N/A if (hs) {
2N/A *serv = hs;
2N/A return (0);
2N/A }
2N/A if (_nderror < 0)
2N/A return (_nderror);
2N/A break;
2N/A }
2N/A }
2N/A /* If we didn't find it try loading it */
2N/A if (!t) {
2N/A if ((t = load_xlate(lr)) != NULL) {
2N/A /* add it to the list */
2N/A (void) mutex_lock(&xlate_lock);
2N/A add_to_xlate_list(t);
2N/A (void) mutex_unlock(&xlate_lock);
2N/A hs = (*(t->gba))(tp, addr);
2N/A if (hs) {
2N/A *serv = hs;
2N/A return (0);
2N/A }
2N/A if (_nderror < 0)
2N/A return (_nderror);
2N/A } else {
2N/A if (_nderror == ND_SYSTEM) { /* retry cache */
2N/A _nderror = ND_OK;
2N/A i--;
2N/A continue;
2N/A }
2N/A }
2N/A }
2N/A }
2N/A return (_nderror); /* No one works */
2N/A}
2N/A
2N/A/*
2N/A * This is the library routine to do transport specific stuff.
2N/A * The code is same as the other similar routines except that it does
2N/A * not bother to try whole bunch of routines since if the first
2N/A * libray cannot resolve the option, then no one can.
2N/A *
2N/A * If it gets a netconfig structure for inet transports with nametoddr libs,
2N/A * it simply calls the inet-specific built in implementation.
2N/A */
2N/Aint
2N/Anetdir_options(struct netconfig *tp, int option, int fd, char *par)
2N/A{
2N/A struct translator *t; /* pointer to translator list */
2N/A char *lr; /* routines to try */
2N/A int i; /* counts the routines */
2N/A
2N/A if (tp == 0) {
2N/A _nderror = ND_BADARG;
2N/A return (_nderror);
2N/A }
2N/A
2N/A if ((strcmp(tp->nc_protofmly, NC_INET) == 0 ||
2N/A strcmp(tp->nc_protofmly, NC_INET6) == 0) &&
2N/A (tp->nc_nlookups == 0)) {
2N/A return (__inet_netdir_options(tp, option, fd, par));
2N/A }
2N/A
2N/A
2N/A for (i = 0; i < tp->nc_nlookups; i++) {
2N/A lr = *((tp->nc_lookups) + i);
2N/A for (t = xlate_list; t; t = t->next) {
2N/A if (strcmp(lr, t->tr_name) == 0)
2N/A return ((*(t->opt))(tp, option, fd, par));
2N/A }
2N/A /* If we didn't find it try loading it */
2N/A if (!t) {
2N/A if ((t = load_xlate(lr)) != NULL) {
2N/A /* add it to the list */
2N/A (void) mutex_lock(&xlate_lock);
2N/A add_to_xlate_list(t);
2N/A (void) mutex_unlock(&xlate_lock);
2N/A return ((*(t->opt))(tp, option, fd, par));
2N/A }
2N/A if (_nderror == ND_SYSTEM) { /* retry cache */
2N/A _nderror = ND_OK;
2N/A i--;
2N/A continue;
2N/A }
2N/A }
2N/A }
2N/A return (_nderror); /* No one works */
2N/A}
2N/A
2N/A/*
2N/A * This is the library routine for translating universal addresses to
2N/A * transport specific addresses. Again it uses the same code as above
2N/A * to search for the appropriate translation routine. Only it doesn't
2N/A * bother trying a whole bunch of routines since either the transport
2N/A * can translate it or it can't.
2N/A */
2N/Astruct netbuf *
2N/Auaddr2taddr(struct netconfig *tp, char *addr)
2N/A{
2N/A struct translator *t; /* pointer to translator list */
2N/A struct netbuf *x; /* the answer we want */
2N/A char *lr; /* routines to try */
2N/A int i; /* counts the routines */
2N/A
2N/A if (tp == 0) {
2N/A _nderror = ND_BADARG;
2N/A return (0);
2N/A }
2N/A if ((strcmp(tp->nc_protofmly, NC_INET) == 0 ||
2N/A strcmp(tp->nc_protofmly, NC_INET6) == 0) &&
2N/A (tp->nc_nlookups == 0)) {
2N/A return (__inet_uaddr2taddr(tp, addr));
2N/A }
2N/A for (i = 0; i < tp->nc_nlookups; i++) {
2N/A lr = *((tp->nc_lookups) + i);
2N/A for (t = xlate_list; t; t = t->next) {
2N/A if (strcmp(lr, t->tr_name) == 0) {
2N/A x = (*(t->u2t))(tp, addr);
2N/A if (x)
2N/A return (x);
2N/A if (_nderror < 0)
2N/A return (0);
2N/A }
2N/A }
2N/A /* If we didn't find it try loading it */
2N/A if (!t) {
2N/A if ((t = load_xlate(lr)) != NULL) {
2N/A /* add it to the list */
2N/A (void) mutex_lock(&xlate_lock);
2N/A add_to_xlate_list(t);
2N/A (void) mutex_unlock(&xlate_lock);
2N/A x = (*(t->u2t))(tp, addr);
2N/A if (x)
2N/A return (x);
2N/A if (_nderror < 0)
2N/A return (0);
2N/A } else {
2N/A if (_nderror == ND_SYSTEM) { /* retry cache */
2N/A _nderror = ND_OK;
2N/A i--;
2N/A continue;
2N/A }
2N/A }
2N/A }
2N/A }
2N/A return (0); /* No one works */
2N/A}
2N/A
2N/A/*
2N/A * This is the library routine for translating transport specific
2N/A * addresses to universal addresses. Again it uses the same code as above
2N/A * to search for the appropriate translation routine. Only it doesn't
2N/A * bother trying a whole bunch of routines since either the transport
2N/A * can translate it or it can't.
2N/A */
2N/Achar *
2N/Ataddr2uaddr(struct netconfig *tp, struct netbuf *addr)
2N/A{
2N/A struct translator *t; /* pointer to translator list */
2N/A char *lr; /* routines to try */
2N/A char *x; /* the answer */
2N/A int i; /* counts the routines */
2N/A
2N/A if (tp == 0) {
2N/A _nderror = ND_BADARG;
2N/A return (0);
2N/A }
2N/A if ((strcmp(tp->nc_protofmly, NC_INET) == 0 ||
2N/A strcmp(tp->nc_protofmly, NC_INET6) == 0) &&
2N/A (tp->nc_nlookups == 0)) {
2N/A return (__inet_taddr2uaddr(tp, addr));
2N/A }
2N/A for (i = 0; i < tp->nc_nlookups; i++) {
2N/A lr = *((tp->nc_lookups) + i);
2N/A for (t = xlate_list; t; t = t->next) {
2N/A if (strcmp(lr, t->tr_name) == 0) {
2N/A x = (*(t->t2u))(tp, addr);
2N/A if (x)
2N/A return (x);
2N/A if (_nderror < 0)
2N/A return (0);
2N/A }
2N/A }
2N/A /* If we didn't find it try loading it */
2N/A if (!t) {
2N/A if ((t = load_xlate(lr)) != NULL) {
2N/A /* add it to the list */
2N/A (void) mutex_lock(&xlate_lock);
2N/A add_to_xlate_list(t);
2N/A (void) mutex_unlock(&xlate_lock);
2N/A x = (*(t->t2u))(tp, addr);
2N/A if (x)
2N/A return (x);
2N/A if (_nderror < 0)
2N/A return (0);
2N/A } else {
2N/A if (_nderror == ND_SYSTEM) { /* retry cache */
2N/A _nderror = ND_OK;
2N/A i--;
2N/A continue;
2N/A }
2N/A }
2N/A }
2N/A }
2N/A return (0); /* No one works */
2N/A}
2N/A
2N/A/*
2N/A * This is the routine that frees the objects that these routines allocate.
2N/A */
2N/Avoid
2N/Anetdir_free(void *ptr, int type)
2N/A{
2N/A struct netbuf *na;
2N/A struct nd_addrlist *nas;
2N/A struct nd_hostserv *hs;
2N/A struct nd_hostservlist *hss;
2N/A int i;
2N/A
2N/A if (ptr == NULL)
2N/A return;
2N/A switch (type) {
2N/A case ND_ADDR :
2N/A na = (struct netbuf *)ptr;
2N/A if (na->buf)
2N/A free(na->buf);
2N/A free(na);
2N/A break;
2N/A
2N/A case ND_ADDRLIST :
2N/A nas = (struct nd_addrlist *)ptr;
2N/A /*
2N/A * XXX: We do NOT try to free all individual netbuf->buf
2N/A * pointers. Free only the first one since they are allocated
2N/A * using one calloc in
2N/A * libnsl/nss/netdir_inet.c:order_haddrlist().
2N/A * This potentially causes memory leaks if a nametoaddr
2N/A * implementation -- from a third party -- has a different
2N/A * allocation scheme.
2N/A */
2N/A if (nas->n_addrs->buf)
2N/A free(nas->n_addrs->buf);
2N/A free(nas->n_addrs);
2N/A free(nas);
2N/A break;
2N/A
2N/A case ND_HOSTSERV :
2N/A hs = (struct nd_hostserv *)ptr;
2N/A if (hs->h_host)
2N/A free(hs->h_host);
2N/A if (hs->h_serv)
2N/A free(hs->h_serv);
2N/A free(hs);
2N/A break;
2N/A
2N/A case ND_HOSTSERVLIST :
2N/A hss = (struct nd_hostservlist *)ptr;
2N/A for (hs = hss->h_hostservs, i = 0; i < hss->h_cnt; i++, hs++) {
2N/A if (hs->h_host)
2N/A free(hs->h_host);
2N/A if (hs->h_serv)
2N/A free(hs->h_serv);
2N/A }
2N/A free(hss->h_hostservs);
2N/A free(hss);
2N/A break;
2N/A
2N/A default :
2N/A _nderror = ND_UKNWN;
2N/A break;
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * load_xlate is a routine that will attempt to dynamically link in the
2N/A * file specified by the network configuration structure.
2N/A */
2N/Astatic struct translator *
2N/Aload_xlate(char *name)
2N/A{
2N/A struct translator *t;
2N/A static struct xlate_list {
2N/A char *library;
2N/A struct xlate_list *next;
2N/A } *xlistp = NULL;
2N/A struct xlate_list *xlp, **xlastp;
2N/A static mutex_t xlist_lock = DEFAULTMUTEX;
2N/A
2N/A (void) mutex_lock(&xlist_lock);
2N/A /*
2N/A * We maintain a list of libraries we have loaded. Loading a library
2N/A * twice is double-plus ungood!
2N/A */
2N/A for (xlp = xlistp, xlastp = &xlistp; xlp != NULL;
2N/A xlastp = &xlp->next, xlp = xlp->next) {
2N/A if (xlp->library != NULL) {
2N/A if (strcmp(xlp->library, name) == 0) {
2N/A _nderror = ND_SYSTEM; /* seen this lib */
2N/A (void) mutex_unlock(&xlist_lock);
2N/A return (0);
2N/A }
2N/A }
2N/A }
2N/A t = malloc(sizeof (struct translator));
2N/A if (!t) {
2N/A _nderror = ND_NOMEM;
2N/A (void) mutex_unlock(&xlist_lock);
2N/A return (0);
2N/A }
2N/A t->tr_name = strdup(name);
2N/A if (!t->tr_name) {
2N/A _nderror = ND_NOMEM;
2N/A free(t);
2N/A (void) mutex_unlock(&xlist_lock);
2N/A return (NULL);
2N/A }
2N/A
2N/A t->tr_fd = dlopen(name, RTLD_LAZY);
2N/A if (t->tr_fd == NULL) {
2N/A _nderror = ND_OPEN;
2N/A goto error;
2N/A }
2N/A
2N/A /* Resolve the getbyname symbol */
2N/A t->gbn = (struct nd_addrlist *(*)())dlsym(t->tr_fd,
2N/A "_netdir_getbyname");
2N/A if (!(t->gbn)) {
2N/A _nderror = ND_NOSYM;
2N/A goto error;
2N/A }
2N/A
2N/A /* resolve the getbyaddr symbol */
2N/A t->gba = (struct nd_hostservlist *(*)())dlsym(t->tr_fd,
2N/A "_netdir_getbyaddr");
2N/A if (!(t->gba)) {
2N/A _nderror = ND_NOSYM;
2N/A goto error;
2N/A }
2N/A
2N/A /* resolve the taddr2uaddr symbol */
2N/A t->t2u = (char *(*)())dlsym(t->tr_fd, "_taddr2uaddr");
2N/A if (!(t->t2u)) {
2N/A _nderror = ND_NOSYM;
2N/A goto error;
2N/A }
2N/A
2N/A /* resolve the uaddr2taddr symbol */
2N/A t->u2t = (struct netbuf *(*)())dlsym(t->tr_fd, "_uaddr2taddr");
2N/A if (!(t->u2t)) {
2N/A _nderror = ND_NOSYM;
2N/A goto error;
2N/A }
2N/A
2N/A /* resolve the netdir_options symbol */
2N/A t->opt = (int (*)())dlsym(t->tr_fd, "_netdir_options");
2N/A if (!(t->opt)) {
2N/A _nderror = ND_NOSYM;
2N/A goto error;
2N/A }
2N/A /*
2N/A * Add this library to the list of loaded libraries.
2N/A */
2N/A *xlastp = malloc(sizeof (struct xlate_list));
2N/A if (*xlastp == NULL) {
2N/A _nderror = ND_NOMEM;
2N/A goto error;
2N/A }
2N/A (*xlastp)->library = strdup(name);
2N/A if ((*xlastp)->library == NULL) {
2N/A _nderror = ND_NOMEM;
2N/A free(*xlastp);
2N/A goto error;
2N/A }
2N/A (*xlastp)->next = NULL;
2N/A (void) mutex_unlock(&xlist_lock);
2N/A return (t);
2N/Aerror:
2N/A if (t->tr_fd != NULL)
2N/A (void) dlclose(t->tr_fd);
2N/A free(t->tr_name);
2N/A free(t);
2N/A (void) mutex_unlock(&xlist_lock);
2N/A return (NULL);
2N/A}
2N/A
2N/A
2N/A#define NDERR_BUFSZ 512
2N/A
2N/A/*
2N/A * This is a routine that returns a string related to the current
2N/A * error in _nderror.
2N/A */
2N/Achar *
2N/Anetdir_sperror(void)
2N/A{
2N/A static pthread_key_t nderrbuf_key = PTHREAD_ONCE_KEY_NP;
2N/A static char buf_main[NDERR_BUFSZ];
2N/A char *str;
2N/A char *dlerrstr;
2N/A
2N/A str = thr_main()?
2N/A buf_main :
2N/A thr_get_storage(&nderrbuf_key, NDERR_BUFSZ, free);
2N/A if (str == NULL)
2N/A return (NULL);
2N/A dlerrstr = dlerror();
2N/A switch (_nderror) {
2N/A case ND_NOMEM :
2N/A (void) snprintf(str, NDERR_BUFSZ,
2N/A dgettext(__nsl_dom, "n2a: memory allocation failed"));
2N/A break;
2N/A case ND_OK :
2N/A (void) snprintf(str, NDERR_BUFSZ,
2N/A dgettext(__nsl_dom, "n2a: successful completion"));
2N/A break;
2N/A case ND_NOHOST :
2N/A (void) snprintf(str, NDERR_BUFSZ,
2N/A dgettext(__nsl_dom, "n2a: hostname not found"));
2N/A break;
2N/A case ND_NOSERV :
2N/A (void) snprintf(str, NDERR_BUFSZ,
2N/A dgettext(__nsl_dom, "n2a: service name not found"));
2N/A break;
2N/A case ND_NOSYM :
2N/A (void) snprintf(str, NDERR_BUFSZ, "%s : %s ",
2N/A dgettext(__nsl_dom,
2N/A "n2a: symbol missing in shared object"),
2N/A dlerrstr ? dlerrstr : " ");
2N/A break;
2N/A case ND_OPEN :
2N/A (void) snprintf(str, NDERR_BUFSZ, "%s - %s ",
2N/A dgettext(__nsl_dom, "n2a: couldn't open shared object"),
2N/A dlerrstr ? dlerrstr : " ");
2N/A break;
2N/A case ND_ACCESS :
2N/A (void) snprintf(str, NDERR_BUFSZ,
2N/A dgettext(__nsl_dom,
2N/A "n2a: access denied for shared object"));
2N/A break;
2N/A case ND_UKNWN :
2N/A (void) snprintf(str, NDERR_BUFSZ,
2N/A dgettext(__nsl_dom,
2N/A "n2a: attempt to free unknown object"));
2N/A break;
2N/A case ND_BADARG :
2N/A (void) snprintf(str, NDERR_BUFSZ,
2N/A dgettext(__nsl_dom,
2N/A "n2a: bad arguments passed to routine"));
2N/A break;
2N/A case ND_NOCTRL:
2N/A (void) snprintf(str, NDERR_BUFSZ,
2N/A dgettext(__nsl_dom, "n2a: unknown option passed"));
2N/A break;
2N/A case ND_FAILCTRL:
2N/A (void) snprintf(str, NDERR_BUFSZ,
2N/A dgettext(__nsl_dom, "n2a: control operation failed"));
2N/A break;
2N/A case ND_SYSTEM:
2N/A (void) snprintf(str, NDERR_BUFSZ, "%s: %s",
2N/A dgettext(__nsl_dom, "n2a: system error"),
2N/A strerror(errno));
2N/A break;
2N/A default :
2N/A (void) snprintf(str, NDERR_BUFSZ, "%s#%d",
2N/A dgettext(__nsl_dom, "n2a: unknown error "), _nderror);
2N/A break;
2N/A }
2N/A return (str);
2N/A}
2N/A
2N/A/*
2N/A * This is a routine that prints out strings related to the current
2N/A * error in _nderror. Like perror() it takes a string to print with a
2N/A * colon first.
2N/A */
2N/Avoid
2N/Anetdir_perror(char *s)
2N/A{
2N/A char *err;
2N/A
2N/A err = netdir_sperror();
2N/A (void) fprintf(stderr, "%s: %s\n", s, err ? err : "n2a: error");
2N/A}