1 /* $NetBSD: ypxfr.c,v 1.12 2002/07/06 00:53:54 wiz 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.12 2002/07/06 00:53:54 wiz 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(int, char *, int, char *, int, char *); 67 68 int main(int, char *[]); 69 int get_local_ordernum(char *, char *, u_int *); 70 int get_remote_ordernum(CLIENT *, char *, char *, u_int, u_int *); 71 void get_map(CLIENT *, char *, char *, struct ypall_callback *); 72 DBM *create_db(char *, char *, char *); 73 int install_db(char *, char *, char *); 74 int unlink_db(char *, char *, char *); 75 int add_order(DBM *, u_int); 76 int add_master(CLIENT *, char *, char *, DBM *); 77 int add_interdomain(CLIENT *, char *, char *, DBM *); 78 int add_secure(CLIENT *, char *, char *, DBM *); 79 int send_clear(CLIENT *); 80 int send_reply(CLIENT *, int, int); 81 82 int 83 main(int argc, char **argv) 84 { 85 int need_usage = 0, cflag = 0, fflag = 0, Cflag = 0; 86 int ch; 87 char *domain; 88 char *host = NULL; 89 char *srcdomain = NULL; 90 char *tid = NULL; 91 char *prog = NULL; 92 char *ipadd = NULL; 93 char *port = NULL; 94 char *map = NULL; 95 u_int ordernum, new_ordernum; 96 struct ypall_callback callback; 97 CLIENT *client; 98 char mapname[] = "ypdbXXXXXX"; 99 int status, xfr_status; 100 101 status = YPPUSH_SUCC; 102 client = NULL; 103 104 if (yp_get_default_domain(&domain)) 105 errx(1, "can't get YP domain name"); 106 107 while ((ch = getopt(argc, argv, "cd:fh:s:C:")) != -1) { 108 switch (ch) { 109 case 'c': 110 cflag = 1; 111 break; 112 113 case 'd': 114 domain = optarg; 115 break; 116 117 case 'f': 118 fflag = 1; 119 break; 120 121 case 'h': 122 host = optarg; 123 break; 124 125 case 's': 126 srcdomain = optarg; 127 break; 128 129 case 'C': 130 if (optind + 3 >= argc) { 131 need_usage = 1; 132 optind = argc; 133 break; 134 } 135 Cflag = 1; 136 tid = optarg; 137 prog = argv[optind++]; 138 ipadd = argv[optind++]; 139 port = argv[optind++]; 140 break; 141 142 default: 143 need_usage = 1; 144 } 145 } 146 argc -= optind; argv += optind; 147 148 if (argc != 1) 149 need_usage = 1; 150 151 map = argv[0]; 152 153 if (need_usage) { 154 status = YPPUSH_BADARGS; 155 fprintf(stderr, "usage: %s [-cf] [-d domain] [-h host] %s\n", 156 getprogname(), 157 "[-s domain] [-C tid prog ipadd port] mapname"); 158 goto punt; 159 } 160 161 #ifdef DEBUG 162 openlog("ypxfr", LOG_PID, LOG_DAEMON); 163 164 syslog(LOG_DEBUG, "ypxfr: Arguments:"); 165 syslog(LOG_DEBUG, "YP clear to local: %s", (cflag) ? "no" : "yes"); 166 syslog(LOG_DEBUG, " Force transfer: %s", (fflag) ? "yes" : "no"); 167 syslog(LOG_DEBUG, " domain: %s", domain); 168 syslog(LOG_DEBUG, " host: %s", host); 169 syslog(LOG_DEBUG, " source domain: %s", srcdomain); 170 syslog(LOG_DEBUG, " transid: %s", tid); 171 syslog(LOG_DEBUG, " prog: %s", prog); 172 syslog(LOG_DEBUG, " port: %s", port); 173 syslog(LOG_DEBUG, " ipadd: %s", ipadd); 174 syslog(LOG_DEBUG, " map: %s", map); 175 #endif 176 177 if (fflag != 0) 178 ordernum = 0; 179 else { 180 status = get_local_ordernum(domain, map, &ordernum); 181 if (status < 0) 182 goto punt; 183 } 184 185 #ifdef DEBUG 186 syslog(LOG_DEBUG, "Get Master"); 187 #endif 188 189 if (host == NULL) { 190 if (srcdomain == NULL) 191 status = yp_master(domain, map, &host); 192 else 193 status = yp_master(srcdomain, map, &host); 194 195 if (status == 0) 196 status = YPPUSH_SUCC; 197 else { 198 status = -status; 199 goto punt; 200 } 201 } 202 203 #ifdef DEBUG 204 syslog(LOG_DEBUG, "Connect host: %s", host); 205 #endif 206 207 client = yp_bind_host(host, YPPROG, YPVERS, 0, 1); 208 209 status = get_remote_ordernum(client, domain, map, ordernum, 210 &new_ordernum); 211 212 213 if (status == YPPUSH_SUCC) { 214 /* Create temporary db */ 215 mktemp(mapname); 216 db = create_db(domain, map, mapname); 217 if (db == NULL) 218 status = YPPUSH_DBM; 219 220 /* Add ORDER */ 221 if (status > 0) 222 status = add_order(db, new_ordernum); 223 224 /* Add MASTER */ 225 if (status > 0) 226 status = add_master(client, domain, map, db); 227 228 /* Add INTERDOMAIN */ 229 if (status > 0) 230 status = add_interdomain(client, domain, map, db); 231 232 /* Add SECURE */ 233 if (status > 0) 234 status = add_secure(client, domain, map, db); 235 236 if (status > 0) { 237 callback.foreach = ypxfr_foreach; 238 get_map(client, domain, map, &callback); 239 } 240 241 /* Close db */ 242 if (db != NULL) 243 ypdb_close(db); 244 245 /* Rename db */ 246 if (status > 0) 247 status = install_db(domain, map, mapname); 248 else 249 status = unlink_db(domain, map, mapname); 250 } 251 252 punt: 253 xfr_status = status; 254 255 if (client != NULL) 256 clnt_destroy(client); 257 258 /* YP_CLEAR */ 259 if (!cflag) { 260 client = yp_bind_local(YPPROG, YPVERS); 261 status = send_clear(client); 262 clnt_destroy(client); 263 } 264 265 if (Cflag > 0) { 266 /* Send Response */ 267 client = yp_bind_host(ipadd, atoi(prog), 1, atoi(port), 0); 268 status = send_reply(client, xfr_status, atoi(tid)); 269 clnt_destroy(client); 270 } 271 272 exit (0); 273 } 274 275 static int 276 ypxfr_foreach(int status, char *keystr, int keylen, char *valstr, 277 int vallen, char *data) 278 { 279 datum key, val; 280 281 if (status == YP_NOMORE) 282 return (0); 283 284 keystr[keylen] = '\0'; 285 valstr[vallen] = '\0'; 286 287 key.dptr = keystr; 288 key.dsize = strlen(keystr); 289 290 val.dptr = valstr; 291 val.dsize = strlen(valstr); 292 293 ypdb_store(db, key, val, YPDB_INSERT); 294 295 return (0); 296 } 297 298 int 299 get_local_ordernum(char *domain, char *map, u_int *lordernum) 300 { 301 char map_path[1024]; 302 char order_key[] = YP_LAST_KEY; 303 char order[MAX_LAST_LEN+1]; 304 struct stat finfo; 305 DBM *db; 306 datum k, v; 307 int status; 308 309 status = YPPUSH_SUCC; 310 311 snprintf(map_path, sizeof(map_path), "%s/%s", YP_DB_PATH, domain); 312 map_path[sizeof(map_path) - 1] = '\0'; 313 314 /* Make sure we serve the domain. */ 315 if ((stat(map_path, &finfo)) != 0 || 316 (S_ISDIR(finfo.st_mode) == 0)) { 317 warnx("domain `%s' not found locally", domain); 318 status = YPPUSH_NODOM; 319 goto out; 320 } 321 322 /* Make sure we serve the map. */ 323 snprintf(map_path, sizeof(map_path), "%s/%s/%s%s", 324 YP_DB_PATH, domain, map, YPDB_SUFFIX); 325 map_path[sizeof(map_path) - 1] = '\0'; 326 if (stat(map_path, &finfo) != 0) { 327 status = YPPUSH_NOMAP; 328 goto out; 329 } 330 331 /* Open the map file. */ 332 snprintf(map_path, sizeof(map_path), "%s/%s/%s", 333 YP_DB_PATH, domain, map); 334 map_path[sizeof(map_path) - 1] = '\0'; 335 db = ypdb_open(map_path, O_RDONLY, 0444); 336 if (db == NULL) { 337 status = YPPUSH_DBM; 338 goto out; 339 } 340 341 k.dptr = (char *)&order_key; 342 k.dsize = YP_LAST_LEN; 343 344 v = ypdb_fetch(db, k); 345 346 if (v.dptr == NULL) 347 *lordernum = 0; 348 else { 349 strncpy(order, v.dptr, v.dsize); 350 order[v.dsize] = '\0'; 351 *lordernum = (u_int)atoi((char *)&order); 352 } 353 ypdb_close(db); 354 355 out: 356 if ((status == YPPUSH_NOMAP) || (status == YPPUSH_DBM)) { 357 *lordernum = 0; 358 status = YPPUSH_SUCC; 359 } 360 361 return (status); 362 } 363 364 int 365 get_remote_ordernum(CLIENT *client, char *domain, char *map, 366 u_int lordernum, u_int *rordernum) 367 { 368 int status; 369 370 status = yp_order_host(client, domain, map, (int *)rordernum); 371 372 if (status == 0) { 373 if (*rordernum <= lordernum) 374 status = YPPUSH_AGE; 375 else 376 status = YPPUSH_SUCC; 377 } 378 379 return status; 380 } 381 382 void 383 get_map(CLIENT *client, char *domain, char *map, 384 struct ypall_callback *incallback) 385 { 386 387 (void)yp_all_host(client, domain, map, incallback); 388 } 389 390 DBM * 391 create_db(char *domain, char *map, char *temp_map) 392 { 393 char db_temp[255]; 394 DBM *db; 395 396 snprintf(db_temp, sizeof(db_temp), "%s/%s/%s", 397 YP_DB_PATH, domain, temp_map); 398 db_temp[sizeof(db_temp) - 1] = '\0'; 399 400 db = ypdb_open(db_temp, O_RDWR|O_CREAT|O_EXCL, 0444); 401 402 return db; 403 } 404 405 int 406 install_db(char *domain, char *map, char *temp_map) 407 { 408 char db_name[255], db_temp[255]; 409 410 snprintf(db_name, sizeof(db_name), "%s/%s/%s%s", 411 YP_DB_PATH, domain, map, YPDB_SUFFIX); 412 db_name[sizeof(db_name) - 1] = '\0'; 413 414 snprintf(db_temp, sizeof(db_temp), "%s/%s/%s%s", 415 YP_DB_PATH, domain, temp_map, YPDB_SUFFIX); 416 db_temp[sizeof(db_temp) - 1] = '\0'; 417 418 if (rename(db_temp, db_name)) { 419 warn("can't rename `%s' -> `%s'", db_temp, db_name); 420 return YPPUSH_YPERR; 421 } 422 423 return YPPUSH_SUCC; 424 } 425 426 int 427 unlink_db(char *domain, char *map, char *temp_map) 428 { 429 char db_temp[255]; 430 431 snprintf(db_temp, sizeof(db_temp), "%s/%s/%s%s", 432 YP_DB_PATH, domain, temp_map, YPDB_SUFFIX); 433 db_temp[sizeof(db_temp) - 1] = '\0'; 434 435 if (unlink(db_temp)) { 436 warn("can't unlink `%s'", db_temp); 437 return YPPUSH_YPERR; 438 } 439 440 return YPPUSH_SUCC; 441 } 442 443 int 444 add_order(DBM *db, u_int ordernum) 445 { 446 char datestr[11]; 447 datum key, val; 448 char keystr[] = YP_LAST_KEY; 449 int status; 450 451 snprintf(datestr, sizeof(datestr), "%010d", ordernum); 452 datestr[sizeof(datestr) - 1] = '\0'; 453 454 key.dptr = keystr; 455 key.dsize = strlen(keystr); 456 457 val.dptr = datestr; 458 val.dsize = strlen(datestr); 459 460 status = ypdb_store(db, key, val, YPDB_INSERT); 461 if(status >= 0) 462 status = YPPUSH_SUCC; 463 else 464 status = YPPUSH_DBM; 465 466 return (status); 467 } 468 469 int 470 add_master(CLIENT *client, char *domain, char *map, DBM *db) 471 { 472 char keystr[] = YP_MASTER_KEY; 473 char *master; 474 int status; 475 datum key, val; 476 477 master = NULL; 478 479 /* Get MASTER */ 480 status = yp_master_host(client, domain, map, &master); 481 482 if (master != NULL) { 483 key.dptr = keystr; 484 key.dsize = strlen(keystr); 485 486 val.dptr = master; 487 val.dsize = strlen(master); 488 489 status = ypdb_store(db, key, val, YPDB_INSERT); 490 if (status >= 0) 491 status = YPPUSH_SUCC; 492 else 493 status = YPPUSH_DBM; 494 } 495 496 return status; 497 } 498 499 int 500 add_interdomain(CLIENT *client, char *domain, char *map, DBM *db) 501 { 502 char keystr[] = YP_INTERDOMAIN_KEY; 503 char *value; 504 int vallen; 505 int status; 506 datum k, v; 507 508 /* Get INTERDOMAIN */ 509 k.dptr = keystr; 510 k.dsize = strlen(keystr); 511 512 status = yp_match_host(client, domain, map, 513 k.dptr, k.dsize, &value, &vallen); 514 515 if (status == 0 && value) { 516 v.dptr = value; 517 v.dsize = vallen; 518 519 if (v.dptr != NULL) { 520 status = ypdb_store(db, k, v, YPDB_INSERT); 521 if (status >= 0) 522 status = YPPUSH_SUCC; 523 else 524 status = YPPUSH_DBM; 525 } 526 } 527 528 return status; 529 } 530 531 int 532 add_secure(CLIENT *client, char *domain, char *map, DBM *db) 533 { 534 char keystr[] = YP_SECURE_KEY; 535 char *value; 536 int vallen; 537 int status; 538 datum k, v; 539 540 /* Get SECURE */ 541 k.dptr = keystr; 542 k.dsize = strlen(keystr); 543 544 status = yp_match_host(client, domain, map, 545 k.dptr, k.dsize, &value, &vallen); 546 547 if (status > 0) { 548 v.dptr = value; 549 v.dsize = vallen; 550 551 if (v.dptr != NULL) { 552 status = ypdb_store(db, k, v, YPDB_INSERT); 553 if (status >= 0) 554 status = YPPUSH_SUCC; 555 else 556 status = YPPUSH_DBM; 557 } 558 } 559 560 return status; 561 } 562 563 int 564 send_clear(CLIENT *client) 565 { 566 struct timeval tv; 567 int r; 568 int status; 569 570 status = YPPUSH_SUCC; 571 572 tv.tv_sec = 10; 573 tv.tv_usec = 0; 574 575 /* Send CLEAR */ 576 r = clnt_call(client, YPPROC_CLEAR, xdr_void, 0, xdr_void, 0, tv); 577 if (r != RPC_SUCCESS) { 578 clnt_perror(client, "yp_clear: clnt_call"); 579 status = YPPUSH_RPC; 580 } 581 582 return status; 583 } 584 585 int 586 send_reply(CLIENT *client, int status, int tid) 587 { 588 struct timeval tv; 589 struct ypresp_xfr resp; 590 int r; 591 592 tv.tv_sec = 10; 593 tv.tv_usec = 0; 594 595 resp.transid = tid; 596 resp.xfrstat = status; 597 598 /* Send XFRRESP */ 599 r = clnt_call(client, YPPUSHPROC_XFRRESP, xdr_ypresp_xfr, &resp, 600 xdr_void, 0, tv); 601 if (r != RPC_SUCCESS) { 602 clnt_perror(client, "yppushresp_xdr: clnt_call"); 603 status = YPPUSH_RPC; 604 } 605 606 return status; 607 } 608