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