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