1290931Srodrigc/*	$OpenBSD: yp.c,v 1.14 2015/02/11 01:26:00 pelikan Exp $ */
2290931Srodrigc/*	$FreeBSD: stable/11/usr.sbin/ypldap/yp.c 351694 2019-09-02 10:20:57Z kib $ */
3290931Srodrigc/*
4290931Srodrigc * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
5290931Srodrigc *
6290931Srodrigc * Permission to use, copy, modify, and distribute this software for any
7290931Srodrigc * purpose with or without fee is hereby granted, provided that the above
8290931Srodrigc * copyright notice and this permission notice appear in all copies.
9290931Srodrigc *
10290931Srodrigc * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11290931Srodrigc * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12290931Srodrigc * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13290931Srodrigc * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14290931Srodrigc * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15290931Srodrigc * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16290931Srodrigc * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17290931Srodrigc */
18290931Srodrigc
19290931Srodrigc#include <sys/types.h>
20290937Srodrigc#include <sys/param.h>
21290931Srodrigc#include <sys/queue.h>
22290931Srodrigc#include <sys/socket.h>
23290931Srodrigc#include <sys/select.h>
24290931Srodrigc#include <sys/tree.h>
25290931Srodrigc
26290931Srodrigc#include <netinet/in.h>
27290931Srodrigc#include <arpa/inet.h>
28290931Srodrigc
29290931Srodrigc#include <errno.h>
30290931Srodrigc#include <event.h>
31290931Srodrigc#include <fcntl.h>
32290931Srodrigc#include <unistd.h>
33290931Srodrigc#include <pwd.h>
34290931Srodrigc#include <stdio.h>
35290931Srodrigc#include <stdlib.h>
36290931Srodrigc#include <string.h>
37290931Srodrigc#include <limits.h>
38290931Srodrigc
39290931Srodrigc#include <rpc/rpc.h>
40290931Srodrigc#include <rpc/xdr.h>
41290931Srodrigc#include <rpc/pmap_clnt.h>
42290931Srodrigc#include <rpc/pmap_prot.h>
43290931Srodrigc#include <rpc/pmap_rmt.h>
44290931Srodrigc#include <rpcsvc/yp.h>
45290931Srodrigc#include <rpcsvc/ypclnt.h>
46290931Srodrigc
47290931Srodrigc#include "ypldap.h"
48290931Srodrigc
49290931Srodrigcvoid	yp_dispatch(struct svc_req *, SVCXPRT *);
50290931Srodrigcvoid	yp_disable_events(void);
51290931Srodrigcvoid	yp_fd_event(int, short, void *);
52290931Srodrigcint	yp_check(struct svc_req *);
53290931Srodrigcint	yp_valid_domain(char *, struct ypresp_val *);
54290931Srodrigcvoid	yp_make_val(struct ypresp_val *, char *, int);
55290931Srodrigcvoid	yp_make_keyval(struct ypresp_key_val *, char *, char *);
56290931Srodrigc
57290931Srodrigcstatic struct env	*env;
58290931Srodrigc
59290931Srodrigcstruct yp_event {
60290931Srodrigc	TAILQ_ENTRY(yp_event)	 ye_entry;
61290931Srodrigc	struct event		 ye_event;
62290931Srodrigc};
63290931Srodrigc
64290931Srodrigcstruct yp_data {
65290931Srodrigc	SVCXPRT			*yp_trans_udp;
66290931Srodrigc	SVCXPRT			*yp_trans_tcp;
67290931Srodrigc	TAILQ_HEAD(, yp_event)	 yd_events;
68290931Srodrigc};
69290931Srodrigc
70290931Srodrigcvoid
71290931Srodrigcyp_disable_events(void)
72290931Srodrigc{
73290931Srodrigc	struct yp_event	*ye;
74290931Srodrigc
75290931Srodrigc	while ((ye = TAILQ_FIRST(&env->sc_yp->yd_events)) != NULL) {
76290931Srodrigc		TAILQ_REMOVE(&env->sc_yp->yd_events, ye, ye_entry);
77290931Srodrigc		event_del(&ye->ye_event);
78290931Srodrigc		free(ye);
79290931Srodrigc	}
80290931Srodrigc}
81290931Srodrigc
82290931Srodrigcvoid
83290931Srodrigcyp_enable_events(void)
84290931Srodrigc{
85290941Srodrigc	int i;
86290931Srodrigc	struct yp_event	*ye;
87290931Srodrigc
88294543Saraujo	for (i = 0; i < getdtablesize(); i++) {
89294543Saraujo		if ((ye = calloc(1, sizeof(*ye))) == NULL)
90294543Saraujo			fatal(NULL);
91294543Saraujo		event_set(&ye->ye_event, i, EV_READ, yp_fd_event, NULL);
92294543Saraujo		event_add(&ye->ye_event, NULL);
93294543Saraujo		TAILQ_INSERT_TAIL(&env->sc_yp->yd_events, ye, ye_entry);
94290931Srodrigc	}
95290931Srodrigc}
96290931Srodrigc
97290931Srodrigcvoid
98290931Srodrigcyp_fd_event(int fd, short event, void *p)
99290931Srodrigc{
100290931Srodrigc	svc_getreq_common(fd);
101290931Srodrigc	yp_disable_events();
102290931Srodrigc	yp_enable_events();
103290931Srodrigc}
104290931Srodrigc
105290931Srodrigcvoid
106290931Srodrigcyp_init(struct env *x_env)
107290931Srodrigc{
108290931Srodrigc	struct yp_data	*yp;
109290931Srodrigc
110290931Srodrigc	if ((yp = calloc(1, sizeof(*yp))) == NULL)
111290931Srodrigc		fatal(NULL);
112290931Srodrigc	TAILQ_INIT(&yp->yd_events);
113290931Srodrigc
114290931Srodrigc	env = x_env;
115290931Srodrigc	env->sc_yp = yp;
116290931Srodrigc
117290931Srodrigc	(void)pmap_unset(YPPROG, YPVERS);
118290931Srodrigc
119290931Srodrigc	if ((yp->yp_trans_udp = svcudp_create(RPC_ANYSOCK)) == NULL)
120290931Srodrigc		fatal("cannot create udp service");
121290931Srodrigc	if ((yp->yp_trans_tcp = svctcp_create(RPC_ANYSOCK, 0, 0)) == NULL)
122290931Srodrigc		fatal("cannot create tcp service");
123290931Srodrigc
124290931Srodrigc	if (!svc_register(yp->yp_trans_udp, YPPROG, YPVERS,
125290931Srodrigc	    yp_dispatch, IPPROTO_UDP)) {
126290931Srodrigc		fatal("unable to register (YPPROG, YPVERS, udp)");
127290931Srodrigc	}
128290931Srodrigc	if (!svc_register(yp->yp_trans_tcp, YPPROG, YPVERS,
129290931Srodrigc	    yp_dispatch, IPPROTO_TCP)) {
130290931Srodrigc		fatal("unable to register (YPPROG, YPVERS, tcp)");
131290931Srodrigc	}
132290931Srodrigc}
133290931Srodrigc
134290931Srodrigc/*
135290931Srodrigc * lots of inspiration from ypserv by Mats O Jansson
136290931Srodrigc */
137290931Srodrigcvoid
138290931Srodrigcyp_dispatch(struct svc_req *req, SVCXPRT *trans)
139290931Srodrigc{
140290931Srodrigc	xdrproc_t		 xdr_argument;
141290931Srodrigc	xdrproc_t		 xdr_result;
142290931Srodrigc	char			*result;
143290931Srodrigc	char			*(*cb)(char *, struct svc_req *);
144290931Srodrigc        union {
145290931Srodrigc		domainname	 ypproc_domain_2_arg;
146290931Srodrigc		domainname	 ypproc_domain_nonack_2_arg;
147290931Srodrigc		ypreq_key	 ypproc_match_2_arg;
148290931Srodrigc		ypreq_nokey	 ypproc_first_2_arg;
149290931Srodrigc		ypreq_key	 ypproc_next_2_arg;
150290931Srodrigc		ypreq_xfr	 ypproc_xfr_2_arg;
151290931Srodrigc		ypreq_nokey	 ypproc_all_2_arg;
152290931Srodrigc		ypreq_nokey	 ypproc_master_2_arg;
153290931Srodrigc		ypreq_nokey	 ypproc_order_2_arg;
154290931Srodrigc		domainname	 ypproc_maplist_2_arg;
155290931Srodrigc	} argument;
156290931Srodrigc
157290931Srodrigc	xdr_argument = (xdrproc_t) xdr_void;
158290931Srodrigc	xdr_result = (xdrproc_t) xdr_void;
159290931Srodrigc	cb = NULL;
160290931Srodrigc	switch (req->rq_proc) {
161290931Srodrigc	case YPPROC_NULL:
162290931Srodrigc		xdr_argument = (xdrproc_t) xdr_void;
163290931Srodrigc		xdr_result = (xdrproc_t) xdr_void;
164290931Srodrigc		if (yp_check(req) == -1)
165290931Srodrigc			return;
166290931Srodrigc		result = NULL;
167290931Srodrigc		if (!svc_sendreply(trans, (xdrproc_t) xdr_void,
168290931Srodrigc		    (void *)&result))
169290931Srodrigc			svcerr_systemerr(trans);
170290931Srodrigc		return;
171290931Srodrigc	case YPPROC_DOMAIN:
172290931Srodrigc		xdr_argument = (xdrproc_t) xdr_domainname;
173290931Srodrigc		xdr_result = (xdrproc_t) xdr_bool;
174290931Srodrigc		if (yp_check(req) == -1)
175290931Srodrigc			return;
176290931Srodrigc		cb = (void *)ypproc_domain_2_svc;
177290931Srodrigc		break;
178290931Srodrigc	case YPPROC_DOMAIN_NONACK:
179290931Srodrigc		xdr_argument = (xdrproc_t) xdr_domainname;
180290931Srodrigc		xdr_result = (xdrproc_t) xdr_bool;
181290931Srodrigc		if (yp_check(req) == -1)
182290931Srodrigc			return;
183290931Srodrigc		cb = (void *)ypproc_domain_nonack_2_svc;
184290931Srodrigc		break;
185290931Srodrigc	case YPPROC_MATCH:
186290931Srodrigc		xdr_argument = (xdrproc_t) xdr_ypreq_key;
187290931Srodrigc		xdr_result = (xdrproc_t) xdr_ypresp_val;
188290931Srodrigc		if (yp_check(req) == -1)
189290931Srodrigc			return;
190290931Srodrigc		cb = (void *)ypproc_match_2_svc;
191290931Srodrigc		break;
192290931Srodrigc	case YPPROC_FIRST:
193290931Srodrigc		xdr_argument = (xdrproc_t) xdr_ypreq_nokey;
194290931Srodrigc		xdr_result = (xdrproc_t) xdr_ypresp_key_val;
195290931Srodrigc		if (yp_check(req) == -1)
196290931Srodrigc			return;
197290931Srodrigc		cb = (void *)ypproc_first_2_svc;
198290931Srodrigc		break;
199290931Srodrigc	case YPPROC_NEXT:
200290931Srodrigc		xdr_argument = (xdrproc_t) xdr_ypreq_key;
201290931Srodrigc		xdr_result = (xdrproc_t) xdr_ypresp_key_val;
202290931Srodrigc		if (yp_check(req) == -1)
203290931Srodrigc			return;
204290931Srodrigc		cb = (void *)ypproc_next_2_svc;
205290931Srodrigc		break;
206290931Srodrigc	case YPPROC_XFR:
207290931Srodrigc		if (yp_check(req) == -1)
208290931Srodrigc			return;
209290931Srodrigc		svcerr_noproc(trans);
210290931Srodrigc		return;
211290931Srodrigc	case YPPROC_CLEAR:
212290931Srodrigc		log_debug("ypproc_clear");
213290931Srodrigc		if (yp_check(req) == -1)
214290931Srodrigc			return;
215290931Srodrigc		svcerr_noproc(trans);
216290931Srodrigc		return;
217290931Srodrigc	case YPPROC_ALL:
218290931Srodrigc		log_debug("ypproc_all");
219296377Saraujo		xdr_argument = (xdrproc_t) xdr_ypreq_nokey;
220296377Saraujo		xdr_result = (xdrproc_t) xdr_ypresp_all;
221290931Srodrigc		if (yp_check(req) == -1)
222290931Srodrigc			return;
223290931Srodrigc		cb = (void *)ypproc_all_2_svc;
224290931Srodrigc		break;
225290931Srodrigc	case YPPROC_MASTER:
226290931Srodrigc		log_debug("ypproc_master");
227296376Saraujo		xdr_argument = (xdrproc_t) xdr_ypreq_nokey;
228296376Saraujo		xdr_result = (xdrproc_t) xdr_ypresp_master;
229290931Srodrigc		if (yp_check(req) == -1)
230290931Srodrigc			return;
231290931Srodrigc		cb = (void *)ypproc_master_2_svc;
232290931Srodrigc		break;
233290931Srodrigc	case YPPROC_ORDER:
234290931Srodrigc		log_debug("ypproc_order");
235290931Srodrigc		if (yp_check(req) == -1)
236290931Srodrigc			return;
237290931Srodrigc		svcerr_noproc(trans);
238290931Srodrigc		return;
239290931Srodrigc	case YPPROC_MAPLIST:
240290931Srodrigc		log_debug("ypproc_maplist");
241296377Saraujo		xdr_argument = (xdrproc_t) xdr_domainname;
242296377Saraujo		xdr_result = (xdrproc_t) xdr_ypresp_maplist;
243290931Srodrigc		if (yp_check(req) == -1)
244290931Srodrigc			return;
245290931Srodrigc		cb = (void *)ypproc_maplist_2_svc;
246290931Srodrigc		break;
247290931Srodrigc	default:
248290931Srodrigc		svcerr_noproc(trans);
249290931Srodrigc		return;
250290931Srodrigc	}
251290931Srodrigc	(void)memset(&argument, 0, sizeof(argument));
252290931Srodrigc
253290931Srodrigc	if (!svc_getargs(trans, xdr_argument, (caddr_t)&argument)) {
254290931Srodrigc		svcerr_decode(trans);
255290931Srodrigc		return;
256290931Srodrigc	}
257290931Srodrigc	result = (*cb)((char *)&argument, req);
258290931Srodrigc	if (result != NULL && !svc_sendreply(trans, xdr_result, result))
259290931Srodrigc		svcerr_systemerr(trans);
260290931Srodrigc	if (!svc_freeargs(trans, xdr_argument, (caddr_t)&argument)) {
261290931Srodrigc		/*
262290931Srodrigc		 * ypserv does it too.
263290931Srodrigc		 */
264290931Srodrigc		fatal("unable to free arguments");
265290931Srodrigc	}
266290931Srodrigc}
267290931Srodrigc
268290931Srodrigcint
269290931Srodrigcyp_check(struct svc_req *req)
270290931Srodrigc{
271290931Srodrigc	struct sockaddr_in	*caller;
272290931Srodrigc
273290931Srodrigc	caller = svc_getcaller(req->rq_xprt);
274290931Srodrigc	/*
275290931Srodrigc	 * We might want to know who we allow here.
276290931Srodrigc	 */
277290931Srodrigc	return (0);
278290931Srodrigc}
279290931Srodrigc
280290931Srodrigcint
281290931Srodrigcyp_valid_domain(char *domain, struct ypresp_val *res)
282290931Srodrigc{
283290931Srodrigc	if (domain == NULL) {
284290931Srodrigc		log_debug("NULL domain !");
285290931Srodrigc		return (-1);
286290931Srodrigc	}
287290931Srodrigc	if (strcmp(domain, env->sc_domainname) != 0) {
288290931Srodrigc		res->stat = YP_NODOM;
289290931Srodrigc		return (-1);
290290931Srodrigc	}
291290931Srodrigc	return (0);
292290931Srodrigc}
293290931Srodrigc
294290931Srodrigcbool_t *
295290931Srodrigcypproc_domain_2_svc(domainname *arg, struct svc_req *req)
296290931Srodrigc{
297290931Srodrigc	static bool_t	res;
298290931Srodrigc
299290931Srodrigc	res = (bool_t)1;
300290931Srodrigc	if (strcmp(*arg, env->sc_domainname) != 0)
301290931Srodrigc		res = (bool_t)0;
302290931Srodrigc	return (&res);
303290931Srodrigc}
304290931Srodrigc
305290931Srodrigcbool_t *
306290931Srodrigcypproc_domain_nonack_2_svc(domainname *arg, struct svc_req *req)
307290931Srodrigc{
308290931Srodrigc	static bool_t	res;
309290931Srodrigc
310290931Srodrigc	if (strcmp(*arg, env->sc_domainname) != 0)
311290931Srodrigc		return NULL;
312290931Srodrigc	res = (bool_t)1;
313290931Srodrigc	return (&res);
314290931Srodrigc}
315290931Srodrigc
316290931Srodrigcypresp_val *
317290931Srodrigcypproc_match_2_svc(ypreq_key *arg, struct svc_req *req)
318290931Srodrigc{
319290931Srodrigc	struct userent		 ukey;
320290931Srodrigc	struct userent		*ue;
321290931Srodrigc	struct groupent		 gkey;
322290931Srodrigc	struct groupent		*ge;
323290931Srodrigc	static struct ypresp_val res;
324290931Srodrigc	const char		*estr;
325290931Srodrigc	char			*bp, *cp;
326351694Skib	char			 *key;
327290931Srodrigc
328290931Srodrigc	log_debug("matching '%.*s' in map %s", arg->key.keydat_len,
329290931Srodrigc	   arg->key.keydat_val, arg->map);
330290931Srodrigc
331290931Srodrigc	if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
332290931Srodrigc		return (&res);
333290931Srodrigc
334290931Srodrigc	if (env->sc_user_names == NULL) {
335290931Srodrigc		/*
336290931Srodrigc		 * tree not ready.
337290931Srodrigc		 */
338290931Srodrigc		return (NULL);
339290931Srodrigc	}
340290931Srodrigc
341290931Srodrigc	if (arg->key.keydat_len > YPMAXRECORD) {
342290931Srodrigc		log_debug("argument too long");
343290931Srodrigc		return (NULL);
344290931Srodrigc	}
345351694Skib	key = calloc(arg->key.keydat_len + 1, 1);
346351694Skib	if (key == NULL)
347351694Skib		return (NULL);
348290931Srodrigc	(void)strncpy(key, arg->key.keydat_val, arg->key.keydat_len);
349290931Srodrigc
350290931Srodrigc	if (strcmp(arg->map, "passwd.byname") == 0 ||
351290931Srodrigc	    strcmp(arg->map, "master.passwd.byname") == 0) {
352290931Srodrigc		ukey.ue_line = key;
353290931Srodrigc		if ((ue = RB_FIND(user_name_tree, env->sc_user_names,
354290931Srodrigc		    &ukey)) == NULL) {
355290931Srodrigc			res.stat = YP_NOKEY;
356351694Skib			goto out;
357290931Srodrigc		}
358290931Srodrigc
359290931Srodrigc		yp_make_val(&res, ue->ue_line, 1);
360351694Skib		goto out;
361290931Srodrigc	} else if (strcmp(arg->map, "passwd.byuid") == 0 ||
362290931Srodrigc		   strcmp(arg->map, "master.passwd.byuid") == 0) {
363290931Srodrigc		ukey.ue_uid = strtonum(key, 0, UID_MAX, &estr);
364290931Srodrigc		if (estr) {
365290931Srodrigc			res.stat = YP_BADARGS;
366351694Skib			goto out;
367290931Srodrigc		}
368290931Srodrigc
369290931Srodrigc		if ((ue = RB_FIND(user_uid_tree, &env->sc_user_uids,
370290931Srodrigc		    &ukey)) == NULL) {
371290931Srodrigc			res.stat = YP_NOKEY;
372351694Skib			goto out;
373290931Srodrigc		}
374290931Srodrigc
375290931Srodrigc		yp_make_val(&res, ue->ue_line, 1);
376290931Srodrigc		return (&res);
377290931Srodrigc	} else if (strcmp(arg->map, "group.bygid") == 0) {
378290931Srodrigc		gkey.ge_gid = strtonum(key, 0, GID_MAX, &estr);
379290931Srodrigc		if (estr) {
380290931Srodrigc			res.stat = YP_BADARGS;
381351694Skib			goto out;
382290931Srodrigc		}
383290931Srodrigc		if ((ge = RB_FIND(group_gid_tree, &env->sc_group_gids,
384290931Srodrigc		    &gkey)) == NULL) {
385290931Srodrigc			res.stat = YP_NOKEY;
386351694Skib			goto out;
387290931Srodrigc		}
388290931Srodrigc
389290931Srodrigc		yp_make_val(&res, ge->ge_line, 1);
390290931Srodrigc		return (&res);
391290931Srodrigc	} else if (strcmp(arg->map, "group.byname") == 0) {
392290931Srodrigc		gkey.ge_line = key;
393290931Srodrigc		if ((ge = RB_FIND(group_name_tree, env->sc_group_names,
394290931Srodrigc		    &gkey)) == NULL) {
395290931Srodrigc			res.stat = YP_NOKEY;
396351694Skib			goto out;
397290931Srodrigc		}
398290931Srodrigc
399290931Srodrigc		yp_make_val(&res, ge->ge_line, 1);
400290931Srodrigc		return (&res);
401290931Srodrigc	} else if (strcmp(arg->map, "netid.byname") == 0) {
402290931Srodrigc		bp = cp = key;
403290931Srodrigc
404290931Srodrigc		if (strncmp(bp, "unix.", strlen("unix.")) != 0) {
405290931Srodrigc			res.stat = YP_BADARGS;
406351694Skib			goto out;
407290931Srodrigc		}
408290931Srodrigc
409290931Srodrigc		bp += strlen("unix.");
410290931Srodrigc
411290931Srodrigc		if (*bp == '\0') {
412290931Srodrigc			res.stat = YP_BADARGS;
413351694Skib			goto out;
414290931Srodrigc		}
415290931Srodrigc
416290931Srodrigc		if (!(cp = strsep(&bp, "@"))) {
417290931Srodrigc			res.stat = YP_BADARGS;
418351694Skib			goto out;
419290931Srodrigc		}
420290931Srodrigc
421290931Srodrigc		if (strcmp(bp, arg->domain) != 0) {
422290931Srodrigc			res.stat = YP_BADARGS;
423351694Skib			goto out;
424290931Srodrigc		}
425290931Srodrigc
426290931Srodrigc		ukey.ue_uid = strtonum(cp, 0, UID_MAX, &estr);
427290931Srodrigc		if (estr) {
428290931Srodrigc			res.stat = YP_BADARGS;
429351694Skib			goto out;
430290931Srodrigc		}
431290931Srodrigc
432290931Srodrigc		if ((ue = RB_FIND(user_uid_tree, &env->sc_user_uids,
433290931Srodrigc		    &ukey)) == NULL) {
434290931Srodrigc			res.stat = YP_NOKEY;
435351694Skib			goto out;
436290931Srodrigc		}
437290931Srodrigc
438290931Srodrigc		yp_make_val(&res, ue->ue_netid_line, 0);
439351694Skib		goto out;
440290931Srodrigc
441290931Srodrigc	} else {
442290931Srodrigc		log_debug("unknown map %s", arg->map);
443290931Srodrigc		res.stat = YP_NOMAP;
444351694Skib		goto out;
445290931Srodrigc	}
446351694Skibout:
447351694Skib	free(key);
448351694Skib	return (&res);
449290931Srodrigc}
450290931Srodrigc
451290931Srodrigcypresp_key_val *
452290931Srodrigcypproc_first_2_svc(ypreq_nokey *arg, struct svc_req *req)
453290931Srodrigc{
454290931Srodrigc	static struct ypresp_key_val	res;
455290931Srodrigc
456290931Srodrigc	if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
457290931Srodrigc		return (&res);
458290931Srodrigc
459290931Srodrigc	if (strcmp(arg->map, "passwd.byname") == 0 ||
460290931Srodrigc	    strcmp(arg->map, "master.passwd.byname") == 0) {
461290931Srodrigc		if (env->sc_user_lines == NULL)
462290931Srodrigc			return (NULL);
463290931Srodrigc
464290931Srodrigc		yp_make_keyval(&res, env->sc_user_lines, env->sc_user_lines);
465290931Srodrigc	} else if (strcmp(arg->map, "group.byname") == 0) {
466290931Srodrigc		if (env->sc_group_lines == NULL)
467290931Srodrigc			return (NULL);
468290931Srodrigc
469290931Srodrigc		yp_make_keyval(&res, env->sc_group_lines, env->sc_group_lines);
470290931Srodrigc	} else {
471290931Srodrigc		log_debug("unknown map %s", arg->map);
472290931Srodrigc		res.stat = YP_NOMAP;
473290931Srodrigc	}
474290931Srodrigc
475290931Srodrigc	return (&res);
476290931Srodrigc}
477290931Srodrigc
478290931Srodrigcypresp_key_val *
479290931Srodrigcypproc_next_2_svc(ypreq_key *arg, struct svc_req *req)
480290931Srodrigc{
481290931Srodrigc	struct userent			 ukey;
482290931Srodrigc	struct userent			*ue;
483290931Srodrigc	struct groupent			 gkey;
484290931Srodrigc	struct groupent			*ge;
485290931Srodrigc	char				*line;
486290931Srodrigc	static struct ypresp_key_val	 res;
487351694Skib	char				 *key;
488290931Srodrigc
489290931Srodrigc	if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
490290931Srodrigc		return (&res);
491290931Srodrigc
492351694Skib	key = NULL;
493290931Srodrigc	if (strcmp(arg->map, "passwd.byname") == 0 ||
494290931Srodrigc	    strcmp(arg->map, "master.passwd.byname") == 0) {
495351694Skib		key = calloc(arg->key.keydat_len + 1, 1);
496351694Skib		if (key == NULL) {
497351694Skib			res.stat = YP_YPERR;
498351694Skib			return (&res);
499351694Skib		}
500290931Srodrigc		(void)strncpy(key, arg->key.keydat_val,
501290931Srodrigc		    arg->key.keydat_len);
502290931Srodrigc		ukey.ue_line = key;
503290931Srodrigc		if ((ue = RB_FIND(user_name_tree, env->sc_user_names,
504290931Srodrigc		    &ukey)) == NULL) {
505290931Srodrigc			/*
506290931Srodrigc			 * canacar's trick:
507290931Srodrigc			 * the user might have been deleted in between calls
508290931Srodrigc			 * to next since the tree may be modified by a reload.
509290931Srodrigc			 * next should still return the next user in
510290931Srodrigc			 * lexicographical order, hence insert the search key
511290931Srodrigc			 * and look up the next field, then remove it again.
512290931Srodrigc			 */
513290931Srodrigc			RB_INSERT(user_name_tree, env->sc_user_names, &ukey);
514290931Srodrigc			if ((ue = RB_NEXT(user_name_tree, &env->sc_user_names,
515290931Srodrigc			    &ukey)) == NULL) {
516290931Srodrigc				RB_REMOVE(user_name_tree, env->sc_user_names,
517290931Srodrigc				    &ukey);
518290931Srodrigc				res.stat = YP_NOKEY;
519351694Skib				free(key);
520290931Srodrigc				return (&res);
521290931Srodrigc			}
522290931Srodrigc			RB_REMOVE(user_name_tree, env->sc_user_names, &ukey);
523290931Srodrigc		}
524290931Srodrigc		line = ue->ue_line + (strlen(ue->ue_line) + 1);
525290931Srodrigc		line = line + (strlen(line) + 1);
526290931Srodrigc		yp_make_keyval(&res, line, line);
527351694Skib		free(key);
528290931Srodrigc		return (&res);
529290931Srodrigc
530290931Srodrigc
531290931Srodrigc	} else if (strcmp(arg->map, "group.byname") == 0) {
532351694Skib		key = calloc(arg->key.keydat_len + 1, 1);
533351694Skib		if (key == NULL) {
534351694Skib			res.stat = YP_YPERR;
535351694Skib			return (&res);
536351694Skib		}
537290931Srodrigc		(void)strncpy(key, arg->key.keydat_val,
538290931Srodrigc		    arg->key.keydat_len);
539290931Srodrigc
540290931Srodrigc		gkey.ge_line = key;
541290931Srodrigc		if ((ge = RB_FIND(group_name_tree, env->sc_group_names,
542290931Srodrigc		    &gkey)) == NULL) {
543290931Srodrigc			/*
544290931Srodrigc			 * canacar's trick reloaded.
545290931Srodrigc			 */
546290931Srodrigc			RB_INSERT(group_name_tree, env->sc_group_names, &gkey);
547290931Srodrigc			if ((ge = RB_NEXT(group_name_tree, &env->sc_group_names,
548290931Srodrigc			    &gkey)) == NULL) {
549290931Srodrigc				RB_REMOVE(group_name_tree, env->sc_group_names,
550290931Srodrigc				    &gkey);
551290931Srodrigc				res.stat = YP_NOKEY;
552351694Skib				free(key);
553290931Srodrigc				return (&res);
554290931Srodrigc			}
555290931Srodrigc			RB_REMOVE(group_name_tree, env->sc_group_names, &gkey);
556290931Srodrigc		}
557290931Srodrigc
558290931Srodrigc		line = ge->ge_line + (strlen(ge->ge_line) + 1);
559290931Srodrigc		line = line + (strlen(line) + 1);
560290931Srodrigc		yp_make_keyval(&res, line, line);
561351694Skib		free(key);
562290931Srodrigc		return (&res);
563290931Srodrigc	} else {
564290931Srodrigc		log_debug("unknown map %s", arg->map);
565290931Srodrigc		res.stat = YP_NOMAP;
566290931Srodrigc		return (&res);
567290931Srodrigc	}
568290931Srodrigc}
569290931Srodrigc
570290931Srodrigcypresp_all *
571290931Srodrigcypproc_all_2_svc(ypreq_nokey *arg, struct svc_req *req)
572290931Srodrigc{
573290931Srodrigc	static struct ypresp_all	res;
574290931Srodrigc
575290931Srodrigc	if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
576290931Srodrigc		return (&res);
577290931Srodrigc
578290931Srodrigc	svcerr_auth(req->rq_xprt, AUTH_FAILED);
579290931Srodrigc	return (NULL);
580290931Srodrigc}
581290931Srodrigc
582290931Srodrigcypresp_master *
583290931Srodrigcypproc_master_2_svc(ypreq_nokey *arg, struct svc_req *req)
584290931Srodrigc{
585290931Srodrigc	static struct ypresp_master	 res;
586296376Saraujo	static char master[YPMAXPEER + 1];
587290931Srodrigc
588309872Saraujo	memset(&res, 0, sizeof(res));
589290931Srodrigc	if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
590290931Srodrigc		return (&res);
591296376Saraujo
592296376Saraujo	if (gethostname(master, sizeof(master)) == 0) {
593296376Saraujo		res.peer = (peername)master;
594296376Saraujo		res.stat = YP_TRUE;
595296376Saraujo	} else
596296376Saraujo		res.stat = YP_NOKEY;
597290931Srodrigc
598290931Srodrigc	return (&res);
599290931Srodrigc}
600290931Srodrigc
601290931Srodrigcypresp_maplist *
602290931Srodrigcypproc_maplist_2_svc(domainname *arg, struct svc_req *req)
603290931Srodrigc{
604290931Srodrigc	size_t			 i;
605290931Srodrigc	static struct {
606290931Srodrigc		char		*name;
607290931Srodrigc		int		 cond;
608290931Srodrigc	}			 mapnames[] = {
609290931Srodrigc		{ "passwd.byname",		YPMAP_PASSWD_BYNAME },
610290931Srodrigc		{ "passwd.byuid",		YPMAP_PASSWD_BYUID },
611290931Srodrigc		{ "master.passwd.byname",	YPMAP_MASTER_PASSWD_BYNAME },
612290931Srodrigc		{ "master.passwd.byuid",	YPMAP_MASTER_PASSWD_BYUID },
613290931Srodrigc		{ "group.byname",		YPMAP_GROUP_BYNAME },
614290931Srodrigc		{ "group.bygid",		YPMAP_GROUP_BYGID },
615290931Srodrigc		{ "netid.byname",		YPMAP_NETID_BYNAME },
616290931Srodrigc	};
617290931Srodrigc	static ypresp_maplist	 res;
618298177Saraujo	static struct ypmaplist	 maps[nitems(mapnames)];
619290931Srodrigc
620290931Srodrigc	if (yp_valid_domain(*arg, (struct ypresp_val *)&res) == -1)
621290931Srodrigc		return (&res);
622290931Srodrigc
623290931Srodrigc	res.stat = YP_TRUE;
624290931Srodrigc	res.maps = NULL;
625298177Saraujo	for (i = 0; i < nitems(mapnames); i++) {
626290931Srodrigc		if (!(env->sc_flags & mapnames[i].cond))
627290931Srodrigc			continue;
628290931Srodrigc		maps[i].map = mapnames[i].name;
629290931Srodrigc		maps[i].next = res.maps;
630290931Srodrigc		res.maps = &maps[i];
631290931Srodrigc	}
632290931Srodrigc
633290931Srodrigc	return (&res);
634290931Srodrigc}
635290931Srodrigc
636290931Srodrigcvoid
637290931Srodrigcyp_make_val(struct ypresp_val *res, char *line, int replacecolon)
638290931Srodrigc{
639290931Srodrigc	static char		 buf[LINE_WIDTH];
640290931Srodrigc
641309872Saraujo	memset(buf, 0, sizeof(buf));
642290931Srodrigc
643290931Srodrigc	if (replacecolon)
644290931Srodrigc		line[strlen(line)] = ':';
645290931Srodrigc	(void)strlcpy(buf, line, sizeof(buf));
646290931Srodrigc	if (replacecolon)
647290931Srodrigc		line[strcspn(line, ":")] = '\0';
648290931Srodrigc	log_debug("sending out %s", buf);
649290931Srodrigc
650290931Srodrigc	res->stat = YP_TRUE;
651290931Srodrigc	res->val.valdat_len = strlen(buf);
652290931Srodrigc	res->val.valdat_val = buf;
653290931Srodrigc}
654290931Srodrigc
655290931Srodrigcvoid
656290931Srodrigcyp_make_keyval(struct ypresp_key_val *res, char *key, char *line)
657290931Srodrigc{
658290931Srodrigc	static char	keybuf[YPMAXRECORD+1];
659290931Srodrigc	static char	buf[LINE_WIDTH];
660290931Srodrigc
661309872Saraujo	memset(keybuf, 0, sizeof(keybuf));
662309872Saraujo	memset(buf, 0, sizeof(buf));
663290931Srodrigc
664290931Srodrigc	(void)strlcpy(keybuf, key, sizeof(keybuf));
665290931Srodrigc	res->key.keydat_len = strlen(keybuf);
666290931Srodrigc	res->key.keydat_val = keybuf;
667290931Srodrigc
668290931Srodrigc	if (*line == '\0') {
669290931Srodrigc		res->stat = YP_NOMORE;
670290931Srodrigc		return;
671290931Srodrigc	}
672290931Srodrigc	res->stat = YP_TRUE;
673290931Srodrigc	line[strlen(line)] = ':';
674290931Srodrigc	(void)strlcpy(buf, line, sizeof(buf));
675290931Srodrigc	line[strcspn(line, ":")] = '\0';
676290931Srodrigc	log_debug("sending out %s => %s", keybuf, buf);
677290931Srodrigc
678290931Srodrigc	res->val.valdat_len = strlen(buf);
679290931Srodrigc	res->val.valdat_val = buf;
680290931Srodrigc}
681