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