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