Home | History | Annotate | Line # | Download | only in ypserv
      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 (at) 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
     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*/
     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 *
     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 *
    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 *
    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 *
    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 *
    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 *
    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*/
    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 *
    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 *
    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 *
    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 *
    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