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