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