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 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * Copyright (c) 2016 by Delphix. All rights reserved. 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 32 * under license from the Regents of the University of 33 * California. 34 */ 35 36 /* 37 * This is a user command which gets a NIS data base from some running 38 * server, and gets it to the local site by using the normal NIS client 39 * enumeration functions. The map is copied to a temp name, then the real 40 * map is removed and the temp map is moved to the real name. ypxfr then 41 * sends a "YPPROC_CLEAR" message to the local server to insure that it will 42 * not hold a removed map open, so serving an obsolete version. 43 * 44 * ypxfr [ -h <host> ] [ -d <domainname> ] 45 * [ -s <domainname> ] [-f] [-c] [-C tid prot name] map 46 * 47 * If the host is ommitted, ypxfr will attempt to discover the master by 48 * using normal NIS services. If it can't get the record, it will use 49 * the address of the callback, if specified. If the host is specified 50 * as an internet address, no NIS services need to be locally available. 51 * 52 * If the domain is not specified, the default domain of the local machine 53 * is used. 54 * 55 * If the -f flag is used, the transfer will be done even if the master's 56 * copy is not newer than the local copy. 57 * 58 * The -c flag suppresses the YPPROC_CLEAR request to the local ypserv. It 59 * may be used if ypserv isn't currently running to suppress the error message. 60 * 61 * The -C flag is used to pass callback information to ypxfr when it is 62 * activated by ypserv. The callback information is used to send a 63 * yppushresp_xfr message with transaction id "tid" to a yppush process 64 * speaking a transient protocol number "prot". The yppush program is 65 * running on the host "name". 66 * 67 * The -s option is used to specify a source domain which may be 68 * different from the destination domain, for transfer of maps 69 * that are identical in different domains (e.g. services.byname) 70 * 71 */ 72 73 #include <ndbm.h> 74 #define DATUM 75 76 #include <stdio.h> 77 #include <errno.h> 78 #include <time.h> 79 #include <ctype.h> 80 #include <netdb.h> 81 #include <netconfig.h> 82 #include <netdir.h> 83 #include <rpc/rpc.h> 84 #include <sys/file.h> 85 #include <sys/stat.h> 86 #include <dirent.h> 87 #include <rpcsvc/ypclnt.h> 88 #include <rpcsvc/yp_prot.h> 89 #include <unistd.h> 90 #include <stdlib.h> 91 #include <rpcsvc/nis.h> 92 #include "ypdefs.h" 93 #include "yp_b.h" 94 #include "shim.h" 95 #include "yptol.h" 96 97 USE_YP_MASTER_NAME 98 USE_YP_SECURE 99 USE_YP_INTERDOMAIN 100 USE_YP_LAST_MODIFIED 101 USE_YPDBPATH 102 USE_DBM 103 104 #define PARANOID 1 /* make sure maps have the right # entries */ 105 106 #define CALLINTER_TRY 10 /* Seconds between callback tries */ 107 #define CALLTIMEOUT CALLINTER_TRY*6 /* Total timeout for callback */ 108 109 DBM *db; 110 111 /* ypxfr never uses N2L mode */ 112 bool_t yptol_mode = FALSE; 113 114 int debug = FALSE; 115 int treepush = FALSE; 116 #define TREEPUSH 1 117 int defwrite = TRUE; 118 119 char *domain = NULL; 120 char *source = NULL; 121 char *map = NULL; 122 char *master = NULL; 123 char *pushhost = NULL; 124 /* 125 * The name of the xfer peer as specified as a 126 * -h option, -C name option or from querying the NIS 127 */ 128 struct dom_binding master_server; /* To talk to above */ 129 unsigned int master_prog_vers; /* YPVERS (barfs at YPOLDVERS !) */ 130 char *master_name = NULL; /* Map's master as contained in the map */ 131 unsigned *master_version = NULL; /* Order number as contained in the map */ 132 char *master_ascii_version; /* ASCII order number as contained in the map */ 133 bool fake_master_version = FALSE; 134 /* 135 * TRUE only if there's no order number in 136 * the map, and the user specified -f 137 */ 138 bool force = FALSE; /* TRUE iff user specified -f flag */ 139 bool logging = FALSE; /* TRUE iff no tty, but log file exists */ 140 bool check_count = FALSE; /* TRUE causes counts to be checked */ 141 bool send_clear = TRUE; /* FALSE iff user specified -c flag */ 142 bool callback = FALSE; 143 /* 144 * TRUE iff -C flag set. tid, proto and name 145 * will be set to point to the command line args. 146 */ 147 bool secure_map = FALSE; /* TRUE if there is yp_secure in the map */ 148 bool interdomain_map = FALSE; 149 /* 150 * TRUE if there is yp_interdomain in either 151 * the local or the master version of the map 152 */ 153 int interdomain_sz = 0; /* Size of the interdomain value */ 154 #define UDPINTER_TRY 10 /* Seconds between tries for udp */ 155 #define UDPTIMEOUT UDPINTER_TRY*4 /* Total timeout for udp */ 156 #define CALLINTER_TRY 10 /* Seconds between callback tries */ 157 #define CALLTIMEOUT CALLINTER_TRY*6 /* Total timeout for callback */ 158 struct timeval udp_timeout = { UDPTIMEOUT, 0}; 159 struct timeval tcp_timeout = { 180, 0}; /* Timeout for map enumeration */ 160 161 char *interdomain_value; /* place to store the interdomain value */ 162 char *tid; 163 char *proto; 164 int entry_count; /* counts entries in the map */ 165 char logfile[] = "/var/yp/ypxfr.log"; 166 static char err_usage[] = 167 "Usage:\n\ 168 ypxfr [-f] [ -h host ] [ -d domainname ]\n\ 169 [ -s domainname ] [-c] [-C tid prot servname ] map\n\n\ 170 where\n\ 171 -f forces transfer even if the master's copy is not newer.\n\ 172 host is the server from where the map should be transfered\n\ 173 -d domainname is specified if other than the default domain\n\ 174 -s domainname is a source for the map that is same across domains\n\ 175 -c inhibits sending a \"Clear map\" message to the local ypserv.\n\ 176 -C is for use only by ypserv to pass callback information.\n"; 177 char err_bad_args[] = 178 "%s argument is bad.\n"; 179 char err_cant_get_kname[] = 180 "Can't get %s back from system call.\n"; 181 char err_null_kname[] = 182 "%s hasn't been set on this machine.\n"; 183 char err_bad_hostname[] = "hostname"; 184 char err_bad_mapname[] = "mapname"; 185 char err_bad_domainname[] = "domainname"; 186 char err_udp_failure[] = 187 "Can't set up a udp connection to ypserv on host %s.\n"; 188 char yptempname_prefix[] = "ypxfr_map."; 189 char ypbkupname_prefix[] = "ypxfr_bkup."; 190 191 void get_command_line_args(); 192 bool bind_to_server(); 193 bool ping_server(); 194 bool get_private_recs(); 195 bool get_order(); 196 bool get_v1order(); 197 bool get_v2order(); 198 bool get_misc_recs(); 199 bool get_master_name(); 200 bool get_v1master_name(); 201 bool get_v2master_name(); 202 void find_map_master(); 203 bool move_map(); 204 unsigned get_local_version(); 205 void mkfilename(); 206 void mk_tmpname(); 207 bool get_map(); 208 bool add_private_entries(); 209 bool new_mapfiles(); 210 void del_mapfiles(); 211 void set_output(); 212 void logprintf(); 213 bool send_ypclear(); 214 void xfr_exit(); 215 void send_callback(); 216 int ypall_callback(); 217 int map_yperr_to_pusherr(); 218 extern CLIENT *__yp_clnt_create_rsvdport(); 219 220 bool_t is_yptol_mode(); 221 222 extern int errno; 223 224 225 /* 226 * This is the mainline for the ypxfr process. 227 */ 228 229 int 230 main(argc, argv) 231 int argc; 232 char **argv; 233 234 { 235 236 static char default_domain_name[YPMAXDOMAIN]; 237 static unsigned big = 0xffffffff; 238 int status; 239 240 set_output(); 241 242 /* 243 * Inter-process lock synchronization structure. Since slave servers 244 * get their maps from another NIS server rather than LDAP they can 245 * never run in N2L mode. We thus do not have to init the update 246 * locking mechanism. 247 */ 248 if (init_lock_map() == FALSE) { 249 exit(1); 250 } 251 252 get_command_line_args(argc, argv); 253 254 if (!domain) { 255 256 if (!getdomainname(default_domain_name, YPMAXDOMAIN)) { 257 domain = default_domain_name; 258 } else { 259 logprintf(err_cant_get_kname, 260 err_bad_domainname); 261 xfr_exit(YPPUSH_RSRC); 262 } 263 264 if (strlen(domain) == 0) { 265 logprintf(err_null_kname, 266 err_bad_domainname); 267 xfr_exit(YPPUSH_RSRC); 268 } 269 } 270 if (!source) 271 source = domain; 272 273 if (!master) { 274 find_map_master(); 275 } 276 /* 277 * if we were unable to get the master name, either from 278 * the -h option or from -C "name" option or from NIS, 279 * we are doomed ! 280 */ 281 if (!master) { 282 xfr_exit(YPPUSH_MADDR); 283 } 284 285 if (!bind_to_server(master, &master_server, 286 &master_prog_vers, &status)) { 287 xfr_exit(status); 288 } 289 290 if (!get_private_recs(&status)) { 291 xfr_exit(status); 292 } 293 294 if (!master_version) { 295 296 if (force) { 297 master_version = &big; 298 fake_master_version = TRUE; 299 } else { 300 logprintf( 301 "Can't get order number for map %s from server at %s: use the -f flag.\n", 302 map, master); 303 xfr_exit(YPPUSH_FORCE); 304 } 305 } 306 307 if (!move_map(&status)) { 308 xfr_exit(status); 309 } 310 311 if (send_clear && !send_ypclear(&status)) { 312 xfr_exit(status); 313 } 314 315 if (logging) { 316 logprintf("Transferred map %s from %s (%d entries).\n", 317 map, master, entry_count); 318 } 319 320 xfr_exit(YPPUSH_SUCC); 321 return (0); 322 /* NOTREACHED */ 323 } 324 325 /* 326 * This decides whether we're being run interactively or not, and, if not, 327 * whether we're supposed to be logging or not. If we are logging, it sets 328 * up stderr to point to the log file, and sets the "logging" 329 * variable. If there's no logging, the output goes in the bit bucket. 330 * Logging output differs from interactive output in the presence of a 331 * timestamp, present only in the log file. stderr is reset, too, because it 332 * it's used by various library functions, including clnt_perror. 333 */ 334 void 335 set_output() 336 { 337 if (!isatty(1)) { 338 if (access(logfile, W_OK)) { 339 (void) freopen("/dev/null", "w", stderr); 340 } else { 341 (void) freopen(logfile, "a", stderr); 342 logging = TRUE; 343 } 344 } 345 } 346 /* 347 * This constructs a logging record. 348 */ 349 void 350 logprintf(arg1, arg2, arg3, arg4, arg5, arg6, arg7) 351 /*VARARGS*/ 352 { 353 struct timeval t; 354 355 fseek(stderr, 0, 2); 356 if (logging) { 357 (void) gettimeofday(&t, NULL); 358 (void) fprintf(stderr, "%19.19s: ", ctime(&t.tv_sec)); 359 } 360 (void) fprintf(stderr, (char *)arg1, arg2, arg3, arg4, arg5, 361 arg6, arg7); 362 fflush(stderr); 363 } 364 365 /* 366 * This does the command line argument processing. 367 */ 368 void 369 get_command_line_args(argc, argv) 370 int argc; 371 char **argv; 372 373 { 374 argv++; 375 376 if (argc < 2) { 377 logprintf(err_usage); 378 xfr_exit(YPPUSH_BADARGS); 379 } 380 381 while (--argc) { 382 383 if ((*argv)[0] == '-') { 384 385 switch ((*argv)[1]) { 386 387 case 'f': { 388 force = TRUE; 389 argv++; 390 break; 391 } 392 393 case 'D': { 394 debug = TRUE; 395 argv++; 396 break; 397 } 398 399 case 'T': { 400 treepush = TRUE; 401 argv++; 402 break; 403 } 404 case 'P': { 405 check_count = TRUE; 406 argv++; 407 break; 408 } 409 case 'W': { 410 defwrite = FALSE; 411 argv++; 412 break; 413 } 414 case 'c': { 415 send_clear = FALSE; 416 argv++; 417 break; 418 } 419 420 case 'h': { 421 422 if (argc > 1) { 423 argv++; 424 argc--; 425 master = *argv; 426 argv++; 427 428 if (strlen(master) > 256) { 429 logprintf( 430 err_bad_args, 431 err_bad_hostname); 432 xfr_exit(YPPUSH_BADARGS); 433 } 434 435 } else { 436 logprintf(err_usage); 437 xfr_exit(YPPUSH_BADARGS); 438 } 439 440 break; 441 } 442 443 case 'd': 444 if (argc > 1) { 445 argv++; 446 argc--; 447 domain = *argv; 448 argv++; 449 450 if (strlen(domain) > YPMAXDOMAIN) { 451 logprintf( 452 err_bad_args, 453 err_bad_domainname); 454 xfr_exit(YPPUSH_BADARGS); 455 } 456 457 } else { 458 logprintf(err_usage); 459 xfr_exit(YPPUSH_BADARGS); 460 } 461 break; 462 463 case 's': 464 if (argc > 1) { 465 argv++; 466 argc--; 467 source = *argv; 468 argv++; 469 470 if (strlen(source) > YPMAXDOMAIN) { 471 logprintf( 472 err_bad_args, 473 err_bad_domainname); 474 xfr_exit(YPPUSH_BADARGS); 475 } 476 477 } else { 478 logprintf(err_usage); 479 xfr_exit(YPPUSH_BADARGS); 480 } 481 break; 482 483 case 'C': 484 if (argc > 3) { 485 callback = TRUE; 486 tid = *(++argv); 487 proto = *(++argv); 488 pushhost = *(++argv); 489 if (strlen(pushhost) > 256) { 490 logprintf(err_bad_args, err_bad_hostname); 491 492 xfr_exit(YPPUSH_BADARGS); 493 } 494 argc -= 3; 495 argv++; 496 } else { 497 logprintf(err_usage); 498 xfr_exit(YPPUSH_BADARGS); 499 } 500 break; 501 502 case 'b': { 503 interdomain_map = TRUE; 504 interdomain_value = ""; 505 interdomain_sz = 0; 506 argv++; 507 break; 508 } 509 510 511 default: { 512 logprintf(err_usage); 513 xfr_exit(YPPUSH_BADARGS); 514 } 515 516 } 517 518 } else { 519 520 if (!map) { 521 map = *argv; 522 argv++; 523 524 if (strlen(map) > YPMAXMAP) { 525 logprintf(err_bad_args, 526 err_bad_mapname); 527 xfr_exit(YPPUSH_BADARGS); 528 } 529 530 } else { 531 logprintf(err_usage); 532 xfr_exit(YPPUSH_BADARGS); 533 } 534 } 535 } 536 537 if (!map) { 538 logprintf(err_usage); 539 xfr_exit(YPPUSH_BADARGS); 540 } 541 } 542 543 /* 544 * This tries to get the master name for the named map, from any 545 * server's version, using the vanilla NIS client interface. If we get a 546 * name back, the global "master" gets pointed to it. 547 */ 548 void 549 find_map_master() 550 { 551 int err; 552 553 if (err = __yp_master_rsvdport(source, map, &master)) { 554 logprintf("Can't get master of %s. Reason: %s.\n", map, 555 yperr_string(err)); 556 } 557 558 yp_unbind(source); 559 } 560 561 #ifdef TREEPUSH 562 int 563 chk_treepush(name) 564 char *name; 565 { 566 char inmap[256]; 567 char inkey[256]; 568 int inkeylen; 569 char *outval; 570 int outvallen; 571 int err; 572 outval = NULL; 573 inkey[0] = 0; 574 strcpy(inmap, "ypslaves."); 575 strcat(inmap, name); 576 gethostname(inkey, 256); 577 inkeylen = strlen(inkey); 578 579 err = yp_match(source, inmap, inkey, inkeylen, &outval, &outvallen); 580 yp_unbind(source); 581 return (err); 582 } 583 #endif 584 585 /* 586 * This sets up a udp connection to speak the correct program and version 587 * to a NIS server. vers is set to YPVERS, doesn't give a damn about 588 * YPOLDVERS. 589 */ 590 bool 591 bind_to_server(host, pdomb, vers, status) 592 char *host; 593 struct dom_binding *pdomb; 594 unsigned int *vers; 595 int *status; 596 { 597 if (ping_server(host, pdomb, YPVERS, status)) { 598 *vers = YPVERS; 599 return (TRUE); 600 } else 601 return (FALSE); 602 } 603 604 /* 605 * This sets up a UDP channel to a server which is assumed to speak an input 606 * version of YPPROG. The channel is tested by pinging the server. In all 607 * error cases except "Program Version Number Mismatch", the error is 608 * reported, and in all error cases, the client handle is destroyed and the 609 * socket associated with the channel is closed. 610 */ 611 bool 612 ping_server(host, pdomb, vers, status) 613 char *host; 614 struct dom_binding *pdomb; 615 unsigned int vers; 616 int *status; 617 { 618 enum clnt_stat rpc_stat; 619 620 if ((pdomb->dom_client = __yp_clnt_create_rsvdport(host, YPPROG, vers, 621 0, 0, 0)) != 0) { 622 623 /* 624 * if we are on a c2 system, we should only accept data 625 * from a server which is on a reserved port. 626 */ 627 /* 628 * NUKE this for 5.0DR. 629 * 630 * if (issecure() && 631 * (pdomb->dom_server_addr.sin_family != AF_INET || 632 * pdomb->dom_server_addr.sin_port >= IPPORT_RESERVED)) { 633 * clnt_destroy(pdomb->dom_client); 634 * close(pdomb->dom_socket); 635 * (void) logprintf("bind_to_server: \ 636 * server is not using a privileged port\n"); 637 * *status = YPPUSH_YPERR; 638 * return (FALSE); 639 * } 640 */ 641 642 rpc_stat = clnt_call(pdomb->dom_client, YPBINDPROC_NULL, 643 xdr_void, 0, xdr_void, 0, udp_timeout); 644 645 if (rpc_stat == RPC_SUCCESS) { 646 return (TRUE); 647 } else { 648 clnt_destroy(pdomb->dom_client); 649 if (rpc_stat != RPC_PROGVERSMISMATCH) { 650 (void) clnt_perror(pdomb->dom_client, 651 "ypxfr: bind_to_server clnt_call error"); 652 } 653 654 *status = YPPUSH_RPC; 655 return (FALSE); 656 } 657 } else { 658 logprintf("bind_to_server __clnt_create_rsvd error"); 659 (void) clnt_pcreateerror(""); 660 fflush(stderr); 661 *status = YPPUSH_RPC; 662 return (FALSE); 663 } 664 } 665 666 /* 667 * This gets values for the YP_LAST_MODIFIED and YP_MASTER_NAME keys from the 668 * master server's version of the map. Values are held in static variables 669 * here. In the success cases, global pointer variables are set to point at 670 * the local statics. 671 */ 672 bool 673 get_private_recs(pushstat) 674 int *pushstat; 675 { 676 static char anumber[20]; 677 static unsigned number; 678 static char name[YPMAXPEER + 1]; 679 int status; 680 681 status = 0; 682 683 if (get_order(anumber, &number, &status)) { 684 master_version = &number; 685 master_ascii_version = anumber; 686 if (debug) fprintf(stderr, 687 "ypxfr: Master Version is %s\n", master_ascii_version); 688 } else { 689 690 if (status != 0) { 691 *pushstat = status; 692 if (debug) fprintf(stderr, 693 "ypxfr: Couldn't get map's master version number, \ 694 status was %d\n", status); 695 return (FALSE); 696 } 697 } 698 699 if (get_master_name(name, &status)) { 700 master_name = name; 701 if (debug) fprintf(stderr, 702 "ypxfr: Maps master is '%s'\n", master_name); 703 } else { 704 705 if (status != 0) { 706 *pushstat = status; 707 if (debug) fprintf(stderr, 708 "ypxfr: Couldn't get map's master name, status was %d\n", 709 status); 710 return (FALSE); 711 } 712 master_name = master; 713 } 714 715 if (debug) 716 fprintf(stderr, 717 "ypxfr: Getting private records from master.\n"); 718 if (get_misc_recs(&status)) { 719 if (debug) 720 fprintf(stderr, 721 "ypxfr: Masters map %s secure and %s an interdomain map.\n", 722 (secure_map) ? "is" : "is not", 723 (interdomain_map) ? "is" : "is not"); 724 } else { 725 if (status != 0) { 726 *pushstat = status; 727 if (debug) 728 fprintf(stderr, 729 "ypxfr: Couldn't get state of secure and interdomain flags in map.\n"); 730 return (FALSE); 731 } 732 } 733 734 return (TRUE); 735 } 736 737 /* 738 * This gets the map's order number from the master server 739 */ 740 bool 741 get_order(an, n, pushstat) 742 char *an; 743 unsigned *n; 744 int *pushstat; 745 { 746 if (master_prog_vers == YPVERS) { 747 return (get_v2order(an, n, pushstat)); 748 } else 749 return (FALSE); 750 } 751 752 bool 753 get_v2order(an, n, pushstat) 754 char *an; 755 unsigned *n; 756 int *pushstat; 757 { 758 struct ypreq_nokey req; 759 struct ypresp_order resp; 760 int retval; 761 762 req.domain = source; 763 req.map = map; 764 765 /* 766 * Get the map''s order number, null-terminate it and store it, 767 * and convert it to binary and store it again. 768 */ 769 retval = FALSE; 770 771 if ((enum clnt_stat) clnt_call(master_server.dom_client, 772 YPPROC_ORDER, (xdrproc_t)xdr_ypreq_nokey, (char *)&req, 773 (xdrproc_t)xdr_ypresp_order, (char *)&resp, 774 udp_timeout) == RPC_SUCCESS) { 775 776 if (resp.status == YP_TRUE) { 777 sprintf(an, "%d", resp.ordernum); 778 *n = resp.ordernum; 779 retval = TRUE; 780 } else if (resp.status != YP_BADDB) { 781 *pushstat = ypprot_err(resp.status); 782 783 if (!logging) { 784 logprintf( 785 "(info) Can't get order number from ypserv at %s. Reason: %s.\n", 786 master, yperr_string( 787 ypprot_err(resp.status))); 788 } 789 } 790 791 CLNT_FREERES(master_server.dom_client, 792 (xdrproc_t)xdr_ypresp_order, 793 (char *)&resp); 794 } else { 795 *pushstat = YPPUSH_RPC; 796 logprintf("ypxfr(get_v2order) RPC call to %s failed", master); 797 clnt_perror(master_server.dom_client, ""); 798 } 799 800 return (retval); 801 } 802 803 /* 804 * Pick up the state of the YP_SECURE and YP_INTERDOMAIN records from the 805 * master. Only works on 4.0 V2 masters that will match a YP_ private key 806 * when asked to explicitly. 807 */ 808 bool 809 get_misc_recs(pushstat) 810 int *pushstat; 811 { 812 struct ypreq_key req; 813 struct ypresp_val resp; 814 int retval; 815 816 req.domain = source; 817 req.map = map; 818 req.keydat.dptr = yp_secure; 819 req.keydat.dsize = yp_secure_sz; 820 821 resp.valdat.dptr = NULL; 822 resp.valdat.dsize = 0; 823 824 /* 825 * Get the value of the IS_SECURE key in the map. 826 */ 827 retval = FALSE; 828 829 if (debug) 830 fprintf(stderr, "ypxfr: Checking masters secure key.\n"); 831 if ((enum clnt_stat) clnt_call(master_server.dom_client, 832 YPPROC_MATCH, (xdrproc_t)xdr_ypreq_key, (char *)&req, 833 (xdrproc_t)xdr_ypresp_val, (char *)&resp, 834 udp_timeout) == RPC_SUCCESS) { 835 if (resp.status == YP_TRUE) { 836 if (debug) 837 fprintf(stderr, "ypxfr: SECURE\n"); 838 secure_map = TRUE; 839 retval = TRUE; 840 } else if ((resp.status != YP_NOKEY) && 841 (resp.status != YP_VERS) && 842 (resp.status != YP_NOMORE)) { 843 *pushstat = ypprot_err(resp.status); 844 845 if (!logging) { 846 logprintf( 847 "(info) Can't get secure flag from ypserv at %s. Reason: %s.\n", 848 master, yperr_string( 849 ypprot_err(resp.status))); 850 } 851 } 852 853 CLNT_FREERES(master_server.dom_client, 854 (xdrproc_t)xdr_ypresp_val, 855 (char *)&resp); 856 } else { 857 *pushstat = YPPUSH_RPC; 858 logprintf("ypxfr(get_misc_recs) RPC call to %s failed", master); 859 clnt_perror(master_server.dom_client, ""); 860 } 861 862 if (debug) 863 fprintf(stderr, "ypxfr: Checking masters INTERDOMAIN key.\n"); 864 req.keydat.dptr = yp_interdomain; 865 req.keydat.dsize = yp_interdomain_sz; 866 867 resp.valdat.dptr = NULL; 868 resp.valdat.dsize = 0; 869 870 /* 871 * Get the value of the INTERDOMAIN key in the map. 872 */ 873 874 if ((enum clnt_stat) clnt_call(master_server.dom_client, 875 YPPROC_MATCH, (xdrproc_t)xdr_ypreq_key, (char *)&req, 876 (xdrproc_t)xdr_ypresp_val, (char *)&resp, 877 udp_timeout) == RPC_SUCCESS) { 878 if (resp.status == YP_TRUE) { 879 if (debug) 880 fprintf(stderr, "ypxfr: INTERDOMAIN\n"); 881 interdomain_map = TRUE; 882 interdomain_value = (char *)malloc(resp.valdat.dsize+1); 883 (void) memmove(interdomain_value, resp.valdat.dptr, 884 resp.valdat.dsize); 885 *(interdomain_value+resp.valdat.dsize) = '\0'; 886 interdomain_sz = resp.valdat.dsize; 887 retval = TRUE; 888 } else if ((resp.status != YP_NOKEY) && 889 (resp.status != YP_VERS) && 890 (resp.status != YP_NOMORE)) { 891 *pushstat = ypprot_err(resp.status); 892 893 if (!logging) { 894 logprintf( 895 "(info) Can't get interdomain flag from ypserv at %s. Reason: %s.\n", 896 master, yperr_string( 897 ypprot_err(resp.status))); 898 } 899 } 900 901 CLNT_FREERES(master_server.dom_client, 902 (xdrproc_t)xdr_ypresp_val, 903 (char *)&resp); 904 } else { 905 *pushstat = YPPUSH_RPC; 906 logprintf("ypxfr(get_misc_recs) RPC call to %s failed", master); 907 clnt_perror(master_server.dom_client, ""); 908 } 909 910 911 return (retval); 912 } 913 914 /* 915 * This gets the map's master name from the master server 916 */ 917 bool 918 get_master_name(name, pushstat) 919 char *name; 920 int *pushstat; 921 { 922 if (master_prog_vers == YPVERS) { 923 return (get_v2master_name(name, pushstat)); 924 } else 925 return (FALSE); 926 } 927 928 bool 929 get_v2master_name(name, pushstat) 930 char *name; 931 int *pushstat; 932 { 933 struct ypreq_nokey req; 934 struct ypresp_master resp; 935 int retval; 936 937 req.domain = source; 938 req.map = map; 939 resp.master = NULL; 940 retval = FALSE; 941 942 if ((enum clnt_stat) clnt_call(master_server.dom_client, 943 YPPROC_MASTER, (xdrproc_t)xdr_ypreq_nokey, (char *)&req, 944 (xdrproc_t)xdr_ypresp_master, (char *)&resp, 945 udp_timeout) == RPC_SUCCESS) { 946 947 if (resp.status == YP_TRUE) { 948 strcpy(name, resp.master); 949 retval = TRUE; 950 } else if (resp.status != YP_BADDB) { 951 *pushstat = ypprot_err(resp.status); 952 953 if (!logging) { 954 logprintf( 955 "(info) Can't get master name from ypserv at %s. Reason: %s.\n", 956 master, yperr_string( 957 ypprot_err(resp.status))); 958 } 959 } 960 961 CLNT_FREERES(master_server.dom_client, 962 (xdrproc_t)xdr_ypresp_master, 963 (char *)&resp); 964 } else { 965 *pushstat = YPPUSH_RPC; 966 logprintf( 967 "ypxfr(get_v2master_name) RPC call to %s failed", master); 968 clnt_perror(master_server.dom_client, ""); 969 } 970 971 return (retval); 972 } 973 974 /* 975 * This does the work of transferring the map. 976 */ 977 bool 978 move_map(pushstat) 979 int *pushstat; 980 { 981 unsigned local_version; 982 char map_name[MAXNAMLEN + 1]; 983 char tmp_name[MAXNAMLEN + 1]; 984 char bkup_name[MAXNAMLEN + 1]; 985 char an[11]; 986 unsigned n; 987 datum key; 988 datum val; 989 int hgstatus; 990 991 mkfilename(map_name); 992 993 if (!force) { 994 local_version = get_local_version(map_name); 995 if (debug) fprintf(stderr, 996 "ypxfr: Local version of map '%s' is %d\n", 997 map_name, local_version); 998 999 if (local_version >= *master_version) { 1000 logprintf( 1001 "Map %s at %s is not more recent than local.\n", 1002 map, master); 1003 *pushstat = YPPUSH_AGE; 1004 return (FALSE); 1005 } 1006 } 1007 1008 mk_tmpname(yptempname_prefix, tmp_name); 1009 1010 if (!new_mapfiles(tmp_name)) { 1011 logprintf( 1012 "Can't create temp map %s.\n", tmp_name); 1013 *pushstat = YPPUSH_FILE; 1014 return (FALSE); 1015 } 1016 1017 if ((hgstatus = ypxfrd_getdbm(tmp_name, master, source, map)) < 0) 1018 { 1019 logprintf( 1020 "(info) %s %s %s ypxfrd getdbm failed (reason = %d) -- using ypxfr\n", 1021 master, domain, map, hgstatus); 1022 1023 db = dbm_open(tmp_name, O_RDWR + O_CREAT + O_TRUNC, 0644); 1024 if (db == NULL) { 1025 logprintf( 1026 "Can't dbm init temp map %s.\n", tmp_name); 1027 del_mapfiles(tmp_name); 1028 *pushstat = YPPUSH_DBM; 1029 return (FALSE); 1030 } 1031 if (defwrite) dbm_setdefwrite(db); 1032 1033 if (!get_map(tmp_name, pushstat)) { 1034 del_mapfiles(tmp_name); 1035 return (FALSE); 1036 } 1037 1038 if (!add_private_entries(tmp_name)) { 1039 del_mapfiles(tmp_name); 1040 *pushstat = YPPUSH_DBM; 1041 return (FALSE); 1042 } 1043 1044 /* 1045 * Decide whether the map just transferred is a secure map. 1046 * If we already know the local version was secure, we do not 1047 * need to check this version. 1048 */ 1049 if (!secure_map) { 1050 key.dptr = yp_secure; 1051 key.dsize = yp_secure_sz; 1052 val = dbm_fetch(db, key); 1053 if (val.dptr != NULL) { 1054 secure_map = TRUE; 1055 } 1056 } 1057 1058 if (dbm_close_status(db) < 0) { 1059 logprintf( 1060 "Can't do dbm close operation on temp map %s.\n", 1061 tmp_name); 1062 del_mapfiles(tmp_name); 1063 *pushstat = YPPUSH_DBM; 1064 return (FALSE); 1065 } 1066 1067 if (!get_order(an, &n, pushstat)) { 1068 return (FALSE); 1069 } 1070 if (n != *master_version) { 1071 logprintf( 1072 "Version skew at %s while transferring map %s.\n", 1073 master, map); 1074 del_mapfiles(tmp_name); 1075 *pushstat = YPPUSH_SKEW; 1076 return (FALSE); 1077 } 1078 1079 if (check_count) 1080 if (!count_mismatch(tmp_name, entry_count)) { 1081 del_mapfiles(tmp_name); 1082 *pushstat = YPPUSH_DBM; 1083 return (FALSE); 1084 } 1085 } else { 1086 /* touch up the map */ 1087 db = dbm_open(tmp_name, 2, 0644); 1088 if (db == NULL) { 1089 logprintf( 1090 "Can't dbm init temp map %s.\n", tmp_name); 1091 del_mapfiles(tmp_name); 1092 *pushstat = YPPUSH_DBM; 1093 return (FALSE); 1094 } 1095 1096 1097 if (!add_private_entries(tmp_name)) { 1098 del_mapfiles(tmp_name); 1099 *pushstat = YPPUSH_DBM; 1100 return (FALSE); 1101 } 1102 1103 /* 1104 * Decide whether the map just transferred is a secure map. 1105 * If we already know the local version was secure, we do not 1106 * need to check this version. 1107 */ 1108 if (!secure_map) { 1109 key.dptr = yp_secure; 1110 key.dsize = yp_secure_sz; 1111 val = dbm_fetch(db, key); 1112 if (val.dptr != NULL) { 1113 secure_map = TRUE; 1114 } 1115 } 1116 1117 if (dbm_close_status(db) < 0) { 1118 logprintf( 1119 "Can't do dbm close operation on temp map %s.\n", 1120 tmp_name); 1121 del_mapfiles(tmp_name); 1122 *pushstat = YPPUSH_DBM; 1123 return (FALSE); 1124 } 1125 1126 } 1127 1128 if (lock_map(map_name) == 0) { 1129 del_mapfiles(tmp_name); 1130 logprintf("Lock error on %s\n", map_name); 1131 *pushstat = YPPUSH_FILE; 1132 return (FALSE); 1133 } 1134 if (!check_map_existence(map_name)) { 1135 1136 if (!rename_map(tmp_name, map_name, secure_map)) { 1137 del_mapfiles(tmp_name); 1138 logprintf( 1139 "Rename error: couldn't mv %s to %s.\n", 1140 tmp_name, map_name); 1141 *pushstat = YPPUSH_FILE; 1142 unlock_map(map_name); 1143 return (FALSE); 1144 } 1145 1146 } else { 1147 mk_tmpname(ypbkupname_prefix, bkup_name); 1148 1149 if (!rename_map(map_name, bkup_name, secure_map)) { 1150 (void) rename_map(bkup_name, map_name, secure_map); 1151 logprintf( 1152 "Rename error: check that old %s is still intact.\n", 1153 map_name); 1154 del_mapfiles(tmp_name); 1155 *pushstat = YPPUSH_FILE; 1156 unlock_map(map_name); 1157 return (FALSE); 1158 } 1159 1160 if (rename_map(tmp_name, map_name, secure_map)) { 1161 del_mapfiles(bkup_name); 1162 } else { 1163 del_mapfiles(tmp_name); 1164 (void) rename_map(bkup_name, map_name, secure_map); 1165 logprintf( 1166 "Rename error: check that old %s is still intact.\n", 1167 map_name); 1168 *pushstat = YPPUSH_FILE; 1169 unlock_map(map_name); 1170 return (FALSE); 1171 } 1172 } 1173 if (unlock_map(map_name) == 0) 1174 return (FALSE); 1175 1176 return (TRUE); 1177 } 1178 1179 /* 1180 * This tries to get the order number out of the local version of the map. 1181 * If the attempt fails for any version, the function will return "0" 1182 */ 1183 unsigned 1184 get_local_version(name) 1185 char *name; 1186 { 1187 datum key; 1188 datum val; 1189 char number[11]; 1190 DBM *db; 1191 1192 if (!check_map_existence(name)) { 1193 return (0); 1194 } 1195 if (debug) fprintf(stderr, 1196 "ypxfr: Map does exist, checking version now.\n"); 1197 1198 if ((db = dbm_open(name, 0, 0)) == 0) { 1199 return (0); 1200 } 1201 1202 key.dptr = yp_last_modified; 1203 key.dsize = yp_last_modified_sz; 1204 val = dbm_fetch(db, key); 1205 if (!val.dptr) { /* Check to see if dptr is NULL */ 1206 return (0); 1207 } 1208 if (val.dsize == 0 || val.dsize > 10) { 1209 return (0); 1210 } 1211 /* Now save this value while we have it available */ 1212 (void) memmove(number, val.dptr, val.dsize); 1213 number[val.dsize] = '\0'; 1214 1215 /* 1216 * Now check to see if it is 'secure'. If we haven't already 1217 * determined that it is secure in get_private_recs() then we check 1218 * the local map here. 1219 */ 1220 if (!secure_map) { 1221 key.dptr = yp_secure; 1222 key.dsize = yp_secure_sz; 1223 val = dbm_fetch(db, key); 1224 secure_map = (val.dptr != NULL); 1225 } 1226 1227 /* 1228 * Now check to see if interdomain requests are made of the local 1229 * map. Keep the value around if they are. 1230 */ 1231 if (!interdomain_map) { 1232 key.dptr = yp_interdomain; 1233 key.dsize = yp_interdomain_sz; 1234 val = dbm_fetch(db, key); 1235 if (interdomain_map = (val.dptr != NULL)) { 1236 interdomain_value = (char *)malloc(val.dsize+1); 1237 (void) memmove(interdomain_value, val.dptr, val.dsize); 1238 *(interdomain_value+val.dsize) = '\0'; 1239 interdomain_sz = val.dsize; 1240 } 1241 } 1242 1243 /* finish up */ 1244 (void) dbm_close_status(db); 1245 1246 return ((unsigned)atoi(number)); 1247 } 1248 1249 /* 1250 * This constructs a file name for a map, minus its dbm_dir 1251 * or dbm_pag extensions 1252 */ 1253 void 1254 mkfilename(ppath) 1255 char *ppath; 1256 { 1257 bool_t yptol_mode; 1258 int len; 1259 1260 /* Work out if we are in yptol mode */ 1261 yptol_mode = is_yptol_mode(); 1262 1263 len = strlen(domain) + strlen(map) + strlen(ypdbpath) + 3; 1264 if (yptol_mode) 1265 len += strlen(NTOL_PREFIX); 1266 1267 if (len > (MAXNAMLEN + 1)) { 1268 logprintf("Map name string too long.\n"); 1269 } 1270 1271 (void) strcpy(ppath, ypdbpath); 1272 (void) strcat(ppath, "/"); 1273 (void) strcat(ppath, domain); 1274 (void) strcat(ppath, "/"); 1275 if (yptol_mode) 1276 (void) strcat(ppath, NTOL_PREFIX); 1277 (void) strcat(ppath, map); 1278 } 1279 1280 /* 1281 * This returns a temporary name for a map transfer minus its dbm_dir or 1282 * dbm_pag extensions. 1283 */ 1284 void 1285 mk_tmpname(prefix, xfr_name) 1286 char *prefix; 1287 char *xfr_name; 1288 { 1289 char xfr_anumber[10]; 1290 long xfr_number; 1291 1292 if (!xfr_name) { 1293 return; 1294 } 1295 1296 xfr_number = getpid(); 1297 (void) sprintf(xfr_anumber, "%d", xfr_number); 1298 1299 (void) strcpy(xfr_name, ypdbpath); 1300 (void) strcat(xfr_name, "/"); 1301 (void) strcat(xfr_name, domain); 1302 (void) strcat(xfr_name, "/"); 1303 (void) strcat(xfr_name, prefix); 1304 (void) strcat(xfr_name, map); 1305 (void) strcat(xfr_name, "."); 1306 (void) strcat(xfr_name, xfr_anumber); 1307 } 1308 1309 /* 1310 * This deletes the .pag and .dir files which implement a map. 1311 * 1312 * Note: No error checking is done here for a garbage input file name or for 1313 * failed unlink operations. 1314 */ 1315 void 1316 del_mapfiles(basename) 1317 char *basename; 1318 { 1319 char dbfilename[MAXNAMLEN + 1]; 1320 1321 if (!basename) { 1322 return; 1323 } 1324 1325 strcpy(dbfilename, basename); 1326 strcat(dbfilename, dbm_pag); 1327 unlink(dbfilename); 1328 strcpy(dbfilename, basename); 1329 strcat(dbfilename, dbm_dir); 1330 unlink(dbfilename); 1331 } 1332 1333 /* 1334 * This creates <pname>.dir and <pname>.pag 1335 */ 1336 bool 1337 new_mapfiles(pname) 1338 char *pname; 1339 { 1340 char dbfile[MAXNAMLEN + 1]; 1341 int f; 1342 int len; 1343 1344 if (!pname || ((len = strlen(pname)) == 0) || 1345 (len + 5) > (MAXNAMLEN + 1)) { 1346 return (FALSE); 1347 } 1348 1349 errno = 0; 1350 (void) strcpy(dbfile, pname); 1351 (void) strcat(dbfile, dbm_dir); 1352 1353 if ((f = open(dbfile, (O_WRONLY | O_CREAT | O_TRUNC), 0600)) >= 0) { 1354 (void) close(f); 1355 (void) strcpy(dbfile, pname); 1356 (void) strcat(dbfile, dbm_pag); 1357 1358 if ((f = open(dbfile, (O_WRONLY | O_CREAT | O_TRUNC), 1359 0600)) >= 0) { 1360 (void) close(f); 1361 return (TRUE); 1362 } else { 1363 return (FALSE); 1364 } 1365 1366 } else { 1367 return (FALSE); 1368 } 1369 } 1370 1371 int 1372 count_callback(status) 1373 int status; 1374 { 1375 if (status != YP_TRUE) { 1376 1377 if (status != YP_NOMORE) { 1378 logprintf( 1379 "Error from ypserv on %s (ypall_callback) = %s.\n", 1380 master, yperr_string(ypprot_err(status))); 1381 } 1382 1383 return (TRUE); 1384 } 1385 1386 entry_count++; 1387 return (FALSE); 1388 } 1389 1390 /* 1391 * This counts the entries in the dbm file after the transfer to 1392 * make sure that the dbm file was built correctly. 1393 * Returns TRUE if everything is OK, FALSE if they mismatch. 1394 */ 1395 int 1396 count_mismatch(pname, oldcount) 1397 char *pname; 1398 int oldcount; 1399 { 1400 datum key; 1401 DBM *db; 1402 #ifdef REALLY_PARANOID 1403 struct ypall_callback cbinfo; 1404 struct ypreq_nokey allreq; 1405 enum clnt_stat s; 1406 struct dom_binding domb; 1407 datum value; 1408 #endif /* REALLY_PARANOID */ 1409 1410 entry_count = 0; 1411 db = dbm_open(pname, 0, 0); 1412 if (db) { 1413 for (key = dbm_firstkey(db); 1414 key.dptr != NULL; key = dbm_nextkey(db)) 1415 entry_count++; 1416 dbm_close_status(db); 1417 } 1418 1419 if (oldcount != entry_count) { 1420 logprintf( 1421 "*** Count mismatch in dbm file %s: old=%d, new=%d ***\n", 1422 map, oldcount, entry_count); 1423 return (FALSE); 1424 } 1425 1426 #ifdef REALLY_PARANOID 1427 1428 if ((domb.dom_client = __yp_clnt_create_rsvdport(master, YPPROG, 1429 master_prog_vers, 1430 "tcp6", 0, 0)) == 0 && 1431 (domb.dom_client = __yp_clnt_create_rsvdport(master, YPPROG, 1432 master_prog_vers, 1433 "tcp", 0, 0)) == 0) { 1434 clnt_pcreateerror("ypxfr (mismatch) - TCP channel " 1435 "create failure"); 1436 return (FALSE); 1437 } 1438 1439 if (master_prog_vers == YPVERS) { 1440 int tmpstat; 1441 1442 allreq.domain = source; 1443 allreq.map = map; 1444 cbinfo.foreach = count_callback; 1445 tmpstat = 0; 1446 cbinfo.data = (char *)&tmpstat; 1447 1448 entry_count = 0; 1449 s = clnt_call(domb.dom_client, YPPROC_ALL, xdr_ypreq_nokey, 1450 &allreq, xdr_ypall, &cbinfo, tcp_timeout); 1451 1452 if (tmpstat == 0) { 1453 if (s == RPC_SUCCESS) { 1454 } else { 1455 clnt_perror(domb.dom_client, 1456 "ypxfr (get_map/all) - RPC clnt_call (TCP) failure"); 1457 return (FALSE); 1458 } 1459 1460 } else { 1461 return (FALSE); 1462 } 1463 1464 } else { 1465 logprintf("Wrong version number!\n"); 1466 return (FALSE); 1467 } 1468 clnt_destroy(domb.dom_client); 1469 close(domb.dom_socket); 1470 entry_count += 2; /* add in YP_entries */ 1471 if (oldcount != entry_count) { 1472 logprintf( 1473 "*** Count mismatch after enumerate %s: old=%d, new=%d ***\n", 1474 map, oldcount, entry_count); 1475 return (FALSE); 1476 } 1477 #endif /* REALLY_PARANOID */ 1478 1479 return (TRUE); 1480 } 1481 1482 /* 1483 * This sets up a TCP connection to the master server, and either gets 1484 * ypall_callback to do all the work of writing it to the local dbm file 1485 * (if the ypserv is current version), or does it itself for an old ypserv. 1486 */ 1487 bool 1488 get_map(pname, pushstat) 1489 char *pname; 1490 int *pushstat; 1491 { 1492 struct dom_binding domb; 1493 enum clnt_stat s; 1494 struct ypreq_nokey allreq; 1495 struct ypall_callback cbinfo; 1496 bool retval = FALSE; 1497 int tmpstat; 1498 int recvsiz = 24 * 1024; 1499 struct netconfig *nconf; 1500 int fd; 1501 struct netbuf *svcaddr; 1502 char *netid[] = { "tcp6", "tcp" }; 1503 int i, lastnetid = (sizeof (netid)/sizeof (netid[0])) - 1; 1504 1505 svcaddr = (struct netbuf *)calloc(1, sizeof (struct netbuf)); 1506 if (! svcaddr) 1507 return (FALSE); 1508 svcaddr->maxlen = 32; 1509 svcaddr->len = 32; 1510 svcaddr->buf = (char *)malloc(32); 1511 if (! svcaddr->buf) { 1512 free(svcaddr); 1513 return (FALSE); 1514 } 1515 1516 for (i = 0; i <= lastnetid; i++) { 1517 fd = RPC_ANYFD; 1518 if ((nconf = getnetconfigent(netid[i])) == NULL) { 1519 if (i != lastnetid) 1520 continue; 1521 logprintf("ypxfr: tcp transport not supported\n"); 1522 free(svcaddr->buf); 1523 free(svcaddr); 1524 return (FALSE); 1525 } 1526 if (rpcb_getaddr(YPPROG, master_prog_vers, nconf, svcaddr, 1527 master) == FALSE) { 1528 freenetconfigent(nconf); 1529 if (i != lastnetid) 1530 continue; 1531 logprintf("ypxfr: could not get %s address\n", master); 1532 free(svcaddr->buf); 1533 free(svcaddr); 1534 return (FALSE); 1535 } 1536 if ((domb.dom_client = __nis_clnt_create(fd, nconf, 0, svcaddr, 1537 0, YPPROG, master_prog_vers, recvsiz, 0)) == 0) { 1538 freenetconfigent(nconf); 1539 if (i != lastnetid) 1540 continue; 1541 clnt_pcreateerror( 1542 "ypxfr (get_map) - TCP channel create failure"); 1543 *pushstat = YPPUSH_RPC; 1544 free(svcaddr->buf); 1545 free(svcaddr); 1546 return (FALSE); 1547 } 1548 break; 1549 } 1550 1551 entry_count = 0; 1552 if (master_prog_vers == YPVERS) { 1553 allreq.domain = source; 1554 allreq.map = map; 1555 cbinfo.foreach = ypall_callback; 1556 tmpstat = 0; 1557 cbinfo.data = (char *)&tmpstat; 1558 1559 s = clnt_call(domb.dom_client, YPPROC_ALL, 1560 (xdrproc_t)xdr_ypreq_nokey, 1561 (char *)&allreq, (xdrproc_t)xdr_ypall, (char *)&cbinfo, 1562 tcp_timeout); 1563 1564 if (tmpstat == 0) { 1565 1566 if (s == RPC_SUCCESS) { 1567 retval = TRUE; 1568 } else { 1569 clnt_perror(domb.dom_client, 1570 "ypxfr (get_map/all) - RPC clnt_call (TCP) failure"); 1571 *pushstat = YPPUSH_RPC; 1572 } 1573 1574 } else { 1575 *pushstat = tmpstat; 1576 } 1577 1578 } else 1579 retval = FALSE; /* barf again at YPOLDVERS */ 1580 cleanup: 1581 clnt_destroy(domb.dom_client); 1582 return (retval); 1583 } 1584 1585 /* 1586 * This sticks each key-value pair into the current map. It returns FALSE as 1587 * long as it wants to keep getting called back, and TRUE on error conditions 1588 * and "No more k-v pairs". 1589 */ 1590 int 1591 ypall_callback(status, key, kl, val, vl, pushstat) 1592 int status; 1593 char *key; 1594 int kl; 1595 char *val; 1596 int vl; 1597 int *pushstat; 1598 { 1599 datum keydat; 1600 datum valdat; 1601 datum test; 1602 1603 if (status != YP_TRUE) { 1604 1605 if (status != YP_NOMORE) { 1606 logprintf( 1607 "Error from ypserv on %s (ypall_callback) = %s.\n", 1608 master, yperr_string(ypprot_err(status))); 1609 *pushstat = map_yperr_to_pusherr(status); 1610 } 1611 1612 return (TRUE); 1613 } 1614 1615 keydat.dptr = key; 1616 keydat.dsize = kl; 1617 valdat.dptr = val; 1618 valdat.dsize = vl; 1619 entry_count++; 1620 /* way too many fetches */ 1621 1622 #ifdef PARANOID 1623 test = dbm_fetch(db, keydat); 1624 if (test.dptr != NULL) { 1625 logprintf("Duplicate key %s in map %s\n", key, map); 1626 *pushstat = YPPUSH_DBM; 1627 return (TRUE); 1628 } 1629 #endif /* PARANOID */ 1630 if (dbm_store(db, keydat, valdat, 0) < 0) { 1631 logprintf( 1632 "Can't do dbm store into temp map %s.\n", map); 1633 *pushstat = YPPUSH_DBM; 1634 return (TRUE); 1635 } 1636 #ifdef PARANOID 1637 test = dbm_fetch(db, keydat); 1638 if (test.dptr == NULL) { 1639 logprintf("Key %s was not inserted into dbm file %s\n", 1640 key, map); 1641 *pushstat = YPPUSH_DBM; 1642 return (TRUE); 1643 } 1644 #endif /* PARANOID */ 1645 1646 if (dbm_error(db)) { 1647 logprintf("Key %s dbm_error raised in file %s\n", 1648 key, map); 1649 *pushstat = YPPUSH_DBM; 1650 return (TRUE); 1651 } 1652 return (FALSE); 1653 } 1654 1655 /* 1656 * This maps a YP_xxxx error code into a YPPUSH_xxxx error code 1657 */ 1658 int 1659 map_yperr_to_pusherr(yperr) 1660 int yperr; 1661 { 1662 int reason; 1663 1664 switch (yperr) { 1665 1666 case YP_NOMORE: 1667 reason = YPPUSH_SUCC; 1668 break; 1669 1670 case YP_NOMAP: 1671 reason = YPPUSH_NOMAP; 1672 break; 1673 1674 case YP_NODOM: 1675 reason = YPPUSH_NODOM; 1676 break; 1677 1678 case YP_NOKEY: 1679 reason = YPPUSH_YPERR; 1680 break; 1681 1682 case YP_BADARGS: 1683 reason = YPPUSH_BADARGS; 1684 break; 1685 1686 case YP_BADDB: 1687 reason = YPPUSH_YPERR; 1688 break; 1689 1690 default: 1691 reason = YPPUSH_XFRERR; 1692 break; 1693 } 1694 1695 return (reason); 1696 } 1697 1698 /* 1699 * This writes the last-modified and master entries into the new dbm file 1700 */ 1701 bool 1702 add_private_entries(pname) 1703 char *pname; 1704 { 1705 datum key; 1706 datum val; 1707 1708 if (!fake_master_version) { 1709 key.dptr = yp_last_modified; 1710 key.dsize = yp_last_modified_sz; 1711 val.dptr = master_ascii_version; 1712 val.dsize = strlen(master_ascii_version); 1713 1714 if (dbm_store(db, key, val, 1) < 0) { 1715 logprintf( 1716 "Can't do dbm store into temp map %s.\n", 1717 pname); 1718 return (FALSE); 1719 } 1720 entry_count++; 1721 } 1722 1723 if (master_name) { 1724 key.dptr = yp_master_name; 1725 key.dsize = yp_master_name_sz; 1726 val.dptr = master_name; 1727 val.dsize = strlen(master_name); 1728 if (dbm_store(db, key, val, 1) < 0) { 1729 logprintf( 1730 "Can't do dbm store into temp map %s.\n", 1731 pname); 1732 return (FALSE); 1733 } 1734 entry_count++; 1735 } 1736 1737 if (interdomain_map) { 1738 key.dptr = yp_interdomain; 1739 key.dsize = yp_interdomain_sz; 1740 val.dptr = interdomain_value; 1741 val.dsize = interdomain_sz; 1742 if (dbm_store(db, key, val, 1) < 0) { 1743 logprintf( 1744 "Can't do dbm store into temp map %s.\n", 1745 pname); 1746 return (FALSE); 1747 } 1748 entry_count++; 1749 } 1750 1751 if (secure_map) { 1752 key.dptr = yp_secure; 1753 key.dsize = yp_secure_sz; 1754 val.dptr = yp_secure; 1755 val.dsize = yp_secure_sz; 1756 if (dbm_store(db, key, val, 1) < 0) { 1757 logprintf( 1758 "Can't do dbm store into temp map %s.\n", 1759 pname); 1760 return (FALSE); 1761 } 1762 entry_count++; 1763 } 1764 1765 return (TRUE); 1766 } 1767 1768 1769 /* 1770 * This sends a YPPROC_CLEAR message to the local ypserv process. 1771 */ 1772 bool 1773 send_ypclear(pushstat) 1774 int *pushstat; 1775 { 1776 struct dom_binding domb; 1777 char local_host_name[256]; 1778 unsigned int progvers; 1779 int status; 1780 1781 if (gethostname(local_host_name, 256)) { 1782 logprintf("Can't get local machine name.\n"); 1783 *pushstat = YPPUSH_RSRC; 1784 return (FALSE); 1785 } 1786 1787 if (!bind_to_server(local_host_name, &domb, 1788 &progvers, &status)) { 1789 *pushstat = YPPUSH_CLEAR; 1790 return (FALSE); 1791 } 1792 1793 if ((enum clnt_stat) clnt_call(domb.dom_client, 1794 YPPROC_CLEAR, xdr_void, 0, xdr_void, 0, 1795 udp_timeout) != RPC_SUCCESS) { 1796 logprintf( 1797 "Can't send ypclear message to ypserv on the local machine.\n"); 1798 xfr_exit(YPPUSH_CLEAR); 1799 } 1800 1801 return (TRUE); 1802 } 1803 1804 /* 1805 * This decides if send_callback has to get called, and does the process exit. 1806 */ 1807 void 1808 xfr_exit(status) 1809 int status; 1810 { 1811 if (callback) { 1812 send_callback(&status); 1813 } 1814 1815 if (status == YPPUSH_SUCC) { 1816 #ifdef TREEPUSH 1817 if (treepush) { 1818 if (debug) 1819 execlp("./yppush", "yppush", "-T", map, 0); 1820 execlp("/usr/etc/yp/yppush", "yppush", "-T", map, 0); 1821 perror("yppush"); 1822 } 1823 #endif 1824 exit(0); 1825 } else { 1826 exit(1); 1827 } 1828 } 1829 1830 /* 1831 * This sets up a UDP connection to the yppush process which contacted our 1832 * parent ypserv, and sends it a status on the requested transfer. 1833 */ 1834 void 1835 send_callback(status) 1836 int *status; 1837 { 1838 struct yppushresp_xfr resp; 1839 struct dom_binding domb; 1840 1841 resp.transid = (unsigned long) atoi(tid); 1842 resp.status = (unsigned long) *status; 1843 1844 udp_timeout.tv_sec = CALLTIMEOUT; 1845 1846 if ((domb.dom_client = __yp_clnt_create_rsvdport(pushhost, 1847 (ulong_t)atoi(proto), 1848 YPPUSHVERS, 1849 0, 0, 0)) == NULL) { 1850 *status = YPPUSH_RPC; 1851 return; 1852 } 1853 1854 if ((enum clnt_stat) clnt_call(domb.dom_client, 1855 YPPUSHPROC_XFRRESP, (xdrproc_t)xdr_yppushresp_xfr, 1856 (char *)&resp, xdr_void, 0, 1857 udp_timeout) != RPC_SUCCESS) { 1858 *status = YPPUSH_RPC; 1859 return; 1860 } 1861 } 1862 1863 /* 1864 * FUNCTION: is_yptol_mode(); 1865 * 1866 * DESCRIPTION: Determines if we should run in N2L or traditional mode based 1867 * on the presence of the N2L mapping file. 1868 * 1869 * This is a copy of a function from libnisdb. If more than this 1870 * one function become required it may be worth linking the 1871 * entire lib. 1872 * 1873 * INPUTS: Nothing 1874 * 1875 * OUTPUTS: TRUE = Run in N2L mode 1876 * FALSE = Run in traditional mode. 1877 */ 1878 bool_t 1879 is_yptol_mode() 1880 { 1881 struct stat filestat; 1882 1883 if (stat(NTOL_MAP_FILE, &filestat) != -1) 1884 return (TRUE); 1885 1886 return (FALSE); 1887 } 1888