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);
3341919Swollman		bzero((char *)ysd, sizeof *ysd);
3351919Swollman		ysd->dom_socket = -1;
3361919Swollman		ysd->dom_vers = 0;
3371919Swollman		new = 1;
33816051Swpaul	} else {
33916051Swpaul	/* Check the socket -- may have been hosed by the caller. */
34071579Sdeischen		if (_getsockname(ysd->dom_socket, (struct sockaddr *)&check,
34116051Swpaul		    &checklen) == -1 || check.sin_family != AF_INET ||
34216051Swpaul		    check.sin_port != ysd->dom_local_port) {
34316051Swpaul		/* Socket became bogus somehow... need to rebind. */
34416051Swpaul			int save, sock;
34516051Swpaul
34616051Swpaul			sock = ysd->dom_socket;
34771579Sdeischen			save = _dup(ysd->dom_socket);
34819520Swpaul			if (ysd->dom_client != NULL)
34919520Swpaul				clnt_destroy(ysd->dom_client);
35016051Swpaul			ysd->dom_vers = 0;
35116051Swpaul			ysd->dom_client = NULL;
35271579Sdeischen			sock = _dup2(save, sock);
35356698Sjasone			_close(save);
35416051Swpaul		}
3551919Swollman	}
35612095Swpaul
3571919Swollmanagain:
3588091Swpaul	retries++;
3598091Swpaul	if (retries > MAX_RETRIES) {
3608091Swpaul		if (new)
3618091Swpaul			free(ysd);
3628091Swpaul		return(YPERR_YPBIND);
3638091Swpaul	}
3641919Swollman#ifdef BINDINGDIR
36590297Sdes	if (ysd->dom_vers == 0) {
36615547Swpaul		/*
36715547Swpaul		 * We're trying to make a new binding: zorch the
36815547Swpaul		 * existing handle now (if any).
36915547Swpaul		 */
37090297Sdes		if (ysd->dom_client != NULL) {
37115547Swpaul			clnt_destroy(ysd->dom_client);
37215547Swpaul			ysd->dom_client = NULL;
37316051Swpaul			ysd->dom_socket = -1;
37415547Swpaul		}
37554167Skris		snprintf(path, sizeof(path), "%s/%s.%d", BINDINGDIR, dom, 2);
376261813Sjilles		if ((fd = _open(path, O_RDONLY | O_CLOEXEC)) == -1) {
3771919Swollman			/* no binding file, YP is dead. */
3788091Swpaul			/* Try to bring it back to life. */
37956698Sjasone			_close(fd);
3808091Swpaul			goto skipit;
3811919Swollman		}
38290297Sdes		if (_flock(fd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK) {
3831919Swollman			struct iovec iov[2];
38412859Swpaul			struct ypbind_resp ybr;
3851919Swollman			u_short	ypb_port;
3861919Swollman
3871919Swollman			iov[0].iov_base = (caddr_t)&ypb_port;
3881919Swollman			iov[0].iov_len = sizeof ypb_port;
3891919Swollman			iov[1].iov_base = (caddr_t)&ybr;
3901919Swollman			iov[1].iov_len = sizeof ybr;
3911919Swollman
39271579Sdeischen			r = _readv(fd, iov, 2);
39390297Sdes			if (r != iov[0].iov_len + iov[1].iov_len) {
39456698Sjasone				_close(fd);
3951919Swollman				ysd->dom_vers = -1;
3961919Swollman				goto again;
3971919Swollman			}
3981919Swollman
3991919Swollman			bzero(&ysd->dom_server_addr, sizeof ysd->dom_server_addr);
4001919Swollman			ysd->dom_server_addr.sin_family = AF_INET;
4011919Swollman			ysd->dom_server_addr.sin_len = sizeof(struct sockaddr_in);
40289084Sjhb			bcopy(&ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr,
40389084Sjhb			    &ysd->dom_server_addr.sin_addr.s_addr,
40489084Sjhb			    sizeof(ysd->dom_server_addr.sin_addr.s_addr));
40589084Sjhb			bcopy(&ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port,
40689084Sjhb			    &ysd->dom_server_addr.sin_port,
40789084Sjhb			    sizeof(ysd->dom_server_addr.sin_port));
4081919Swollman
4091919Swollman			ysd->dom_server_port = ysd->dom_server_addr.sin_port;
41056698Sjasone			_close(fd);
4111919Swollman			goto gotit;
4121919Swollman		} else {
4131919Swollman			/* no lock on binding file, YP is dead. */
4148091Swpaul			/* Try to bring it back to life. */
41556698Sjasone			_close(fd);
4168091Swpaul			goto skipit;
4171919Swollman		}
4181919Swollman	}
4197722Swpaulskipit:
4201919Swollman#endif
42190297Sdes	if (ysd->dom_vers == -1 || ysd->dom_vers == 0) {
42215547Swpaul		/*
42315547Swpaul		 * We're trying to make a new binding: zorch the
42415547Swpaul		 * existing handle now (if any).
42515547Swpaul		 */
42690297Sdes		if (ysd->dom_client != NULL) {
42715547Swpaul			clnt_destroy(ysd->dom_client);
42815547Swpaul			ysd->dom_client = NULL;
42916051Swpaul			ysd->dom_socket = -1;
43015547Swpaul		}
4311919Swollman		bzero((char *)&clnt_sin, sizeof clnt_sin);
4321919Swollman		clnt_sin.sin_family = AF_INET;
4331919Swollman		clnt_sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
4348870Srgrimes
4351919Swollman		clnt_sock = RPC_ANYSOCK;
4361919Swollman		client = clnttcp_create(&clnt_sin, YPBINDPROG, YPBINDVERS, &clnt_sock,
4371919Swollman			0, 0);
43890297Sdes		if (client == NULL) {
43914776Swpaul			/*
44014776Swpaul			 * These conditions indicate ypbind just isn't
44114776Swpaul			 * alive -- we probably don't want to shoot our
44215547Swpaul			 * mouth off in this case; instead generate error
44314776Swpaul			 * messages only for really exotic problems.
44414776Swpaul			 */
44514776Swpaul			if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED &&
44614776Swpaul			   (rpc_createerr.cf_stat != RPC_SYSTEMERROR &&
44715547Swpaul			   rpc_createerr.cf_error.re_errno == ECONNREFUSED))
44815547Swpaul				clnt_pcreateerror("clnttcp_create");
44990297Sdes			if (new)
4501919Swollman				free(ysd);
4518091Swpaul			return (YPERR_YPBIND);
4521919Swollman		}
4531919Swollman
45417162Swpaul		/*
45517162Swpaul		 * Check the port number -- should be < IPPORT_RESERVED.
45617162Swpaul		 * If not, it's possible someone has registered a bogus
45717162Swpaul		 * ypbind with the portmapper and is trying to trick us.
45817162Swpaul		 */
45917162Swpaul		if (ntohs(clnt_sin.sin_port) >= IPPORT_RESERVED) {
46019520Swpaul			if (client != NULL)
46119520Swpaul				clnt_destroy(client);
46217162Swpaul			if (new)
46317162Swpaul				free(ysd);
46417162Swpaul			return(YPERR_YPBIND);
46517162Swpaul		}
4668091Swpaul		tv.tv_sec = _yplib_timeout/2;
4671919Swollman		tv.tv_usec = 0;
4681919Swollman		r = clnt_call(client, YPBINDPROC_DOMAIN,
46995658Sdes			(xdrproc_t)xdr_domainname, &dom,
47095658Sdes			(xdrproc_t)xdr_ypbind_resp, &ypbr, tv);
47190297Sdes		if (r != RPC_SUCCESS) {
47214776Swpaul			clnt_destroy(client);
47314776Swpaul			ysd->dom_vers = -1;
47416051Swpaul			if (r == RPC_PROGUNAVAIL || r == RPC_PROCUNAVAIL) {
47516051Swpaul				if (new)
47616051Swpaul					free(ysd);
47714776Swpaul				return(YPERR_YPBIND);
47816051Swpaul			}
4791919Swollman			fprintf(stderr,
4807721Swpaul			"YP: server for domain %s not responding, retrying\n", dom);
4811919Swollman			goto again;
4827982Swpaul		} else {
4837982Swpaul			if (ypbr.ypbind_status != YPBIND_SUCC_VAL) {
48456698Sjasone				struct timespec time_to_sleep, time_remaining;
48590297Sdes
4868091Swpaul				clnt_destroy(client);
4878091Swpaul				ysd->dom_vers = -1;
48856698Sjasone
48956698Sjasone				time_to_sleep.tv_sec = _yplib_timeout/2;
49056698Sjasone				time_to_sleep.tv_nsec = 0;
49156698Sjasone				_nanosleep(&time_to_sleep,
49256698Sjasone				    &time_remaining);
4938091Swpaul				goto again;
4947982Swpaul			}
4951919Swollman		}
4961919Swollman		clnt_destroy(client);
4971919Swollman
4981919Swollman		bzero((char *)&ysd->dom_server_addr, sizeof ysd->dom_server_addr);
4991919Swollman		ysd->dom_server_addr.sin_family = AF_INET;
50089084Sjhb		bcopy(&ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port,
50189084Sjhb		    &ysd->dom_server_addr.sin_port,
50289084Sjhb		    sizeof(ysd->dom_server_addr.sin_port));
50389084Sjhb		bcopy(&ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr,
50489084Sjhb		    &ysd->dom_server_addr.sin_addr.s_addr,
50589084Sjhb		    sizeof(ysd->dom_server_addr.sin_addr.s_addr));
50617162Swpaul
50717162Swpaul		/*
50817162Swpaul		 * We could do a reserved port check here too, but this
50917162Swpaul		 * could pose compatibility problems. The local ypbind is
51017162Swpaul		 * supposed to decide whether or not to trust yp servers
51117162Swpaul		 * on insecure ports. For now, we trust its judgement.
51217162Swpaul		 */
5131919Swollman		ysd->dom_server_port =
51412859Swpaul			*(u_short *)&ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port;
5151919Swollmangotit:
5161919Swollman		ysd->dom_vers = YPVERS;
517114443Snectar		strlcpy(ysd->dom_domain, dom, sizeof(ysd->dom_domain));
5181919Swollman	}
5191919Swollman
52015547Swpaul	/* Don't rebuild the connection to the server unless we have to. */
52115547Swpaul	if (ysd->dom_client == NULL) {
52215547Swpaul		tv.tv_sec = _yplib_timeout/2;
52315547Swpaul		tv.tv_usec = 0;
52415547Swpaul		ysd->dom_socket = RPC_ANYSOCK;
52534146Swpaul		ysd->dom_client = clntudp_bufcreate(&ysd->dom_server_addr,
52634146Swpaul			YPPROG, YPVERS, tv, &ysd->dom_socket, 1280, 2304);
52790297Sdes		if (ysd->dom_client == NULL) {
52815547Swpaul			clnt_pcreateerror("clntudp_create");
52915547Swpaul			ysd->dom_vers = -1;
53015547Swpaul			goto again;
53115547Swpaul		}
53290297Sdes		if (_fcntl(ysd->dom_socket, F_SETFD, 1) == -1)
53315547Swpaul			perror("fcntl: F_SETFD");
53416051Swpaul		/*
53516051Swpaul		 * We want a port number associated with this socket
53616051Swpaul		 * so that we can check its authenticity later.
53716051Swpaul		 */
53816051Swpaul		checklen = sizeof(struct sockaddr_in);
53916051Swpaul		bzero((char *)&check, checklen);
54071579Sdeischen		_bind(ysd->dom_socket, (struct sockaddr *)&check, checklen);
54116051Swpaul		check.sin_family = AF_INET;
54271579Sdeischen		if (!_getsockname(ysd->dom_socket,
54316051Swpaul		    (struct sockaddr *)&check, &checklen)) {
54416051Swpaul			ysd->dom_local_port = check.sin_port;
54516051Swpaul		} else {
54616051Swpaul			clnt_destroy(ysd->dom_client);
54716051Swpaul			if (new)
54816051Swpaul				free(ysd);
54916051Swpaul			return(YPERR_YPBIND);
55016051Swpaul		}
5511919Swollman	}
5521919Swollman
55390297Sdes	if (new) {
5541919Swollman		ysd->dom_pnext = _ypbindlist;
5551919Swollman		_ypbindlist = ysd;
5561919Swollman	}
5571919Swollman
558171563Ssimon	/*
559171563Ssimon	 * Set low retry timeout to realistically handle UDP packet
560171563Ssimon	 * loss for YP packet bursts.
561171563Ssimon	 */
562171563Ssimon	tv.tv_sec = 1;
563171563Ssimon	tv.tv_usec = 0;
564171563Ssimon	clnt_control(ysd->dom_client, CLSET_RETRY_TIMEOUT, (char*)&tv);
565171563Ssimon
56690297Sdes	if (ypdb != NULL)
5671919Swollman		*ypdb = ysd;
56890297Sdes	return (0);
5691919Swollman}
5701919Swollman
5711919Swollmanstatic void
57290298Sdes_yp_unbind(struct dom_binding *ypb)
5731919Swollman{
57419520Swpaul	struct sockaddr_in check;
575143415Sstefanf	socklen_t checklen = sizeof(struct sockaddr_in);
57619520Swpaul
57719520Swpaul	if (ypb->dom_client != NULL) {
57819520Swpaul		/* Check the socket -- may have been hosed by the caller. */
57971579Sdeischen		if (_getsockname(ypb->dom_socket, (struct sockaddr *)&check,
58019520Swpaul	    	&checklen) == -1 || check.sin_family != AF_INET ||
58119520Swpaul	    	check.sin_port != ypb->dom_local_port) {
58219520Swpaul			int save, sock;
58319520Swpaul
58419520Swpaul			sock = ypb->dom_socket;
58571579Sdeischen			save = _dup(ypb->dom_socket);
58619520Swpaul			clnt_destroy(ypb->dom_client);
58771579Sdeischen			sock = _dup2(save, sock);
58856698Sjasone			_close(save);
58919520Swpaul		} else
59019520Swpaul			clnt_destroy(ypb->dom_client);
59119520Swpaul	}
59219520Swpaul
5931919Swollman	ypb->dom_client = NULL;
5941919Swollman	ypb->dom_socket = -1;
59515793Swpaul	ypb->dom_vers = -1;
59634146Swpaul#ifdef YPMATCHCACHE
59734146Swpaul	ypmatch_cache_flush(ypb);
59834146Swpaul#endif
5991919Swollman}
6001919Swollman
601145849Sumestatic int
602145849Sumeyp_bind_locked(char *dom)
603145849Sume{
604145849Sume	return (_yp_dobind(dom, NULL));
605145849Sume}
606145849Sume
6071919Swollmanint
60890298Sdesyp_bind(char *dom)
6091919Swollman{
610145849Sume	int r;
611145849Sume
612145849Sume	YPLOCK();
613145849Sume	r = yp_bind_locked(dom);
614145849Sume	YPUNLOCK();
615145849Sume	return (r);
6161919Swollman}
6171919Swollman
618145849Sumestatic void
619145849Sumeyp_unbind_locked(char *dom)
6201919Swollman{
6211919Swollman	struct dom_binding *ypb, *ypbp;
6221919Swollman
6231919Swollman	ypbp = NULL;
62490297Sdes	for (ypb = _ypbindlist; ypb; ypb = ypb->dom_pnext) {
62590297Sdes		if (strcmp(dom, ypb->dom_domain) == 0) {
62615793Swpaul			_yp_unbind(ypb);
62790297Sdes			if (ypbp)
6281919Swollman				ypbp->dom_pnext = ypb->dom_pnext;
6291919Swollman			else
6301919Swollman				_ypbindlist = ypb->dom_pnext;
6311919Swollman			free(ypb);
6321919Swollman			return;
6331919Swollman		}
6341919Swollman		ypbp = ypb;
6351919Swollman	}
6361919Swollman	return;
6371919Swollman}
6381919Swollman
639145849Sumevoid
640145849Sumeyp_unbind(char *dom)
641145849Sume{
642145849Sume	YPLOCK();
643145849Sume	yp_unbind_locked(dom);
644145849Sume	YPUNLOCK();
645145849Sume}
646145849Sume
6471919Swollmanint
64890298Sdesyp_match(char *indomain, char *inmap, const char *inkey, int inkeylen,
64990298Sdes    char **outval, int *outvallen)
6501919Swollman{
6511919Swollman	struct dom_binding *ysd;
6521919Swollman	struct ypresp_val yprv;
6531919Swollman	struct timeval tv;
6541919Swollman	struct ypreq_key yprk;
6551919Swollman	int r;
656293896Sglebius	int retries = 0;
6571919Swollman	*outval = NULL;
6581919Swollman	*outvallen = 0;
6591919Swollman
6607337Swpaul	/* Sanity check */
6617290Swpaul
6627337Swpaul	if (inkey == NULL || !strlen(inkey) || inkeylen <= 0 ||
6637337Swpaul	    inmap == NULL || !strlen(inmap) ||
6647337Swpaul	    indomain == NULL || !strlen(indomain))
66590297Sdes		return (YPERR_BADARGS);
6667290Swpaul
667145849Sume	YPLOCK();
668145849Sume	if (_yp_dobind(indomain, &ysd) != 0) {
669145849Sume		YPUNLOCK();
67034146Swpaul		return(YPERR_DOMAIN);
671145849Sume	}
67234146Swpaul
67334146Swpaul	yprk.domain = indomain;
67434146Swpaul	yprk.map = inmap;
67534146Swpaul	yprk.key.keydat_val = (char *)inkey;
67634146Swpaul	yprk.key.keydat_len = inkeylen;
67734146Swpaul
6781919Swollman#ifdef YPMATCHCACHE
67934146Swpaul	if (ypmatch_cache_lookup(ysd, yprk.map, &yprk.key, &yprv.val) == TRUE) {
68034146Swpaul/*
68190297Sdes	if (!strcmp(_yp_domain, indomain) && ypmatch_find(inmap, inkey,
68212816Swpaul	    inkeylen, &yprv.val.valdat_val, &yprv.val.valdat_len)) {
68334146Swpaul*/
68412816Swpaul		*outvallen = yprv.val.valdat_len;
6851919Swollman		*outval = (char *)malloc(*outvallen+1);
68612816Swpaul		bcopy(yprv.val.valdat_val, *outval, *outvallen);
6871919Swollman		(*outval)[*outvallen] = '\0';
688145849Sume		YPUNLOCK();
68990297Sdes		return (0);
6901919Swollman	}
6911919Swollman#endif
6921919Swollman
69310522Swpaulagain:
694293896Sglebius	if (retries > MAX_RETRIES) {
695293896Sglebius		YPUNLOCK();
696293896Sglebius		return (YPERR_RPC);
697293896Sglebius	}
698293896Sglebius
699145849Sume	if (_yp_dobind(indomain, &ysd) != 0) {
700145849Sume		YPUNLOCK();
70190297Sdes		return (YPERR_DOMAIN);
702145849Sume	}
70310522Swpaul
7041919Swollman	tv.tv_sec = _yplib_timeout;
7051919Swollman	tv.tv_usec = 0;
7061919Swollman
7071919Swollman	bzero((char *)&yprv, sizeof yprv);
7081919Swollman
7091919Swollman	r = clnt_call(ysd->dom_client, YPPROC_MATCH,
71095658Sdes		(xdrproc_t)xdr_ypreq_key, &yprk,
71195658Sdes		(xdrproc_t)xdr_ypresp_val, &yprv, tv);
71290297Sdes	if (r != RPC_SUCCESS) {
7131919Swollman		clnt_perror(ysd->dom_client, "yp_match: clnt_call");
71415793Swpaul		_yp_unbind(ysd);
715293896Sglebius		retries++;
7161919Swollman		goto again;
7171919Swollman	}
71815547Swpaul
71990297Sdes	if (!(r = ypprot_err(yprv.stat))) {
72012816Swpaul		*outvallen = yprv.val.valdat_len;
7211919Swollman		*outval = (char *)malloc(*outvallen+1);
72212816Swpaul		bcopy(yprv.val.valdat_val, *outval, *outvallen);
7231919Swollman		(*outval)[*outvallen] = '\0';
7241919Swollman#ifdef YPMATCHCACHE
72534146Swpaul		ypmatch_cache_insert(ysd, yprk.map, &yprk.key, &yprv.val);
7261919Swollman#endif
72715793Swpaul	}
72815547Swpaul
72995658Sdes	xdr_free((xdrproc_t)xdr_ypresp_val, &yprv);
730145849Sume	YPUNLOCK();
73190297Sdes	return (r);
7321919Swollman}
7331919Swollman
734144678Sumestatic int
735144678Sumeyp_get_default_domain_locked(char **domp)
7361919Swollman{
7371919Swollman	*domp = NULL;
73890297Sdes	if (_yp_domain[0] == '\0')
73990297Sdes		if (getdomainname(_yp_domain, sizeof _yp_domain))
74090297Sdes			return (YPERR_NODOM);
7411919Swollman	*domp = _yp_domain;
74290297Sdes	return (0);
7431919Swollman}
7441919Swollman
7451919Swollmanint
746144678Sumeyp_get_default_domain(char **domp)
747144678Sume{
748144678Sume	int r;
749144678Sume
750144678Sume	YPLOCK();
751144678Sume	r = yp_get_default_domain_locked(domp);
752144678Sume	YPUNLOCK();
753144678Sume	return (r);
754144678Sume}
755144678Sume
756144678Sumeint
75790298Sdesyp_first(char *indomain, char *inmap, char **outkey, int *outkeylen,
75890298Sdes    char **outval, int *outvallen)
7591919Swollman{
7601919Swollman	struct ypresp_key_val yprkv;
7611919Swollman	struct ypreq_nokey yprnk;
7621919Swollman	struct dom_binding *ysd;
7631919Swollman	struct timeval tv;
7641919Swollman	int r;
765293896Sglebius	int retries = 0;
7667337Swpaul	/* Sanity check */
7677337Swpaul
7687337Swpaul	if (indomain == NULL || !strlen(indomain) ||
7697337Swpaul	    inmap == NULL || !strlen(inmap))
77090297Sdes		return (YPERR_BADARGS);
7717337Swpaul
7721919Swollman	*outkey = *outval = NULL;
7731919Swollman	*outkeylen = *outvallen = 0;
7741919Swollman
775145849Sume	YPLOCK();
7761919Swollmanagain:
777293896Sglebius	if (retries > MAX_RETRIES) {
778293896Sglebius		YPUNLOCK();
779293896Sglebius		return (YPERR_RPC);
780293896Sglebius	}
781293896Sglebius
782145849Sume	if (_yp_dobind(indomain, &ysd) != 0) {
783145849Sume		YPUNLOCK();
78490297Sdes		return (YPERR_DOMAIN);
785145849Sume	}
7861919Swollman
7871919Swollman	tv.tv_sec = _yplib_timeout;
7881919Swollman	tv.tv_usec = 0;
7891919Swollman
7901919Swollman	yprnk.domain = indomain;
7911919Swollman	yprnk.map = inmap;
7921919Swollman	bzero((char *)&yprkv, sizeof yprkv);
7931919Swollman
7941919Swollman	r = clnt_call(ysd->dom_client, YPPROC_FIRST,
79595658Sdes		(xdrproc_t)xdr_ypreq_nokey, &yprnk,
79695658Sdes		(xdrproc_t)xdr_ypresp_key_val, &yprkv, tv);
79790297Sdes	if (r != RPC_SUCCESS) {
7981919Swollman		clnt_perror(ysd->dom_client, "yp_first: clnt_call");
79915793Swpaul		_yp_unbind(ysd);
800293896Sglebius		retries++;
8011919Swollman		goto again;
8021919Swollman	}
80390297Sdes	if (!(r = ypprot_err(yprkv.stat))) {
80412816Swpaul		*outkeylen = yprkv.key.keydat_len;
8051919Swollman		*outkey = (char *)malloc(*outkeylen+1);
80612816Swpaul		bcopy(yprkv.key.keydat_val, *outkey, *outkeylen);
8071919Swollman		(*outkey)[*outkeylen] = '\0';
80812816Swpaul		*outvallen = yprkv.val.valdat_len;
8091919Swollman		*outval = (char *)malloc(*outvallen+1);
81012816Swpaul		bcopy(yprkv.val.valdat_val, *outval, *outvallen);
8111919Swollman		(*outval)[*outvallen] = '\0';
81215793Swpaul	}
81315547Swpaul
81495658Sdes	xdr_free((xdrproc_t)xdr_ypresp_key_val, &yprkv);
815145849Sume	YPUNLOCK();
81690297Sdes	return (r);
8171919Swollman}
8181919Swollman
8191919Swollmanint
82090298Sdesyp_next(char *indomain, char *inmap, char *inkey, int inkeylen,
82190298Sdes    char **outkey, int *outkeylen, char **outval, int *outvallen)
8221919Swollman{
8231919Swollman	struct ypresp_key_val yprkv;
8241919Swollman	struct ypreq_key yprk;
8251919Swollman	struct dom_binding *ysd;
8261919Swollman	struct timeval tv;
8271919Swollman	int r;
828293896Sglebius	int retries = 0;
8297337Swpaul	/* Sanity check */
8307337Swpaul
8317337Swpaul	if (inkey == NULL || !strlen(inkey) || inkeylen <= 0 ||
8327337Swpaul	    inmap == NULL || !strlen(inmap) ||
8337337Swpaul	    indomain == NULL || !strlen(indomain))
83490297Sdes		return (YPERR_BADARGS);
8357337Swpaul
8361919Swollman	*outkey = *outval = NULL;
8371919Swollman	*outkeylen = *outvallen = 0;
8381919Swollman
839145849Sume	YPLOCK();
8401919Swollmanagain:
841293896Sglebius	if (retries > MAX_RETRIES) {
842293896Sglebius		YPUNLOCK();
843293896Sglebius		return (YPERR_RPC);
844293896Sglebius	}
845293896Sglebius
846145849Sume	if (_yp_dobind(indomain, &ysd) != 0) {
847145849Sume		YPUNLOCK();
84890297Sdes		return (YPERR_DOMAIN);
849145849Sume	}
8501919Swollman
8511919Swollman	tv.tv_sec = _yplib_timeout;
8521919Swollman	tv.tv_usec = 0;
8531919Swollman
8541919Swollman	yprk.domain = indomain;
8551919Swollman	yprk.map = inmap;
85612816Swpaul	yprk.key.keydat_val = inkey;
85712816Swpaul	yprk.key.keydat_len = inkeylen;
8581919Swollman	bzero((char *)&yprkv, sizeof yprkv);
8591919Swollman
8601919Swollman	r = clnt_call(ysd->dom_client, YPPROC_NEXT,
86195658Sdes		(xdrproc_t)xdr_ypreq_key, &yprk,
86295658Sdes		(xdrproc_t)xdr_ypresp_key_val, &yprkv, tv);
86390297Sdes	if (r != RPC_SUCCESS) {
8641919Swollman		clnt_perror(ysd->dom_client, "yp_next: clnt_call");
86515793Swpaul		_yp_unbind(ysd);
866293896Sglebius		retries++;
8671919Swollman		goto again;
8681919Swollman	}
86990297Sdes	if (!(r = ypprot_err(yprkv.stat))) {
87012816Swpaul		*outkeylen = yprkv.key.keydat_len;
8711919Swollman		*outkey = (char *)malloc(*outkeylen+1);
87212816Swpaul		bcopy(yprkv.key.keydat_val, *outkey, *outkeylen);
8731919Swollman		(*outkey)[*outkeylen] = '\0';
87412816Swpaul		*outvallen = yprkv.val.valdat_len;
8751919Swollman		*outval = (char *)malloc(*outvallen+1);
87612816Swpaul		bcopy(yprkv.val.valdat_val, *outval, *outvallen);
8771919Swollman		(*outval)[*outvallen] = '\0';
87815793Swpaul	}
87915547Swpaul
88095658Sdes	xdr_free((xdrproc_t)xdr_ypresp_key_val, &yprkv);
881145849Sume	YPUNLOCK();
88290297Sdes	return (r);
8831919Swollman}
8841919Swollman
8851919Swollmanint
88690298Sdesyp_all(char *indomain, char *inmap, struct ypall_callback *incallback)
8871919Swollman{
8881919Swollman	struct ypreq_nokey yprnk;
8891919Swollman	struct dom_binding *ysd;
8901919Swollman	struct timeval tv;
8911919Swollman	struct sockaddr_in clnt_sin;
8921919Swollman	CLIENT *clnt;
89314719Swpaul	u_long status, savstat;
8941919Swollman	int clnt_sock;
895293896Sglebius	int retries = 0;
8967337Swpaul	/* Sanity check */
8977337Swpaul
8987337Swpaul	if (indomain == NULL || !strlen(indomain) ||
8997337Swpaul	    inmap == NULL || !strlen(inmap))
90090297Sdes		return (YPERR_BADARGS);
9017337Swpaul
902145849Sume	YPLOCK();
90315793Swpaulagain:
904293896Sglebius	if (retries > MAX_RETRIES) {
905293896Sglebius		YPUNLOCK();
906293896Sglebius		return (YPERR_RPC);
907293896Sglebius	}
90815793Swpaul
909145849Sume	if (_yp_dobind(indomain, &ysd) != 0) {
910145849Sume		YPUNLOCK();
91190297Sdes		return (YPERR_DOMAIN);
912145849Sume	}
9131919Swollman
9141919Swollman	tv.tv_sec = _yplib_timeout;
9151919Swollman	tv.tv_usec = 0;
91615793Swpaul
91715793Swpaul	/* YPPROC_ALL manufactures its own channel to ypserv using TCP */
91815793Swpaul
9191919Swollman	clnt_sock = RPC_ANYSOCK;
9201919Swollman	clnt_sin = ysd->dom_server_addr;
9211919Swollman	clnt_sin.sin_port = 0;
9221919Swollman	clnt = clnttcp_create(&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0);
92390297Sdes	if (clnt == NULL) {
924145849Sume		YPUNLOCK();
9251919Swollman		printf("clnttcp_create failed\n");
92690297Sdes		return (YPERR_PMAP);
9271919Swollman	}
9281919Swollman
9291919Swollman	yprnk.domain = indomain;
9301919Swollman	yprnk.map = inmap;
9311919Swollman	ypresp_allfn = incallback->foreach;
9321919Swollman	ypresp_data = (void *)incallback->data;
9331919Swollman
93415793Swpaul	if (clnt_call(clnt, YPPROC_ALL,
93595658Sdes		(xdrproc_t)xdr_ypreq_nokey, &yprnk,
93695658Sdes		(xdrproc_t)xdr_ypresp_all_seq, &status, tv) != RPC_SUCCESS) {
937293896Sglebius			clnt_perror(clnt, "yp_all: clnt_call");
93815793Swpaul			clnt_destroy(clnt);
93915793Swpaul			_yp_unbind(ysd);
940293896Sglebius			retries++;
94115793Swpaul			goto again;
94215793Swpaul	}
94315793Swpaul
9441919Swollman	clnt_destroy(clnt);
94514719Swpaul	savstat = status;
94695658Sdes	xdr_free((xdrproc_t)xdr_ypresp_all_seq, &status);	/* not really needed... */
947145849Sume	YPUNLOCK();
94890297Sdes	if (savstat != YP_NOMORE)
94990297Sdes		return (ypprot_err(savstat));
95090297Sdes	return (0);
9511919Swollman}
9521919Swollman
9531919Swollmanint
95490298Sdesyp_order(char *indomain, char *inmap, int *outorder)
9551919Swollman{
9561919Swollman 	struct dom_binding *ysd;
9571919Swollman	struct ypresp_order ypro;
9581919Swollman	struct ypreq_nokey yprnk;
9591919Swollman	struct timeval tv;
9601919Swollman	int r;
9611919Swollman
9627337Swpaul	/* Sanity check */
9637337Swpaul
9647337Swpaul	if (indomain == NULL || !strlen(indomain) ||
9657337Swpaul	    inmap == NULL || !strlen(inmap))
96690297Sdes		return (YPERR_BADARGS);
9677337Swpaul
968145849Sume	YPLOCK();
9691919Swollmanagain:
970145849Sume	if (_yp_dobind(indomain, &ysd) != 0) {
971145849Sume		YPUNLOCK();
97290297Sdes		return (YPERR_DOMAIN);
973145849Sume	}
9741919Swollman
9751919Swollman	tv.tv_sec = _yplib_timeout;
9761919Swollman	tv.tv_usec = 0;
9771919Swollman
9781919Swollman	yprnk.domain = indomain;
9791919Swollman	yprnk.map = inmap;
9801919Swollman
9811919Swollman	bzero((char *)(char *)&ypro, sizeof ypro);
9821919Swollman
9831919Swollman	r = clnt_call(ysd->dom_client, YPPROC_ORDER,
98495658Sdes		(xdrproc_t)xdr_ypreq_nokey, &yprnk,
98595658Sdes		(xdrproc_t)xdr_ypresp_order, &ypro, tv);
98619520Swpaul
98719520Swpaul	/*
98819520Swpaul	 * NIS+ in YP compat mode doesn't support the YPPROC_ORDER
98919520Swpaul	 * procedure.
99019520Swpaul	 */
99119520Swpaul	if (r == RPC_PROCUNAVAIL) {
992145849Sume		YPUNLOCK();
99319520Swpaul		return(YPERR_YPERR);
99419520Swpaul	}
99590297Sdes
99690297Sdes	if (r != RPC_SUCCESS) {
9971919Swollman		clnt_perror(ysd->dom_client, "yp_order: clnt_call");
99815793Swpaul		_yp_unbind(ysd);
9991919Swollman		goto again;
10001919Swollman	}
10011919Swollman
100290297Sdes	if (!(r = ypprot_err(ypro.stat))) {
100315547Swpaul		*outorder = ypro.ordernum;
100415793Swpaul	}
100515547Swpaul
100695658Sdes	xdr_free((xdrproc_t)xdr_ypresp_order, &ypro);
1007145849Sume	YPUNLOCK();
100815793Swpaul	return (r);
10091919Swollman}
10101919Swollman
10111919Swollmanint
101290298Sdesyp_master(char *indomain, char *inmap, char **outname)
10131919Swollman{
10141919Swollman	struct dom_binding *ysd;
10151919Swollman	struct ypresp_master yprm;
10161919Swollman	struct ypreq_nokey yprnk;
10171919Swollman	struct timeval tv;
10181919Swollman	int r;
10191919Swollman
10207337Swpaul	/* Sanity check */
10217337Swpaul
10227337Swpaul	if (indomain == NULL || !strlen(indomain) ||
10237337Swpaul	    inmap == NULL || !strlen(inmap))
102490297Sdes		return (YPERR_BADARGS);
1025145849Sume	YPLOCK();
10261919Swollmanagain:
1027145849Sume	if (_yp_dobind(indomain, &ysd) != 0) {
1028145849Sume		YPUNLOCK();
102990297Sdes		return (YPERR_DOMAIN);
1030145849Sume	}
10311919Swollman
10321919Swollman	tv.tv_sec = _yplib_timeout;
10331919Swollman	tv.tv_usec = 0;
10341919Swollman
10351919Swollman	yprnk.domain = indomain;
10361919Swollman	yprnk.map = inmap;
10371919Swollman
10381919Swollman	bzero((char *)&yprm, sizeof yprm);
10391919Swollman
10401919Swollman	r = clnt_call(ysd->dom_client, YPPROC_MASTER,
104195658Sdes		(xdrproc_t)xdr_ypreq_nokey, &yprnk,
104295658Sdes		(xdrproc_t)xdr_ypresp_master, &yprm, tv);
104390297Sdes	if (r != RPC_SUCCESS) {
10441919Swollman		clnt_perror(ysd->dom_client, "yp_master: clnt_call");
104515793Swpaul		_yp_unbind(ysd);
10461919Swollman		goto again;
10471919Swollman	}
104815793Swpaul
104990297Sdes	if (!(r = ypprot_err(yprm.stat))) {
105012816Swpaul		*outname = (char *)strdup(yprm.peer);
105115793Swpaul	}
105215547Swpaul
105395658Sdes	xdr_free((xdrproc_t)xdr_ypresp_master, &yprm);
1054145849Sume	YPUNLOCK();
105515793Swpaul	return (r);
10561919Swollman}
105790298Sdes
10587722Swpaulint
105990298Sdesyp_maplist(char *indomain, struct ypmaplist **outmaplist)
10601919Swollman{
10611919Swollman	struct dom_binding *ysd;
10621919Swollman	struct ypresp_maplist ypml;
10631919Swollman	struct timeval tv;
10641919Swollman	int r;
10651919Swollman
10667337Swpaul	/* Sanity check */
10677337Swpaul
10687337Swpaul	if (indomain == NULL || !strlen(indomain))
106990297Sdes		return (YPERR_BADARGS);
10707337Swpaul
1071145849Sume	YPLOCK();
10721919Swollmanagain:
1073145849Sume	if (_yp_dobind(indomain, &ysd) != 0) {
1074145849Sume		YPUNLOCK();
107590297Sdes		return (YPERR_DOMAIN);
1076145849Sume	}
10771919Swollman
10781919Swollman	tv.tv_sec = _yplib_timeout;
10791919Swollman	tv.tv_usec = 0;
10801919Swollman
10811919Swollman	bzero((char *)&ypml, sizeof ypml);
10821919Swollman
10831919Swollman	r = clnt_call(ysd->dom_client, YPPROC_MAPLIST,
108495658Sdes		(xdrproc_t)xdr_domainname, &indomain,
108595658Sdes		(xdrproc_t)xdr_ypresp_maplist, &ypml,tv);
10861919Swollman	if (r != RPC_SUCCESS) {
10871919Swollman		clnt_perror(ysd->dom_client, "yp_maplist: clnt_call");
108815793Swpaul		_yp_unbind(ysd);
10891919Swollman		goto again;
10901919Swollman	}
109190297Sdes	if (!(r = ypprot_err(ypml.stat))) {
109215547Swpaul		*outmaplist = ypml.maps;
109315793Swpaul	}
109415793Swpaul
109595658Sdes	/* NO: xdr_free((xdrproc_t)xdr_ypresp_maplist, &ypml);*/
1096145849Sume	YPUNLOCK();
109715793Swpaul	return (r);
10981919Swollman}
10991919Swollman
110095658Sdesconst char *
110190298Sdesyperr_string(int incode)
11021919Swollman{
11031919Swollman	static char err[80];
11041919Swollman
110590297Sdes	switch (incode) {
11061919Swollman	case 0:
110790297Sdes		return ("Success");
11081919Swollman	case YPERR_BADARGS:
110990297Sdes		return ("Request arguments bad");
11101919Swollman	case YPERR_RPC:
111190297Sdes		return ("RPC failure");
11121919Swollman	case YPERR_DOMAIN:
111390297Sdes		return ("Can't bind to server which serves this domain");
11141919Swollman	case YPERR_MAP:
111590297Sdes		return ("No such map in server's domain");
11161919Swollman	case YPERR_KEY:
111790297Sdes		return ("No such key in map");
11181919Swollman	case YPERR_YPERR:
111990297Sdes		return ("YP server error");
11201919Swollman	case YPERR_RESRC:
112190297Sdes		return ("Local resource allocation failure");
11221919Swollman	case YPERR_NOMORE:
112390297Sdes		return ("No more records in map database");
11241919Swollman	case YPERR_PMAP:
112590297Sdes		return ("Can't communicate with portmapper");
11261919Swollman	case YPERR_YPBIND:
112790297Sdes		return ("Can't communicate with ypbind");
11281919Swollman	case YPERR_YPSERV:
112990297Sdes		return ("Can't communicate with ypserv");
11301919Swollman	case YPERR_NODOM:
113190297Sdes		return ("Local domain name not set");
11321919Swollman	case YPERR_BADDB:
113390297Sdes		return ("Server data base is bad");
11341919Swollman	case YPERR_VERS:
113590297Sdes		return ("YP server version mismatch - server can't supply service.");
11361919Swollman	case YPERR_ACCESS:
113790297Sdes		return ("Access violation");
11381919Swollman	case YPERR_BUSY:
113990297Sdes		return ("Database is busy");
11401919Swollman	}
11411919Swollman	sprintf(err, "YP unknown error %d\n", incode);
114290297Sdes	return (err);
11431919Swollman}
11441919Swollman
11451919Swollmanint
114690298Sdesypprot_err(unsigned int incode)
11471919Swollman{
114890297Sdes	switch (incode) {
11491919Swollman	case YP_TRUE:
115090297Sdes		return (0);
11511919Swollman	case YP_FALSE:
115290297Sdes		return (YPERR_YPBIND);
11531919Swollman	case YP_NOMORE:
115490297Sdes		return (YPERR_NOMORE);
11551919Swollman	case YP_NOMAP:
115690297Sdes		return (YPERR_MAP);
11571919Swollman	case YP_NODOM:
115890297Sdes		return (YPERR_DOMAIN);
11591919Swollman	case YP_NOKEY:
116090297Sdes		return (YPERR_KEY);
11611919Swollman	case YP_BADOP:
116290297Sdes		return (YPERR_YPERR);
11631919Swollman	case YP_BADDB:
116490297Sdes		return (YPERR_BADDB);
11651919Swollman	case YP_YPERR:
116690297Sdes		return (YPERR_YPERR);
11671919Swollman	case YP_BADARGS:
116890297Sdes		return (YPERR_BADARGS);
11691919Swollman	case YP_VERS:
117090297Sdes		return (YPERR_VERS);
11711919Swollman	}
117290297Sdes	return (YPERR_YPERR);
11731919Swollman}
11741919Swollman
11751919Swollmanint
117690298Sdes_yp_check(char **dom)
11771919Swollman{
11781919Swollman	char *unused;
11791919Swollman
1180144678Sume	YPLOCK();
118190297Sdes	if (_yp_domain[0]=='\0')
1182144678Sume		if (yp_get_default_domain_locked(&unused)) {
1183144678Sume			YPUNLOCK();
118490297Sdes			return (0);
1185144678Sume		}
11861919Swollman
118790297Sdes	if (dom)
11881919Swollman		*dom = _yp_domain;
11891919Swollman
1190145849Sume	if (yp_bind_locked(_yp_domain) == 0) {
1191145849Sume		yp_unbind_locked(_yp_domain);
1192144678Sume		YPUNLOCK();
119390297Sdes		return (1);
119412095Swpaul	}
1195144678Sume	YPUNLOCK();
119690297Sdes	return (0);
11971919Swollman}
1198