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