xref: /openbsd/usr.sbin/ypldap/yp.c (revision 3cab2bb3)
1 /*	$OpenBSD: yp.c,v 1.19 2017/12/07 05:21:57 zhuk Exp $ */
2 /*
3  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/types.h>
19 #include <sys/queue.h>
20 #include <sys/socket.h>
21 #include <sys/select.h>
22 #include <sys/tree.h>
23 
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 
27 #include <errno.h>
28 #include <event.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31 #include <pwd.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <limits.h>
36 
37 #include <rpc/rpc.h>
38 #include <rpc/xdr.h>
39 #include <rpc/pmap_clnt.h>
40 #include <rpc/pmap_prot.h>
41 #include <rpc/pmap_rmt.h>
42 #include <rpcsvc/yp.h>
43 #include <rpcsvc/ypclnt.h>
44 
45 #include "ypldap.h"
46 
47 void	yp_dispatch(struct svc_req *, SVCXPRT *);
48 void	yp_disable_events(void);
49 void	yp_fd_event(int, short, void *);
50 int	yp_check(struct svc_req *);
51 int	yp_valid_domain(char *, struct ypresp_val *);
52 void	yp_make_val(struct ypresp_val *, char *, int);
53 void	yp_make_keyval(struct ypresp_key_val *, char *, char *);
54 
55 static struct env	*env;
56 
57 struct yp_event {
58 	TAILQ_ENTRY(yp_event)	 ye_entry;
59 	struct event		 ye_event;
60 };
61 
62 struct yp_data {
63 	SVCXPRT			*yp_trans_udp;
64 	SVCXPRT			*yp_trans_tcp;
65 	TAILQ_HEAD(, yp_event)	 yd_events;
66 };
67 
68 void
69 yp_disable_events(void)
70 {
71 	struct yp_event	*ye;
72 
73 	while ((ye = TAILQ_FIRST(&env->sc_yp->yd_events)) != NULL) {
74 		TAILQ_REMOVE(&env->sc_yp->yd_events, ye, ye_entry);
75 		event_del(&ye->ye_event);
76 		free(ye);
77 	}
78 }
79 
80 void
81 yp_enable_events(void)
82 {
83 	int		 i;
84 	extern fd_set	*__svc_fdset;
85 	extern int	 __svc_fdsetsize;
86 	struct yp_event	*ye;
87 
88 	for (i = 0; i < __svc_fdsetsize; i++) {
89 		if (FD_ISSET(i, __svc_fdset)) {
90 			if ((ye = calloc(1, sizeof(*ye))) == NULL)
91 				fatal(NULL);
92 			event_set(&ye->ye_event, i, EV_READ, yp_fd_event, NULL);
93 			event_add(&ye->ye_event, NULL);
94 			TAILQ_INSERT_TAIL(&env->sc_yp->yd_events, ye, ye_entry);
95 		}
96 	}
97 }
98 
99 void
100 yp_fd_event(int fd, short event, void *p)
101 {
102 	svc_getreq_common(fd);
103 	yp_disable_events();
104 	yp_enable_events();
105 }
106 
107 void
108 yp_init(struct env *x_env)
109 {
110 	struct yp_data	*yp;
111 
112 	if ((yp = calloc(1, sizeof(*yp))) == NULL)
113 		fatal(NULL);
114 	TAILQ_INIT(&yp->yd_events);
115 
116 	env = x_env;
117 	env->sc_yp = yp;
118 
119 	(void)pmap_unset(YPPROG, YPVERS);
120 
121 	if ((yp->yp_trans_udp = svcudp_create(RPC_ANYSOCK)) == NULL)
122 		fatal("cannot create udp service");
123 	if ((yp->yp_trans_tcp = svctcp_create(RPC_ANYSOCK, 0, 0)) == NULL)
124 		fatal("cannot create tcp service");
125 
126 	if (!svc_register(yp->yp_trans_udp, YPPROG, YPVERS,
127 	    yp_dispatch, IPPROTO_UDP)) {
128 		fatal("unable to register (YPPROG, YPVERS, udp)");
129 	}
130 	if (!svc_register(yp->yp_trans_tcp, YPPROG, YPVERS,
131 	    yp_dispatch, IPPROTO_TCP)) {
132 		fatal("unable to register (YPPROG, YPVERS, tcp)");
133 	}
134 }
135 
136 /*
137  * lots of inspiration from ypserv by Mats O Jansson
138  */
139 void
140 yp_dispatch(struct svc_req *req, SVCXPRT *trans)
141 {
142 	xdrproc_t		 xdr_argument;
143 	xdrproc_t		 xdr_result;
144 	char			*result;
145 	char			*(*cb)(char *, struct svc_req *);
146         union {
147 		domainname	 ypproc_domain_2_arg;
148 		domainname	 ypproc_domain_nonack_2_arg;
149 		ypreq_key	 ypproc_match_2_arg;
150 		ypreq_nokey	 ypproc_first_2_arg;
151 		ypreq_key	 ypproc_next_2_arg;
152 		ypreq_xfr	 ypproc_xfr_2_arg;
153 		ypreq_nokey	 ypproc_all_2_arg;
154 		ypreq_nokey	 ypproc_master_2_arg;
155 		ypreq_nokey	 ypproc_order_2_arg;
156 		domainname	 ypproc_maplist_2_arg;
157 	} argument;
158 
159 	xdr_argument = (xdrproc_t) xdr_void;
160 	xdr_result = (xdrproc_t) xdr_void;
161 	cb = NULL;
162 	switch (req->rq_proc) {
163 	case YPPROC_NULL:
164 		xdr_argument = (xdrproc_t) xdr_void;
165 		xdr_result = (xdrproc_t) xdr_void;
166 		if (yp_check(req) == -1)
167 			return;
168 		result = NULL;
169 		if (!svc_sendreply(trans, (xdrproc_t) xdr_void,
170 		    (void *)&result))
171 			svcerr_systemerr(trans);
172 		return;
173 	case YPPROC_DOMAIN:
174 		xdr_argument = (xdrproc_t) xdr_domainname;
175 		xdr_result = (xdrproc_t) xdr_bool;
176 		if (yp_check(req) == -1)
177 			return;
178 		cb = (void *)ypproc_domain_2_svc;
179 		break;
180 	case YPPROC_DOMAIN_NONACK:
181 		xdr_argument = (xdrproc_t) xdr_domainname;
182 		xdr_result = (xdrproc_t) xdr_bool;
183 		if (yp_check(req) == -1)
184 			return;
185 		cb = (void *)ypproc_domain_nonack_2_svc;
186 		break;
187 	case YPPROC_MATCH:
188 		xdr_argument = (xdrproc_t) xdr_ypreq_key;
189 		xdr_result = (xdrproc_t) xdr_ypresp_val;
190 		if (yp_check(req) == -1)
191 			return;
192 		cb = (void *)ypproc_match_2_svc;
193 		break;
194 	case YPPROC_FIRST:
195 		xdr_argument = (xdrproc_t) xdr_ypreq_nokey;
196 		xdr_result = (xdrproc_t) xdr_ypresp_key_val;
197 		if (yp_check(req) == -1)
198 			return;
199 		cb = (void *)ypproc_first_2_svc;
200 		break;
201 	case YPPROC_NEXT:
202 		xdr_argument = (xdrproc_t) xdr_ypreq_key;
203 		xdr_result = (xdrproc_t) xdr_ypresp_key_val;
204 		if (yp_check(req) == -1)
205 			return;
206 		cb = (void *)ypproc_next_2_svc;
207 		break;
208 	case YPPROC_XFR:
209 		if (yp_check(req) == -1)
210 			return;
211 		svcerr_noproc(trans);
212 		return;
213 	case YPPROC_CLEAR:
214 		log_debug("ypproc_clear");
215 		if (yp_check(req) == -1)
216 			return;
217 		svcerr_noproc(trans);
218 		return;
219 	case YPPROC_ALL:
220 		log_debug("ypproc_all");
221 		xdr_argument = (xdrproc_t) xdr_ypreq_nokey;
222 		xdr_result = (xdrproc_t) xdr_ypresp_all;
223 		if (yp_check(req) == -1)
224 			return;
225 		cb = (void *)ypproc_all_2_svc;
226 		break;
227 	case YPPROC_MASTER:
228 		xdr_argument = (xdrproc_t) xdr_ypreq_nokey;
229 		xdr_result = (xdrproc_t) xdr_ypresp_master;
230 		if (yp_check(req) == -1)
231 			return;
232 		cb = (void *)ypproc_master_2_svc;
233 		break;
234 	case YPPROC_ORDER:
235 		log_debug("ypproc_order");
236 		if (yp_check(req) == -1)
237 			return;
238 		svcerr_noproc(trans);
239 		return;
240 	case YPPROC_MAPLIST:
241 		xdr_argument = (xdrproc_t) xdr_domainname;
242 		xdr_result = (xdrproc_t) xdr_ypresp_maplist;
243 		if (yp_check(req) == -1)
244 			return;
245 		cb = (void *)ypproc_maplist_2_svc;
246 		break;
247 	default:
248 		svcerr_noproc(trans);
249 		return;
250 	}
251 	(void)memset(&argument, 0, sizeof(argument));
252 
253 	if (!svc_getargs(trans, xdr_argument, (caddr_t)&argument)) {
254 		svcerr_decode(trans);
255 		return;
256 	}
257 	result = (*cb)((char *)&argument, req);
258 	if (result != NULL && !svc_sendreply(trans, xdr_result, result))
259 		svcerr_systemerr(trans);
260 	if (!svc_freeargs(trans, xdr_argument, (caddr_t)&argument)) {
261 		/*
262 		 * ypserv does it too.
263 		 */
264 		fatal("unable to free arguments");
265 	}
266 }
267 
268 int
269 yp_check(struct svc_req *req)
270 {
271 	struct sockaddr_in	*caller;
272 
273 	caller = svc_getcaller(req->rq_xprt);
274 	/*
275 	 * We might want to know who we allow here.
276 	 */
277 	return (0);
278 }
279 
280 int
281 yp_valid_domain(char *domain, struct ypresp_val *res)
282 {
283 	if (domain == NULL) {
284 		log_debug("NULL domain !");
285 		return (-1);
286 	}
287 	if (strcmp(domain, env->sc_domainname) != 0) {
288 		res->stat = YP_NODOM;
289 		return (-1);
290 	}
291 	return (0);
292 }
293 
294 bool_t *
295 ypproc_domain_2_svc(domainname *arg, struct svc_req *req)
296 {
297 	static bool_t	res;
298 
299 	res = (bool_t)1;
300 	if (strcmp(*arg, env->sc_domainname) != 0)
301 		res = (bool_t)0;
302 	return (&res);
303 }
304 
305 bool_t *
306 ypproc_domain_nonack_2_svc(domainname *arg, struct svc_req *req)
307 {
308 	static bool_t	res;
309 
310 	if (strcmp(*arg, env->sc_domainname) != 0)
311 		return NULL;
312 	res = (bool_t)1;
313 	return (&res);
314 }
315 
316 ypresp_val *
317 ypproc_match_2_svc(ypreq_key *arg, struct svc_req *req)
318 {
319 	struct userent		 ukey;
320 	struct userent		*ue;
321 	struct groupent		 gkey;
322 	struct groupent		*ge;
323 	static struct ypresp_val res;
324 	const char		*estr;
325 	char			*bp, *cp;
326 	char			 key[YPMAXRECORD+1];
327 
328 	log_debug("matching '%.*s' in map %s", arg->key.keydat_len,
329 	   arg->key.keydat_val, arg->map);
330 
331 	if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
332 		return (&res);
333 
334 	if (env->sc_user_names == NULL) {
335 		/*
336 		 * tree not ready.
337 		 */
338 		return (NULL);
339 	}
340 
341 	if (arg->key.keydat_len > YPMAXRECORD) {
342 		log_debug("argument too long");
343 		return (NULL);
344 	}
345 	memset(key, 0, sizeof(key));
346 	(void)strncpy(key, arg->key.keydat_val, arg->key.keydat_len);
347 
348 	if (strcmp(arg->map, "passwd.byname") == 0 ||
349 	    strcmp(arg->map, "master.passwd.byname") == 0) {
350 		ukey.ue_line = key;
351 		if ((ue = RB_FIND(user_name_tree, env->sc_user_names,
352 		    &ukey)) == NULL) {
353 			res.stat = YP_NOKEY;
354 			return (&res);
355 		}
356 
357 		yp_make_val(&res, ue->ue_line, 1);
358 		return (&res);
359 	} else if (strcmp(arg->map, "passwd.byuid") == 0 ||
360 		   strcmp(arg->map, "master.passwd.byuid") == 0) {
361 		ukey.ue_uid = strtonum(key, 0, UID_MAX, &estr);
362 		if (estr) {
363 			res.stat = YP_BADARGS;
364 			return (&res);
365 		}
366 
367 		if ((ue = RB_FIND(user_uid_tree, &env->sc_user_uids,
368 		    &ukey)) == NULL) {
369 			res.stat = YP_NOKEY;
370 			return (&res);
371 		}
372 
373 		yp_make_val(&res, ue->ue_line, 1);
374 		return (&res);
375 	} else if (strcmp(arg->map, "group.bygid") == 0) {
376 		gkey.ge_gid = strtonum(key, 0, GID_MAX, &estr);
377 		if (estr) {
378 			res.stat = YP_BADARGS;
379 			return (&res);
380 		}
381 		if ((ge = RB_FIND(group_gid_tree, &env->sc_group_gids,
382 		    &gkey)) == NULL) {
383 			res.stat = YP_NOKEY;
384 			return (&res);
385 		}
386 
387 		yp_make_val(&res, ge->ge_line, 1);
388 		return (&res);
389 	} else if (strcmp(arg->map, "group.byname") == 0) {
390 		gkey.ge_line = key;
391 		if ((ge = RB_FIND(group_name_tree, env->sc_group_names,
392 		    &gkey)) == NULL) {
393 			res.stat = YP_NOKEY;
394 			return (&res);
395 		}
396 
397 		yp_make_val(&res, ge->ge_line, 1);
398 		return (&res);
399 	} else if (strcmp(arg->map, "netid.byname") == 0) {
400 		bp = cp = key;
401 
402 		if (strncmp(bp, "unix.", strlen("unix.")) != 0) {
403 			res.stat = YP_BADARGS;
404 			return (&res);
405 		}
406 
407 		bp += strlen("unix.");
408 
409 		if (*bp == '\0') {
410 			res.stat = YP_BADARGS;
411 			return (&res);
412 		}
413 
414 		if (!(cp = strsep(&bp, "@"))) {
415 			res.stat = YP_BADARGS;
416 			return (&res);
417 		}
418 
419 		if (strcmp(bp, arg->domain) != 0) {
420 			res.stat = YP_BADARGS;
421 			return (&res);
422 		}
423 
424 		ukey.ue_uid = strtonum(cp, 0, UID_MAX, &estr);
425 		if (estr) {
426 			res.stat = YP_BADARGS;
427 			return (&res);
428 		}
429 
430 		if ((ue = RB_FIND(user_uid_tree, &env->sc_user_uids,
431 		    &ukey)) == NULL) {
432 			res.stat = YP_NOKEY;
433 			return (&res);
434 		}
435 
436 		yp_make_val(&res, ue->ue_netid_line, 0);
437 		return (&res);
438 
439 	} else {
440 		log_debug("unknown map %s", arg->map);
441 		res.stat = YP_NOMAP;
442 		return (&res);
443 	}
444 }
445 
446 ypresp_key_val *
447 ypproc_first_2_svc(ypreq_nokey *arg, struct svc_req *req)
448 {
449 	static struct ypresp_key_val	res;
450 
451 	if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
452 		return (&res);
453 
454 	if (strcmp(arg->map, "passwd.byname") == 0 ||
455 	    strcmp(arg->map, "master.passwd.byname") == 0) {
456 		if (env->sc_user_lines == NULL)
457 			return (NULL);
458 
459 		yp_make_keyval(&res, env->sc_user_lines, env->sc_user_lines);
460 	} else if (strcmp(arg->map, "group.byname") == 0) {
461 		if (env->sc_group_lines == NULL)
462 			return (NULL);
463 
464 		yp_make_keyval(&res, env->sc_group_lines, env->sc_group_lines);
465 	} else {
466 		log_debug("unknown map %s", arg->map);
467 		res.stat = YP_NOMAP;
468 	}
469 
470 	return (&res);
471 }
472 
473 ypresp_key_val *
474 ypproc_next_2_svc(ypreq_key *arg, struct svc_req *req)
475 {
476 	struct userent			 ukey;
477 	struct userent			*ue;
478 	struct groupent			 gkey;
479 	struct groupent			*ge;
480 	char				*line;
481 	static struct ypresp_key_val	 res;
482 	char				 key[YPMAXRECORD+1];
483 
484 	if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
485 		return (&res);
486 
487 	if (strcmp(arg->map, "passwd.byname") == 0 ||
488 	    strcmp(arg->map, "master.passwd.byname") == 0) {
489 		memset(key, 0, sizeof(key));
490 		(void)strncpy(key, arg->key.keydat_val,
491 		    arg->key.keydat_len);
492 		ukey.ue_line = key;
493 		if ((ue = RB_NFIND(user_name_tree, env->sc_user_names,
494 		    &ukey)) == NULL) {
495 			res.stat = YP_NOKEY;
496 			return (&res);
497 		}
498 		line = ue->ue_line + (strlen(ue->ue_line) + 1);
499 		line = line + (strlen(line) + 1);
500 		yp_make_keyval(&res, line, line);
501 		return (&res);
502 
503 
504 	} else if (strcmp(arg->map, "group.byname") == 0) {
505 		memset(key, 0, sizeof(key));
506 		(void)strncpy(key, arg->key.keydat_val,
507 		    arg->key.keydat_len);
508 
509 		gkey.ge_line = key;
510 		if ((ge = RB_NFIND(group_name_tree, env->sc_group_names,
511 		    &gkey)) == NULL) {
512 			res.stat = YP_NOKEY;
513 			return (&res);
514 		}
515 
516 		line = ge->ge_line + (strlen(ge->ge_line) + 1);
517 		line = line + (strlen(line) + 1);
518 		yp_make_keyval(&res, line, line);
519 		return (&res);
520 	} else {
521 		log_debug("unknown map %s", arg->map);
522 		res.stat = YP_NOMAP;
523 		return (&res);
524 	}
525 }
526 
527 ypresp_all *
528 ypproc_all_2_svc(ypreq_nokey *arg, struct svc_req *req)
529 {
530 	static struct ypresp_all	res;
531 
532 	if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
533 		return (&res);
534 
535 	svcerr_auth(req->rq_xprt, AUTH_FAILED);
536 	return (NULL);
537 }
538 
539 ypresp_master *
540 ypproc_master_2_svc(ypreq_nokey *arg, struct svc_req *req)
541 {
542 	static struct ypresp_master	 res;
543 	static char master[YPMAXPEER + 1];
544 
545 	memset(&res, 0, sizeof(res));
546 	if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
547 		return (&res);
548 	if (gethostname(master, sizeof(master)) == 0) {
549 		res.peer = (peername)master;
550 		res.stat = YP_TRUE;
551 	} else
552 		res.stat = YP_NOKEY;
553 	return (&res);
554 }
555 
556 ypresp_maplist *
557 ypproc_maplist_2_svc(domainname *arg, struct svc_req *req)
558 {
559 	size_t			 i;
560 	static struct {
561 		char		*name;
562 		int		 cond;
563 	}			 mapnames[] = {
564 		{ "passwd.byname",		YPMAP_PASSWD_BYNAME },
565 		{ "passwd.byuid",		YPMAP_PASSWD_BYUID },
566 		{ "master.passwd.byname",	YPMAP_MASTER_PASSWD_BYNAME },
567 		{ "master.passwd.byuid",	YPMAP_MASTER_PASSWD_BYUID },
568 		{ "group.byname",		YPMAP_GROUP_BYNAME },
569 		{ "group.bygid",		YPMAP_GROUP_BYGID },
570 		{ "netid.byname",		YPMAP_NETID_BYNAME },
571 	};
572 	static ypresp_maplist	 res;
573 	static struct ypmaplist	 maps[sizeof(mapnames) / sizeof(mapnames[0])];
574 
575 	if (yp_valid_domain(*arg, (struct ypresp_val *)&res) == -1)
576 		return (&res);
577 
578 	res.stat = YP_TRUE;
579 	res.maps = NULL;
580 	for (i = 0; i < sizeof(mapnames) / sizeof(mapnames[0]); i++) {
581 		if (!(env->sc_flags & mapnames[i].cond))
582 			continue;
583 		maps[i].map = mapnames[i].name;
584 		maps[i].next = res.maps;
585 		res.maps = &maps[i];
586 	}
587 
588 	return (&res);
589 }
590 
591 void
592 yp_make_val(struct ypresp_val *res, char *line, int replacecolon)
593 {
594 	static char		 buf[LINE_WIDTH];
595 
596 	memset(buf, 0, sizeof(buf));
597 
598 	if (replacecolon)
599 		line[strlen(line)] = ':';
600 	(void)strlcpy(buf, line, sizeof(buf));
601 	if (replacecolon)
602 		line[strcspn(line, ":")] = '\0';
603 	log_debug("sending out %s", buf);
604 
605 	res->stat = YP_TRUE;
606 	res->val.valdat_len = strlen(buf);
607 	res->val.valdat_val = buf;
608 }
609 
610 void
611 yp_make_keyval(struct ypresp_key_val *res, char *key, char *line)
612 {
613 	static char	keybuf[YPMAXRECORD+1];
614 	static char	buf[LINE_WIDTH];
615 
616 	memset(keybuf, 0, sizeof(keybuf));
617 	memset(buf, 0, sizeof(buf));
618 
619 	(void)strlcpy(keybuf, key, sizeof(keybuf));
620 	res->key.keydat_len = strlen(keybuf);
621 	res->key.keydat_val = keybuf;
622 
623 	if (*line == '\0') {
624 		res->stat = YP_NOMORE;
625 		return;
626 	}
627 	res->stat = YP_TRUE;
628 	line[strlen(line)] = ':';
629 	(void)strlcpy(buf, line, sizeof(buf));
630 	line[strcspn(line, ":")] = '\0';
631 	log_debug("sending out %s => %s", keybuf, buf);
632 
633 	res->val.valdat_len = strlen(buf);
634 	res->val.valdat_val = buf;
635 }
636