11919Swollman/*
21919Swollman * Copyright (c) 1992/3 Theo de Raadt <deraadt@fsa.ca>
334146Swpaul * Copyright (c) 1998 Bill Paul <wpaul@ctr.columbia.edu>
41919Swollman * All rights reserved.
51919Swollman *
61919Swollman * Redistribution and use in source and binary forms, with or without
71919Swollman * modification, are permitted provided that the following conditions
81919Swollman * are met:
91919Swollman * 1. Redistributions of source code must retain the above copyright
101919Swollman *    notice, this list of conditions and the following disclaimer.
111919Swollman * 2. Redistributions in binary form must reproduce the above copyright
121919Swollman *    notice, this list of conditions and the following disclaimer in the
131919Swollman *    documentation and/or other materials provided with the distribution.
141919Swollman * 3. The name of the author may not be used to endorse or promote
151919Swollman *    products derived from this software without specific prior written
161919Swollman *    permission.
171919Swollman *
181919Swollman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
191919Swollman * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
201919Swollman * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
211919Swollman * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
221919Swollman * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
231919Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
241919Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
251919Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
261919Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
271919Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
281919Swollman * SUCH DAMAGE.
291919Swollman */
301919Swollman
3192986Sobrien#include <sys/cdefs.h>
3292986Sobrien__FBSDID("$FreeBSD$");
331919Swollman
3471579Sdeischen#include "namespace.h"
35144678Sume#include "reentrant.h"
361919Swollman#include <sys/param.h>
371919Swollman#include <sys/types.h>
381919Swollman#include <sys/socket.h>
391919Swollman#include <sys/file.h>
401919Swollman#include <sys/uio.h>
4190868Smike#include <arpa/inet.h>
421919Swollman#include <errno.h>
431919Swollman#include <stdio.h>
441919Swollman#include <string.h>
457722Swpaul#include <stdlib.h>
467722Swpaul#include <unistd.h>
471919Swollman#include <rpc/rpc.h>
481919Swollman#include <rpc/xdr.h>
4912816Swpaul#include <rpcsvc/yp.h>
5071579Sdeischen#include "un-namespace.h"
5171579Sdeischen#include "libc_private.h"
5212816Swpaul
5312816Swpaul/*
5412816Swpaul * We have to define these here due to clashes between yp_prot.h and
5512816Swpaul * yp.h.
5612816Swpaul */
5712816Swpaul
5834146Swpaul#define YPMATCHCACHE
5934146Swpaul
6034146Swpaul#ifdef YPMATCHCACHE
6134146Swpaulstruct ypmatch_ent {
6234146Swpaul        char			*ypc_map;
6334146Swpaul	keydat			ypc_key;
6434146Swpaul	valdat			ypc_val;
6534146Swpaul        time_t			ypc_expire_t;
6634146Swpaul        struct ypmatch_ent	*ypc_next;
6734146Swpaul};
6834146Swpaul#define YPLIB_MAXCACHE	5	/* At most 5 entries */
6934146Swpaul#define YPLIB_EXPIRE	5	/* Expire after 5 seconds */
7034146Swpaul#endif
7134146Swpaul
7212816Swpaulstruct dom_binding {
7334146Swpaul        struct dom_binding *dom_pnext;
7434146Swpaul        char dom_domain[YPMAXDOMAIN + 1];
7534146Swpaul        struct sockaddr_in dom_server_addr;
7634146Swpaul        u_short dom_server_port;
7734146Swpaul        int dom_socket;
7834146Swpaul        CLIENT *dom_client;
7934146Swpaul        u_short dom_local_port; /* now I finally know what this is for. */
8034146Swpaul        long dom_vers;
8134146Swpaul#ifdef YPMATCHCACHE
8234146Swpaul	struct ypmatch_ent *cache;
8334146Swpaul	int ypmatch_cachecnt;
8434146Swpaul#endif
8512816Swpaul};
8612816Swpaul
871919Swollman#include <rpcsvc/ypclnt.h>
881919Swollman
891919Swollman#ifndef BINDINGDIR
901919Swollman#define BINDINGDIR "/var/yp/binding"
911919Swollman#endif
928091Swpaul#define MAX_RETRIES 20
931919Swollman
941919Swollmanextern bool_t xdr_domainname(), xdr_ypbind_resp();
951919Swollmanextern bool_t xdr_ypreq_key(), xdr_ypresp_val();
961919Swollmanextern bool_t xdr_ypreq_nokey(), xdr_ypresp_key_val();
971919Swollmanextern bool_t xdr_ypresp_all(), xdr_ypresp_all_seq();
981919Swollmanextern bool_t xdr_ypresp_master();
991919Swollman
1001919Swollmanint (*ypresp_allfn)();
1011919Swollmanvoid *ypresp_data;
1021919Swollman
10390297Sdesstatic void _yp_unbind(struct dom_binding *);
1041919Swollmanstruct dom_binding *_ypbindlist;
1051919Swollmanstatic char _yp_domain[MAXHOSTNAMELEN];
106167197Ssimonint _yplib_timeout = 20;
1071919Swollman
108144714Sumestatic mutex_t _ypmutex = MUTEX_INITIALIZER;
109144678Sume#define YPLOCK()	mutex_lock(&_ypmutex);
110144678Sume#define YPUNLOCK()	mutex_unlock(&_ypmutex);
111144678Sume
1121919Swollman#ifdef YPMATCHCACHE
11390298Sdesstatic void
11490298Sdesypmatch_cache_delete(struct dom_binding *ypdb, struct ypmatch_ent *prev,
11590298Sdes    struct ypmatch_ent *cur)
11634146Swpaul{
11734146Swpaul	if (prev == NULL)
11834146Swpaul		ypdb->cache = cur->ypc_next;
11934146Swpaul	else
12034146Swpaul		prev->ypc_next = cur->ypc_next;
1211919Swollman
12234146Swpaul	free(cur->ypc_map);
12334146Swpaul	free(cur->ypc_key.keydat_val);
12434146Swpaul	free(cur->ypc_val.valdat_val);
12534146Swpaul	free(cur);
1261919Swollman
12734146Swpaul	ypdb->ypmatch_cachecnt--;
12834146Swpaul
12934146Swpaul	return;
13034146Swpaul}
13134146Swpaul
13290298Sdesstatic void
13390298Sdesypmatch_cache_flush(struct dom_binding *ypdb)
1341919Swollman{
13534146Swpaul	struct ypmatch_ent	*n, *c = ypdb->cache;
1361919Swollman
13734146Swpaul	while (c != NULL) {
13834146Swpaul		n = c->ypc_next;
13934146Swpaul		ypmatch_cache_delete(ypdb, NULL, c);
14034146Swpaul		c = n;
14134146Swpaul	}
14234146Swpaul
14334146Swpaul	return;
14434146Swpaul}
14534146Swpaul
14690298Sdesstatic void
14790298Sdesypmatch_cache_expire(struct dom_binding *ypdb)
14834146Swpaul{
14934146Swpaul	struct ypmatch_ent	*c = ypdb->cache;
15034146Swpaul	struct ypmatch_ent	*n, *p = NULL;
15134146Swpaul	time_t			t;
15234146Swpaul
1531919Swollman	time(&t);
1541919Swollman
15534146Swpaul	while (c != NULL) {
15634146Swpaul		if (t >= c->ypc_expire_t) {
15734146Swpaul			n = c->ypc_next;
15834146Swpaul			ypmatch_cache_delete(ypdb, p, c);
15934146Swpaul			c = n;
16034146Swpaul		} else {
16134146Swpaul			p = c;
16234146Swpaul			c = c->ypc_next;
16334146Swpaul		}
1641919Swollman	}
1651919Swollman
16634146Swpaul	return;
16734146Swpaul}
1681919Swollman
16990298Sdesstatic void
17090298Sdesypmatch_cache_insert(struct dom_binding *ypdb, char *map, keydat *key,
17190298Sdes    valdat *val)
17234146Swpaul{
17334146Swpaul	struct ypmatch_ent	*new;
1741919Swollman
17534146Swpaul	/* Do an expire run to maybe open up a slot. */
17634146Swpaul	if (ypdb->ypmatch_cachecnt)
17734146Swpaul		ypmatch_cache_expire(ypdb);
17834146Swpaul
17934146Swpaul	/*
18034146Swpaul	 * If there are no slots free, then force an expire of
18134146Swpaul	 * the least recently used entry.
18234146Swpaul 	 */
18334146Swpaul	if (ypdb->ypmatch_cachecnt >= YPLIB_MAXCACHE) {
18434146Swpaul		struct ypmatch_ent	*o = NULL, *c = ypdb->cache;
18534146Swpaul		time_t			oldest = 0;
18634146Swpaul
18734146Swpaul		oldest = ~oldest;
18834146Swpaul
18990297Sdes		while (c != NULL) {
19034146Swpaul			if (c->ypc_expire_t < oldest) {
19134146Swpaul				oldest = c->ypc_expire_t;
19234146Swpaul				o = c;
19334146Swpaul			}
19434146Swpaul			c = c->ypc_next;
19534146Swpaul		}
19634146Swpaul
19734146Swpaul		if (o == NULL)
19834146Swpaul			return;
19934146Swpaul		o->ypc_expire_t = 0;
20034146Swpaul		ypmatch_cache_expire(ypdb);
20134146Swpaul	}
20234146Swpaul
20334146Swpaul	new = malloc(sizeof(struct ypmatch_ent));
20434146Swpaul	if (new == NULL)
2051919Swollman		return;
2061919Swollman
20734146Swpaul	new->ypc_map = strdup(map);
20834146Swpaul	if (new->ypc_map == NULL) {
20934146Swpaul		free(new);
2101919Swollman		return;
2111919Swollman	}
21234146Swpaul	new->ypc_key.keydat_val = malloc(key->keydat_len);
21334146Swpaul	if (new->ypc_key.keydat_val == NULL) {
21434146Swpaul		free(new->ypc_map);
21534146Swpaul		free(new);
21634146Swpaul		return;
21734146Swpaul	}
21834146Swpaul	new->ypc_val.valdat_val = malloc(val->valdat_len);
21934146Swpaul	if (new->ypc_val.valdat_val == NULL) {
22034146Swpaul		free(new->ypc_val.valdat_val);
22134146Swpaul		free(new->ypc_map);
22234146Swpaul		free(new);
22334146Swpaul		return;
22434146Swpaul	}
2251919Swollman
22634146Swpaul	new->ypc_expire_t = time(NULL) + YPLIB_EXPIRE;
22734146Swpaul	new->ypc_key.keydat_len = key->keydat_len;
22834146Swpaul	new->ypc_val.valdat_len = val->valdat_len;
22934146Swpaul	bcopy(key->keydat_val, new->ypc_key.keydat_val, key->keydat_len);
23034146Swpaul	bcopy(val->valdat_val, new->ypc_val.valdat_val, val->valdat_len);
2311919Swollman
23234146Swpaul	new->ypc_next = ypdb->cache;
23334146Swpaul	ypdb->cache = new;
2341919Swollman
23534146Swpaul	ypdb->ypmatch_cachecnt++;
23634146Swpaul
23734146Swpaul	return;
2381919Swollman}
2391919Swollman
24090298Sdesstatic bool_t
24190298Sdesypmatch_cache_lookup(struct dom_binding *ypdb, char *map, keydat *key,
24290298Sdes    valdat *val)
2431919Swollman{
244199784Swollman	struct ypmatch_ent	*c;
2451919Swollman
24634146Swpaul	ypmatch_cache_expire(ypdb);
2471919Swollman
24834146Swpaul	for (c = ypdb->cache; c != NULL; c = c->ypc_next) {
24934146Swpaul		if (strcmp(map, c->ypc_map))
2501919Swollman			continue;
25134146Swpaul		if (key->keydat_len != c->ypc_key.keydat_len)
2521919Swollman			continue;
25334146Swpaul		if (bcmp(key->keydat_val, c->ypc_key.keydat_val,
25434146Swpaul				key->keydat_len))
2551919Swollman			continue;
25634146Swpaul	}
2571919Swollman
25834146Swpaul	if (c == NULL)
25934146Swpaul		return(FALSE);
26034146Swpaul
26134146Swpaul	val->valdat_len = c->ypc_val.valdat_len;
26234146Swpaul	val->valdat_val = c->ypc_val.valdat_val;
26334146Swpaul
26434146Swpaul	return(TRUE);
2651919Swollman}
2661919Swollman#endif
2671919Swollman
26895658Sdesconst char *
26990298Sdesypbinderr_string(int incode)
2707982Swpaul{
2717982Swpaul	static char err[80];
27290297Sdes	switch (incode) {
2737982Swpaul	case 0:
27490297Sdes		return ("Success");
2758245Swpaul	case YPBIND_ERR_ERR:
27690297Sdes		return ("Internal ypbind error");
2778245Swpaul	case YPBIND_ERR_NOSERV:
27890297Sdes		return ("Domain not bound");
2798245Swpaul	case YPBIND_ERR_RESC:
28090297Sdes		return ("System resource allocation failure");
2817982Swpaul	}
2828245Swpaul	sprintf(err, "Unknown ypbind error: #%d\n", incode);
28390297Sdes	return (err);
2847982Swpaul}
2857982Swpaul
2861919Swollmanint
28790298Sdes_yp_dobind(char *dom, struct dom_binding **ypdb)
2881919Swollman{
28916096Sjraynard	static pid_t pid = -1;
2901919Swollman	char path[MAXPATHLEN];
2911919Swollman	struct dom_binding *ysd, *ysd2;
29212859Swpaul	struct ypbind_resp ypbr;
2931919Swollman	struct timeval tv;
2941919Swollman	struct sockaddr_in clnt_sin;
29517141Sjkh	int clnt_sock, fd;
29616106Sjraynard	pid_t gpid;
2971919Swollman	CLIENT *client;
2988091Swpaul	int new = 0, r;
2998091Swpaul	int retries = 0;
30016051Swpaul	struct sockaddr_in check;
301143415Sstefanf	socklen_t checklen = sizeof(struct sockaddr_in);
3021919Swollman
30324797Swpaul	/* Not allowed; bad doggie. Bad. */
30424797Swpaul	if (strchr(dom, '/') != NULL)
30524797Swpaul		return(YPERR_BADARGS);
30624797Swpaul
3071919Swollman	gpid = getpid();
30890297Sdes	if (!(pid == -1 || pid == gpid)) {
3091919Swollman		ysd = _ypbindlist;
31090297Sdes		while (ysd) {
31190297Sdes			if (ysd->dom_client != NULL)
31220716Swpaul				_yp_unbind(ysd);
3131919Swollman			ysd2 = ysd->dom_pnext;
3141919Swollman			free(ysd);
3151919Swollman			ysd = ysd2;
3161919Swollman		}
3171919Swollman		_ypbindlist = NULL;
3181919Swollman	}
3191919Swollman	pid = gpid;
3201919Swollman
32190297Sdes	if (ypdb != NULL)
3221919Swollman		*ypdb = NULL;
3231919Swollman
32490297Sdes	if (dom == NULL || strlen(dom) == 0)
32590297Sdes		return (YPERR_BADARGS);
3261919Swollman
32790297Sdes	for (ysd = _ypbindlist; ysd; ysd = ysd->dom_pnext)
32890297Sdes		if (strcmp(dom, ysd->dom_domain) == 0)
3291919Swollman			break;
33015547Swpaul
33116051Swpaul
33290297Sdes	if (ysd == NULL) {
3331919Swollman		ysd = (struct dom_binding *)malloc(sizeof *ysd);
334228828Sghelmer		if (ysd == NULL)
335228828Sghelmer			return (YPERR_RESRC);
3361919Swollman		bzero((char *)ysd, sizeof *ysd);
3371919Swollman		ysd->dom_socket = -1;
3381919Swollman		ysd->dom_vers = 0;
3391919Swollman		new = 1;
34016051Swpaul	} else {
34116051Swpaul	/* Check the socket -- may have been hosed by the caller. */
34271579Sdeischen		if (_getsockname(ysd->dom_socket, (struct sockaddr *)&check,
34316051Swpaul		    &checklen) == -1 || check.sin_family != AF_INET ||
34416051Swpaul		    check.sin_port != ysd->dom_local_port) {
34516051Swpaul		/* Socket became bogus somehow... need to rebind. */
34616051Swpaul			int save, sock;
34716051Swpaul
34816051Swpaul			sock = ysd->dom_socket;
34971579Sdeischen			save = _dup(ysd->dom_socket);
35019520Swpaul			if (ysd->dom_client != NULL)
35119520Swpaul				clnt_destroy(ysd->dom_client);
35216051Swpaul			ysd->dom_vers = 0;
35316051Swpaul			ysd->dom_client = NULL;
35471579Sdeischen			sock = _dup2(save, sock);
35556698Sjasone			_close(save);
35616051Swpaul		}
3571919Swollman	}
35812095Swpaul
3591919Swollmanagain:
3608091Swpaul	retries++;
3618091Swpaul	if (retries > MAX_RETRIES) {
3628091Swpaul		if (new)
3638091Swpaul			free(ysd);
3648091Swpaul		return(YPERR_YPBIND);
3658091Swpaul	}
3661919Swollman#ifdef BINDINGDIR
36790297Sdes	if (ysd->dom_vers == 0) {
36815547Swpaul		/*
36915547Swpaul		 * We're trying to make a new binding: zorch the
37015547Swpaul		 * existing handle now (if any).
37115547Swpaul		 */
37290297Sdes		if (ysd->dom_client != NULL) {
37315547Swpaul			clnt_destroy(ysd->dom_client);
37415547Swpaul			ysd->dom_client = NULL;
37516051Swpaul			ysd->dom_socket = -1;
37615547Swpaul		}
37754167Skris		snprintf(path, sizeof(path), "%s/%s.%d", BINDINGDIR, dom, 2);
378241046Sjilles		if ((fd = _open(path, O_RDONLY | O_CLOEXEC)) == -1) {
3791919Swollman			/* no binding file, YP is dead. */
3808091Swpaul			/* Try to bring it back to life. */
38156698Sjasone			_close(fd);
3828091Swpaul			goto skipit;
3831919Swollman		}
38490297Sdes		if (_flock(fd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK) {
3851919Swollman			struct iovec iov[2];
38612859Swpaul			struct ypbind_resp ybr;
3871919Swollman			u_short	ypb_port;
3881919Swollman
3891919Swollman			iov[0].iov_base = (caddr_t)&ypb_port;
3901919Swollman			iov[0].iov_len = sizeof ypb_port;
3911919Swollman			iov[1].iov_base = (caddr_t)&ybr;
3921919Swollman			iov[1].iov_len = sizeof ybr;
3931919Swollman
39471579Sdeischen			r = _readv(fd, iov, 2);
39590297Sdes			if (r != iov[0].iov_len + iov[1].iov_len) {
39656698Sjasone				_close(fd);
3971919Swollman				ysd->dom_vers = -1;
3981919Swollman				goto again;
3991919Swollman			}
4001919Swollman
4011919Swollman			bzero(&ysd->dom_server_addr, sizeof ysd->dom_server_addr);
4021919Swollman			ysd->dom_server_addr.sin_family = AF_INET;
4031919Swollman			ysd->dom_server_addr.sin_len = sizeof(struct sockaddr_in);
40489084Sjhb			bcopy(&ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr,
40589084Sjhb			    &ysd->dom_server_addr.sin_addr.s_addr,
40689084Sjhb			    sizeof(ysd->dom_server_addr.sin_addr.s_addr));
40789084Sjhb			bcopy(&ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port,
40889084Sjhb			    &ysd->dom_server_addr.sin_port,
40989084Sjhb			    sizeof(ysd->dom_server_addr.sin_port));
4101919Swollman
4111919Swollman			ysd->dom_server_port = ysd->dom_server_addr.sin_port;
41256698Sjasone			_close(fd);
4131919Swollman			goto gotit;
4141919Swollman		} else {
4151919Swollman			/* no lock on binding file, YP is dead. */
4168091Swpaul			/* Try to bring it back to life. */
41756698Sjasone			_close(fd);
4188091Swpaul			goto skipit;
4191919Swollman		}
4201919Swollman	}
4217722Swpaulskipit:
4221919Swollman#endif
42390297Sdes	if (ysd->dom_vers == -1 || ysd->dom_vers == 0) {
42415547Swpaul		/*
42515547Swpaul		 * We're trying to make a new binding: zorch the
42615547Swpaul		 * existing handle now (if any).
42715547Swpaul		 */
42890297Sdes		if (ysd->dom_client != NULL) {
42915547Swpaul			clnt_destroy(ysd->dom_client);
43015547Swpaul			ysd->dom_client = NULL;
43116051Swpaul			ysd->dom_socket = -1;
43215547Swpaul		}
4331919Swollman		bzero((char *)&clnt_sin, sizeof clnt_sin);
4341919Swollman		clnt_sin.sin_family = AF_INET;
4351919Swollman		clnt_sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
4368870Srgrimes
4371919Swollman		clnt_sock = RPC_ANYSOCK;
4381919Swollman		client = clnttcp_create(&clnt_sin, YPBINDPROG, YPBINDVERS, &clnt_sock,
4391919Swollman			0, 0);
44090297Sdes		if (client == NULL) {
44114776Swpaul			/*
44214776Swpaul			 * These conditions indicate ypbind just isn't
44314776Swpaul			 * alive -- we probably don't want to shoot our
44415547Swpaul			 * mouth off in this case; instead generate error
44514776Swpaul			 * messages only for really exotic problems.
44614776Swpaul			 */
44714776Swpaul			if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED &&
44814776Swpaul			   (rpc_createerr.cf_stat != RPC_SYSTEMERROR &&
44915547Swpaul			   rpc_createerr.cf_error.re_errno == ECONNREFUSED))
45015547Swpaul				clnt_pcreateerror("clnttcp_create");
45190297Sdes			if (new)
4521919Swollman				free(ysd);
4538091Swpaul			return (YPERR_YPBIND);
4541919Swollman		}
4551919Swollman
45617162Swpaul		/*
45717162Swpaul		 * Check the port number -- should be < IPPORT_RESERVED.
45817162Swpaul		 * If not, it's possible someone has registered a bogus
45917162Swpaul		 * ypbind with the portmapper and is trying to trick us.
46017162Swpaul		 */
46117162Swpaul		if (ntohs(clnt_sin.sin_port) >= IPPORT_RESERVED) {
46219520Swpaul			if (client != NULL)
46319520Swpaul				clnt_destroy(client);
46417162Swpaul			if (new)
46517162Swpaul				free(ysd);
46617162Swpaul			return(YPERR_YPBIND);
46717162Swpaul		}
4688091Swpaul		tv.tv_sec = _yplib_timeout/2;
4691919Swollman		tv.tv_usec = 0;
4701919Swollman		r = clnt_call(client, YPBINDPROC_DOMAIN,
47195658Sdes			(xdrproc_t)xdr_domainname, &dom,
47295658Sdes			(xdrproc_t)xdr_ypbind_resp, &ypbr, tv);
47390297Sdes		if (r != RPC_SUCCESS) {
47414776Swpaul			clnt_destroy(client);
47514776Swpaul			ysd->dom_vers = -1;
47616051Swpaul			if (r == RPC_PROGUNAVAIL || r == RPC_PROCUNAVAIL) {
47716051Swpaul				if (new)
47816051Swpaul					free(ysd);
47914776Swpaul				return(YPERR_YPBIND);
48016051Swpaul			}
4811919Swollman			fprintf(stderr,
4827721Swpaul			"YP: server for domain %s not responding, retrying\n", dom);
4831919Swollman			goto again;
4847982Swpaul		} else {
4857982Swpaul			if (ypbr.ypbind_status != YPBIND_SUCC_VAL) {
48656698Sjasone				struct timespec time_to_sleep, time_remaining;
48790297Sdes
4888091Swpaul				clnt_destroy(client);
4898091Swpaul				ysd->dom_vers = -1;
49056698Sjasone
49156698Sjasone				time_to_sleep.tv_sec = _yplib_timeout/2;
49256698Sjasone				time_to_sleep.tv_nsec = 0;
49356698Sjasone				_nanosleep(&time_to_sleep,
49456698Sjasone				    &time_remaining);
4958091Swpaul				goto again;
4967982Swpaul			}
4971919Swollman		}
4981919Swollman		clnt_destroy(client);
4991919Swollman
5001919Swollman		bzero((char *)&ysd->dom_server_addr, sizeof ysd->dom_server_addr);
5011919Swollman		ysd->dom_server_addr.sin_family = AF_INET;
50289084Sjhb		bcopy(&ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port,
50389084Sjhb		    &ysd->dom_server_addr.sin_port,
50489084Sjhb		    sizeof(ysd->dom_server_addr.sin_port));
50589084Sjhb		bcopy(&ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr,
50689084Sjhb		    &ysd->dom_server_addr.sin_addr.s_addr,
50789084Sjhb		    sizeof(ysd->dom_server_addr.sin_addr.s_addr));
50817162Swpaul
50917162Swpaul		/*
51017162Swpaul		 * We could do a reserved port check here too, but this
51117162Swpaul		 * could pose compatibility problems. The local ypbind is
51217162Swpaul		 * supposed to decide whether or not to trust yp servers
51317162Swpaul		 * on insecure ports. For now, we trust its judgement.
51417162Swpaul		 */
5151919Swollman		ysd->dom_server_port =
51612859Swpaul			*(u_short *)&ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port;
5171919Swollmangotit:
5181919Swollman		ysd->dom_vers = YPVERS;
519114443Snectar		strlcpy(ysd->dom_domain, dom, sizeof(ysd->dom_domain));
5201919Swollman	}
5211919Swollman
52215547Swpaul	/* Don't rebuild the connection to the server unless we have to. */
52315547Swpaul	if (ysd->dom_client == NULL) {
52415547Swpaul		tv.tv_sec = _yplib_timeout/2;
52515547Swpaul		tv.tv_usec = 0;
52615547Swpaul		ysd->dom_socket = RPC_ANYSOCK;
52734146Swpaul		ysd->dom_client = clntudp_bufcreate(&ysd->dom_server_addr,
52834146Swpaul			YPPROG, YPVERS, tv, &ysd->dom_socket, 1280, 2304);
52990297Sdes		if (ysd->dom_client == NULL) {
53015547Swpaul			clnt_pcreateerror("clntudp_create");
53115547Swpaul			ysd->dom_vers = -1;
53215547Swpaul			goto again;
53315547Swpaul		}
53490297Sdes		if (_fcntl(ysd->dom_socket, F_SETFD, 1) == -1)
53515547Swpaul			perror("fcntl: F_SETFD");
53616051Swpaul		/*
53716051Swpaul		 * We want a port number associated with this socket
53816051Swpaul		 * so that we can check its authenticity later.
53916051Swpaul		 */
54016051Swpaul		checklen = sizeof(struct sockaddr_in);
54116051Swpaul		bzero((char *)&check, checklen);
54271579Sdeischen		_bind(ysd->dom_socket, (struct sockaddr *)&check, checklen);
54316051Swpaul		check.sin_family = AF_INET;
54471579Sdeischen		if (!_getsockname(ysd->dom_socket,
54516051Swpaul		    (struct sockaddr *)&check, &checklen)) {
54616051Swpaul			ysd->dom_local_port = check.sin_port;
54716051Swpaul		} else {
54816051Swpaul			clnt_destroy(ysd->dom_client);
54916051Swpaul			if (new)
55016051Swpaul				free(ysd);
55116051Swpaul			return(YPERR_YPBIND);
55216051Swpaul		}
5531919Swollman	}
5541919Swollman
55590297Sdes	if (new) {
5561919Swollman		ysd->dom_pnext = _ypbindlist;
5571919Swollman		_ypbindlist = ysd;
5581919Swollman	}
5591919Swollman
560171563Ssimon	/*
561171563Ssimon	 * Set low retry timeout to realistically handle UDP packet
562171563Ssimon	 * loss for YP packet bursts.
563171563Ssimon	 */
564171563Ssimon	tv.tv_sec = 1;
565171563Ssimon	tv.tv_usec = 0;
566171563Ssimon	clnt_control(ysd->dom_client, CLSET_RETRY_TIMEOUT, (char*)&tv);
567171563Ssimon
56890297Sdes	if (ypdb != NULL)
5691919Swollman		*ypdb = ysd;
57090297Sdes	return (0);
5711919Swollman}
5721919Swollman
5731919Swollmanstatic void
57490298Sdes_yp_unbind(struct dom_binding *ypb)
5751919Swollman{
57619520Swpaul	struct sockaddr_in check;
577143415Sstefanf	socklen_t checklen = sizeof(struct sockaddr_in);
57819520Swpaul
57919520Swpaul	if (ypb->dom_client != NULL) {
58019520Swpaul		/* Check the socket -- may have been hosed by the caller. */
58171579Sdeischen		if (_getsockname(ypb->dom_socket, (struct sockaddr *)&check,
58219520Swpaul	    	&checklen) == -1 || check.sin_family != AF_INET ||
58319520Swpaul	    	check.sin_port != ypb->dom_local_port) {
58419520Swpaul			int save, sock;
58519520Swpaul
58619520Swpaul			sock = ypb->dom_socket;
58771579Sdeischen			save = _dup(ypb->dom_socket);
58819520Swpaul			clnt_destroy(ypb->dom_client);
58971579Sdeischen			sock = _dup2(save, sock);
59056698Sjasone			_close(save);
59119520Swpaul		} else
59219520Swpaul			clnt_destroy(ypb->dom_client);
59319520Swpaul	}
59419520Swpaul
5951919Swollman	ypb->dom_client = NULL;
5961919Swollman	ypb->dom_socket = -1;
59715793Swpaul	ypb->dom_vers = -1;
59834146Swpaul#ifdef YPMATCHCACHE
59934146Swpaul	ypmatch_cache_flush(ypb);
60034146Swpaul#endif
6011919Swollman}
6021919Swollman
603145849Sumestatic int
604145849Sumeyp_bind_locked(char *dom)
605145849Sume{
606145849Sume	return (_yp_dobind(dom, NULL));
607145849Sume}
608145849Sume
6091919Swollmanint
61090298Sdesyp_bind(char *dom)
6111919Swollman{
612145849Sume	int r;
613145849Sume
614145849Sume	YPLOCK();
615145849Sume	r = yp_bind_locked(dom);
616145849Sume	YPUNLOCK();
617145849Sume	return (r);
6181919Swollman}
6191919Swollman
620145849Sumestatic void
621145849Sumeyp_unbind_locked(char *dom)
6221919Swollman{
6231919Swollman	struct dom_binding *ypb, *ypbp;
6241919Swollman
6251919Swollman	ypbp = NULL;
62690297Sdes	for (ypb = _ypbindlist; ypb; ypb = ypb->dom_pnext) {
62790297Sdes		if (strcmp(dom, ypb->dom_domain) == 0) {
62815793Swpaul			_yp_unbind(ypb);
62990297Sdes			if (ypbp)
6301919Swollman				ypbp->dom_pnext = ypb->dom_pnext;
6311919Swollman			else
6321919Swollman				_ypbindlist = ypb->dom_pnext;
6331919Swollman			free(ypb);
6341919Swollman			return;
6351919Swollman		}
6361919Swollman		ypbp = ypb;
6371919Swollman	}
6381919Swollman	return;
6391919Swollman}
6401919Swollman
641145849Sumevoid
642145849Sumeyp_unbind(char *dom)
643145849Sume{
644145849Sume	YPLOCK();
645145849Sume	yp_unbind_locked(dom);
646145849Sume	YPUNLOCK();
647145849Sume}
648145849Sume
6491919Swollmanint
65090298Sdesyp_match(char *indomain, char *inmap, const char *inkey, int inkeylen,
65190298Sdes    char **outval, int *outvallen)
6521919Swollman{
6531919Swollman	struct dom_binding *ysd;
6541919Swollman	struct ypresp_val yprv;
6551919Swollman	struct timeval tv;
6561919Swollman	struct ypreq_key yprk;
6571919Swollman	int r;
6581919Swollman
6591919Swollman	*outval = NULL;
6601919Swollman	*outvallen = 0;
6611919Swollman
6627337Swpaul	/* Sanity check */
6637290Swpaul
6647337Swpaul	if (inkey == NULL || !strlen(inkey) || inkeylen <= 0 ||
6657337Swpaul	    inmap == NULL || !strlen(inmap) ||
6667337Swpaul	    indomain == NULL || !strlen(indomain))
66790297Sdes		return (YPERR_BADARGS);
6687290Swpaul
669145849Sume	YPLOCK();
670145849Sume	if (_yp_dobind(indomain, &ysd) != 0) {
671145849Sume		YPUNLOCK();
67234146Swpaul		return(YPERR_DOMAIN);
673145849Sume	}
67434146Swpaul
67534146Swpaul	yprk.domain = indomain;
67634146Swpaul	yprk.map = inmap;
67734146Swpaul	yprk.key.keydat_val = (char *)inkey;
67834146Swpaul	yprk.key.keydat_len = inkeylen;
67934146Swpaul
6801919Swollman#ifdef YPMATCHCACHE
68134146Swpaul	if (ypmatch_cache_lookup(ysd, yprk.map, &yprk.key, &yprv.val) == TRUE) {
68234146Swpaul/*
68390297Sdes	if (!strcmp(_yp_domain, indomain) && ypmatch_find(inmap, inkey,
68412816Swpaul	    inkeylen, &yprv.val.valdat_val, &yprv.val.valdat_len)) {
68534146Swpaul*/
68612816Swpaul		*outvallen = yprv.val.valdat_len;
6871919Swollman		*outval = (char *)malloc(*outvallen+1);
688228828Sghelmer		if (*outval == NULL) {
689228828Sghelmer			_yp_unbind(ysd);
690228828Sghelmer			*outvallen = 0;
691228828Sghelmer			YPUNLOCK();
692228828Sghelmer			return (YPERR_RESRC);
693228828Sghelmer		}
69412816Swpaul		bcopy(yprv.val.valdat_val, *outval, *outvallen);
6951919Swollman		(*outval)[*outvallen] = '\0';
696145849Sume		YPUNLOCK();
69790297Sdes		return (0);
6981919Swollman	}
699228828Sghelmer	_yp_unbind(ysd);
7001919Swollman#endif
7011919Swollman
70210522Swpaulagain:
703145849Sume	if (_yp_dobind(indomain, &ysd) != 0) {
704145849Sume		YPUNLOCK();
70590297Sdes		return (YPERR_DOMAIN);
706145849Sume	}
70710522Swpaul
7081919Swollman	tv.tv_sec = _yplib_timeout;
7091919Swollman	tv.tv_usec = 0;
7101919Swollman
7111919Swollman	bzero((char *)&yprv, sizeof yprv);
7121919Swollman
7131919Swollman	r = clnt_call(ysd->dom_client, YPPROC_MATCH,
71495658Sdes		(xdrproc_t)xdr_ypreq_key, &yprk,
71595658Sdes		(xdrproc_t)xdr_ypresp_val, &yprv, tv);
71690297Sdes	if (r != RPC_SUCCESS) {
7171919Swollman		clnt_perror(ysd->dom_client, "yp_match: clnt_call");
71815793Swpaul		_yp_unbind(ysd);
7191919Swollman		goto again;
7201919Swollman	}
72115547Swpaul
72290297Sdes	if (!(r = ypprot_err(yprv.stat))) {
72312816Swpaul		*outvallen = yprv.val.valdat_len;
7241919Swollman		*outval = (char *)malloc(*outvallen+1);
725228828Sghelmer		if (*outval == NULL) {
726228828Sghelmer			_yp_unbind(ysd);
727228828Sghelmer			*outvallen = 0;
728228828Sghelmer			xdr_free((xdrproc_t)xdr_ypresp_val, &yprv);
729228828Sghelmer			YPUNLOCK();
730228828Sghelmer			return (YPERR_RESRC);
731228828Sghelmer		}
73212816Swpaul		bcopy(yprv.val.valdat_val, *outval, *outvallen);
7331919Swollman		(*outval)[*outvallen] = '\0';
7341919Swollman#ifdef YPMATCHCACHE
73534146Swpaul		ypmatch_cache_insert(ysd, yprk.map, &yprk.key, &yprv.val);
7361919Swollman#endif
73715793Swpaul	}
73815547Swpaul
73995658Sdes	xdr_free((xdrproc_t)xdr_ypresp_val, &yprv);
740145849Sume	YPUNLOCK();
74190297Sdes	return (r);
7421919Swollman}
7431919Swollman
744144678Sumestatic int
745144678Sumeyp_get_default_domain_locked(char **domp)
7461919Swollman{
7471919Swollman	*domp = NULL;
74890297Sdes	if (_yp_domain[0] == '\0')
74990297Sdes		if (getdomainname(_yp_domain, sizeof _yp_domain))
75090297Sdes			return (YPERR_NODOM);
7511919Swollman	*domp = _yp_domain;
75290297Sdes	return (0);
7531919Swollman}
7541919Swollman
7551919Swollmanint
756144678Sumeyp_get_default_domain(char **domp)
757144678Sume{
758144678Sume	int r;
759144678Sume
760144678Sume	YPLOCK();
761144678Sume	r = yp_get_default_domain_locked(domp);
762144678Sume	YPUNLOCK();
763144678Sume	return (r);
764144678Sume}
765144678Sume
766144678Sumeint
76790298Sdesyp_first(char *indomain, char *inmap, char **outkey, int *outkeylen,
76890298Sdes    char **outval, int *outvallen)
7691919Swollman{
7701919Swollman	struct ypresp_key_val yprkv;
7711919Swollman	struct ypreq_nokey yprnk;
7721919Swollman	struct dom_binding *ysd;
7731919Swollman	struct timeval tv;
7741919Swollman	int r;
7751919Swollman
7767337Swpaul	/* Sanity check */
7777337Swpaul
7787337Swpaul	if (indomain == NULL || !strlen(indomain) ||
7797337Swpaul	    inmap == NULL || !strlen(inmap))
78090297Sdes		return (YPERR_BADARGS);
7817337Swpaul
7821919Swollman	*outkey = *outval = NULL;
7831919Swollman	*outkeylen = *outvallen = 0;
7841919Swollman
785145849Sume	YPLOCK();
7861919Swollmanagain:
787145849Sume	if (_yp_dobind(indomain, &ysd) != 0) {
788145849Sume		YPUNLOCK();
78990297Sdes		return (YPERR_DOMAIN);
790145849Sume	}
7911919Swollman
7921919Swollman	tv.tv_sec = _yplib_timeout;
7931919Swollman	tv.tv_usec = 0;
7941919Swollman
7951919Swollman	yprnk.domain = indomain;
7961919Swollman	yprnk.map = inmap;
7971919Swollman	bzero((char *)&yprkv, sizeof yprkv);
7981919Swollman
7991919Swollman	r = clnt_call(ysd->dom_client, YPPROC_FIRST,
80095658Sdes		(xdrproc_t)xdr_ypreq_nokey, &yprnk,
80195658Sdes		(xdrproc_t)xdr_ypresp_key_val, &yprkv, tv);
80290297Sdes	if (r != RPC_SUCCESS) {
8031919Swollman		clnt_perror(ysd->dom_client, "yp_first: clnt_call");
80415793Swpaul		_yp_unbind(ysd);
8051919Swollman		goto again;
8061919Swollman	}
80790297Sdes	if (!(r = ypprot_err(yprkv.stat))) {
80812816Swpaul		*outkeylen = yprkv.key.keydat_len;
8091919Swollman		*outkey = (char *)malloc(*outkeylen+1);
810228828Sghelmer		if (*outkey == NULL) {
811228828Sghelmer			_yp_unbind(ysd);
812228828Sghelmer			*outkeylen = 0;
813228828Sghelmer			xdr_free((xdrproc_t)xdr_ypresp_key_val, &yprkv);
814228828Sghelmer			YPUNLOCK();
815228828Sghelmer			return (YPERR_RESRC);
816228828Sghelmer		}
81712816Swpaul		bcopy(yprkv.key.keydat_val, *outkey, *outkeylen);
8181919Swollman		(*outkey)[*outkeylen] = '\0';
81912816Swpaul		*outvallen = yprkv.val.valdat_len;
8201919Swollman		*outval = (char *)malloc(*outvallen+1);
821228828Sghelmer		if (*outval == NULL) {
822228828Sghelmer			free(*outkey);
823228828Sghelmer			_yp_unbind(ysd);
824228828Sghelmer			*outkeylen = *outvallen = 0;
825228828Sghelmer			xdr_free((xdrproc_t)xdr_ypresp_key_val, &yprkv);
826228828Sghelmer			YPUNLOCK();
827228828Sghelmer			return (YPERR_RESRC);
828228828Sghelmer		}
82912816Swpaul		bcopy(yprkv.val.valdat_val, *outval, *outvallen);
8301919Swollman		(*outval)[*outvallen] = '\0';
83115793Swpaul	}
83215547Swpaul
83395658Sdes	xdr_free((xdrproc_t)xdr_ypresp_key_val, &yprkv);
834145849Sume	YPUNLOCK();
83590297Sdes	return (r);
8361919Swollman}
8371919Swollman
8381919Swollmanint
83990298Sdesyp_next(char *indomain, char *inmap, char *inkey, int inkeylen,
84090298Sdes    char **outkey, int *outkeylen, char **outval, int *outvallen)
8411919Swollman{
8421919Swollman	struct ypresp_key_val yprkv;
8431919Swollman	struct ypreq_key yprk;
8441919Swollman	struct dom_binding *ysd;
8451919Swollman	struct timeval tv;
8461919Swollman	int r;
8471919Swollman
8487337Swpaul	/* Sanity check */
8497337Swpaul
8507337Swpaul	if (inkey == NULL || !strlen(inkey) || inkeylen <= 0 ||
8517337Swpaul	    inmap == NULL || !strlen(inmap) ||
8527337Swpaul	    indomain == NULL || !strlen(indomain))
85390297Sdes		return (YPERR_BADARGS);
8547337Swpaul
8551919Swollman	*outkey = *outval = NULL;
8561919Swollman	*outkeylen = *outvallen = 0;
8571919Swollman
858145849Sume	YPLOCK();
8591919Swollmanagain:
860145849Sume	if (_yp_dobind(indomain, &ysd) != 0) {
861145849Sume		YPUNLOCK();
86290297Sdes		return (YPERR_DOMAIN);
863145849Sume	}
8641919Swollman
8651919Swollman	tv.tv_sec = _yplib_timeout;
8661919Swollman	tv.tv_usec = 0;
8671919Swollman
8681919Swollman	yprk.domain = indomain;
8691919Swollman	yprk.map = inmap;
87012816Swpaul	yprk.key.keydat_val = inkey;
87112816Swpaul	yprk.key.keydat_len = inkeylen;
8721919Swollman	bzero((char *)&yprkv, sizeof yprkv);
8731919Swollman
8741919Swollman	r = clnt_call(ysd->dom_client, YPPROC_NEXT,
87595658Sdes		(xdrproc_t)xdr_ypreq_key, &yprk,
87695658Sdes		(xdrproc_t)xdr_ypresp_key_val, &yprkv, tv);
87790297Sdes	if (r != RPC_SUCCESS) {
8781919Swollman		clnt_perror(ysd->dom_client, "yp_next: clnt_call");
87915793Swpaul		_yp_unbind(ysd);
8801919Swollman		goto again;
8811919Swollman	}
88290297Sdes	if (!(r = ypprot_err(yprkv.stat))) {
88312816Swpaul		*outkeylen = yprkv.key.keydat_len;
8841919Swollman		*outkey = (char *)malloc(*outkeylen+1);
885228828Sghelmer		if (*outkey == NULL) {
886228828Sghelmer			_yp_unbind(ysd);
887228828Sghelmer			*outkeylen = 0;
888228828Sghelmer			xdr_free((xdrproc_t)xdr_ypresp_key_val, &yprkv);
889228828Sghelmer			YPUNLOCK();
890228828Sghelmer			return (YPERR_RESRC);
891228828Sghelmer		}
89212816Swpaul		bcopy(yprkv.key.keydat_val, *outkey, *outkeylen);
8931919Swollman		(*outkey)[*outkeylen] = '\0';
89412816Swpaul		*outvallen = yprkv.val.valdat_len;
8951919Swollman		*outval = (char *)malloc(*outvallen+1);
896228828Sghelmer		if (*outval == NULL) {
897228828Sghelmer			free(*outkey);
898228828Sghelmer			_yp_unbind(ysd);
899228828Sghelmer			*outkeylen = *outvallen = 0;
900228828Sghelmer			xdr_free((xdrproc_t)xdr_ypresp_key_val, &yprkv);
901228828Sghelmer			YPUNLOCK();
902228828Sghelmer			return (YPERR_RESRC);
903228828Sghelmer		}
90412816Swpaul		bcopy(yprkv.val.valdat_val, *outval, *outvallen);
9051919Swollman		(*outval)[*outvallen] = '\0';
90615793Swpaul	}
90715547Swpaul
90895658Sdes	xdr_free((xdrproc_t)xdr_ypresp_key_val, &yprkv);
909145849Sume	YPUNLOCK();
91090297Sdes	return (r);
9111919Swollman}
9121919Swollman
9131919Swollmanint
91490298Sdesyp_all(char *indomain, char *inmap, struct ypall_callback *incallback)
9151919Swollman{
9161919Swollman	struct ypreq_nokey yprnk;
9171919Swollman	struct dom_binding *ysd;
9181919Swollman	struct timeval tv;
9191919Swollman	struct sockaddr_in clnt_sin;
9201919Swollman	CLIENT *clnt;
92114719Swpaul	u_long status, savstat;
9221919Swollman	int clnt_sock;
9231919Swollman
9247337Swpaul	/* Sanity check */
9257337Swpaul
9267337Swpaul	if (indomain == NULL || !strlen(indomain) ||
9277337Swpaul	    inmap == NULL || !strlen(inmap))
92890297Sdes		return (YPERR_BADARGS);
9297337Swpaul
930145849Sume	YPLOCK();
93115793Swpaulagain:
93215793Swpaul
933145849Sume	if (_yp_dobind(indomain, &ysd) != 0) {
934145849Sume		YPUNLOCK();
93590297Sdes		return (YPERR_DOMAIN);
936145849Sume	}
9371919Swollman
9381919Swollman	tv.tv_sec = _yplib_timeout;
9391919Swollman	tv.tv_usec = 0;
94015793Swpaul
94115793Swpaul	/* YPPROC_ALL manufactures its own channel to ypserv using TCP */
94215793Swpaul
9431919Swollman	clnt_sock = RPC_ANYSOCK;
9441919Swollman	clnt_sin = ysd->dom_server_addr;
9451919Swollman	clnt_sin.sin_port = 0;
9461919Swollman	clnt = clnttcp_create(&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0);
94790297Sdes	if (clnt == NULL) {
948145849Sume		YPUNLOCK();
9491919Swollman		printf("clnttcp_create failed\n");
95090297Sdes		return (YPERR_PMAP);
9511919Swollman	}
9521919Swollman
9531919Swollman	yprnk.domain = indomain;
9541919Swollman	yprnk.map = inmap;
9551919Swollman	ypresp_allfn = incallback->foreach;
9561919Swollman	ypresp_data = (void *)incallback->data;
9571919Swollman
95815793Swpaul	if (clnt_call(clnt, YPPROC_ALL,
95995658Sdes		(xdrproc_t)xdr_ypreq_nokey, &yprnk,
96095658Sdes		(xdrproc_t)xdr_ypresp_all_seq, &status, tv) != RPC_SUCCESS) {
96177044Spirzyk			clnt_perror(ysd->dom_client, "yp_all: clnt_call");
96215793Swpaul			clnt_destroy(clnt);
96315793Swpaul			_yp_unbind(ysd);
96415793Swpaul			goto again;
96515793Swpaul	}
96615793Swpaul
9671919Swollman	clnt_destroy(clnt);
96814719Swpaul	savstat = status;
96995658Sdes	xdr_free((xdrproc_t)xdr_ypresp_all_seq, &status);	/* not really needed... */
970145849Sume	YPUNLOCK();
97190297Sdes	if (savstat != YP_NOMORE)
97290297Sdes		return (ypprot_err(savstat));
97390297Sdes	return (0);
9741919Swollman}
9751919Swollman
9761919Swollmanint
97790298Sdesyp_order(char *indomain, char *inmap, int *outorder)
9781919Swollman{
9791919Swollman 	struct dom_binding *ysd;
9801919Swollman	struct ypresp_order ypro;
9811919Swollman	struct ypreq_nokey yprnk;
9821919Swollman	struct timeval tv;
9831919Swollman	int r;
9841919Swollman
9857337Swpaul	/* Sanity check */
9867337Swpaul
9877337Swpaul	if (indomain == NULL || !strlen(indomain) ||
9887337Swpaul	    inmap == NULL || !strlen(inmap))
98990297Sdes		return (YPERR_BADARGS);
9907337Swpaul
991145849Sume	YPLOCK();
9921919Swollmanagain:
993145849Sume	if (_yp_dobind(indomain, &ysd) != 0) {
994145849Sume		YPUNLOCK();
99590297Sdes		return (YPERR_DOMAIN);
996145849Sume	}
9971919Swollman
9981919Swollman	tv.tv_sec = _yplib_timeout;
9991919Swollman	tv.tv_usec = 0;
10001919Swollman
10011919Swollman	yprnk.domain = indomain;
10021919Swollman	yprnk.map = inmap;
10031919Swollman
10041919Swollman	bzero((char *)(char *)&ypro, sizeof ypro);
10051919Swollman
10061919Swollman	r = clnt_call(ysd->dom_client, YPPROC_ORDER,
100795658Sdes		(xdrproc_t)xdr_ypreq_nokey, &yprnk,
100895658Sdes		(xdrproc_t)xdr_ypresp_order, &ypro, tv);
100919520Swpaul
101019520Swpaul	/*
101119520Swpaul	 * NIS+ in YP compat mode doesn't support the YPPROC_ORDER
101219520Swpaul	 * procedure.
101319520Swpaul	 */
101419520Swpaul	if (r == RPC_PROCUNAVAIL) {
1015145849Sume		YPUNLOCK();
101619520Swpaul		return(YPERR_YPERR);
101719520Swpaul	}
101890297Sdes
101990297Sdes	if (r != RPC_SUCCESS) {
10201919Swollman		clnt_perror(ysd->dom_client, "yp_order: clnt_call");
102115793Swpaul		_yp_unbind(ysd);
10221919Swollman		goto again;
10231919Swollman	}
10241919Swollman
102590297Sdes	if (!(r = ypprot_err(ypro.stat))) {
102615547Swpaul		*outorder = ypro.ordernum;
102715793Swpaul	}
102815547Swpaul
102995658Sdes	xdr_free((xdrproc_t)xdr_ypresp_order, &ypro);
1030145849Sume	YPUNLOCK();
103115793Swpaul	return (r);
10321919Swollman}
10331919Swollman
10341919Swollmanint
103590298Sdesyp_master(char *indomain, char *inmap, char **outname)
10361919Swollman{
10371919Swollman	struct dom_binding *ysd;
10381919Swollman	struct ypresp_master yprm;
10391919Swollman	struct ypreq_nokey yprnk;
10401919Swollman	struct timeval tv;
10411919Swollman	int r;
10421919Swollman
10437337Swpaul	/* Sanity check */
10447337Swpaul
10457337Swpaul	if (indomain == NULL || !strlen(indomain) ||
10467337Swpaul	    inmap == NULL || !strlen(inmap))
104790297Sdes		return (YPERR_BADARGS);
1048145849Sume	YPLOCK();
10491919Swollmanagain:
1050145849Sume	if (_yp_dobind(indomain, &ysd) != 0) {
1051145849Sume		YPUNLOCK();
105290297Sdes		return (YPERR_DOMAIN);
1053145849Sume	}
10541919Swollman
10551919Swollman	tv.tv_sec = _yplib_timeout;
10561919Swollman	tv.tv_usec = 0;
10571919Swollman
10581919Swollman	yprnk.domain = indomain;
10591919Swollman	yprnk.map = inmap;
10601919Swollman
10611919Swollman	bzero((char *)&yprm, sizeof yprm);
10621919Swollman
10631919Swollman	r = clnt_call(ysd->dom_client, YPPROC_MASTER,
106495658Sdes		(xdrproc_t)xdr_ypreq_nokey, &yprnk,
106595658Sdes		(xdrproc_t)xdr_ypresp_master, &yprm, tv);
106690297Sdes	if (r != RPC_SUCCESS) {
10671919Swollman		clnt_perror(ysd->dom_client, "yp_master: clnt_call");
106815793Swpaul		_yp_unbind(ysd);
10691919Swollman		goto again;
10701919Swollman	}
107115793Swpaul
107290297Sdes	if (!(r = ypprot_err(yprm.stat))) {
107312816Swpaul		*outname = (char *)strdup(yprm.peer);
107415793Swpaul	}
107515547Swpaul
107695658Sdes	xdr_free((xdrproc_t)xdr_ypresp_master, &yprm);
1077145849Sume	YPUNLOCK();
107815793Swpaul	return (r);
10791919Swollman}
108090298Sdes
10817722Swpaulint
108290298Sdesyp_maplist(char *indomain, struct ypmaplist **outmaplist)
10831919Swollman{
10841919Swollman	struct dom_binding *ysd;
10851919Swollman	struct ypresp_maplist ypml;
10861919Swollman	struct timeval tv;
10871919Swollman	int r;
10881919Swollman
10897337Swpaul	/* Sanity check */
10907337Swpaul
10917337Swpaul	if (indomain == NULL || !strlen(indomain))
109290297Sdes		return (YPERR_BADARGS);
10937337Swpaul
1094145849Sume	YPLOCK();
10951919Swollmanagain:
1096145849Sume	if (_yp_dobind(indomain, &ysd) != 0) {
1097145849Sume		YPUNLOCK();
109890297Sdes		return (YPERR_DOMAIN);
1099145849Sume	}
11001919Swollman
11011919Swollman	tv.tv_sec = _yplib_timeout;
11021919Swollman	tv.tv_usec = 0;
11031919Swollman
11041919Swollman	bzero((char *)&ypml, sizeof ypml);
11051919Swollman
11061919Swollman	r = clnt_call(ysd->dom_client, YPPROC_MAPLIST,
110795658Sdes		(xdrproc_t)xdr_domainname, &indomain,
110895658Sdes		(xdrproc_t)xdr_ypresp_maplist, &ypml,tv);
11091919Swollman	if (r != RPC_SUCCESS) {
11101919Swollman		clnt_perror(ysd->dom_client, "yp_maplist: clnt_call");
111115793Swpaul		_yp_unbind(ysd);
11121919Swollman		goto again;
11131919Swollman	}
111490297Sdes	if (!(r = ypprot_err(ypml.stat))) {
111515547Swpaul		*outmaplist = ypml.maps;
111615793Swpaul	}
111715793Swpaul
111895658Sdes	/* NO: xdr_free((xdrproc_t)xdr_ypresp_maplist, &ypml);*/
1119145849Sume	YPUNLOCK();
112015793Swpaul	return (r);
11211919Swollman}
11221919Swollman
112395658Sdesconst char *
112490298Sdesyperr_string(int incode)
11251919Swollman{
11261919Swollman	static char err[80];
11271919Swollman
112890297Sdes	switch (incode) {
11291919Swollman	case 0:
113090297Sdes		return ("Success");
11311919Swollman	case YPERR_BADARGS:
113290297Sdes		return ("Request arguments bad");
11331919Swollman	case YPERR_RPC:
113490297Sdes		return ("RPC failure");
11351919Swollman	case YPERR_DOMAIN:
113690297Sdes		return ("Can't bind to server which serves this domain");
11371919Swollman	case YPERR_MAP:
113890297Sdes		return ("No such map in server's domain");
11391919Swollman	case YPERR_KEY:
114090297Sdes		return ("No such key in map");
11411919Swollman	case YPERR_YPERR:
114290297Sdes		return ("YP server error");
11431919Swollman	case YPERR_RESRC:
114490297Sdes		return ("Local resource allocation failure");
11451919Swollman	case YPERR_NOMORE:
114690297Sdes		return ("No more records in map database");
11471919Swollman	case YPERR_PMAP:
114890297Sdes		return ("Can't communicate with portmapper");
11491919Swollman	case YPERR_YPBIND:
115090297Sdes		return ("Can't communicate with ypbind");
11511919Swollman	case YPERR_YPSERV:
115290297Sdes		return ("Can't communicate with ypserv");
11531919Swollman	case YPERR_NODOM:
115490297Sdes		return ("Local domain name not set");
11551919Swollman	case YPERR_BADDB:
115690297Sdes		return ("Server data base is bad");
11571919Swollman	case YPERR_VERS:
115890297Sdes		return ("YP server version mismatch - server can't supply service.");
11591919Swollman	case YPERR_ACCESS:
116090297Sdes		return ("Access violation");
11611919Swollman	case YPERR_BUSY:
116290297Sdes		return ("Database is busy");
11631919Swollman	}
11641919Swollman	sprintf(err, "YP unknown error %d\n", incode);
116590297Sdes	return (err);
11661919Swollman}
11671919Swollman
11681919Swollmanint
116990298Sdesypprot_err(unsigned int incode)
11701919Swollman{
117190297Sdes	switch (incode) {
11721919Swollman	case YP_TRUE:
117390297Sdes		return (0);
11741919Swollman	case YP_FALSE:
117590297Sdes		return (YPERR_YPBIND);
11761919Swollman	case YP_NOMORE:
117790297Sdes		return (YPERR_NOMORE);
11781919Swollman	case YP_NOMAP:
117990297Sdes		return (YPERR_MAP);
11801919Swollman	case YP_NODOM:
118190297Sdes		return (YPERR_DOMAIN);
11821919Swollman	case YP_NOKEY:
118390297Sdes		return (YPERR_KEY);
11841919Swollman	case YP_BADOP:
118590297Sdes		return (YPERR_YPERR);
11861919Swollman	case YP_BADDB:
118790297Sdes		return (YPERR_BADDB);
11881919Swollman	case YP_YPERR:
118990297Sdes		return (YPERR_YPERR);
11901919Swollman	case YP_BADARGS:
119190297Sdes		return (YPERR_BADARGS);
11921919Swollman	case YP_VERS:
119390297Sdes		return (YPERR_VERS);
11941919Swollman	}
119590297Sdes	return (YPERR_YPERR);
11961919Swollman}
11971919Swollman
11981919Swollmanint
119990298Sdes_yp_check(char **dom)
12001919Swollman{
12011919Swollman	char *unused;
12021919Swollman
1203144678Sume	YPLOCK();
120490297Sdes	if (_yp_domain[0]=='\0')
1205144678Sume		if (yp_get_default_domain_locked(&unused)) {
1206144678Sume			YPUNLOCK();
120790297Sdes			return (0);
1208144678Sume		}
12091919Swollman
121090297Sdes	if (dom)
12111919Swollman		*dom = _yp_domain;
12121919Swollman
1213145849Sume	if (yp_bind_locked(_yp_domain) == 0) {
1214145849Sume		yp_unbind_locked(_yp_domain);
1215144678Sume		YPUNLOCK();
121690297Sdes		return (1);
121712095Swpaul	}
1218144678Sume	YPUNLOCK();
121990297Sdes	return (0);
12201919Swollman}
1221