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