Files
seta75D d6fe8fe829 Init
2021-10-11 22:19:34 -03:00

916 lines
23 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
static char sccsid[] = "@(#)26 1.15 src/bos/usr/ccs/lib/libc/yp_bind.c, libcyp, bos411, 9432B411a 7/25/94 14:26:06";
/*
* COMPONENT_NAME: (LIBCYP) Yellow Pages Library
*
* FUNCTIONS: _default_domain, _yp_dobind, check_binder_up, check_binding,
* check_pmap_up, get_binder_port, load_dom_binding, newborn,
* talk2_binder, talk2_pmap, talk2_server, usingypmap, yp_bind,
* yp_get_default_domain, yp_unbind
*
* ORIGINS: 24 27
*
* This module contains IBM CONFIDENTIAL code. -- (IBM
* Confidential Restricted when combined with the aggregated
* modules for this product)
* SOURCE MATERIALS
* (C) COPYRIGHT International Business Machines Corp. 1988, 1992
* All Rights Reserved
*
* US Government Users Restricted Rights - Use, duplication or
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
*
* Copyright (c) 1988 by Sun Microsystems, Inc.
*/
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <rpc/rpc.h>
#include <rpc/pmap_prot.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <rpcsvc/yp_prot.h>
#include <rpcsvc/ypv1_prot.h>
#include <rpcsvc/ypclnt.h>
/* This should match the one in ypbind.c */
#define CACHE_DIR "/var/yp/binding"
extern int errno;
extern unsigned int sleep();
extern char *malloc();
extern char *strcpy();
enum bind_status {
BS_BAGIT,
BS_RETRY,
BS_OK
};
/*
* Time parameters when talking to the ypbind and pmap processes
*/
#define YPSLEEPTIME 5 /* Time to sleep between tries */
unsigned int _ypsleeptime = YPSLEEPTIME;
#define YPBIND_TIMEOUT 30 /* Total seconds for timeout */
#define YPBIND_INTER_TRY 30 /* Seconds between tries */
/*
* Time parameters when talking to the ypserv process
*/
#ifdef DEBUG
#define YPTIMEOUT 120 /* Total seconds for timeout */
#define YPINTER_TRY 60 /* Seconds between tries */
#else
#define YPTIMEOUT 20 /* Total seconds for timeout */
#define YPINTER_TRY 5 /* Seconds between tries */
#endif
#define MAX_TRIES_FOR_NEW_YP 1 /* Number of times we'll try to get
* a new YP server before we'll
* settle for an old one. */
static struct in_addr my_addr; /* Local internet addr */
static struct dom_binding *bound_domains; /* List of bound domains */
static char *default_domain;
static char bfname[YPMAXDOMAIN+32]; /* Binding file name */
static char bfvalid = TRUE; /* Binding file valid */
static int bf; /* Binding file fd */
/*
* binder_port holds what we believe to be the local port for ypbind. It is
* set only by talk2_pmap. It is cleared (set to 0) by:
* 1. talk2_pmap: always upon entry.
* 2. check_binder_up if:
* - It can't create a socket to speak to the binder.
* - If it fails to bind to the port.
* 3. talk2_binder if there are RPC errors when trying to use the port.
*/
static unsigned long binder_port; /* Initialize to "no port" */
/* These are used to distinguish which type of timeout is desired */
typedef enum { ypbind_intertry,
ypbind_timeout,
ypserv_intertry,
ypserv_timeout} time_types ;
/*
* This function allows the environment variable YPTIMEOUT to
* affect the amount of time spent waiting for server to time out
*/
struct timeval yprpc_time(time_types timetype)
{
static char *yptimeout=(char*)-1;
static int timeout=0;
struct timeval tv;
if (yptimeout==(char*)-1) {
yptimeout=getenv("YPTIMEOUT");
timeout=(yptimeout?atol(yptimeout):0);
}
tv.tv_usec=0;
if (timeout>0) {
tv.tv_sec=timeout;
} else {
switch(timetype) {
case ypbind_intertry:
tv.tv_sec=YPBIND_INTER_TRY;
break;
case ypbind_timeout:
tv.tv_sec=YPBIND_TIMEOUT;
break;
case ypserv_intertry:
tv.tv_sec=YPINTER_TRY;
break;
case ypserv_timeout:
/* intentional fall-through */
default:
tv.tv_sec=YPTIMEOUT;
}
}
return tv;
}
/*
* This checks to see if this is a new process incarnation which has
* inherited bindings from a parent, and unbinds the world if so.
*/
static void
newborn()
{
static long int mypid = 0; /* Cached to detect forks */
long int testpid;
if ((testpid = getpid() ) != mypid) {
mypid = testpid;
while (bound_domains) {
yp_unbind(bound_domains->dom_domain);
}
}
}
/*
* This checks that the socket for a domain which has already been bound
* hasn't been closed or changed under us. If it has, unbind the domain
* without closing the socket, which may be in use by some higher level
* code. This returns TRUE and points the binding parameter at the found
* dom_binding if the binding is found and the socket looks OK, and FALSE
* otherwise.
*/
static bool
check_binding(domain, binding)
char *domain;
struct dom_binding **binding;
{
struct dom_binding *pdomb;
struct sockaddr_in local_name;
int local_name_len = sizeof(struct sockaddr_in);
bool rebind = FALSE;
for (pdomb = bound_domains; pdomb != NULL; pdomb = pdomb->dom_pnext) {
if (strcmp(domain, pdomb->dom_domain) == 0) {
if (getsockname(pdomb->dom_socket,
(struct sockaddr *) &local_name,
&local_name_len) == 0) {
if (local_name.sin_family != AF_INET) {
rebind = TRUE;
}
if (pdomb->dom_local_port !=
local_name.sin_port) {
rebind = TRUE;
}
} else {
rebind = TRUE;
}
if (rebind) {
pdomb->dom_socket = -1;
yp_unbind(domain);
pdomb = (struct dom_binding *) NULL;
break;
} else {
*binding = pdomb;
return (TRUE);
}
}
}
return (FALSE);
}
/*
* This checks whether the portmapper is up. If the connect fails, the
* portmapper is dead. As a side effect, the pmapper sockaddr_in is
* initialized. The connection is not used for anything else, so it is
* immediately closed.
*
* If there is a valid binding file we assume pmap is up.
*/
static bool
check_pmap_up(pmapper, err)
struct sockaddr_in *pmapper;
int *err;
{
int sokt;
int status;
struct linger l = { 1, 0 };
pmapper->sin_addr = my_addr;
pmapper->sin_len = sizeof(struct sockaddr_in);
pmapper->sin_family = AF_INET;
pmapper->sin_port = htons(PMAPPORT);
bzero(pmapper->sin_zero, 8);
if (bf == -1) { /* No valid binding */
sokt = socket(AF_INET, SOCK_STREAM, 0);
if (sokt == -1) {
*err = YPERR_RESRC;
return (FALSE);
}
/*
* this prevents the closed socket from going into the
* TIME_WAIT state for a minute, holding onto 4 mbufs
* while it waits.
*/
(void) setsockopt(sokt, SOL_SOCKET, SO_LINGER, &l, sizeof(l));
if ((status = connect(sokt, (struct sockaddr *) pmapper,
sizeof(struct sockaddr_in))) < 0) {
(void) close(sokt);
*err = YPERR_PMAP;
return (FALSE);
}
(void) close(sokt);
}
return (TRUE);
}
/*
* This checks whether ypbind is up. If the bind succeeds, ypbind is dead,
* because the binder port returned from portmap should already be in use.
* There are two side effects. The ypbind sockaddr_in is initialized. If
* the function returns FALSE, the global binder_port will be set to 0.
*/
static bool
check_binder_up(ypbinder, err)
struct sockaddr_in *ypbinder;
int *err;
{
int sokt;
int status;
int bind_errno;
if (binder_port == 0) {
return (FALSE);
}
ypbinder->sin_addr = my_addr;
ypbinder->sin_len = sizeof(struct sockaddr_in);
ypbinder->sin_family = AF_INET;
ypbinder->sin_port = htons(binder_port);
bzero(ypbinder->sin_zero, 8);
sokt = socket(AF_INET, SOCK_DGRAM, 0); /* Throw-away socket */
if (sokt == -1) {
binder_port = 0;
*err = YPERR_RESRC;
return (FALSE);
}
errno = 0;
status = bind(sokt, (struct sockaddr *) ypbinder,
sizeof(struct sockaddr_in));
bind_errno = errno;
(void) close(sokt);
if (status == -1) {
if (bind_errno == EADDRINUSE) {
/*
* since we cannot grab the port, ypbind must be
* up and healthy.
*/
return (TRUE);
}
if ((bind_errno == EACCES) &&
(binder_port < IPPORT_RESERVED) &&
(geteuid() != 0)) {
/*
* The port is priviledged. This must be "secure"
* unix where have to use the yelow pages.
*/
return (TRUE);
}
}
binder_port = 0;
*err = YPERR_YPBIND;
return (FALSE);
}
/*
* This asks the portmapper for addressing info for ypbind speaking a passed
* program version number. If it gets that info, the port number is stashed
* in binder_port, but binder_port will be set to 0 when talk2_pmap returns
* anything except BS_OK. If the RPC call to the portmapper failed, the
* current process will be put to sleep for _ypsleeptime seconds before
* this function returns.
*/
static enum bind_status
talk2_pmap(pmapper, vers, err)
struct sockaddr_in *pmapper;
int vers;
int *err;
{
int sokt;
CLIENT *client;
struct pmap portmap;
enum clnt_stat clnt_stat;
binder_port = 0;
portmap.pm_prog = YPBINDPROG;
portmap.pm_vers = vers;
portmap.pm_prot = IPPROTO_UDP;
portmap.pm_port = 0; /* Don't care */
sokt = RPC_ANYSOCK;
if ((client = clntudp_bufcreate(pmapper, PMAPPROG, PMAPVERS,
yprpc_time(ypbind_intertry), &sokt, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE)) == NULL) {
*err = YPERR_RPC;
return (BS_BAGIT);
}
clnt_stat = (enum clnt_stat) clnt_call(client, PMAPPROC_GETPORT,
xdr_pmap, &portmap, xdr_u_long, &binder_port, yprpc_time(ypbind_timeout));
clnt_destroy(client);
(void) close(sokt);
if (clnt_stat == RPC_SUCCESS) {
if (binder_port != 0) {
return (BS_OK);
} else {
*err = YPERR_YPBIND;
return (BS_BAGIT);
}
} else {
(void) sleep(_ypsleeptime);
*err = YPERR_RPC;
return (BS_RETRY);
}
}
/*
* This talks to the local ypbind process, and asks for a binding for the
* passed domain. As a side effect, if a version mismatch is detected, the
* ypbind program version number may be changed to the old version. In the
* success case, the ypbind response will be returned as it was loaded by
* ypbind - that is, containing a valid binding. If the RPC call to ypbind
* failed, the current process will be put to sleep for _ypsleeptime seconds
* before this function returns.
*/
static enum bind_status
talk2_binder(ypbinder, vers, tries, ppdomain, ypbind_resp, err)
struct sockaddr_in *ypbinder;
int *vers;
int tries;
char **ppdomain;
struct ypbind_resp *ypbind_resp;
int *err;
{
int sokt;
CLIENT *client;
enum clnt_stat clnt_stat;
if ((bf != -1) && bfvalid) {
/* this should work but we check anyway */
bf = open(bfname,O_RDONLY);
if (bf != -1) {
lseek(bf,(long)(sizeof(u_short)),L_SET);
read(bf,ypbind_resp,sizeof(struct ypbind_resp));
close(bf);
clnt_stat = RPC_SUCCESS;
}
} else {
sokt = RPC_ANYSOCK;
if ((*vers == YPBINDVERS) && (tries > MAX_TRIES_FOR_NEW_YP) )
*vers = YPBINDOLDVERS;
if ((client = clntudp_bufcreate(ypbinder, YPBINDPROG, *vers,
yprpc_time(ypbind_intertry), &sokt, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE)) == NULL) {
*err = YPERR_RPC;
return (BS_BAGIT);
}
clnt_stat = (enum clnt_stat)clnt_call(client, YPBINDPROC_DOMAIN,
xdr_ypdomain_wrap_string, ppdomain, xdr_ypbind_resp,
ypbind_resp, yprpc_time(ypbind_timeout));
clnt_destroy(client);
(void) close(sokt);
bfvalid = (clnt_stat == RPC_SUCCESS);
}
if (clnt_stat == RPC_SUCCESS) {
if (ypbind_resp->ypbind_status == YPBIND_SUCC_VAL) {
/* Binding successfully returned from ypbind */
return (BS_OK);
} else {
if ( ((*vers == YPBINDVERS) &&
(tries < MAX_TRIES_FOR_NEW_YP)) ||
(*vers == YPBINDOLDVERS) ) {
(void) sleep(_ypsleeptime);
}
bfvalid = FALSE;
*err = YPERR_DOMAIN;
return (BS_RETRY);
}
} else {
bfvalid = FALSE;
if (clnt_stat == RPC_PROGVERSMISMATCH) {
if (*vers == YPBINDOLDVERS) {
*err = YPERR_YPBIND;
return (BS_BAGIT);
} else {
*vers = YPBINDOLDVERS;
}
} else {
(void) sleep(_ypsleeptime);
binder_port = 0;
}
*err = YPERR_RPC;
return (BS_RETRY);
}
}
/*
* This handles all the conversation with the portmapper to find the port
* ypbind is listening on. If binder_port is already non-zero, this returns
* BS_OK immediately without changing anything.
*/
static enum bind_status
get_binder_port(vers, err)
int vers; /* !ypbind! program version number */
int *err;
{
struct sockaddr_in pmapper;
if (binder_port) {
return (BS_OK);
}
if (!check_pmap_up(&pmapper, err) ) {
return (BS_BAGIT);
}
return (talk2_pmap(&pmapper, vers, err) );
}
/*
* This allocates some memory for a domain binding, initialize it, and
* returns a pointer to it. Based on the program version we ended up
* talking to ypbind with, fill out an opvector of appropriate protocol
* modules.
*/
static struct dom_binding *
load_dom_binding(ypbind_resp, vers, domain, err)
struct ypbind_resp *ypbind_resp;
int vers;
char *domain;
int *err;
{
struct dom_binding *pdomb;
struct sockaddr_in dummy; /* To get a port bound to socket */
struct sockaddr_in local_name;
int local_name_len = sizeof(struct sockaddr_in);
pdomb = (struct dom_binding *) NULL;
if ((pdomb = (struct dom_binding *) malloc(sizeof(struct dom_binding)))
== NULL) {
(void) fprintf(stderr, "load_dom_binding: malloc failure.\n");
*err = YPERR_RESRC;
return (struct dom_binding *) (NULL);
}
pdomb->dom_server_addr.sin_addr =
ypbind_resp->ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr;
pdomb->dom_server_addr.sin_family = AF_INET;
pdomb->dom_server_addr.sin_port =
ypbind_resp->ypbind_respbody.ypbind_bindinfo.ypbind_binding_port;
bzero(pdomb->dom_server_addr.sin_zero, 8);
pdomb->dom_server_port =
ypbind_resp->ypbind_respbody.ypbind_bindinfo.ypbind_binding_port;
pdomb->dom_socket = RPC_ANYSOCK;
pdomb->dom_vers = (vers == YPBINDOLDVERS) ? YPOLDVERS : YPVERS;
/*
* Open up a udp path to the server, which will remain active globally.
*/
if ((pdomb->dom_client = clntudp_bufcreate(&(pdomb->dom_server_addr),
YPPROG, ((vers == YPBINDVERS) ? YPVERS : YPOLDVERS) ,
yprpc_time(ypserv_intertry), &(pdomb->dom_socket), RPCSMALLMSGSIZE, YPMSGSZ))
== NULL) {
free((char *) pdomb);
*err = YPERR_RPC;
return (struct dom_binding *) (NULL);
}
/*
* Bind the socket to a bogus address so a port gets allocated for
* the socket, but so that sendto will still work.
*/
(void) fcntl(pdomb->dom_socket, F_SETFD, 1);
bzero((char *)&dummy, sizeof (dummy));
dummy.sin_family = AF_INET;
(void)bind(pdomb->dom_socket, (struct sockaddr *)&dummy, sizeof(dummy));
/*
* Remember the bound port number
*/
if (getsockname(pdomb->dom_socket, (struct sockaddr *) &local_name,
&local_name_len) == 0) {
pdomb->dom_local_port = local_name.sin_port;
} else {
free((char *) pdomb);
*err = YPERR_YPERR;
return (struct dom_binding *) (NULL);
}
(void) strcpy(pdomb->dom_domain, domain);/* Remember the domain name */
pdomb->dom_pnext = bound_domains; /* Link this to the list as */
bound_domains = pdomb; /* ... the head entry */
return (pdomb);
}
/*
* This checks to see if a ypserv which we know speaks v1 YP program number
* also speaks v2 version. This makes the assumption that the yp service at
* the node is supplied by a single process, and that RPC will deliver a
* message for a different program version number than that which the server
* regestered.
*/
static void
talk2_server(pdomb)
struct dom_binding *pdomb;
{
int sokt;
CLIENT *client;
enum clnt_stat clnt_stat;
sokt = RPC_ANYSOCK;
if ((client = clntudp_bufcreate(&(pdomb->dom_server_addr),
YPPROG, YPVERS, yprpc_time(ypserv_intertry), &sokt, RPCSMALLMSGSIZE, YPMSGSZ))
== NULL) {
return;
}
clnt_stat = (enum clnt_stat) clnt_call(client, YPBINDPROC_NULL,
xdr_void, 0, xdr_void, 0, yprpc_time(ypserv_timeout));
if (clnt_stat == RPC_SUCCESS) {
clnt_destroy(pdomb->dom_client);
(void) close(pdomb->dom_socket);
pdomb->dom_client = client;
pdomb->dom_socket = sokt;
pdomb->dom_vers = YPVERS;
} else {
clnt_destroy(client);
(void) close(sokt);
}
}
static char *
_default_domain()
{
char temp[256];
if (default_domain)
return (default_domain);
if (getdomainname(temp, sizeof(temp)))
return (0);
if (strlen(temp) > 0) {
default_domain = (char *)malloc(strlen(temp)+1);
if (default_domain == 0)
return (0);
strcpy(default_domain, temp);
return (default_domain);
}
return (0);
}
/*
* Handy utility function that other libc routine can call to
* see that are getting data from a yp map.
*/
int
usingypmap(ddn, map)
char **ddn; /* the default domainname set by this routine */
char *map; /* the map we are interested in. */
{
char in, *outval = NULL;
int outvallen, stat;
if (_default_domain() == 0) return (FALSE);
/* does the map exist ? */
in = 0xFF;
stat = yp_match(*ddn=default_domain, map, &in, 1, &outval, &outvallen);
if (outval != NULL)
free(outval);
switch (stat) {
case 0: /* it actually succeeded! */
case YPERR_KEY: /* no such key in map */
case YPERR_NOMORE:
case YPERR_BUSY:
return (TRUE);
}
return (FALSE);
}
/*
* Attempts to locate a yellow pages server that serves a passed domain. If
* one is found, an entry is created on the static list of domain-server pairs
* pointed to by cell bound_domains, a udp path to the server is created and
* the function returns 0. Otherwise, the function returns a defined errorcode
* YPERR_xxxx.
*/
int
_yp_dobind(domain, binding)
char *domain;
struct dom_binding **binding; /* if result == 0, ptr to dom_binding */
{
struct dom_binding *pdomb; /* Ptr to new domain binding */
struct sockaddr_in ypbinder; /* To talk with ypbinder */
char *pdomain; /* For xdr interface */
struct ypbind_resp ypbind_resp; /* Response from local ypbinder */
int vers; /* ypbind program version number */
int tries; /* Number of times we've tried with
* the current protocol */
int status;
u_short b_port;
enum bind_status loopctl;
bool bound;
bool oldport = FALSE;
if ( (domain == NULL) ||(strlen(domain) == 0) ) {
return (YPERR_BADARGS);
}
newborn();
if (bfvalid) {
/* the sprintf below has been replaced by several strcat */
/* calls to avoid having more of the stdio library dragged */
/* in. This keeps the size down of things like csh which */
/* use their own printf routines. CAR 7/5/88 */
/* sprintf(bfname,"%s/%s.%d",CACHE_DIR,domain,YPVERS); */
char prbuf[11];
register char *cp, *bfp;
unsigned long n = YPVERS;
strcpy(bfname,CACHE_DIR);
strcat(bfname,"/");
strcat(bfname,domain);
strcat(bfname,".");
bfp=bfname+strlen(bfname);
cp = prbuf;
do {
*cp++ = "0123456789"[n%10];
n /= 10;
} while (n);
do
*bfp++ = *--cp;
while (cp > prbuf);
if ((bf = open(bfname,O_RDONLY)) != -1) {
read(bf,&b_port,sizeof(u_short));
binder_port = b_port;
close(bf);
}
}
if (check_binding(domain, binding) )
return (0); /* We are bound */
/*
* Use loopback address.
*/
my_addr.s_addr = htonl(INADDR_LOOPBACK);
pdomain = domain;
/*
* Try to get the binder's port, using the current program version.
* The version may be changed to the old version, deep in the bowels
* of talk2_binder.
*/
for (bound = FALSE, vers = YPBINDVERS; !bound; ) {
if (binder_port) {
oldport = TRUE;
} else {
oldport = FALSE;
/*
* Get the binder's port. We'll loop as long as
* get_binder_port returns BS_RETRY.
*/
for (loopctl = BS_RETRY; loopctl != BS_OK; ) {
switch (loopctl =
get_binder_port(vers, &status) ) {
case BS_BAGIT:
return (status);
case BS_OK:
break;
}
}
}
/*
* See whether ypbind is up. If no, bag it if it's a
* resource error, or if we are using a port we just got
* from the port mapper. Otherwise loop around to try to
* get a valid port.
*/
if (!check_binder_up(&ypbinder, &status)) {
if (status == YPERR_RESRC) {
return (status);
}
if (!oldport && status == YPERR_YPBIND) {
return (status);
}
continue;
}
/*
* At this point, we think we know how to talk to the
* binder, and the binder is apparently alive. Until we
* succeed in binding the domain, or we know we can't ever
* bind the domain, we will try forever. This loops when
* talk2_binder returns BS_RETRY, and terminates when
* talk2_binder returns BS_BAGIT, or BS_OK. If binder_port
* gets cleared, we will not execute this loop again, but
* will go to the top of the enclosing loop to try to get
* the binder's port again. It is never the case that both
* talk2_binder returns BS_OK and that it clears the
* binder_port.
*/
for (loopctl = BS_RETRY, tries = 1;
binder_port && (loopctl != BS_OK); tries++) {
switch (loopctl = talk2_binder(&ypbinder, &vers,
tries, &pdomain, &ypbind_resp, &status) ) {
case BS_BAGIT:
return (status);
case BS_OK:
bound = TRUE;
}
}
}
if ( (pdomb = load_dom_binding(&ypbind_resp, vers, domain, &status) ) ==
(struct dom_binding *) NULL) {
return (status);
}
if (vers == YPBINDOLDVERS) {
talk2_server(pdomb);
}
*binding = pdomb; /* Return ptr to the binding
* entry */
return (0); /* This is the go path */
}
/*
* This is a "wrapper" function for _yp_dobind for vanilla user-level
* functions which neither know nor care about struct dom_bindings.
*/
int
yp_bind(domain)
char *domain;
{
struct dom_binding *binding;
return (_yp_dobind(domain, &binding) );
}
/*
* Attempts to find a dom_binding in the list at bound_domains having the
* domain name field equal to the passed domain name, and removes it if found.
* The domain-server binding will not exist after the call to this function.
* All resources associated with the binding will be freed.
*/
void
yp_unbind (domain)
char *domain;
{
struct dom_binding *pdomb;
struct dom_binding *ptrail;
if ( (domain == NULL) ||(strlen(domain) == 0) ) {
return;
}
bfvalid = FALSE; /* Don't use binding file again */
for (pdomb = bound_domains; pdomb != NULL;
ptrail = pdomb, pdomb = pdomb->dom_pnext) {
if (strcmp(domain, pdomb->dom_domain) == 0) {
if(pdomb->dom_client)
clnt_destroy(pdomb->dom_client);
(void) close(pdomb->dom_socket);
if (pdomb == bound_domains) {
bound_domains = pdomb->dom_pnext;
} else {
ptrail->dom_pnext = pdomb->dom_pnext;
}
free((char *) pdomb);
break;
}
}
}
/*
* This is a wrapper for the system call getdomainname which returns a
* ypclnt.h error code in the failure case. It also checks to see that
* the domain name is non-null, knowing that the null string is going to
* get rejected elsewhere in the yp client package.
*/
int
yp_get_default_domain(domain)
char **domain;
{
if ((*domain = _default_domain()) != 0)
return (0);
return (YPERR_YPERR);
}
/*
* Handy utility function that other libc routines can call to
* see that are getting data from a NIS map.
* e.g. if a yp_match fails and the stat is checked by this
* routine FALSE is a fatal error and you should stop using NIS
* TRUE means that the map exists and you should return
* the error.
*/
int
yp_ismapthere(stat)
int stat;
{
switch (stat) {
case 0: /* it actually succeeded! */
case YPERR_KEY: /* no such key in map */
case YPERR_NOMORE:
case YPERR_BUSY:
return (TRUE);
}
return (FALSE);
}