xref: /netbsd/usr.sbin/ypserv/ypserv/ypserv_proc.c (revision 789fb81b)
1 /*	$NetBSD: ypserv_proc.c,v 1.18 2018/01/17 03:16:10 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1994 Mats O Jansson <moj@stacken.kth.se>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
17  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 #ifndef lint
31 __RCSID("$NetBSD: ypserv_proc.c,v 1.18 2018/01/17 03:16:10 christos Exp $");
32 #endif
33 
34 #include <sys/stat.h>
35 #include <sys/socket.h>
36 #include <sys/param.h>
37 #include <netinet/in.h>
38 #include <netdb.h>
39 #include <fcntl.h>
40 #include <dirent.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <stdlib.h>
45 #ifdef LIBWRAP
46 #include <syslog.h>
47 #endif
48 
49 #include <rpc/rpc.h>
50 #include <rpc/xdr.h>
51 #include <rpcsvc/yp_prot.h>
52 #include <rpcsvc/ypclnt.h>
53 
54 #include "ypserv.h"
55 #include "ypdb.h"
56 #include "ypdef.h"
57 
58 #ifdef LIBWRAP
59 #define	YPLOG(x)	if (lflag) syslog x
60 static const char *True = "TRUE";
61 static const char *False = "FALSE";
62 #define	TORF(x)	(x) ? True : False
63 #else
64 #define	YPLOG(x)	/* nothing */
65 #endif
66 
67 static int
securecheck(struct sockaddr * caller)68 securecheck(struct sockaddr *caller)
69 {
70 	char sbuf[NI_MAXSERV];
71 
72 	if (getnameinfo(caller, (socklen_t)caller->sa_len, NULL, 0, sbuf,
73 	    sizeof(sbuf), NI_NUMERICSERV))
74 		return (1);
75 
76 	return (atoi(sbuf) >= IPPORT_RESERVED);
77 }
78 
79 void *
80 /*ARGSUSED*/
ypproc_null_2_svc(void * argp,struct svc_req * rqstp)81 ypproc_null_2_svc(void *argp, struct svc_req *rqstp)
82 {
83 	static char result;
84 
85 	YPLOG((allow_severity, "null_2: request from %.500s", clientstr));
86 
87 	(void)memset(&result, 0, sizeof(result));
88 	return ((void *)&result);
89 }
90 
91 void *
ypproc_domain_2_svc(void * argp,struct svc_req * rqstp)92 ypproc_domain_2_svc(void *argp, struct svc_req *rqstp)
93 {
94 	static bool_t result;		/* is domain_served? */
95 	char *domain = *(char **)argp;
96 	char domain_path[MAXPATHLEN];
97 	struct stat finfo;
98 
99 	if (_yp_invalid_domain(domain)) {
100 		svcerr_auth(rqstp->rq_xprt, AUTH_FAILED);
101 		return (NULL);
102 	}
103 	(void)snprintf(domain_path, sizeof(domain_path), "%s/%s",
104 	    YP_DB_PATH, domain);
105 	if ((stat(domain_path, &finfo) == 0) && S_ISDIR(finfo.st_mode))
106 		result = TRUE;
107 	else
108 		result = FALSE;
109 
110 	YPLOG((allow_severity,
111 	    "domain_2: request from %.500s, domain %s, served %s",
112 	    clientstr, domain, TORF(result)));
113 
114 	return ((void *)&result);
115 }
116 
117 void *
ypproc_domain_nonack_2_svc(void * argp,struct svc_req * rqstp)118 ypproc_domain_nonack_2_svc(void *argp, struct svc_req *rqstp)
119 {
120 	static bool_t result;		/* is domain served? */
121 	char *domain = *(char **)argp;
122 	char domain_path[MAXPATHLEN];
123 	struct stat finfo;
124 
125 	if (_yp_invalid_domain(domain)) {
126 		svcerr_auth(rqstp->rq_xprt, AUTH_FAILED);
127 		return (NULL);
128 	}
129 	(void)snprintf(domain_path, sizeof(domain_path), "%s/%s",
130 	    YP_DB_PATH, domain);
131 	if ((stat(domain_path, &finfo) == 0) && S_ISDIR(finfo.st_mode))
132 		result = TRUE;
133 	else
134 		result = FALSE;
135 
136 	YPLOG((allow_severity,
137 	    "domain_nonack_2: request from %.500s, domain %s, served %s",
138 	    clientstr, domain, TORF(result)));
139 
140 	if (!result)
141 		return (NULL);	/* don't send nack */
142 
143 	return ((void *)&result);
144 }
145 
146 void *
ypproc_match_2_svc(void * argp,struct svc_req * rqstp)147 ypproc_match_2_svc(void *argp, struct svc_req *rqstp)
148 {
149 	static struct ypresp_val res;
150 	struct sockaddr *caller = svc_getrpccaller(rqstp->rq_xprt)->buf;
151 	struct ypreq_key *k = argp;
152 	int secure;
153 
154 	if (_yp_invalid_domain(k->domain) || _yp_invalid_map(k->map)) {
155 		svcerr_auth(rqstp->rq_xprt, AUTH_FAILED);
156 		return (NULL);
157 	}
158 
159 	secure = ypdb_secure(k->domain, k->map);
160 
161 	YPLOG((allow_severity,
162 	    "match_2: request from %.500s, secure %s, domain %s, map %s, "
163 	    "key %.*s", clientstr, TORF(secure), k->domain, k->map,
164 	    k->keydat.dsize, k->keydat.dptr));
165 
166 	if (secure && securecheck(caller)) {
167 		memset(&res, 0, sizeof(res));
168 		res.status = YP_YPERR;
169 	} else
170 		res = ypdb_get_record(k->domain, k->map, k->keydat, secure);
171 
172 	return ((void *)&res);
173 }
174 
175 void *
ypproc_first_2_svc(void * argp,struct svc_req * rqstp)176 ypproc_first_2_svc(void *argp, struct svc_req *rqstp)
177 {
178 	static struct ypresp_key_val res;
179 	struct sockaddr *caller = svc_getrpccaller(rqstp->rq_xprt)->buf;
180 	struct ypreq_nokey *k = argp;
181 	int secure;
182 
183 	if (_yp_invalid_domain(k->domain) || _yp_invalid_map(k->map)) {
184 		svcerr_auth(rqstp->rq_xprt, AUTH_FAILED);
185 		return (NULL);
186 	}
187 
188 	secure = ypdb_secure(k->domain, k->map);
189 
190 	YPLOG((allow_severity,
191 	    "first_2: request from %.500s, secure %s, domain %s, map %s",
192 	    clientstr, TORF(secure), k->domain, k->map));
193 
194 	if (secure && securecheck(caller)) {
195 		memset(&res, 0, sizeof(res));
196 		res.status = YP_YPERR;
197 	} else
198 		res = ypdb_get_first(k->domain, k->map, FALSE);
199 
200 	return ((void *)&res);
201 }
202 
203 void *
ypproc_next_2_svc(void * argp,struct svc_req * rqstp)204 ypproc_next_2_svc(void *argp, struct svc_req *rqstp)
205 {
206 	static struct ypresp_key_val res;
207 	struct sockaddr *caller = svc_getrpccaller(rqstp->rq_xprt)->buf;
208 	struct ypreq_key *k = argp;
209 	int secure;
210 
211 	if (_yp_invalid_domain(k->domain) || _yp_invalid_map(k->map)) {
212 		svcerr_auth(rqstp->rq_xprt, AUTH_FAILED);
213 		return (NULL);
214 	}
215 
216 	secure = ypdb_secure(k->domain, k->map);
217 
218 	YPLOG((allow_severity,
219 	    "next_2: request from %.500s, secure %s, domain %s, map %s, "
220 	    "key %.*s", clientstr, TORF(secure), k->domain, k->map,
221 	    k->keydat.dsize, k->keydat.dptr));
222 
223 	if (secure && securecheck(caller)) {
224 		memset(&res, 0, sizeof(res));
225 		res.status = YP_YPERR;
226 	} else
227 		res = ypdb_get_next(k->domain, k->map, k->keydat, FALSE);
228 
229 	return ((void *)&res);
230 }
231 
232 void *
ypproc_xfr_2_svc(void * argp,struct svc_req * rqstp)233 ypproc_xfr_2_svc(void *argp, struct svc_req *rqstp)
234 {
235 	static struct ypresp_xfr res;
236 	struct sockaddr *caller = svc_getrpccaller(rqstp->rq_xprt)->buf;
237 	struct ypreq_xfr *ypx = argp;
238 	char tid[11], prog[11], port[11];
239 	char hbuf[NI_MAXHOST];
240 	char ypxfr_proc[] = YPXFR_PROC;
241 
242 	(void)memset(&res, 0, sizeof(res));
243 
244 	YPLOG((allow_severity,
245 	    "xfr_2: request from %.500s, domain %s, tid %d, prog %d, port %d, "
246 	    "map %s", clientstr, ypx->map_parms.domain, ypx->transid,
247 	    ypx->proto, ypx->port, ypx->map_parms.map));
248 
249 	if (_yp_invalid_domain(ypx->map_parms.domain) ||
250 	    _yp_invalid_map(ypx->map_parms.map) ||
251 	    securecheck(caller)) {
252 		svcerr_auth(rqstp->rq_xprt, AUTH_FAILED);
253 		return (NULL);
254 	}
255 
256 	switch (vfork()) {
257 	case -1:
258 		svcerr_systemerr(rqstp->rq_xprt);
259 		return (NULL);
260 
261 	case 0:
262 		(void)snprintf(tid, sizeof(tid), "%d", ypx->transid);
263 		(void)snprintf(prog, sizeof(prog), "%d", ypx->proto);
264 		(void)snprintf(port, sizeof(port), "%d", ypx->port);
265 		if (getnameinfo(caller, (socklen_t)caller->sa_len, hbuf,
266 		    sizeof(hbuf), NULL, 0, 0))
267 			_exit(1);	/* XXX report error ? */
268 
269 		(void)execl(ypxfr_proc, "ypxfr", "-d", ypx->map_parms.domain,
270 		    "-C", tid, prog, hbuf, port, ypx->map_parms.map, NULL);
271 		_exit(1);		/* XXX report error? */
272 	}
273 
274 	/*
275 	 * XXX: fill in res
276 	 */
277 
278 	return ((void *)&res);
279 }
280 
281 void *
282 /*ARGSUSED*/
ypproc_clear_2_svc(void * argp,struct svc_req * rqstp)283 ypproc_clear_2_svc(void *argp, struct svc_req *rqstp)
284 {
285 	static char res;
286 	struct sockaddr *caller = svc_getrpccaller(rqstp->rq_xprt)->buf;
287 #ifdef OPTIMIZE_DB
288 	const char *optdbstr = True;
289 #else
290 	const char *optdbstr = False;
291 #endif
292 
293 	YPLOG((allow_severity,
294 	    "clear_2: request from %.500s, optimize_db %s",
295 	    clientstr, optdbstr));
296 
297 	if (securecheck(caller)) {
298 		svcerr_auth(rqstp->rq_xprt, AUTH_FAILED);
299 		return (NULL);
300 	}
301 
302 #ifdef OPTIMIZE_DB
303         ypdb_close_all();
304 #endif
305 
306 	(void)memset(&res, 0, sizeof(res));
307 	return ((void *)&res);
308 }
309 
310 void *
ypproc_all_2_svc(void * argp,struct svc_req * rqstp)311 ypproc_all_2_svc(void *argp, struct svc_req *rqstp)
312 {
313 	static struct ypresp_all res;
314 	struct sockaddr *caller = svc_getrpccaller(rqstp->rq_xprt)->buf;
315 	struct ypreq_nokey *k = argp;
316 	int secure;
317 
318 	if (_yp_invalid_domain(k->domain) || _yp_invalid_map(k->map)) {
319 		svcerr_auth(rqstp->rq_xprt, AUTH_FAILED);
320 		return (NULL);
321 	}
322 
323 	secure = ypdb_secure(k->domain, k->map);
324 
325 	YPLOG((allow_severity,
326 	    "all_2: request from %.500s, secure %s, domain %s, map %s",
327 	    clientstr, TORF(secure), k->domain, k->map));
328 
329 	(void)memset(&res, 0, sizeof(res));
330 
331 	if (secure && securecheck(caller)) {
332 		memset(&res, 0, sizeof(res));
333 		res.ypresp_all_u.val.status = YP_YPERR;
334 		return (&res);
335 	}
336 
337 	switch (fork()) {
338 	case -1:
339 		/* XXXCDC An error has occurred */
340 		return (NULL);
341 
342 	case 0:
343 		/* CHILD: send result, then exit */
344 		if (!svc_sendreply(rqstp->rq_xprt, (xdrproc_t)ypdb_xdr_get_all, (void *)k))
345 			svcerr_systemerr(rqstp->rq_xprt);
346 
347 		/* Note: no need to free args; we're exiting. */
348 		exit(0);
349 	}
350 
351 	/* PARENT: just continue */
352 	return (NULL);
353 }
354 
355 void *
ypproc_master_2_svc(void * argp,struct svc_req * rqstp)356 ypproc_master_2_svc(void *argp, struct svc_req *rqstp)
357 {
358 	static struct ypresp_master res;
359 	static const char *nopeer = "";
360 	struct sockaddr *caller = svc_getrpccaller(rqstp->rq_xprt)->buf;
361 	struct ypreq_nokey *k = argp;
362 	int secure;
363 
364 	if (_yp_invalid_domain(k->domain) || _yp_invalid_map(k->map)) {
365 		svcerr_auth(rqstp->rq_xprt, AUTH_FAILED);
366 		return (NULL);
367 	}
368 
369 	secure = ypdb_secure(k->domain, k->map);
370 
371 	YPLOG((allow_severity,
372 	    "master_2: request from %.500s, secure %s, domain %s, map %s",
373 	    clientstr, TORF(secure), k->domain, k->map));
374 
375 	if (secure && securecheck(caller)) {
376 		memset(&res, 0, sizeof(res));
377 		res.status = YP_YPERR;
378 	} else
379 		res = ypdb_get_master(k->domain, k->map);
380 
381 	/*
382 	 * This code was added because a yppoll <unknown-domain>
383 	 * from a sun crashed the server in xdr_string, trying
384 	 * to access the peer through a NULL-pointer. yppoll in
385 	 * this server start asking for order. If order is ok
386 	 * then it will ask for master. SunOS 4 asks for both
387 	 * always. I'm not sure this is the best place for the
388 	 * fix, but for now it will do. xdr_peername or
389 	 * xdr_string in ypserv_xdr.c may be a better place?
390 	 */
391 	if (res.master == NULL)
392 		res.master = __UNCONST(nopeer);
393 
394 	return ((void *)&res);
395 }
396 
397 
398 void *
ypproc_order_2_svc(void * argp,struct svc_req * rqstp)399 ypproc_order_2_svc(void *argp, struct svc_req *rqstp)
400 {
401 	static struct ypresp_order res;
402 	struct sockaddr *caller = svc_getrpccaller(rqstp->rq_xprt)->buf;
403 	struct ypreq_nokey *k = argp;
404 	int secure;
405 
406 	if (_yp_invalid_domain(k->domain)) {
407 		svcerr_auth(rqstp->rq_xprt, AUTH_FAILED);
408 		return (NULL);
409 	}
410 
411 	secure = ypdb_secure(k->domain, k->map);
412 
413 	YPLOG((allow_severity,
414 	    "order_2: request from %.500s, secure %s, domain %s, map %s",
415 	    clientstr, TORF(secure), k->domain, k->map));
416 
417 	if (secure && securecheck(caller)) {
418 		memset(&res, 0, sizeof(res));
419 		res.status = YP_YPERR;
420 	} else if (_yp_invalid_map(k->map)) {
421 		memset(&res, 0, sizeof(res));
422 		res.status = YP_NOMAP;
423 	} else {
424 		res = ypdb_get_order(k->domain, k->map);
425 	}
426 
427 	return ((void *)&res);
428 }
429 
430 void *
ypproc_maplist_2_svc(void * argp,struct svc_req * rqstp)431 ypproc_maplist_2_svc(void *argp, struct svc_req *rqstp)
432 {
433 	static struct ypresp_maplist res;
434 	char domain_path[MAXPATHLEN];
435 	char *domain = *(char **)argp;
436 	struct stat finfo;
437 	DIR *dirp = NULL;
438 	struct dirent *dp;
439 	char *suffix;
440 	u_int status;
441 	struct ypmaplist *m;
442 
443 	if (_yp_invalid_domain(domain)) {
444 		svcerr_auth(rqstp->rq_xprt, AUTH_FAILED);
445 		return (NULL);
446 	}
447 
448 	YPLOG((allow_severity,
449 	    "maplist_2: request from %.500s, domain %s",
450 	    clientstr, domain));
451 
452 	(void)memset(&res, 0, sizeof(res));
453 
454 	(void)snprintf(domain_path, sizeof(domain_path), "%s/%s", YP_DB_PATH,
455 	    domain);
456 
457 	memset(&res, 0, sizeof(res));
458 	status = YP_TRUE;
459 
460 	if ((stat(domain_path, &finfo) != 0) || !S_ISDIR(finfo.st_mode)) {
461 		status = YP_NODOM;
462 		goto out;
463 	}
464 
465 	if ((dirp = opendir(domain_path)) == NULL) {
466 		status = YP_NODOM;
467 		goto out;
468 	}
469 
470 	/*
471 	 * Look for the .db files; they're the maps.
472 	 *
473 	 * XXX This might need some re-thinking for supporting
474 	 * XXX alternate password databases.
475 	 */
476 	for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
477 		/* Eliminate impossible names. */
478 		if ((strcmp(dp->d_name, ".") == 0) ||
479 		    ((strcmp(dp->d_name, "..") == 0)) ||
480 		    (dp->d_namlen < 4) || (dp->d_namlen > YPMAXMAP + 3))
481 			continue;
482 
483 		/* Check the file suffix. */
484 		suffix = (char *)&dp->d_name[dp->d_namlen - 3];
485 		if (strcmp(suffix, ".db") == 0) {
486 			/* Found one. */
487 			m = calloc(1, sizeof(struct ypmaplist));
488 			if (m == NULL) {
489 				status = YP_YPERR;
490 				goto out;
491 			}
492 
493 			(void)strlcpy(m->ypml_name, dp->d_name,
494 			    (size_t)(dp->d_namlen - 2));
495 			m->ypml_next = res.list;
496 			res.list = m;
497 		}
498 	}
499 
500  out:
501 	if (dirp != NULL)
502 		(void)closedir(dirp);
503 
504 	res.status = status;
505 
506 	return ((void *)&res);
507 }
508