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