1/* 2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights 7 * Reserved. This file contains Original Code and/or Modifications of 8 * Original Code as defined in and that are subject to the Apple Public 9 * Source License Version 1.0 (the 'License'). You may not use this file 10 * except in compliance with the License. Please obtain a copy of the 11 * License at http://www.apple.com/publicsource and read it before using 12 * this file. 13 * 14 * The Original Code and all software distributed under the License are 15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 19 * License for the specific language governing rights and limitations 20 * under the License." 21 * 22 * @APPLE_LICENSE_HEADER_END@ 23 */ 24/* $OpenBSD: ypxfr.c,v 1.22 1997/07/30 12:07:02 maja Exp $ */ 25 26/* 27 * Copyright (c) 1994 Mats O Jansson <moj@stacken.kth.se> 28 * All rights reserved. 29 * 30 * Redistribution and use in source and binary forms, with or without 31 * modification, are permitted provided that the following conditions 32 * are met: 33 * 1. Redistributions of source code must retain the above copyright 34 * notice, this list of conditions and the following disclaimer. 35 * 2. Redistributions in binary form must reproduce the above copyright 36 * notice, this list of conditions and the following disclaimer in the 37 * documentation and/or other materials provided with the distribution. 38 * 3. All advertising materials mentioning features or use of this software 39 * must display the following acknowledgement: 40 * This product includes software developed by Mats O Jansson 41 * 4. The name of the author may not be used to endorse or promote products 42 * derived from this software without specific prior written permission. 43 * 44 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 45 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 46 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 47 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 48 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 54 * SUCH DAMAGE. 55 */ 56 57#include <sys/cdefs.h> 58#ifndef LINT 59__unused static char rcsid[] = "$OpenBSD: ypxfr.c,v 1.22 1997/07/30 12:07:02 maja Exp $"; 60#endif 61 62#include <sys/types.h> 63#include <sys/stat.h> 64#include <sys/socket.h> 65#include <sys/param.h> 66#include <netinet/in.h> 67#include <arpa/inet.h> 68 69#include <stdio.h> 70#include <stdlib.h> 71#include <unistd.h> 72#include <fcntl.h> 73#include <string.h> 74#include <netdb.h> 75 76#include <rpc/rpc.h> 77#include <rpc/xdr.h> 78#include <rpcsvc/yp.h> 79#include <rpcsvc/ypclnt.h> 80 81#include "yplib_host.h" 82#include "yplog.h" 83#include "ypdb.h" 84#include "ypdef.h" 85 86extern char *__progname; /* from crt0.o */ 87DBM *db; 88 89extern bool_t xdr_ypresp_all_seq(); 90extern int getrpcport(char *, int, int, int); 91 92extern int (*ypresp_allfn)(); 93extern void *ypresp_data; 94 95static int 96ypxfr_foreach(status,keystr,keylen,valstr,vallen,data) 97int status,keylen,vallen; 98char *keystr,*valstr,*data; 99{ 100 datum key,val; 101 102 if (status == YP_NOMORE) 103 return(0); 104 105 keystr[keylen] = '\0'; 106 valstr[vallen] = '\0'; 107 108 key.dptr = keystr; 109 key.dsize = strlen(keystr); 110 111 val.dptr = valstr; 112 val.dsize = strlen(valstr); 113 114 ypdb_store(db, key, val, YPDB_INSERT); 115 116 return 0; 117} 118 119int 120get_local_ordernum(domain, map, lordernum) 121char *domain; 122char *map; 123u_int32_t *lordernum; 124{ 125 char map_path[MAXPATHLEN]; 126 char order_key[] = YP_LAST_KEY; 127 char order[MAX_LAST_LEN+1]; 128 struct stat finfo; 129 DBM *db; 130 datum k,v; 131 int status; 132 133 /* This routine returns YPPUSH_SUCC or YPPUSH_NODOM */ 134 135 status = YPPUSH_SUCC; 136 137 snprintf(map_path, sizeof map_path, "%s/%s", YP_DB_PATH, domain); 138 if (!((stat(map_path, &finfo) == 0) && 139 ((finfo.st_mode & S_IFMT) == S_IFDIR))) { 140 fprintf(stderr, "%s: domain %s not found locally\n", 141 __progname, domain); 142 status = YPPUSH_NODOM; 143 } 144 145 if(status > 0) { 146 snprintf(map_path, sizeof map_path, "%s/%s/%s%s", 147 YP_DB_PATH, domain, map, YPDB_SUFFIX); 148 if(!(stat(map_path, &finfo) == 0)) { 149 status = YPPUSH_NOMAP; 150 } 151 } 152 153 if(status > 0) { 154 snprintf(map_path, sizeof map_path, "%s/%s/%s", 155 YP_DB_PATH, domain, map); 156 db = ypdb_open(map_path, O_RDONLY, 0444); 157 if(db == NULL) { 158 status = YPPUSH_DBM; 159 } 160 161 } 162 163 if(status > 0) { 164 k.dptr = (char *)&order_key; 165 k.dsize = YP_LAST_LEN; 166 167 v = ypdb_fetch(db,k); 168 ypdb_close(db); 169 170 if (v.dptr == NULL) { 171 *lordernum = 0; 172 } else { 173 strncpy(order, v.dptr, sizeof order-1); 174 order[sizeof order-1] = '\0'; 175 *lordernum = (u_int32_t)atol(order); 176 } 177 } 178 179 if((status == YPPUSH_NOMAP) || (status == YPPUSH_DBM)) { 180 *lordernum = 0; 181 status = YPPUSH_SUCC; 182 } 183 184 return(status); 185 186} 187 188int 189get_remote_ordernum(client, domain, map, lordernum, rordernum) 190CLIENT *client; 191char *domain; 192char *map; 193u_int32_t lordernum; 194u_int32_t *rordernum; 195{ 196 int status; 197 198 status = yp_order_host(client, domain, map, rordernum); 199 200 if (status == 0) { 201 if(*rordernum <= lordernum) { 202 status = YPPUSH_AGE; 203 } else { 204 status = YPPUSH_SUCC; 205 } 206 } 207 208 return status; 209} 210 211void 212get_map(client,domain,map,incallback) 213CLIENT *client; 214char *domain; 215char *map; 216struct ypall_callback *incallback; 217{ 218 (void)yp_all_host(client, domain, map, incallback); 219 220} 221 222DBM * 223create_db(domain,map,temp_map) 224char *domain; 225char *map; 226char *temp_map; 227{ 228 return ypdb_open_suf(temp_map, O_RDWR, 0444); 229} 230 231int 232install_db(domain,map,temp_map) 233char *domain; 234char *map; 235char *temp_map; 236{ 237 char db_name[MAXPATHLEN]; 238 239 snprintf(db_name, sizeof db_name, "%s/%s/%s%s", 240 YP_DB_PATH, domain, map, YPDB_SUFFIX); 241 rename(temp_map, db_name); 242 243 return YPPUSH_SUCC; 244} 245 246int 247add_order(db, ordernum) 248DBM *db; 249u_int32_t ordernum; 250{ 251 char datestr[11]; 252 datum key,val; 253 char keystr[] = YP_LAST_KEY; 254 int status; 255 256 sprintf(datestr, "%010u", ordernum); 257 258 key.dptr = keystr; 259 key.dsize = strlen(keystr); 260 261 val.dptr = datestr; 262 val.dsize = strlen(datestr); 263 264 status = ypdb_store(db, key, val, YPDB_INSERT); 265 if(status >= 0) { 266 status = YPPUSH_SUCC; 267 } else { 268 status = YPPUSH_DBM; 269 } 270 return(status); 271} 272 273int 274add_master(client, domain, map, db) 275CLIENT *client; 276char *domain; 277char *map; 278DBM *db; 279{ 280 char keystr[] = YP_MASTER_KEY; 281 char *master; 282 int status; 283 datum key,val; 284 285 master = NULL; 286 287 /* Get MASTER */ 288 289 status = yp_master_host(client, domain, map, &master); 290 291 if(master != NULL) { 292 key.dptr = keystr; 293 key.dsize = strlen(keystr); 294 295 val.dptr = master; 296 val.dsize = strlen(master); 297 298 status = ypdb_store(db, key, val, YPDB_INSERT); 299 if(status >= 0) { 300 status = YPPUSH_SUCC; 301 } else { 302 status = YPPUSH_DBM; 303 } 304 } 305 306 return status; 307} 308 309int 310add_interdomain(client, domain, map, db) 311CLIENT *client; 312char *domain; 313char *map; 314DBM *db; 315{ 316 char keystr[] = YP_INTERDOMAIN_KEY; 317 char *value; 318 int vallen; 319 int status; 320 datum k,v; 321 322 /* Get INTERDOMAIN */ 323 324 k.dptr = keystr; 325 k.dsize = strlen(keystr); 326 327 status = yp_match_host(client, domain, map, 328 k.dptr, k.dsize, &value, &vallen); 329 330 if(status == 0 && value) { 331 v.dptr = value; 332 v.dsize = vallen; 333 334 if(v.dptr != NULL) { 335 status = ypdb_store(db,k,v,YPDB_INSERT); 336 if(status >= 0) { 337 status = YPPUSH_SUCC; 338 } else { 339 status = YPPUSH_DBM; 340 } 341 } 342 } 343 344 return 1; 345} 346 347int 348add_secure(client, domain, map, db) 349CLIENT *client; 350char *domain; 351char *map; 352DBM *db; 353{ 354 char keystr[] = YP_SECURE_KEY; 355 char *value; 356 int vallen; 357 int status; 358 datum k,v; 359 360 /* Get SECURE */ 361 362 k.dptr = keystr; 363 k.dsize = strlen(keystr); 364 365 status = yp_match_host(client, domain, map, 366 k.dptr, k.dsize, &value, &vallen); 367 368 if(status > 0) { 369 v.dptr = value; 370 v.dsize = vallen; 371 372 if(v.dptr != NULL) { 373 status = ypdb_store(db,k,v,YPDB_INSERT); 374 if(status >= 0) { 375 status = YPPUSH_SUCC; 376 } else { 377 status = YPPUSH_DBM; 378 } 379 } 380 } 381 382 return status; 383 384} 385 386int 387send_clear(client) 388CLIENT *client; 389{ 390 struct timeval tv; 391 int r; 392 int status; 393 394 status = YPPUSH_SUCC; 395 396 tv.tv_sec = 10; 397 tv.tv_usec = 0; 398 399 /* Send CLEAR */ 400 401 r = clnt_call(client, YPPROC_CLEAR, 402 (xdrproc_t)xdr_void, 0, (xdrproc_t)xdr_void, 0, tv); 403 if(r != RPC_SUCCESS) { 404 clnt_perror(client, "yp_clear: clnt_call"); 405 } 406 407 return status; 408 409} 410 411int 412send_reply(client,status,tid) 413CLIENT *client; 414u_long status; 415u_long tid; 416{ 417 struct timeval tv; 418 struct ypresp_xfr resp; 419 int r; 420 421 tv.tv_sec = 10; 422 tv.tv_usec = 0; 423 424 resp.transid = tid; 425 resp.xfrstat = status; 426 427 /* Send CLEAR */ 428 429 r = clnt_call(client, 1, 430 (xdrproc_t)xdr_ypresp_xfr, &resp, (xdrproc_t)xdr_void, 0, tv); 431 if(r != RPC_SUCCESS) { 432 clnt_perror(client, "yppushresp_xdr: clnt_call"); 433 } 434 435 return status; 436 437} 438 439int 440main (argc,argv) 441int argc; 442char *argv[]; 443{ 444 int usage = 0; 445 int cflag = 0; 446 int fflag = 0; 447 int Cflag = 0; 448 int ch; 449 extern char *optarg; 450 char *domain; 451 char *host = NULL; 452 char *srcdomain = NULL; 453 char *tid = NULL; 454 char *prog = NULL; 455 char *ipadd = NULL; 456 char *port = NULL; 457 char *map = NULL; 458 u_int32_t ordernum, new_ordernum; 459 struct ypall_callback callback; 460 CLIENT *client; 461 int status,xfr_status; 462 int srvport; 463 464 status = YPPUSH_SUCC; 465 client = NULL; 466 467 yp_get_default_domain(&domain); 468 469 while ((ch = getopt(argc, argv, "cd:fh:s:C:")) != -1) 470 switch (ch) { 471 case 'c': 472 cflag++; 473 break; 474 case 'd': 475 if (strchr(optarg, '/')) /* Ha ha, we are not listening */ 476 break; 477 domain = optarg; 478 break; 479 case 'f': 480 fflag++; 481 break; 482 case 'h': 483 host = optarg; 484 break; 485 case 's': 486 if (strchr(optarg, '/')) /* Ha ha, we are not listening */ 487 break; 488 srcdomain = optarg; 489 break; 490 case 'C': 491 if (optind + 3 >= argc) { 492 usage++; 493 optind = argc; 494 break; 495 } 496 Cflag++; 497 tid = optarg; 498 prog = argv[optind++]; 499 ipadd = argv[optind++]; 500 port = argv[optind++]; 501 break; 502 default: 503 usage++; 504 break; 505 } 506 507 if(optind + 1 != argc) { 508 usage++; 509 } else { 510 map = argv[optind]; 511 } 512 513 if (usage) { 514 status = YPPUSH_BADARGS; 515 fprintf(stderr, "usage: %s %s %s\n", 516 "[-cf] [-d domain] [-h host] [-s domain]", 517 "[-C tid prog ipadd port] mapname\n", 518 __progname); 519 } 520 521 if (status > 0) { 522 ypopenlog(); 523 524 yplog("ypxfr: Arguments:"); 525 yplog("YP clear to local: %s", (cflag) ? "no" : "yes"); 526 yplog(" Force transfer: %s", (fflag) ? "yes" : "no"); 527 yplog(" domain: %s", domain); 528 yplog(" host: %s", host); 529 yplog(" source domain: %s", srcdomain); 530 yplog(" transid: %s", tid); 531 yplog(" prog: %s", prog); 532 yplog(" port: %s", port); 533 yplog(" ipadd: %s", ipadd); 534 yplog(" map: %s", map); 535 536 if(fflag != 0) { 537 ordernum = 0; 538 } else { 539 status = get_local_ordernum(domain, map, &ordernum); 540 } 541 } 542 543 if (status > 0) { 544 545 yplog("Get Master"); 546 547 if (host == NULL) { 548 if (srcdomain == NULL) { 549 status = yp_master(domain,map,&host); 550 } else { 551 status = yp_master(srcdomain,map,&host); 552 } 553 if(status == 0) { 554 status = YPPUSH_SUCC; 555 } else { 556 status = -status; 557 } 558 } 559 }; 560 561 /* XXX this is raceable if portmap has holes! */ 562 if (status > 0) { 563 564 yplog("Check for reserved port on host: %s", host); 565 566 srvport = getrpcport(host,YPPROG,YPVERS,IPPROTO_TCP); 567 if (srvport >= IPPORT_RESERVED) 568 status = YPPUSH_REFUSED; 569 570 } 571 572 if (status > 0) { 573 574 yplog("Connect host: %s", host); 575 576 client = yp_bind_host(host,YPPROG,YPVERS,0,1); 577 578 status = get_remote_ordernum(client, domain, map, 579 ordernum, &new_ordernum); 580 581 } 582 583 if (status == YPPUSH_SUCC) { 584 char tmpmapname[MAXPATHLEN]; 585 int fd; 586 587 /* Create temporary db */ 588 snprintf(tmpmapname, sizeof tmpmapname, 589 "%s/%s/ypdbXXXXXXXXXX", YP_DB_PATH, domain); 590 fd = mkstemp(tmpmapname); 591 if (fd == -1) 592 status = YPPUSH_DBM; 593 else 594 close(fd); 595 596 if (status > 0) { 597 db = create_db(domain,map,tmpmapname); 598 if(db == NULL) 599 status = YPPUSH_DBM; 600 } 601 602 /* Add ORDER */ 603 if(status > 0) { 604 status = add_order(db, new_ordernum); 605 } 606 607 /* Add MASTER */ 608 if(status > 0) { 609 status = add_master(client,domain,map,db); 610 } 611 612 /* Add INTERDOMAIN */ 613 if(status > 0) { 614 status = add_interdomain(client,domain,map,db); 615 } 616 617 /* Add SECURE */ 618 if(status > 0) { 619 status = add_secure(client,domain,map,db); 620 } 621 622 if(status > 0) { 623 callback.foreach=ypxfr_foreach; 624 get_map(client,domain,map,&callback); 625 } 626 627 /* Close db */ 628 if(db != NULL) { 629 ypdb_close(db); 630 } 631 632 /* Rename db */ 633 if(status > 0) { 634 status = install_db(domain,map,tmpmapname); 635 } else { 636 unlink(tmpmapname); 637 status = YPPUSH_SUCC; 638 } 639 640 } 641 642 xfr_status = status; 643 644 if(client != NULL) { 645 clnt_destroy(client); 646 } 647 648 /* YP_CLEAR */ 649 650 if(!cflag) { 651 client = yp_bind_local(YPPROG,YPVERS); 652 status = send_clear(client); 653 clnt_destroy(client); 654 } 655 656 if(Cflag > 0) { 657 /* Send Response */ 658 client = yp_bind_host(ipadd, 659 atoi(prog), 660 1, 661 atoi(port), 662 0); 663 status = send_reply(client,xfr_status,atoi(tid)); 664 clnt_destroy(client); 665 } 666 667 return(0); 668 669} 670 671