1/*	$NetBSD: ypserv_proc.c,v 1.15 2011/07/01 03:09:29 joerg 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.15 2011/07/01 03:09:29 joerg 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
60static const char *True = "TRUE";
61static const char *False = "FALSE";
62#define	TORF(x)	(x) ? True : False
63#else
64#define	YPLOG(x)	/* nothing */
65#endif
66
67static int
68securecheck(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
79void *
80/*ARGSUSED*/
81ypproc_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
91void *
92ypproc_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
117void *
118ypproc_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
146void *
147ypproc_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		res.status = YP_YPERR;
168	else
169		res = ypdb_get_record(k->domain, k->map, k->keydat, FALSE);
170
171	return ((void *)&res);
172}
173
174void *
175ypproc_first_2_svc(void *argp, struct svc_req *rqstp)
176{
177	static struct ypresp_key_val res;
178	struct sockaddr *caller = svc_getrpccaller(rqstp->rq_xprt)->buf;
179	struct ypreq_nokey *k = argp;
180	int secure;
181
182	if (_yp_invalid_domain(k->domain) || _yp_invalid_map(k->map)) {
183		svcerr_auth(rqstp->rq_xprt, AUTH_FAILED);
184		return (NULL);
185	}
186
187	secure = ypdb_secure(k->domain, k->map);
188
189	YPLOG((allow_severity,
190	    "first_2: request from %.500s, secure %s, domain %s, map %s",
191	    clientstr, TORF(secure), k->domain, k->map));
192
193	if (secure && securecheck(caller))
194		res.status = YP_YPERR;
195	else
196		res = ypdb_get_first(k->domain, k->map, FALSE);
197
198	return ((void *)&res);
199}
200
201void *
202ypproc_next_2_svc(void *argp, struct svc_req *rqstp)
203{
204	static struct ypresp_key_val res;
205	struct sockaddr *caller = svc_getrpccaller(rqstp->rq_xprt)->buf;
206	struct ypreq_key *k = argp;
207	int secure;
208
209	if (_yp_invalid_domain(k->domain) || _yp_invalid_map(k->map)) {
210		svcerr_auth(rqstp->rq_xprt, AUTH_FAILED);
211		return (NULL);
212	}
213
214	secure = ypdb_secure(k->domain, k->map);
215
216	YPLOG((allow_severity,
217	    "next_2: request from %.500s, secure %s, domain %s, map %s, "
218	    "key %.*s", clientstr, TORF(secure), k->domain, k->map,
219	    k->keydat.dsize, k->keydat.dptr));
220
221	if (secure && securecheck(caller))
222		res.status = YP_YPERR;
223	else
224		res = ypdb_get_next(k->domain, k->map, k->keydat, FALSE);
225
226	return ((void *)&res);
227}
228
229void *
230ypproc_xfr_2_svc(void *argp, struct svc_req *rqstp)
231{
232	static struct ypresp_xfr res;
233	struct sockaddr *caller = svc_getrpccaller(rqstp->rq_xprt)->buf;
234	struct ypreq_xfr *ypx = argp;
235	char tid[11], prog[11], port[11];
236	char hbuf[NI_MAXHOST];
237	char ypxfr_proc[] = YPXFR_PROC;
238
239	(void)memset(&res, 0, sizeof(res));
240
241	YPLOG((allow_severity,
242	    "xfr_2: request from %.500s, domain %s, tid %d, prog %d, port %d, "
243	    "map %s", clientstr, ypx->map_parms.domain, ypx->transid,
244	    ypx->proto, ypx->port, ypx->map_parms.map));
245
246	if (_yp_invalid_domain(ypx->map_parms.domain) ||
247	    _yp_invalid_map(ypx->map_parms.map) ||
248	    securecheck(caller)) {
249		svcerr_auth(rqstp->rq_xprt, AUTH_FAILED);
250		return (NULL);
251	}
252
253	switch (vfork()) {
254	case -1:
255		svcerr_systemerr(rqstp->rq_xprt);
256		return (NULL);
257
258	case 0:
259		(void)snprintf(tid, sizeof(tid), "%d", ypx->transid);
260		(void)snprintf(prog, sizeof(prog), "%d", ypx->proto);
261		(void)snprintf(port, sizeof(port), "%d", ypx->port);
262		if (getnameinfo(caller, (socklen_t)caller->sa_len, hbuf,
263		    sizeof(hbuf), NULL, 0, 0))
264			_exit(1);	/* XXX report error ? */
265
266		(void)execl(ypxfr_proc, "ypxfr", "-d", ypx->map_parms.domain,
267		    "-C", tid, prog, hbuf, port, ypx->map_parms.map, NULL);
268		_exit(1);		/* XXX report error? */
269	}
270
271	/*
272	 * XXX: fill in res
273	 */
274
275	return ((void *)&res);
276}
277
278void *
279/*ARGSUSED*/
280ypproc_clear_2_svc(void *argp, struct svc_req *rqstp)
281{
282	static char res;
283	struct sockaddr *caller = svc_getrpccaller(rqstp->rq_xprt)->buf;
284#ifdef OPTIMIZE_DB
285	const char *optdbstr = True;
286#else
287	const char *optdbstr = False;
288#endif
289
290	YPLOG((allow_severity,
291	    "clear_2: request from %.500s, optimize_db %s",
292	    clientstr, optdbstr));
293
294	if (securecheck(caller)) {
295		svcerr_auth(rqstp->rq_xprt, AUTH_FAILED);
296		return (NULL);
297	}
298
299#ifdef OPTIMIZE_DB
300        ypdb_close_all();
301#endif
302
303	(void)memset(&res, 0, sizeof(res));
304	return ((void *)&res);
305}
306
307void *
308ypproc_all_2_svc(void *argp, struct svc_req *rqstp)
309{
310	static struct ypresp_all res;
311	struct sockaddr *caller = svc_getrpccaller(rqstp->rq_xprt)->buf;
312	struct ypreq_nokey *k = argp;
313	int secure;
314
315	if (_yp_invalid_domain(k->domain) || _yp_invalid_map(k->map)) {
316		svcerr_auth(rqstp->rq_xprt, AUTH_FAILED);
317		return (NULL);
318	}
319
320	secure = ypdb_secure(k->domain, k->map);
321
322	YPLOG((allow_severity,
323	    "all_2: request from %.500s, secure %s, domain %s, map %s",
324	    clientstr, TORF(secure), k->domain, k->map));
325
326	(void)memset(&res, 0, sizeof(res));
327
328	if (secure && securecheck(caller)) {
329		res.ypresp_all_u.val.status = YP_YPERR;
330		return (&res);
331	}
332
333	switch (fork()) {
334	case -1:
335		/* XXXCDC An error has occurred */
336		return (NULL);
337
338	case 0:
339		/* CHILD: send result, then exit */
340		if (!svc_sendreply(rqstp->rq_xprt, (xdrproc_t)ypdb_xdr_get_all, (void *)k))
341			svcerr_systemerr(rqstp->rq_xprt);
342
343		/* Note: no need to free args; we're exiting. */
344		exit(0);
345	}
346
347	/* PARENT: just continue */
348	return (NULL);
349}
350
351void *
352ypproc_master_2_svc(void *argp, struct svc_req *rqstp)
353{
354	static struct ypresp_master res;
355	static const char *nopeer = "";
356	struct sockaddr *caller = svc_getrpccaller(rqstp->rq_xprt)->buf;
357	struct ypreq_nokey *k = argp;
358	int secure;
359
360	if (_yp_invalid_domain(k->domain) || _yp_invalid_map(k->map)) {
361		svcerr_auth(rqstp->rq_xprt, AUTH_FAILED);
362		return (NULL);
363	}
364
365	secure = ypdb_secure(k->domain, k->map);
366
367	YPLOG((allow_severity,
368	    "master_2: request from %.500s, secure %s, domain %s, map %s",
369	    clientstr, TORF(secure), k->domain, k->map));
370
371	if (secure && securecheck(caller))
372		res.status = YP_YPERR;
373	else
374		res = ypdb_get_master(k->domain, k->map);
375
376	/*
377	 * This code was added because a yppoll <unknown-domain>
378	 * from a sun crashed the server in xdr_string, trying
379	 * to access the peer through a NULL-pointer. yppoll in
380	 * this server start asking for order. If order is ok
381	 * then it will ask for master. SunOS 4 asks for both
382	 * always. I'm not sure this is the best place for the
383	 * fix, but for now it will do. xdr_peername or
384	 * xdr_string in ypserv_xdr.c may be a better place?
385	 */
386	if (res.master == NULL)
387		res.master = __UNCONST(nopeer);
388
389	return ((void *)&res);
390}
391
392
393void *
394ypproc_order_2_svc(void *argp, struct svc_req *rqstp)
395{
396	static struct ypresp_order res;
397	struct sockaddr *caller = svc_getrpccaller(rqstp->rq_xprt)->buf;
398	struct ypreq_nokey *k = argp;
399	int secure;
400
401	if (_yp_invalid_domain(k->domain)) {
402		svcerr_auth(rqstp->rq_xprt, AUTH_FAILED);
403		return (NULL);
404	}
405
406	secure = ypdb_secure(k->domain, k->map);
407
408	YPLOG((allow_severity,
409	    "order_2: request from %.500s, secure %s, domain %s, map %s",
410	    clientstr, TORF(secure), k->domain, k->map));
411
412	if (secure && securecheck(caller))
413		res.status = YP_YPERR;
414	else if (_yp_invalid_map(k->map))
415		res.status = YP_NOMAP;
416	else
417		res = ypdb_get_order(k->domain, k->map);
418
419	return ((void *)&res);
420}
421
422void *
423ypproc_maplist_2_svc(void *argp, struct svc_req *rqstp)
424{
425	static struct ypresp_maplist res;
426	char domain_path[MAXPATHLEN];
427	char *domain = *(char **)argp;
428	struct stat finfo;
429	DIR *dirp = NULL;
430	struct dirent *dp;
431	char *suffix;
432	u_int status;
433	struct ypmaplist *m;
434
435	if (_yp_invalid_domain(domain)) {
436		svcerr_auth(rqstp->rq_xprt, AUTH_FAILED);
437		return (NULL);
438	}
439
440	YPLOG((allow_severity,
441	    "maplist_2: request from %.500s, domain %s",
442	    clientstr, domain));
443
444	(void)memset(&res, 0, sizeof(res));
445
446	(void)snprintf(domain_path, sizeof(domain_path), "%s/%s", YP_DB_PATH,
447	    domain);
448
449	res.list = NULL;
450	status = YP_TRUE;
451
452	if ((stat(domain_path, &finfo) != 0) || !S_ISDIR(finfo.st_mode)) {
453		status = YP_NODOM;
454		goto out;
455	}
456
457	if ((dirp = opendir(domain_path)) == NULL) {
458		status = YP_NODOM;
459		goto out;
460	}
461
462	/*
463	 * Look for the .db files; they're the maps.
464	 *
465	 * XXX This might need some re-thinking for supporting
466	 * XXX alternate password databases.
467	 */
468	for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
469		/* Eliminate impossible names. */
470		if ((strcmp(dp->d_name, ".") == 0) ||
471		    ((strcmp(dp->d_name, "..") == 0)) ||
472		    (dp->d_namlen < 4) || (dp->d_namlen > YPMAXMAP + 3))
473			continue;
474
475		/* Check the file suffix. */
476		suffix = (char *)&dp->d_name[dp->d_namlen - 3];
477		if (strcmp(suffix, ".db") == 0) {
478			/* Found one. */
479			m = calloc(1, sizeof(struct ypmaplist));
480			if (m == NULL) {
481				status = YP_YPERR;
482				goto out;
483			}
484
485			(void)strlcpy(m->ypml_name, dp->d_name,
486			    (size_t)(dp->d_namlen - 2));
487			m->ypml_next = res.list;
488			res.list = m;
489		}
490	}
491
492 out:
493	if (dirp != NULL)
494		(void)closedir(dirp);
495
496	res.status = status;
497
498	return ((void *)&res);
499}
500