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