1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * Copyright (c) 2016 by Delphix. All rights reserved. 26 */ 27 28 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 29 /* All Rights Reserved */ 30 31 /* 32 * Portions of this source code were derived from Berkeley 4.3 BSD 33 * under license from the Regents of the University of California. 34 */ 35 36 /* 37 * 38 * This contains YP server code which supplies the set of functions 39 * requested using rpc. The top level functions in this module 40 * are those which have symbols of the form YPPROC_xxxx defined in 41 * yp_prot.h, and symbols of the form YPOLDPROC_xxxx defined in ypsym.h. 42 * The latter exist to provide compatibility to the old version of the yp 43 * protocol/server, and may emulate the behavior of the previous software 44 * by invoking some other program. 45 * 46 * This module also contains functions which are used by (and only by) the 47 * top-level functions here. 48 */ 49 50 #include <sys/types.h> 51 #include <sys/socket.h> 52 #include <netinet/in.h> 53 #include <arpa/inet.h> 54 #include <dirent.h> 55 #include <limits.h> 56 #include <sys/systeminfo.h> 57 #include <rpc/rpc.h> 58 #include <string.h> 59 #include <malloc.h> 60 #include <stdlib.h> 61 #include <unistd.h> 62 #include <stdio.h> 63 #include "ypsym.h" 64 #include "ypdefs.h" 65 #include <ctype.h> 66 67 /* Use shim version of DBM calls */ 68 #include "shim.h" 69 #include "shim_hooks.h" 70 71 USE_YP_PREFIX 72 USE_YP_SECURE 73 USE_YP_INTERDOMAIN 74 75 #ifndef YPXFR_PROC 76 #define YPXFR_PROC "/usr/lib/netsvc/yp/ypxfr" 77 #endif 78 static char ypxfr_proc[] = YPXFR_PROC; 79 #ifndef YPPUSH_PROC 80 #define YPPUSH_PROC "/usr/lib/netsvc/yp/yppush" 81 #endif 82 static char yppush_proc[] = YPPUSH_PROC; 83 struct yppriv_sym { 84 char *sym; 85 unsigned len; 86 }; 87 static char err_fork[] = "ypserv: %s fork failure.\n"; 88 #define FORK_ERR logprintf(err_fork, fun) 89 static char err_execl[] = "ypserv: %s execl failure.\n"; 90 #define EXEC_ERR logprintf(err_execl, fun) 91 static char err_respond[] = "ypserv: %s can't respond to rpc request.\n"; 92 #define RESPOND_ERR logprintf(err_respond, fun) 93 static char err_free[] = "ypserv: %s can't free args.\n"; 94 #define FREE_ERR logprintf(err_free, fun) 95 static char err_map[] = "ypserv: %s no such map or access denied.\n"; 96 #define MAP_ERR logprintf(err_map, fun) 97 static char err_vers[] = "ypserv: %s version not supported.\n"; 98 #define VERS_ERR logprintf(err_vers, fun) 99 100 static void ypfilter(DBM *fdb, datum *inkey, datum *outkey, datum *val, 101 uint_t *status, bool_t update); 102 static bool isypsym(datum *key); 103 static bool xdrypserv_ypall(XDR *xdrs, struct ypreq_nokey *req); 104 static int multihomed(struct ypreq_key req, struct ypresp_val *resp, 105 SVCXPRT *xprt, DBM *fdb); 106 static int omultihomed(struct yprequest req, struct ypresponse *resp, 107 SVCXPRT *xprt, DBM *fdb); 108 109 110 /* For DNS forwarding */ 111 extern bool dnsforward; 112 extern bool client_setup_failure; 113 extern int resolv_pid; 114 extern CLIENT *resolv_client; 115 extern char *resolv_tp; 116 117 /* 118 * This determines whether or not a passed domain is served by this 119 * server, and returns a boolean. Used by both old and new protocol 120 * versions. 121 */ 122 void 123 ypdomain(SVCXPRT *transp, bool always_respond) 124 { 125 char domain_name[YPMAXDOMAIN + 1]; 126 char *pdomain_name = domain_name; 127 bool isserved; 128 char *fun = "ypdomain"; 129 struct netbuf *nbuf; 130 sa_family_t af; 131 132 memset(domain_name, 0, sizeof (domain_name)); 133 134 if (!svc_getargs(transp, (xdrproc_t)xdr_ypdomain_wrap_string, 135 (caddr_t)&pdomain_name)) { 136 svcerr_decode(transp); 137 return; 138 } 139 140 /* 141 * If the file /var/yp/securenets is present on the server, and if 142 * the hostname is present in the file, then let the client bind to 143 * the server. 144 */ 145 nbuf = svc_getrpccaller(transp); 146 af = ((struct sockaddr_storage *)nbuf->buf)->ss_family; 147 if (af != AF_INET && af != AF_INET6) { 148 logprintf("Protocol incorrect\n"); 149 return; 150 } 151 152 if (!(check_secure_net_ti(nbuf, fun))) { 153 MAP_ERR; 154 return; 155 } 156 157 isserved = ypcheck_domain(domain_name); 158 159 if (isserved || always_respond) { 160 161 if (!svc_sendreply(transp, xdr_bool, (char *)&isserved)) { 162 RESPOND_ERR; 163 } 164 if (!isserved) 165 logprintf("Domain %s not supported\n", 166 domain_name); 167 168 } else { 169 /* 170 * This case is the one in which the domain is not 171 * supported, and in which we are not to respond in the 172 * unsupported case. We are going to make an error happen 173 * to allow the portmapper to end its wait without the 174 * normal timeout period. The assumption here is that 175 * the only process in the world which is using the function 176 * in its no-answer-if-nack form is the portmapper, which is 177 * doing the krock for pseudo-broadcast. If some poor fool 178 * calls this function as a single-cast message, the nack 179 * case will look like an incomprehensible error. Sigh... 180 * (The traditional Unix disclaimer) 181 */ 182 183 svcerr_decode(transp); 184 logprintf("Domain %s not supported (broadcast)\n", 185 domain_name); 186 } 187 } 188 189 /* 190 * This implements the yp "match" function. 191 */ 192 void 193 ypmatch(SVCXPRT *transp, struct svc_req *rqstp) 194 { 195 struct ypreq_key req; 196 struct ypresp_val resp; 197 char *fun = "ypmatch"; 198 DBM *fdb; 199 200 memset(&req, 0, sizeof (req)); 201 memset(&resp, 0, sizeof (resp)); 202 resp.status = (unsigned)YP_NOKEY; 203 204 if (!svc_getargs(transp, (xdrproc_t)xdr_ypreq_key, (char *)&req)) { 205 svcerr_decode(transp); 206 return; 207 } 208 209 /* 210 * sanity check the map name and to a DBM lookup 211 * also perform an access check... 212 */ 213 if ((fdb = ypset_current_map(req.map, req.domain, 214 &resp.status)) != NULL && 215 yp_map_access(transp, &resp.status, fdb)) { 216 217 /* Check with the DBM database */ 218 resp.valdat = dbm_fetch(fdb, req.keydat); 219 if (resp.valdat.dptr != NULL) { 220 resp.status = YP_TRUE; 221 if (!silent) 222 printf("%s: dbm: %40.40s\n", 223 fun, resp.valdat.dptr); 224 goto send_reply; 225 } 226 227 /* 228 * If we're being asked to match YP_SECURE or YP_INTERDOMAIN 229 * and we haven't found it in the dbm file, then we don't 230 * really want to waste any more time. Specifically, we don't 231 * want to ask DNS 232 */ 233 if (req.keydat.dsize == 0 || 234 req.keydat.dptr == NULL || 235 req.keydat.dptr[0] == '\0' || 236 strncmp(req.keydat.dptr, yp_secure, req.keydat.dsize) == 0 || 237 strncmp(req.keydat.dptr, yp_interdomain, req.keydat.dsize) == 0) { 238 goto send_reply; 239 } 240 241 /* Let's try the YP_MULTI_ hack... */ 242 #ifdef MINUS_C_OPTION 243 if (multiflag == TRUE && multihomed(req, &resp, transp, fdb)) 244 goto send_reply; 245 #else 246 if (multihomed(req, &resp, transp, fdb)) 247 goto send_reply; 248 #endif 249 250 /* 251 * Let's try DNS, but if client_setup_failure is set, 252 * we have tried DNS in the past and failed, there is 253 * no reason in forcing an infinite loop by turning 254 * off DNS in setup_resolv() only to turn it back on 255 * again here. 256 */ 257 if (!dnsforward && !client_setup_failure) { 258 datum idkey, idval; 259 idkey.dptr = yp_interdomain; 260 idkey.dsize = yp_interdomain_sz; 261 idval = dbm_fetch(fdb, idkey); 262 if (idval.dptr) 263 dnsforward = TRUE; 264 } 265 266 if (dnsforward) { 267 if (!resolv_pid || !resolv_client) { 268 setup_resolv(&dnsforward, &resolv_pid, 269 &resolv_client, resolv_tp, 0); 270 if (resolv_client == NULL) 271 client_setup_failure = TRUE; 272 } 273 274 if (resolv_req(&dnsforward, &resolv_client, 275 &resolv_pid, resolv_tp, 276 rqstp->rq_xprt, &req, 277 req.map) == TRUE) 278 goto free_args; 279 } 280 } 281 send_reply: 282 283 if (!svc_sendreply(transp, (xdrproc_t)xdr_ypresp_val, 284 (caddr_t)&resp)) { 285 RESPOND_ERR; 286 } 287 288 free_args: 289 290 if (!svc_freeargs(transp, (xdrproc_t)xdr_ypreq_key, 291 (char *)&req)) { 292 FREE_ERR; 293 } 294 } 295 296 297 /* 298 * This implements the yp "get first" function. 299 */ 300 void 301 ypfirst(SVCXPRT *transp) 302 { 303 struct ypreq_nokey req; 304 struct ypresp_key_val resp; 305 char *fun = "ypfirst"; 306 DBM *fdb; 307 308 memset(&req, 0, sizeof (req)); 309 memset(&resp, 0, sizeof (resp)); 310 311 if (!svc_getargs(transp, 312 (xdrproc_t)xdr_ypreq_nokey, 313 (char *)&req)) { 314 svcerr_decode(transp); 315 return; 316 } 317 318 if ((fdb = ypset_current_map(req.map, req.domain, 319 &resp.status)) != NULL && 320 yp_map_access(transp, &resp.status, fdb)) { 321 ypfilter(fdb, NULL, 322 &resp.keydat, &resp.valdat, &resp.status, FALSE); 323 } 324 325 if (!svc_sendreply(transp, 326 (xdrproc_t)xdr_ypresp_key_val, 327 (char *)&resp)) { 328 RESPOND_ERR; 329 } 330 331 if (!svc_freeargs(transp, (xdrproc_t)xdr_ypreq_nokey, 332 (char *)&req)) { 333 FREE_ERR; 334 } 335 } 336 337 /* 338 * This implements the yp "get next" function. 339 */ 340 void 341 ypnext(SVCXPRT *transp) 342 { 343 struct ypreq_key req; 344 struct ypresp_key_val resp; 345 char *fun = "ypnext"; 346 DBM *fdb; 347 348 memset(&req, 0, sizeof (req)); 349 memset(&resp, 0, sizeof (resp)); 350 351 if (!svc_getargs(transp, (xdrproc_t)xdr_ypreq_key, (char *)&req)) { 352 svcerr_decode(transp); 353 return; 354 } 355 356 if ((fdb = ypset_current_map(req.map, req.domain, 357 &resp.status)) != NULL && 358 yp_map_access(transp, &resp.status, fdb)) { 359 ypfilter(fdb, &req.keydat, 360 &resp.keydat, &resp.valdat, &resp.status, FALSE); 361 } 362 363 if (!svc_sendreply(transp, 364 (xdrproc_t)xdr_ypresp_key_val, 365 (char *)&resp)) { 366 RESPOND_ERR; 367 } 368 369 if (!svc_freeargs(transp, 370 (xdrproc_t)xdr_ypreq_key, 371 (char *)&req)) { 372 FREE_ERR; 373 } 374 } 375 376 /* 377 * This implements the "transfer map" function. It takes the domain 378 * and map names and the callback information provided by the 379 * requester (yppush on some node), and execs a ypxfr process to do 380 * the actual transfer. 381 */ 382 void 383 ypxfr(SVCXPRT *transp, int prog) 384 { 385 struct ypreq_newxfr newreq; 386 struct ypreq_xfr oldreq; 387 struct ypresp_val resp; /* not returned to the caller */ 388 char transid[32]; 389 char proto[32]; 390 char name[256]; 391 char *pdomain, *pmap; 392 pid_t pid = -1; 393 char *fun = "ypxfr"; 394 DBM *fdb; 395 396 if (prog == YPPROC_NEWXFR) { 397 memset(&newreq, 0, sizeof (newreq)); 398 if (!svc_getargs(transp, (xdrproc_t)xdr_ypreq_newxfr, 399 (char *)&newreq)) { 400 svcerr_decode(transp); 401 return; 402 } 403 404 #ifdef OPCOM_DEBUG 405 fprintf(stderr, "newreq:\n" 406 "\tmap_parms:\n" 407 "\t\tdomain: %s\n" 408 "\t\tmap: %s\n" 409 "\t\tordernum: %u\n" 410 "\t\towner: %s\n" 411 "\ttransid: %u\n" 412 "\tproto: %u\n" 413 "\tname: %s\n\n", 414 newreq.map_parms.domain, 415 newreq.map_parms.map, 416 newreq.map_parms.ordernum, 417 newreq.map_parms.owner, 418 newreq.transid, 419 newreq.proto, 420 newreq.name); 421 #endif 422 sprintf(transid, "%u", newreq.transid); 423 sprintf(proto, "%u", newreq.proto); 424 sprintf(name, "%s", newreq.ypxfr_owner); 425 pdomain = newreq.ypxfr_domain; 426 pmap = newreq.ypxfr_map; 427 } else if (prog == YPPROC_XFR) { 428 memset(&oldreq, 0, sizeof (oldreq)); 429 if (!svc_getargs(transp, 430 (xdrproc_t)xdr_ypreq_xfr, 431 (char *)&oldreq)) { 432 svcerr_decode(transp); 433 return; 434 } 435 436 #ifdef OPCOM_DEBUG 437 fprintf(stderr, "oldreq:\n" 438 "\tmap_parms:\n" 439 "\t\tdomain: %s\n" 440 "\t\tmap: %s\n" 441 "\t\tordernum: %u\n" 442 "\t\towner: %s\n" 443 "\ttransid: %u\n" 444 "\tproto: %u\n" 445 "\tport: %u\n\n", 446 oldreq.map_parms.domain, 447 oldreq.map_parms.map, 448 oldreq.map_parms.ordernum, 449 oldreq.map_parms.owner, 450 oldreq.transid, 451 oldreq.proto, 452 oldreq.port); 453 #endif 454 455 sprintf(transid, "%u", oldreq.transid); 456 sprintf(proto, "%u", oldreq.proto); 457 sprintf(name, "%s", oldreq.ypxfr_owner); 458 pdomain = oldreq.ypxfr_domain; 459 pmap = oldreq.ypxfr_map; 460 } else { 461 VERS_ERR; 462 } 463 464 /* Check that the map exists and is accessible */ 465 if ((fdb = ypset_current_map(pmap, pdomain, &resp.status)) != NULL && 466 yp_map_access(transp, &resp.status, fdb)) { 467 468 pid = vfork(); 469 if (pid == -1) { 470 FORK_ERR; 471 } else if (pid == 0) { 472 if (prog == YPPROC_NEWXFR || prog == YPPROC_XFR) { 473 #ifdef OPCOM_DEBUG 474 fprintf(stderr, 475 "EXECL: %s, -d, %s, -C, %s, %s, %s, %s\n", 476 ypxfr_proc, pdomain, 477 transid, proto, name, pmap); 478 #endif 479 if (execl(ypxfr_proc, "ypxfr", "-d", 480 pdomain, "-C", transid, proto, 481 name, pmap, NULL)) 482 EXEC_ERR; 483 } else { 484 VERS_ERR; 485 } 486 _exit(1); 487 } 488 489 } else { 490 MAP_ERR; 491 } 492 if (!svc_sendreply(transp, xdr_void, 0)) { 493 RESPOND_ERR; 494 } 495 496 if (prog == YPPROC_NEWXFR) { 497 if (!svc_freeargs(transp, 498 (xdrproc_t)xdr_ypreq_newxfr, 499 (char *)&newreq)) { 500 FREE_ERR; 501 } 502 } 503 } 504 505 /* 506 * This implements the "get all" function. 507 */ 508 void 509 ypall(SVCXPRT *transp) 510 { 511 struct ypreq_nokey req; 512 struct ypresp_val resp; /* not returned to the caller */ 513 pid_t pid; 514 char *fun = "ypall"; 515 DBM *fdb; 516 517 req.domain = req.map = NULL; 518 519 memset((char *)&req, 0, sizeof (req)); 520 521 if (!svc_getargs(transp, 522 (xdrproc_t)xdr_ypreq_nokey, 523 (char *)&req)) { 524 svcerr_decode(transp); 525 return; 526 } 527 528 pid = fork1(); 529 530 if (pid) { 531 532 if (pid == -1) { 533 FORK_ERR; 534 } 535 536 if (!svc_freeargs(transp, 537 (xdrproc_t)xdr_ypreq_nokey, 538 (char *)&req)) { 539 FREE_ERR; 540 } 541 542 return; 543 } 544 545 /* 546 * access control hack: If denied then invalidate the map name. 547 */ 548 ypclr_current_map(); 549 if ((fdb = ypset_current_map(req.map, 550 req.domain, &resp.status)) != NULL && 551 !yp_map_access(transp, &resp.status, fdb)) { 552 553 req.map[0] = '-'; 554 } 555 556 /* 557 * This is the child process. The work gets done by xdrypserv_ypall/ 558 * we must clear the "current map" first so that we do not 559 * share a seek pointer with the parent server. 560 */ 561 562 if (!svc_sendreply(transp, 563 (xdrproc_t)xdrypserv_ypall, 564 (char *)&req)) { 565 RESPOND_ERR; 566 } 567 568 if (!svc_freeargs(transp, 569 (xdrproc_t)xdr_ypreq_nokey, 570 (char *)&req)) { 571 FREE_ERR; 572 } 573 574 /* 575 * In yptol mode we may start a cache update thread within a child 576 * process. It is thus important that child processes do not exit, 577 * killing any such threads, before the thread has completed. 578 */ 579 if (yptol_mode) { 580 thr_join(0, NULL, NULL); 581 } 582 583 exit(0); 584 } 585 586 /* 587 * This implements the "get master name" function. 588 */ 589 void 590 ypmaster(SVCXPRT *transp) 591 { 592 struct ypreq_nokey req; 593 struct ypresp_master resp; 594 char *nullstring = ""; 595 char *fun = "ypmaster"; 596 DBM *fdb; 597 598 memset((char *)&req, 0, sizeof (req)); 599 resp.master = nullstring; 600 resp.status = YP_TRUE; 601 602 if (!svc_getargs(transp, 603 (xdrproc_t)xdr_ypreq_nokey, 604 (char *)&req)) { 605 svcerr_decode(transp); 606 return; 607 } 608 609 if ((fdb = ypset_current_map(req.map, 610 req.domain, &resp.status)) != NULL && 611 yp_map_access(transp, &resp.status, fdb)) { 612 613 if (!ypget_map_master(&resp.master, fdb)) { 614 resp.status = (unsigned)YP_BADDB; 615 } 616 } 617 618 if (!svc_sendreply(transp, 619 (xdrproc_t)xdr_ypresp_master, 620 (char *)&resp)) { 621 RESPOND_ERR; 622 } 623 624 if (!svc_freeargs(transp, 625 (xdrproc_t)xdr_ypreq_nokey, 626 (char *)&req)) { 627 FREE_ERR; 628 } 629 } 630 631 /* 632 * This implements the "get order number" function. 633 */ 634 void 635 yporder(SVCXPRT *transp) 636 { 637 struct ypreq_nokey req; 638 struct ypresp_order resp; 639 char *fun = "yporder"; 640 DBM *fdb; 641 642 req.domain = req.map = NULL; 643 resp.status = YP_TRUE; 644 resp.ordernum = 0; 645 646 memset((char *)&req, 0, sizeof (req)); 647 648 if (!svc_getargs(transp, 649 (xdrproc_t)xdr_ypreq_nokey, 650 (char *)&req)) { 651 svcerr_decode(transp); 652 return; 653 } 654 655 resp.ordernum = 0; 656 657 if ((fdb = ypset_current_map(req.map, 658 req.domain, 659 &resp.status)) != NULL && 660 yp_map_access(transp, &resp.status, fdb)) { 661 662 if (!ypget_map_order(req.map, req.domain, &resp.ordernum)) { 663 resp.status = (unsigned)YP_BADDB; 664 } 665 } 666 667 if (!svc_sendreply(transp, 668 (xdrproc_t)xdr_ypresp_order, 669 (char *)&resp)) { 670 RESPOND_ERR; 671 } 672 673 if (!svc_freeargs(transp, 674 (xdrproc_t)xdr_ypreq_nokey, 675 (char *)&req)) { 676 FREE_ERR; 677 } 678 } 679 680 void 681 ypmaplist(SVCXPRT *transp) 682 { 683 char domain_name[YPMAXDOMAIN + 1]; 684 char *pdomain = domain_name; 685 char *fun = "ypmaplist"; 686 struct ypresp_maplist maplist; 687 struct ypmaplist *tmp; 688 689 maplist.list = (struct ypmaplist *)NULL; 690 691 memset(domain_name, 0, sizeof (domain_name)); 692 693 if (!svc_getargs(transp, 694 (xdrproc_t)xdr_ypdomain_wrap_string, 695 (caddr_t)&pdomain)) { 696 svcerr_decode(transp); 697 return; 698 } 699 700 maplist.status = yplist_maps(domain_name, &maplist.list); 701 702 if (!svc_sendreply(transp, 703 (xdrproc_t)xdr_ypresp_maplist, 704 (char *)&maplist)) { 705 RESPOND_ERR; 706 } 707 708 while (maplist.list) { 709 tmp = maplist.list->ypml_next; 710 free((char *)maplist.list); 711 maplist.list = tmp; 712 } 713 } 714 715 /* 716 * Ancillary functions used by the top-level functions within this 717 * module 718 */ 719 720 /* 721 * This returns TRUE if a given key is a yp-private symbol, otherwise 722 * FALSE 723 */ 724 static bool 725 isypsym(datum *key) 726 { 727 if ((key->dptr == NULL) || 728 (key->dsize < yp_prefix_sz) || 729 memcmp(yp_prefix, key->dptr, yp_prefix_sz) || 730 (!memcmp(key->dptr, "YP_MULTI_", 9))) { 731 return (FALSE); 732 } 733 return (TRUE); 734 } 735 736 /* 737 * This provides private-symbol filtration for the enumeration functions. 738 */ 739 static void 740 ypfilter(DBM *fdb, datum *inkey, datum *outkey, datum *val, uint_t *status, 741 bool_t update) 742 { 743 datum k; 744 745 if (inkey) { 746 747 if (isypsym(inkey)) { 748 *status = (unsigned)YP_BADARGS; 749 return; 750 } 751 752 k = dbm_do_nextkey(fdb, *inkey); 753 } else { 754 k = dbm_firstkey(fdb); 755 } 756 757 while (k.dptr && isypsym(&k)) { 758 k = dbm_nextkey(fdb); 759 } 760 761 if (k.dptr == NULL) { 762 *status = YP_NOMORE; 763 return; 764 } 765 766 *outkey = k; 767 768 /* 769 * In N2L mode we must call a version of dbm_fetch() that either does 770 * or does not check for entry updates. In non N2L mode both of these 771 * will end up doing a normal dbm_fetch(). 772 */ 773 if (update) 774 *val = shim_dbm_fetch(fdb, k); 775 else 776 *val = shim_dbm_fetch_noupdate(fdb, k); 777 778 if (val->dptr != NULL) { 779 *status = YP_TRUE; 780 } else { 781 *status = (unsigned)YP_BADDB; 782 } 783 } 784 785 /* 786 * Serializes a stream of struct ypresp_key_val's. This is used 787 * only by the ypserv side of the transaction. 788 */ 789 static bool 790 xdrypserv_ypall(XDR *xdrs, struct ypreq_nokey *req) 791 { 792 bool_t more = TRUE; 793 struct ypresp_key_val resp; 794 DBM *fdb; 795 796 resp.keydat.dptr = resp.valdat.dptr = (char *)NULL; 797 resp.keydat.dsize = resp.valdat.dsize = 0; 798 799 if ((fdb = ypset_current_map(req->map, req->domain, 800 &resp.status)) != NULL) { 801 ypfilter(fdb, (datum *) NULL, &resp.keydat, &resp.valdat, 802 &resp.status, FALSE); 803 804 while (resp.status == YP_TRUE) { 805 if (!xdr_bool(xdrs, &more)) { 806 return (FALSE); 807 } 808 809 if (!xdr_ypresp_key_val(xdrs, &resp)) { 810 return (FALSE); 811 } 812 813 ypfilter(fdb, &resp.keydat, &resp.keydat, &resp.valdat, 814 &resp.status, FALSE); 815 } 816 } 817 818 if (!xdr_bool(xdrs, &more)) { 819 return (FALSE); 820 } 821 822 if (!xdr_ypresp_key_val(xdrs, &resp)) { 823 return (FALSE); 824 } 825 826 more = FALSE; 827 828 if (!xdr_bool(xdrs, &more)) { 829 return (FALSE); 830 } 831 832 return (TRUE); 833 } 834 835 /* 836 * Additions for sparc cluster support 837 */ 838 839 /* 840 * Check for special multihomed host cookie in the key. If there, 841 * collect the addresses from the comma separated list and return 842 * the one that's nearest the client. 843 */ 844 static int 845 multihomed(struct ypreq_key req, struct ypresp_val *resp, 846 SVCXPRT *xprt, DBM *fdb) 847 { 848 char *cp, *bp; 849 ulong_t bestaddr, call_addr; 850 struct netbuf *nbuf; 851 char name[PATH_MAX]; 852 static char localbuf[_PBLKSIZ]; /* buffer for multihomed IPv6 addr */ 853 854 if (strcmp(req.map, "hosts.byname") && 855 strcmp(req.map, "ipnodes.byname")) 856 /* default status is YP_NOKEY */ 857 return (0); 858 859 if (strncmp(req.keydat.dptr, "YP_MULTI_", 9)) { 860 datum tmpname; 861 862 strncpy(name, "YP_MULTI_", 9); 863 strncpy(name + 9, req.keydat.dptr, req.keydat.dsize); 864 tmpname.dsize = req.keydat.dsize + 9; 865 tmpname.dptr = name; 866 resp->valdat = dbm_fetch(fdb, tmpname); 867 } else { 868 /* 869 * Return whole line (for debugging) if YP_MULTI_hostnam 870 * is specified. 871 */ 872 resp->valdat = dbm_fetch(fdb, req.keydat); 873 if (resp->valdat.dptr != NULL) 874 return (1); 875 } 876 877 if (resp->valdat.dptr == NULL) 878 return (0); 879 880 strncpy(name, req.keydat.dptr, req.keydat.dsize); 881 name[req.keydat.dsize] = NULL; 882 883 if (strcmp(req.map, "ipnodes.byname") == 0) { 884 /* 885 * This section handles multihomed IPv6 addresses. 886 * It returns all the IPv6 addresses one per line and only 887 * the requested hostname is returned. NO aliases will be 888 * returned. This is done exactly the same way DNS forwarding 889 * daemon handles multihomed hosts. 890 * New IPv6 enabled clients should be able to handle this 891 * information returned. The sorting is also the client's 892 * responsibility. 893 */ 894 895 char *buf, *endbuf; 896 897 if ((buf = strdup(resp->valdat.dptr)) == NULL) /* no memory */ 898 return (0); 899 if ((bp = strtok(buf, " \t")) == NULL) { /* no address field */ 900 free(buf); 901 return (0); 902 } 903 if ((cp = strtok(NULL, "")) == NULL) { /* no host field */ 904 free(buf); 905 return (0); 906 } 907 if ((cp = strtok(bp, ",")) != NULL) { /* multihomed host */ 908 int bsize; 909 910 localbuf[0] = '\0'; 911 bsize = sizeof (localbuf); 912 endbuf = localbuf; 913 914 while (cp) { 915 if ((strlen(cp) + strlen(name)) >= bsize) { 916 /* out of range */ 917 break; 918 } 919 sprintf(endbuf, "%s %s\n", cp, name); 920 cp = strtok(NULL, ","); 921 endbuf = &endbuf[strlen(endbuf)]; 922 bsize = &localbuf[sizeof (localbuf)] - endbuf; 923 } 924 resp->valdat.dptr = localbuf; 925 resp->valdat.dsize = strlen(localbuf); 926 } 927 928 free(buf); 929 /* remove trailing newline */ 930 if (resp->valdat.dsize && 931 resp->valdat.dptr[resp->valdat.dsize-1] == '\n') { 932 resp->valdat.dptr[resp->valdat.dsize-1] = '\0'; 933 resp->valdat.dsize -= 1; 934 } 935 936 resp->status = YP_TRUE; 937 return (1); 938 } 939 nbuf = svc_getrpccaller(xprt); 940 /* 941 * OK, now I have a netbuf structure which I'm supposed to 942 * treat as opaque... I hate transport independance! 943 * So, we're just gonna doit wrong... By wrong I mean that 944 * we assume that the buf part of the netbuf structure is going 945 * to be a sockaddr_in. We'll then check the assumed family 946 * member and hope that we find AF_INET in there... if not 947 * then we can't continue. 948 */ 949 if (((struct sockaddr_in *)(nbuf->buf))->sin_family != AF_INET) 950 return (0); 951 952 call_addr = ((struct sockaddr_in *)(nbuf->buf))->sin_addr.s_addr; 953 954 cp = resp->valdat.dptr; 955 if ((bp = strtok(cp, " \t")) == NULL) /* no address field */ 956 return (0); 957 if ((cp = strtok(NULL, "")) == NULL) /* no host field */ 958 return (0); 959 bp = strtok(bp, ","); 960 961 bestaddr = inet_addr(bp); 962 while (cp = strtok(NULL, ",")) { 963 ulong_t taddr; 964 965 taddr = inet_addr(cp); 966 if (ntohl(call_addr ^ taddr) < ntohl(call_addr ^ bestaddr)) 967 bestaddr = taddr; 968 } 969 cp = resp->valdat.dptr; 970 sprintf(cp, "%s %s", inet_ntoa(*(struct in_addr *)&bestaddr), name); 971 resp->valdat.dsize = strlen(cp); 972 973 resp->status = YP_TRUE; 974 975 return (1); 976 } 977 978 /* V1 dispatch routines */ 979 void 980 ypoldmatch(SVCXPRT *transp, struct svc_req *rqstp) 981 { 982 bool dbmop_ok = TRUE; 983 struct yprequest req; 984 struct ypreq_key nrq; 985 struct ypresponse resp; 986 char *fun = "ypoldmatch"; 987 DBM *fdb; 988 989 memset((void *) &req, 0, sizeof (req)); 990 memset((void *) &resp, 0, sizeof (resp)); 991 992 if (!svc_getargs(transp, 993 (xdrproc_t)_xdr_yprequest, 994 (caddr_t)&req)) { 995 svcerr_decode(transp); 996 return; 997 } 998 999 if (req.yp_reqtype != YPMATCH_REQTYPE) { 1000 resp.ypmatch_resp_status = (unsigned)YP_BADARGS; 1001 dbmop_ok = FALSE; 1002 } 1003 1004 if (dbmop_ok && 1005 (((fdb = ypset_current_map(req.ypmatch_req_map, 1006 req.ypmatch_req_domain, 1007 &resp.ypmatch_resp_status)) 1008 != NULL) && 1009 yp_map_access(transp, 1010 &resp.ypmatch_resp_status, 1011 fdb))) { 1012 1013 /* Check with the DBM database */ 1014 resp.ypmatch_resp_valdat = dbm_fetch(fdb, 1015 req.ypmatch_req_keydat); 1016 1017 if (resp.ypmatch_resp_valptr != NULL) { 1018 resp.ypmatch_resp_status = YP_TRUE; 1019 if (!silent) 1020 printf("%s: dbm: %s\n", 1021 fun, resp.ypmatch_resp_valptr); 1022 goto send_oldreply; 1023 } 1024 1025 /* 1026 * If we're being asked to match YP_SECURE or YP_INTERDOMAIN 1027 * and we haven't found it in the dbm file, then we don't 1028 * really want to waste any more time. Specifically, we don't 1029 * want to ask DNS 1030 */ 1031 if (req.ypmatch_req_keysize == 0 || 1032 req.ypmatch_req_keyptr == NULL || 1033 req.ypmatch_req_keyptr[0] == '\0' || 1034 strncmp(req.ypmatch_req_keyptr, "YP_SECURE", 9) == 0 || 1035 strncmp(req.ypmatch_req_keyptr, "YP_INTERDOMAIN", 14) == 0) 1036 1037 goto send_oldreply; 1038 1039 /* Let's try the YP_MULTI_ hack... */ 1040 #ifdef MINUS_C_OPTION 1041 if (multiflag == TRUE && omultihomed(req, &resp, transp, fdb)) 1042 goto send_oldreply; 1043 #else 1044 if (omultihomed(req, &resp, transp, fdb)) 1045 goto send_oldreply; 1046 #endif 1047 1048 /* Let's try DNS */ 1049 if (!dnsforward) { 1050 USE_YP_INTERDOMAIN 1051 datum idkey, idval; 1052 idkey.dptr = yp_interdomain; 1053 idkey.dsize = yp_interdomain_sz; 1054 idval = dbm_fetch(fdb, idkey); 1055 if (idval.dptr) 1056 dnsforward = TRUE; 1057 } 1058 1059 if (dnsforward) { 1060 if (!resolv_pid) 1061 setup_resolv(&dnsforward, &resolv_pid, &resolv_client, 1062 resolv_tp, 0); 1063 1064 if (req.yp_reqtype == YPREQ_KEY) { 1065 nrq = req.yp_reqbody.yp_req_keytype; 1066 1067 resolv_req(&dnsforward, &resolv_client, &resolv_pid, 1068 resolv_tp, rqstp->rq_xprt, 1069 &nrq, nrq.map); 1070 } 1071 return; 1072 } 1073 } 1074 1075 send_oldreply: 1076 1077 if (!svc_sendreply(transp, 1078 (xdrproc_t)_xdr_ypresponse, 1079 (caddr_t)&resp)) { 1080 RESPOND_ERR; 1081 } 1082 1083 if (!svc_freeargs(transp, 1084 (xdrproc_t)_xdr_yprequest, 1085 (char *)&req)) { 1086 FREE_ERR; 1087 } 1088 } 1089 1090 void 1091 ypoldfirst(SVCXPRT *transp) 1092 { 1093 bool dbmop_ok = TRUE; 1094 struct yprequest req; 1095 struct ypresponse resp; 1096 char *fun = "ypoldfirst"; 1097 DBM *fdb; 1098 1099 memset((void *) &req, 0, sizeof (req)); 1100 memset((void *) &resp, 0, sizeof (resp)); 1101 1102 if (!svc_getargs(transp, 1103 (xdrproc_t)_xdr_yprequest, 1104 (caddr_t)&req)) { 1105 svcerr_decode(transp); 1106 return; 1107 } 1108 1109 if (req.yp_reqtype != YPFIRST_REQTYPE) { 1110 resp.ypfirst_resp_status = (unsigned)YP_BADARGS; 1111 dbmop_ok = FALSE; 1112 } 1113 1114 if (dbmop_ok && 1115 ((fdb = ypset_current_map(req.ypfirst_req_map, 1116 req.ypfirst_req_domain, 1117 &resp.ypfirst_resp_status)) 1118 != NULL) && 1119 yp_map_access(transp, 1120 &resp.ypfirst_resp_status, 1121 fdb)) { 1122 1123 resp.ypfirst_resp_keydat = dbm_firstkey(fdb); 1124 1125 if (resp.ypfirst_resp_keyptr != NULL) { 1126 resp.ypfirst_resp_valdat = 1127 dbm_fetch(fdb, resp.ypfirst_resp_keydat); 1128 1129 if (resp.ypfirst_resp_valptr != NULL) { 1130 resp.ypfirst_resp_status = YP_TRUE; 1131 } else { 1132 resp.ypfirst_resp_status = (unsigned)YP_BADDB; 1133 } 1134 } else { 1135 resp.ypfirst_resp_status = (unsigned)YP_NOKEY; 1136 } 1137 } 1138 1139 resp.yp_resptype = YPFIRST_RESPTYPE; 1140 1141 if (!svc_sendreply(transp, 1142 (xdrproc_t)_xdr_ypresponse, 1143 (caddr_t)&resp)) { 1144 RESPOND_ERR; 1145 } 1146 1147 if (!svc_freeargs(transp, 1148 (xdrproc_t)_xdr_yprequest, 1149 (caddr_t)&req)) { 1150 FREE_ERR; 1151 } 1152 } 1153 1154 void 1155 ypoldnext(SVCXPRT *transp) 1156 { 1157 bool dbmop_ok = TRUE; 1158 struct yprequest req; 1159 struct ypresponse resp; 1160 char *fun = "ypoldnext"; 1161 DBM *fdb; 1162 1163 memset((void *) &req, 0, sizeof (req)); 1164 memset((void *) &resp, 0, sizeof (resp)); 1165 1166 if (!svc_getargs(transp, 1167 (xdrproc_t)_xdr_yprequest, 1168 (caddr_t)&req)) { 1169 svcerr_decode(transp); 1170 return; 1171 } 1172 1173 if (req.yp_reqtype != YPNEXT_REQTYPE) { 1174 resp.ypnext_resp_status = (unsigned)YP_BADARGS; 1175 dbmop_ok = FALSE; 1176 } 1177 1178 if (dbmop_ok && 1179 ((fdb = ypset_current_map(req.ypnext_req_map, 1180 req.ypnext_req_domain, 1181 &resp.ypnext_resp_status)) != NULL && 1182 yp_map_access(transp, &resp.ypnext_resp_status, fdb))) { 1183 1184 resp.ypnext_resp_keydat = dbm_nextkey(fdb); 1185 1186 if (resp.ypnext_resp_keyptr != NULL) { 1187 resp.ypnext_resp_valdat = 1188 dbm_fetch(fdb, resp.ypnext_resp_keydat); 1189 1190 if (resp.ypnext_resp_valptr != NULL) { 1191 resp.ypnext_resp_status = YP_TRUE; 1192 } else { 1193 resp.ypnext_resp_status = (unsigned)YP_BADDB; 1194 } 1195 } else { 1196 resp.ypnext_resp_status = (unsigned)YP_NOMORE; 1197 } 1198 } 1199 1200 resp.yp_resptype = YPNEXT_RESPTYPE; 1201 1202 if (!svc_sendreply(transp, 1203 (xdrproc_t)_xdr_ypresponse, 1204 (caddr_t)&resp)) { 1205 RESPOND_ERR; 1206 } 1207 1208 if (!svc_freeargs(transp, 1209 (xdrproc_t)_xdr_yprequest, 1210 (caddr_t)&req)) { 1211 FREE_ERR; 1212 } 1213 } 1214 1215 /* 1216 * This retrieves the order number and master peer name from the map. 1217 * The conditions for the various message fields are: domain is filled 1218 * in iff the domain exists. map is filled in iff the map exists. 1219 * order number is filled in iff it's in the map. owner is filled in 1220 * iff the master peer is in the map. 1221 */ 1222 void 1223 ypoldpoll(SVCXPRT *transp) 1224 { 1225 struct yprequest req; 1226 struct ypresponse resp; 1227 char *map = ""; 1228 char *domain = ""; 1229 char *owner = ""; 1230 uint_t error; 1231 char *fun = "ypoldpoll"; 1232 DBM *fdb; 1233 1234 memset((void *) &req, 0, sizeof (req)); 1235 memset((void *) &resp, 0, sizeof (resp)); 1236 1237 if (!svc_getargs(transp, 1238 (xdrproc_t)_xdr_yprequest, 1239 (caddr_t)&req)) { 1240 svcerr_decode(transp); 1241 return; 1242 } 1243 1244 if (req.yp_reqtype == YPPOLL_REQTYPE) { 1245 if (strcmp(req.yppoll_req_domain, "yp_private") == 0 || 1246 strcmp(req.yppoll_req_map, "ypdomains") == 0 || 1247 strcmp(req.yppoll_req_map, "ypmaps") == 0) { 1248 1249 /* 1250 * Backward comatibility for 2.0 NIS servers 1251 */ 1252 domain = req.yppoll_req_domain; 1253 map = req.yppoll_req_map; 1254 } else if ((fdb = ypset_current_map(req.yppoll_req_map, 1255 req.yppoll_req_domain, 1256 &error)) != NULL) { 1257 domain = req.yppoll_req_domain; 1258 map = req.yppoll_req_map; 1259 ypget_map_order(map, domain, 1260 &resp.yppoll_resp_ordernum); 1261 ypget_map_master(&owner, fdb); 1262 } else { 1263 switch ((int)error) { 1264 case YP_BADDB: 1265 map = req.yppoll_req_map; 1266 /* Fall through to set the domain too. */ 1267 1268 case YP_NOMAP: 1269 domain = req.yppoll_req_domain; 1270 break; 1271 } 1272 } 1273 } 1274 1275 resp.yp_resptype = YPPOLL_RESPTYPE; 1276 resp.yppoll_resp_domain = domain; 1277 resp.yppoll_resp_map = map; 1278 resp.yppoll_resp_owner = owner; 1279 1280 if (!svc_sendreply(transp, 1281 (xdrproc_t)_xdr_ypresponse, 1282 (caddr_t)&resp)) { 1283 RESPOND_ERR; 1284 } 1285 1286 if (!svc_freeargs(transp, 1287 (xdrproc_t)_xdr_yprequest, 1288 (caddr_t)&req)) { 1289 FREE_ERR; 1290 } 1291 } 1292 1293 void 1294 ypoldpush(SVCXPRT *transp) 1295 { 1296 struct yprequest req; 1297 struct ypresp_val resp; 1298 pid_t pid = -1; 1299 char *fun = "ypoldpush"; 1300 DBM *fdb; 1301 1302 memset((void *) &req, 0, sizeof (req)); 1303 1304 if (!svc_getargs(transp, 1305 (xdrproc_t)_xdr_yprequest, 1306 (caddr_t)&req)) { 1307 svcerr_decode(transp); 1308 return; 1309 } 1310 1311 if (((fdb = ypset_current_map(req.yppush_req_map, 1312 req.yppush_req_domain, 1313 &resp.status)) != NULL) && 1314 (yp_map_access(transp, &resp.status, fdb))) { 1315 1316 pid = vfork(); 1317 } 1318 1319 if (pid == -1) { 1320 FORK_ERR; 1321 } else if (pid == 0) { 1322 ypclr_current_map(); 1323 1324 if (execl(yppush_proc, "yppush", "-d", req.yppush_req_domain, 1325 req.yppush_req_map, NULL)) { 1326 EXEC_ERR; 1327 } 1328 _exit(1); 1329 } 1330 1331 if (!svc_sendreply(transp, 1332 (xdrproc_t)xdr_void, 1333 (caddr_t)NULL)) { 1334 RESPOND_ERR; 1335 } 1336 1337 if (!svc_freeargs(transp, 1338 (xdrproc_t)_xdr_yprequest, 1339 (caddr_t)&req)) { 1340 FREE_ERR; 1341 } 1342 } 1343 1344 void 1345 ypoldpull(SVCXPRT *transp) 1346 { 1347 struct yprequest req; 1348 struct ypresp_val resp; 1349 pid_t pid = -1; 1350 char *fun = "ypoldpull"; 1351 DBM *fdb; 1352 1353 memset((void *) &req, 0, sizeof (req)); 1354 1355 if (!svc_getargs(transp, 1356 (xdrproc_t)_xdr_yprequest, 1357 (caddr_t)&req)) { 1358 svcerr_decode(transp); 1359 return; 1360 } 1361 1362 if (req.yp_reqtype == YPPULL_REQTYPE) { 1363 1364 if (((fdb = ypset_current_map(req.yppull_req_map, 1365 req.yppull_req_domain, 1366 &resp.status)) == NULL) || 1367 (yp_map_access(transp, &resp.status, fdb))) { 1368 pid = vfork(); 1369 } 1370 1371 if (pid == -1) { 1372 FORK_ERR; 1373 } else if (pid == 0) { 1374 ypclr_current_map(); 1375 1376 if (execl(ypxfr_proc, "ypxfr", "-d", 1377 req.yppull_req_domain, 1378 req.yppull_req_map, NULL)) { 1379 EXEC_ERR; 1380 } 1381 _exit(1); 1382 } 1383 } 1384 1385 if (!svc_freeargs(transp, 1386 (xdrproc_t)_xdr_yprequest, 1387 (caddr_t)&req)) { 1388 FREE_ERR; 1389 } 1390 } 1391 1392 void 1393 ypoldget(SVCXPRT *transp) 1394 { 1395 struct yprequest req; 1396 struct ypresp_val resp; 1397 pid_t pid = -1; 1398 char *fun = "ypoldget"; 1399 DBM *fdb; 1400 1401 memset((void *) &req, 0, sizeof (req)); 1402 1403 if (!svc_getargs(transp, 1404 (xdrproc_t)_xdr_yprequest, 1405 (caddr_t)&req)) { 1406 svcerr_decode(transp); 1407 return; 1408 } 1409 1410 if (!svc_sendreply(transp, xdr_void, 0)) { 1411 RESPOND_ERR; 1412 } 1413 1414 if (req.yp_reqtype == YPGET_REQTYPE) { 1415 1416 if (((fdb = ypset_current_map(req.ypget_req_map, 1417 req.ypget_req_domain, 1418 &resp.status)) == NULL) || 1419 (yp_map_access(transp, &resp.status, fdb))) { 1420 1421 pid = vfork(); 1422 } 1423 1424 if (pid == -1) { 1425 FORK_ERR; 1426 } else if (pid == 0) { 1427 1428 ypclr_current_map(); 1429 1430 if (execl(ypxfr_proc, "ypxfr", "-d", 1431 req.ypget_req_domain, "-h", 1432 req.ypget_req_owner, 1433 req.ypget_req_map, NULL)) { 1434 1435 EXEC_ERR; 1436 } 1437 _exit(1); 1438 } 1439 } 1440 1441 if (!svc_freeargs(transp, 1442 (xdrproc_t)_xdr_yprequest, 1443 (caddr_t)&req)) { 1444 RESPOND_ERR; 1445 } 1446 } 1447 1448 static int 1449 omultihomed(struct yprequest req, 1450 struct ypresponse *resp, SVCXPRT *xprt, DBM *fdb) 1451 { 1452 char *cp, *bp; 1453 char name[PATH_MAX]; 1454 struct netbuf *nbuf; 1455 ulong_t bestaddr, call_addr; 1456 1457 if (strcmp(req.ypmatch_req_map, "hosts.byname")) 1458 return (0); 1459 1460 if (strncmp(req.ypmatch_req_keyptr, "YP_MULTI_", 9)) { 1461 datum tmpname; 1462 1463 strncpy(name, "YP_MULTI_", 9); 1464 strncpy(name + 9, req.ypmatch_req_keyptr, 1465 req.ypmatch_req_keysize); 1466 tmpname.dsize = req.ypmatch_req_keysize + 9; 1467 tmpname.dptr = name; 1468 resp->ypmatch_resp_valdat = dbm_fetch(fdb, tmpname); 1469 } else { 1470 resp->ypmatch_resp_valdat = 1471 dbm_fetch(fdb, req.ypmatch_req_keydat); 1472 if (resp->ypmatch_resp_valptr != NULL) 1473 return (1); 1474 } 1475 1476 if (resp->ypmatch_resp_valptr == NULL) 1477 return (0); 1478 1479 strncpy(name, req.ypmatch_req_keyptr, req.ypmatch_req_keysize); 1480 name[req.ypmatch_req_keysize] = NULL; 1481 1482 nbuf = svc_getrpccaller(xprt); 1483 1484 /* 1485 * OK, now I have a netbuf structure which I'm supposed to treat 1486 * as opaque... I hate transport independance! So, we're just 1487 * gonna doit wrong... By wrong I mean that we assume that the 1488 * buf part of the netbuf structure is going to be a sockaddr_in. 1489 * We'll then check the assumed family member and hope that we 1490 * find AF_INET in there... if not then we can't continue. 1491 */ 1492 if (((struct sockaddr_in *)(nbuf->buf))->sin_family != AF_INET) 1493 return (0); 1494 1495 call_addr = ((struct sockaddr_in *)(nbuf->buf))->sin_addr.s_addr; 1496 1497 cp = resp->ypmatch_resp_valptr; 1498 if ((bp = strtok(cp, "\t")) == NULL) /* No address field */ 1499 return (0); 1500 if ((cp = strtok(NULL, "")) == NULL) /* No host field */ 1501 return (0); 1502 bp = strtok(bp, ","); 1503 1504 bestaddr = inet_addr(bp); 1505 while (cp = strtok(NULL, ",")) { 1506 ulong_t taddr; 1507 1508 taddr = inet_addr(cp); 1509 if (ntohl(call_addr ^ taddr) < ntohl(call_addr ^ bestaddr)) 1510 bestaddr = taddr; 1511 } 1512 1513 cp = resp->ypmatch_resp_valptr; 1514 sprintf(cp, "%s %s", inet_ntoa(*(struct in_addr *)&bestaddr), name); 1515 resp->ypmatch_resp_valsize = strlen(cp); 1516 1517 resp->ypmatch_resp_status = YP_TRUE; 1518 1519 return (1); 1520 } 1521