1 /* $OpenBSD: server.c,v 1.22 2011/04/10 15:47:28 krw Exp $ */ 2 3 /* 4 * Copyright (c) 1983 Regents of the University of California. 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. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 #include "defs.h" 32 33 /* 34 * Server routines 35 */ 36 37 char tempname[sizeof _RDIST_TMP + 1]; /* Tmp file name */ 38 char buf[BUFSIZ]; /* general purpose buffer */ 39 char target[MAXPATHLEN]; /* target/source directory name */ 40 char *ptarget; /* pointer to end of target name */ 41 int catname = 0; /* cat name to target name */ 42 char *sptarget[32]; /* stack of saved ptarget's for directories */ 43 char *fromhost = NULL; /* Client hostname */ 44 static int64_t min_freespace = 0; /* Minimium free space on a filesystem */ 45 static int64_t min_freefiles = 0; /* Minimium free # files on a filesystem */ 46 int oumask; /* Old umask */ 47 48 static int cattarget(char *); 49 static int setownership(char *, int, UID_T, GID_T, int); 50 static int setfilemode(char *, int, int, int); 51 static int fchog(int, char *, char *, char *, int); 52 static int removefile(struct stat *, int); 53 static void doclean(char *); 54 static void clean(char *); 55 static void dospecial(char *); 56 static void docmdspecial(void); 57 static void query(char *); 58 static int chkparent(char *, opt_t); 59 static char *savetarget(char *, opt_t); 60 static void recvfile(char *, opt_t, int, char *, char *, time_t, time_t, off_t); 61 static void recvdir(opt_t, int, char *, char *); 62 static void recvlink(char *, opt_t, int, off_t); 63 static void hardlink(char *); 64 static void setconfig(char *); 65 static void recvit(char *, int); 66 static void dochmog(char *); 67 static void settarget(char *, int); 68 69 /* 70 * Cat "string" onto the target buffer with error checking. 71 */ 72 static int 73 cattarget(char *string) 74 { 75 if (strlen(string) + strlen(target) + 2 > sizeof(target)) { 76 message(MT_INFO, "target buffer is not large enough."); 77 return(-1); 78 } 79 if (!ptarget) { 80 message(MT_INFO, "NULL target pointer set."); 81 return(-10); 82 } 83 84 (void) snprintf(ptarget, sizeof(target) - (ptarget - target), 85 "/%s", string); 86 87 return(0); 88 } 89 90 /* 91 * Set uid and gid ownership of a file. 92 */ 93 static int 94 setownership(char *file, int fd, UID_T uid, GID_T gid, int link) 95 { 96 int status = -1; 97 98 /* 99 * We assume only the Superuser can change uid ownership. 100 */ 101 if (getuid() != 0) 102 uid = -1; 103 104 /* 105 * If we are dealing with a symlink, only try to change it if 106 * we have lchown, if we don't leave it alone. 107 */ 108 #if defined(HAVE_LCHOWN) 109 if (link) 110 status = lchown(file, (CHOWN_UID_T) uid, 111 (CHOWN_GID_T) gid); 112 #else 113 if (link) 114 return 0; 115 #endif 116 117 #if defined(HAVE_FCHOWN) 118 if (fd != -1 && !link) 119 status = fchown(fd, (CHOWN_UID_T) uid, 120 (CHOWN_GID_T) gid); 121 #endif 122 if (status < 0 && !link) 123 status = chown(file, (CHOWN_UID_T) uid, 124 (CHOWN_GID_T) gid); 125 126 if (status < 0) { 127 if (uid == (UID_T) -1) 128 message(MT_NOTICE, "%s: chgrp %d failed: %s", 129 target, gid, SYSERR); 130 else 131 message(MT_NOTICE, "%s: chown %d.%d failed: %s", 132 target, uid, gid, SYSERR); 133 return(-1); 134 } 135 136 return(0); 137 } 138 139 /* 140 * Set mode of a file 141 */ 142 static int 143 setfilemode(char *file, int fd, int mode, int link) 144 { 145 int status = -1; 146 147 if (mode == -1) 148 return(0); 149 150 /* 151 * If we are dealing with a symlink, only try to change it if 152 * we have lchown, if we don't leave it alone. 153 */ 154 #if defined(HAVE_LCHMOD) 155 if (link) 156 status = lchmod(file, mode); 157 #else 158 if (link) 159 return 0; 160 #endif 161 162 #if defined(HAVE_FCHMOD) 163 if (fd != -1 && !link) 164 status = fchmod(fd, mode); 165 #endif 166 167 if (status < 0 && !link) 168 status = chmod(file, mode); 169 170 if (status < 0) { 171 message(MT_NOTICE, "%s: chmod failed: %s", target, SYSERR); 172 return(-1); 173 } 174 175 return(0); 176 } 177 /* 178 * Change owner, group and mode of file. 179 */ 180 static int 181 fchog(int fd, char *file, char *owner, char *group, int mode) 182 { 183 static struct group *gr = NULL; 184 extern char *locuser; 185 int i; 186 struct stat st; 187 UID_T uid; 188 GID_T gid; 189 GID_T primegid = (GID_T)-2; 190 191 uid = userid; 192 if (userid == 0) { /* running as root; take anything */ 193 if (*owner == ':') { 194 uid = (UID_T) atoi(owner + 1); 195 } else if (pw == NULL || strcmp(owner, pw->pw_name) != 0) { 196 if ((pw = getpwnam(owner)) == NULL) { 197 if (mode != -1 && IS_ON(mode, S_ISUID)) { 198 message(MT_NOTICE, 199 "%s: unknown login name \"%s\", clearing setuid", 200 target, owner); 201 mode &= ~S_ISUID; 202 uid = 0; 203 } else 204 message(MT_NOTICE, 205 "%s: unknown login name \"%s\"", 206 target, owner); 207 } else 208 uid = pw->pw_uid; 209 } else { 210 uid = pw->pw_uid; 211 primegid = pw->pw_gid; 212 } 213 if (*group == ':') { 214 gid = (GID_T) atoi(group + 1); 215 goto ok; 216 } 217 } else { /* not root, setuid only if user==owner */ 218 struct passwd *lupw; 219 220 if (mode != -1) { 221 if (IS_ON(mode, S_ISUID) && 222 strcmp(locuser, owner) != 0) 223 mode &= ~S_ISUID; 224 if (mode) 225 mode &= ~S_ISVTX; /* and strip sticky too */ 226 } 227 228 if ((lupw = getpwnam(locuser)) != NULL) 229 primegid = lupw->pw_gid; 230 } 231 232 gid = (GID_T) -1; 233 if (gr == NULL || strcmp(group, gr->gr_name) != 0) { 234 if ((*group == ':' && 235 (getgrgid(gid = atoi(group + 1)) == NULL)) 236 || ((gr = (struct group *)getgrnam(group)) == NULL)) { 237 if (mode != -1 && IS_ON(mode, S_ISGID)) { 238 message(MT_NOTICE, 239 "%s: unknown group \"%s\", clearing setgid", 240 target, group); 241 mode &= ~S_ISGID; 242 } else 243 message(MT_NOTICE, 244 "%s: unknown group \"%s\"", 245 target, group); 246 } else 247 gid = gr->gr_gid; 248 } else 249 gid = gr->gr_gid; 250 251 if (userid && gid >= 0 && gid != primegid) { 252 if (gr) 253 for (i = 0; gr->gr_mem[i] != NULL; i++) 254 if (strcmp(locuser, gr->gr_mem[i]) == 0) 255 goto ok; 256 if (mode != -1 && IS_ON(mode, S_ISGID)) { 257 message(MT_NOTICE, 258 "%s: user %s not in group %s, clearing setgid", 259 target, locuser, group); 260 mode &= ~S_ISGID; 261 } 262 gid = (GID_T) -1; 263 } 264 ok: 265 if (stat(file, &st) == -1) { 266 error("%s: Stat failed %s", file, SYSERR); 267 return -1; 268 } 269 /* 270 * Set uid and gid ownership. If that fails, strip setuid and 271 * setgid bits from mode. Once ownership is set, successful 272 * or otherwise, set the new file mode. 273 */ 274 if (setownership(file, fd, uid, gid, S_ISLNK(st.st_mode)) < 0) { 275 if (mode != -1 && IS_ON(mode, S_ISUID)) { 276 message(MT_NOTICE, 277 "%s: chown failed, clearing setuid", target); 278 mode &= ~S_ISUID; 279 } 280 if (mode != -1 && IS_ON(mode, S_ISGID)) { 281 message(MT_NOTICE, 282 "%s: chown failed, clearing setgid", target); 283 mode &= ~S_ISGID; 284 } 285 } 286 (void) setfilemode(file, fd, mode, S_ISLNK(st.st_mode)); 287 288 289 return(0); 290 } 291 292 /* 293 * Remove a file or directory (recursively) and send back an acknowledge 294 * or an error message. 295 */ 296 static int 297 removefile(struct stat *statb, int silent) 298 { 299 DIR *d; 300 static DIRENTRY *dp; 301 char *cp; 302 struct stat stb; 303 char *optarget; 304 int len, failures = 0; 305 306 switch (statb->st_mode & S_IFMT) { 307 case S_IFREG: 308 case S_IFLNK: 309 case S_IFCHR: 310 case S_IFBLK: 311 #ifdef S_IFSOCK 312 case S_IFSOCK: 313 #endif 314 #ifdef S_IFIFO 315 case S_IFIFO: 316 #endif 317 if (unlink(target) < 0) { 318 if (errno == ETXTBSY) { 319 if (!silent) 320 message(MT_REMOTE|MT_NOTICE, 321 "%s: unlink failed: %s", 322 target, SYSERR); 323 return(0); 324 } else { 325 error("%s: unlink failed: %s", target, SYSERR); 326 return(-1); 327 } 328 } 329 goto removed; 330 331 case S_IFDIR: 332 break; 333 334 default: 335 error("%s: not a plain file", target); 336 return(-1); 337 } 338 339 errno = 0; 340 if ((d = opendir(target)) == NULL) { 341 error("%s: opendir failed: %s", target, SYSERR); 342 return(-1); 343 } 344 345 optarget = ptarget; 346 len = ptarget - target; 347 while ((dp = readdir(d)) != NULL) { 348 if ((D_NAMLEN(dp) == 1 && dp->d_name[0] == '.') || 349 (D_NAMLEN(dp) == 2 && dp->d_name[0] == '.' && 350 dp->d_name[1] == '.')) 351 continue; 352 353 if (len + 1 + (int)strlen(dp->d_name) >= MAXPATHLEN - 1) { 354 if (!silent) 355 message(MT_REMOTE|MT_WARNING, 356 "%s/%s: Name too long", 357 target, dp->d_name); 358 continue; 359 } 360 ptarget = optarget; 361 *ptarget++ = '/'; 362 cp = dp->d_name; 363 while ((*ptarget++ = *cp++) != '\0') 364 continue; 365 ptarget--; 366 if (lstat(target, &stb) < 0) { 367 if (!silent) 368 message(MT_REMOTE|MT_WARNING, 369 "%s: lstat failed: %s", 370 target, SYSERR); 371 continue; 372 } 373 if (removefile(&stb, 0) < 0) 374 ++failures; 375 } 376 (void) closedir(d); 377 ptarget = optarget; 378 *ptarget = CNULL; 379 380 if (failures) 381 return(-1); 382 383 if (rmdir(target) < 0) { 384 error("%s: rmdir failed: %s", target, SYSERR); 385 return(-1); 386 } 387 removed: 388 #if NEWWAY 389 if (!silent) 390 message(MT_CHANGE|MT_REMOTE, "%s: removed", target); 391 #else 392 /* 393 * We use MT_NOTICE instead of MT_CHANGE because this function is 394 * sometimes called by other functions that are suppose to return a 395 * single ack() back to the client (rdist). This is a kludge until 396 * the Rdist protocol is re-done. Sigh. 397 */ 398 message(MT_NOTICE|MT_REMOTE, "%s: removed", target); 399 #endif 400 return(0); 401 } 402 403 /* 404 * Check the current directory (initialized by the 'T' command to server()) 405 * for extraneous files and remove them. 406 */ 407 static void 408 doclean(char *cp) 409 { 410 DIR *d; 411 DIRENTRY *dp; 412 struct stat stb; 413 char *optarget, *ep; 414 int len; 415 opt_t opts; 416 char targ[MAXPATHLEN*4]; 417 418 opts = strtol(cp, &ep, 8); 419 if (*ep != CNULL) { 420 error("clean: options not delimited"); 421 return; 422 } 423 if ((d = opendir(target)) == NULL) { 424 error("%s: opendir failed: %s", target, SYSERR); 425 return; 426 } 427 ack(); 428 429 optarget = ptarget; 430 len = ptarget - target; 431 while ((dp = readdir(d)) != NULL) { 432 if ((D_NAMLEN(dp) == 1 && dp->d_name[0] == '.') || 433 (D_NAMLEN(dp) == 2 && dp->d_name[0] == '.' && 434 dp->d_name[1] == '.')) 435 continue; 436 437 if (len + 1 + (int)strlen(dp->d_name) >= MAXPATHLEN - 1) { 438 message(MT_REMOTE|MT_WARNING, "%s/%s: Name too long", 439 target, dp->d_name); 440 continue; 441 } 442 ptarget = optarget; 443 *ptarget++ = '/'; 444 cp = dp->d_name; 445 while ((*ptarget++ = *cp++) != '\0') 446 continue; 447 ptarget--; 448 if (lstat(target, &stb) < 0) { 449 message(MT_REMOTE|MT_WARNING, "%s: lstat failed: %s", 450 target, SYSERR); 451 continue; 452 } 453 454 ENCODE(targ, dp->d_name); 455 (void) sendcmd(CC_QUERY, "%s", targ); 456 (void) remline(cp = buf, sizeof(buf), TRUE); 457 458 if (*cp != CC_YES) 459 continue; 460 461 if (IS_ON(opts, DO_VERIFY)) 462 message(MT_REMOTE|MT_INFO, "%s: need to remove", 463 target); 464 else 465 (void) removefile(&stb, 0); 466 } 467 (void) closedir(d); 468 469 ptarget = optarget; 470 *ptarget = CNULL; 471 } 472 473 /* 474 * Frontend to doclean(). 475 */ 476 static void 477 clean(char *cp) 478 { 479 doclean(cp); 480 (void) sendcmd(CC_END, NULL); 481 (void) response(); 482 } 483 484 /* 485 * Execute a shell command to handle special cases. 486 * We can't really set an alarm timeout here since we 487 * have no idea how long the command should take. 488 */ 489 static void 490 dospecial(char *xcmd) 491 { 492 char cmd[BUFSIZ]; 493 if (DECODE(cmd, xcmd) == -1) { 494 error("dospecial: Cannot decode command."); 495 return; 496 } 497 runcommand(cmd); 498 } 499 500 /* 501 * Do a special cmd command. This differs from normal special 502 * commands in that it's done after an entire command has been updated. 503 * The list of updated target files is sent one at a time with RC_FILE 504 * commands. Each one is added to an environment variable defined by 505 * E_FILES. When an RC_COMMAND is finally received, the E_FILES variable 506 * is stuffed into our environment and a normal dospecial() command is run. 507 */ 508 static void 509 docmdspecial(void) 510 { 511 char *cp; 512 char *cmd, *env = NULL; 513 int n; 514 size_t len; 515 516 /* We're ready */ 517 ack(); 518 519 for ( ; ; ) { 520 n = remline(cp = buf, sizeof(buf), FALSE); 521 if (n <= 0) { 522 error("cmdspecial: premature end of input."); 523 return; 524 } 525 526 switch (*cp++) { 527 case RC_FILE: 528 if (env == NULL) { 529 len = (2 * sizeof(E_FILES)) + strlen(cp) + 10; 530 env = (char *) xmalloc(len); 531 (void) snprintf(env, len, "export %s;%s=%s", 532 E_FILES, E_FILES, cp); 533 } else { 534 len = strlen(env) + 1 + strlen(cp) + 1; 535 env = (char *) xrealloc(env, len); 536 (void) strlcat(env, ":", len); 537 (void) strlcat(env, cp, len); 538 } 539 ack(); 540 break; 541 542 case RC_COMMAND: 543 if (env) { 544 len = strlen(env) + 1 + strlen(cp) + 1; 545 env = (char *) xrealloc(env, len); 546 (void) strlcat(env, ";", len); 547 (void) strlcat(env, cp, len); 548 cmd = env; 549 } else 550 cmd = cp; 551 552 dospecial(cmd); 553 if (env) 554 (void) free(env); 555 return; 556 557 default: 558 error("Unknown cmdspecial command '%s'.", cp); 559 return; 560 } 561 } 562 } 563 564 /* 565 * Query. Check to see if file exists. Return one of the following: 566 * 567 #ifdef NFS_CHECK 568 * QC_ONNFS - resides on a NFS 569 #endif NFS_CHECK 570 #ifdef RO_CHECK 571 * QC_ONRO - resides on a Read-Only filesystem 572 #endif RO_CHECK 573 * QC_NO - doesn't exist 574 * QC_YESsize mtime - exists and its a regular file (size & mtime of file) 575 * QC_YES - exists and its a directory or symbolic link 576 * QC_ERRMSGmessage - error message 577 */ 578 static void 579 query(char *xname) 580 { 581 static struct stat stb; 582 int s = -1, stbvalid = 0; 583 char name[MAXPATHLEN]; 584 585 if (DECODE(name, xname) == -1) { 586 error("query: Cannot decode filename"); 587 return; 588 } 589 590 if (catname && cattarget(name) < 0) 591 return; 592 593 #if defined(NFS_CHECK) 594 if (IS_ON(options, DO_CHKNFS)) { 595 s = is_nfs_mounted(target, &stb, &stbvalid); 596 if (s > 0) 597 (void) sendcmd(QC_ONNFS, NULL); 598 599 /* Either the above check was true or an error occurred */ 600 /* and is_nfs_mounted sent the error message */ 601 if (s != 0) { 602 *ptarget = CNULL; 603 return; 604 } 605 } 606 #endif /* NFS_CHECK */ 607 608 #if defined(RO_CHECK) 609 if (IS_ON(options, DO_CHKREADONLY)) { 610 s = is_ro_mounted(target, &stb, &stbvalid); 611 if (s > 0) 612 (void) sendcmd(QC_ONRO, NULL); 613 614 /* Either the above check was true or an error occurred */ 615 /* and is_ro_mounted sent the error message */ 616 if (s != 0) { 617 *ptarget = CNULL; 618 return; 619 } 620 } 621 #endif /* RO_CHECK */ 622 623 if (IS_ON(options, DO_CHKSYM)) { 624 if (is_symlinked(target, &stb, &stbvalid) > 0) { 625 (void) sendcmd(QC_SYM, NULL); 626 return; 627 } 628 } 629 630 /* 631 * If stbvalid is false, "stb" is not valid because: 632 * a) RO_CHECK and NFS_CHECK were not defined 633 * b) The stat by is_*_mounted() either failed or 634 * does not match "target". 635 */ 636 if (!stbvalid && lstat(target, &stb) < 0) { 637 if (errno == ENOENT) 638 (void) sendcmd(QC_NO, NULL); 639 else 640 error("%s: lstat failed: %s", target, SYSERR); 641 *ptarget = CNULL; 642 return; 643 } 644 645 switch (stb.st_mode & S_IFMT) { 646 case S_IFLNK: 647 case S_IFDIR: 648 case S_IFREG: 649 #ifdef notyet 650 case S_IFCHR: 651 case S_IFBLK: 652 #ifdef S_IFSOCK 653 case S_IFSOCK: 654 #endif 655 #ifdef S_IFIFO 656 case S_IFIFO: 657 #endif 658 #endif 659 (void) sendcmd(QC_YES, "%lld %ld %o %s %s", 660 (long long) stb.st_size, stb.st_mtime, 661 stb.st_mode & 07777, 662 getusername(stb.st_uid, target, options), 663 getgroupname(stb.st_gid, target, options)); 664 break; 665 666 default: 667 error("%s: not a file or directory", target); 668 break; 669 } 670 *ptarget = CNULL; 671 } 672 673 /* 674 * Check to see if parent directory exists and create one if not. 675 */ 676 static int 677 chkparent(char *name, opt_t opts) 678 { 679 char *cp; 680 struct stat stb; 681 int r = -1; 682 683 debugmsg(DM_CALL, "chkparent(%s, %o) start\n", name, opts); 684 685 cp = strrchr(name, '/'); 686 if (cp == NULL || cp == name) 687 return(0); 688 689 *cp = CNULL; 690 691 if (lstat(name, &stb) < 0) { 692 if (errno == ENOENT && chkparent(name, opts) >= 0) { 693 if (mkdir(name, 0777 & ~oumask) == 0) { 694 message(MT_NOTICE, "%s: mkdir", name); 695 r = 0; 696 } else 697 debugmsg(DM_MISC, 698 "chkparent(%s, %o) mkdir fail: %s\n", 699 name, opts, SYSERR); 700 } 701 } else /* It exists */ 702 r = 0; 703 704 /* Put back what we took away */ 705 *cp = '/'; 706 707 return(r); 708 } 709 710 /* 711 * Save a copy of 'file' by renaming it. 712 */ 713 static char * 714 savetarget(char *file, opt_t opts) 715 { 716 static char savefile[MAXPATHLEN]; 717 718 if (strlen(file) + sizeof(SAVE_SUFFIX) + 1 > MAXPATHLEN) { 719 error("%s: Cannot save: Save name too long", file); 720 return(NULL); 721 } 722 723 if (IS_ON(opts, DO_HISTORY)) { 724 int i; 725 struct stat st; 726 /* 727 * There is a race here, but the worst that can happen 728 * is to lose a version of the file 729 */ 730 for (i = 1; i < 1000; i++) { 731 (void) snprintf(savefile, sizeof(savefile), 732 "%s;%.3d", file, i); 733 if (stat(savefile, &st) == -1 && errno == ENOENT) 734 break; 735 736 } 737 if (i == 1000) { 738 message(MT_NOTICE, 739 "%s: More than 1000 versions for %s; reusing 1\n", 740 savefile, SYSERR); 741 i = 1; 742 (void) snprintf(savefile, sizeof(savefile), 743 "%s;%.3d", file, i); 744 } 745 } 746 else { 747 (void) snprintf(savefile, sizeof(savefile), "%s%s", 748 file, SAVE_SUFFIX); 749 750 if (unlink(savefile) != 0 && errno != ENOENT) { 751 message(MT_NOTICE, "%s: remove failed: %s", 752 savefile, SYSERR); 753 return(NULL); 754 } 755 } 756 757 if (rename(file, savefile) != 0 && errno != ENOENT) { 758 error("%s -> %s: rename failed: %s", 759 file, savefile, SYSERR); 760 return(NULL); 761 } 762 763 return(savefile); 764 } 765 766 /* 767 * Receive a file 768 */ 769 static void 770 recvfile(char *new, opt_t opts, int mode, char *owner, char *group, 771 time_t mtime, time_t atime, off_t size) 772 { 773 int f, wrerr, olderrno; 774 off_t i; 775 char *cp; 776 char *savefile = NULL; 777 static struct stat statbuff; 778 779 /* 780 * Create temporary file 781 */ 782 if ((f = mkstemp(new)) < 0) { 783 if (errno != ENOENT || chkparent(new, opts) < 0 || 784 (f = mkstemp(new)) < 0) { 785 error("%s: create failed: %s", new, SYSERR); 786 return; 787 } 788 } 789 790 /* 791 * Receive the file itself 792 */ 793 ack(); 794 wrerr = 0; 795 olderrno = 0; 796 for (i = 0; i < size; i += BUFSIZ) { 797 off_t amt = BUFSIZ; 798 799 cp = buf; 800 if (i + amt > size) 801 amt = size - i; 802 do { 803 ssize_t j; 804 805 j = readrem(cp, amt); 806 if (j <= 0) { 807 (void) close(f); 808 (void) unlink(new); 809 fatalerr( 810 "Read error occurred while receiving file."); 811 finish(); 812 } 813 amt -= j; 814 cp += j; 815 } while (amt > 0); 816 amt = BUFSIZ; 817 if (i + amt > size) 818 amt = size - i; 819 if (wrerr == 0 && xwrite(f, buf, amt) != amt) { 820 olderrno = errno; 821 wrerr++; 822 } 823 } 824 825 if (response() < 0) { 826 (void) close(f); 827 (void) unlink(new); 828 return; 829 } 830 831 if (wrerr) { 832 error("%s: Write error: %s", new, strerror(olderrno)); 833 (void) close(f); 834 (void) unlink(new); 835 return; 836 } 837 838 /* 839 * Do file comparison if enabled 840 */ 841 if (IS_ON(opts, DO_COMPARE)) { 842 FILE *f1, *f2; 843 int c; 844 845 errno = 0; /* fopen is not a syscall */ 846 if ((f1 = fopen(target, "r")) == NULL) { 847 error("%s: open for read failed: %s", target, SYSERR); 848 (void) close(f); 849 (void) unlink(new); 850 return; 851 } 852 errno = 0; 853 if ((f2 = fopen(new, "r")) == NULL) { 854 error("%s: open for read failed: %s", new, SYSERR); 855 (void) fclose(f1); 856 (void) close(f); 857 (void) unlink(new); 858 return; 859 } 860 while ((c = getc(f1)) == getc(f2)) 861 if (c == EOF) { 862 debugmsg(DM_MISC, 863 "Files are the same '%s' '%s'.", 864 target, new); 865 (void) fclose(f1); 866 (void) fclose(f2); 867 (void) close(f); 868 (void) unlink(new); 869 /* 870 * This isn't an error per-se, but we 871 * need to indicate to the master that 872 * the file was not updated. 873 */ 874 error(""); 875 return; 876 } 877 debugmsg(DM_MISC, "Files are different '%s' '%s'.", 878 target, new); 879 (void) fclose(f1); 880 (void) fclose(f2); 881 if (IS_ON(opts, DO_VERIFY)) { 882 message(MT_REMOTE|MT_INFO, "%s: need to update", 883 target); 884 (void) close(f); 885 (void) unlink(new); 886 return; 887 } 888 } 889 890 /* 891 * Set owner, group, and file mode 892 */ 893 if (fchog(f, new, owner, group, mode) < 0) { 894 (void) close(f); 895 (void) unlink(new); 896 return; 897 } 898 (void) close(f); 899 900 /* 901 * Perform utimes() after file is closed to make 902 * certain OS's, such as NeXT 2.1, happy. 903 */ 904 if (setfiletime(new, time((time_t *) 0), mtime) < 0) 905 message(MT_NOTICE, "%s: utimes failed: %s", new, SYSERR); 906 907 /* 908 * Try to save target file from being over-written 909 */ 910 if (IS_ON(opts, DO_SAVETARGETS)) 911 if ((savefile = savetarget(target, opts)) == NULL) { 912 (void) unlink(new); 913 return; 914 } 915 916 /* 917 * If the target is a directory, we need to remove it first 918 * before we can rename the new file. 919 */ 920 if ((stat(target, &statbuff) == 0) && S_ISDIR(statbuff.st_mode)) { 921 char *saveptr = ptarget; 922 923 ptarget = &target[strlen(target)]; 924 removefile(&statbuff, 0); 925 ptarget = saveptr; 926 } 927 928 /* 929 * Install new (temporary) file as the actual target 930 */ 931 if (rename(new, target) < 0) { 932 static char fmt[] = "%s -> %s: rename failed: %s"; 933 struct stat stb; 934 /* 935 * If the rename failed due to "Text file busy", then 936 * try to rename the target file and retry the rename. 937 */ 938 switch (errno) { 939 case ETXTBSY: 940 /* Save the target */ 941 if ((savefile = savetarget(target, opts)) != NULL) { 942 /* Retry installing new file as target */ 943 if (rename(new, target) < 0) { 944 error(fmt, new, target, SYSERR); 945 /* Try to put back save file */ 946 if (rename(savefile, target) < 0) 947 error(fmt, 948 savefile, target, SYSERR); 949 (void) unlink(new); 950 } else 951 message(MT_NOTICE, "%s: renamed to %s", 952 target, savefile); 953 /* 954 * XXX: We should remove the savefile here. 955 * But we are nice to nfs clients and 956 * we keep it. 957 */ 958 } 959 break; 960 case EISDIR: 961 /* 962 * See if target is a directory and remove it if it is 963 */ 964 if (lstat(target, &stb) == 0) { 965 if (S_ISDIR(stb.st_mode)) { 966 char *optarget = ptarget; 967 for (ptarget = target; *ptarget; 968 ptarget++); 969 /* If we failed to remove, we'll catch 970 it later */ 971 (void) removefile(&stb, 1); 972 ptarget = optarget; 973 } 974 } 975 if (rename(new, target) >= 0) 976 break; 977 /*FALLTHROUGH*/ 978 979 default: 980 error(fmt, new, target, SYSERR); 981 (void) unlink(new); 982 break; 983 } 984 } 985 986 if (IS_ON(opts, DO_COMPARE)) 987 message(MT_REMOTE|MT_CHANGE, "%s: updated", target); 988 else 989 ack(); 990 } 991 992 /* 993 * Receive a directory 994 */ 995 static void 996 recvdir(opt_t opts, int mode, char *owner, char *group) 997 { 998 static char lowner[100], lgroup[100]; 999 char *cp; 1000 struct stat stb; 1001 int s; 1002 1003 s = lstat(target, &stb); 1004 if (s == 0) { 1005 /* 1006 * If target is not a directory, remove it 1007 */ 1008 if (!S_ISDIR(stb.st_mode)) { 1009 if (IS_ON(opts, DO_VERIFY)) 1010 message(MT_NOTICE, "%s: need to remove", 1011 target); 1012 else { 1013 if (unlink(target) < 0) { 1014 error("%s: remove failed: %s", 1015 target, SYSERR); 1016 return; 1017 } 1018 } 1019 s = -1; 1020 errno = ENOENT; 1021 } else { 1022 if (!IS_ON(opts, DO_NOCHKMODE) && 1023 (stb.st_mode & 07777) != mode) { 1024 if (IS_ON(opts, DO_VERIFY)) 1025 message(MT_NOTICE, 1026 "%s: need to chmod to %o", 1027 target, mode); 1028 else { 1029 if (chmod(target, mode) != 0) 1030 message(MT_NOTICE, 1031 "%s: chmod from %o to %o failed: %s", 1032 target, 1033 stb.st_mode & 07777, 1034 mode, 1035 SYSERR); 1036 else 1037 message(MT_NOTICE, 1038 "%s: chmod from %o to %o", 1039 target, 1040 stb.st_mode & 07777, 1041 mode); 1042 } 1043 } 1044 1045 /* 1046 * Check ownership and set if necessary 1047 */ 1048 lowner[0] = CNULL; 1049 lgroup[0] = CNULL; 1050 1051 if (!IS_ON(opts, DO_NOCHKOWNER) && owner) { 1052 int o; 1053 1054 o = (owner[0] == ':') ? opts & DO_NUMCHKOWNER : 1055 opts; 1056 if ((cp = getusername(stb.st_uid, target, o)) 1057 != NULL) 1058 if (strcmp(owner, cp)) 1059 (void) strlcpy(lowner, cp, 1060 sizeof(lowner)); 1061 } 1062 if (!IS_ON(opts, DO_NOCHKGROUP) && group) { 1063 int o; 1064 1065 o = (group[0] == ':') ? opts & DO_NUMCHKGROUP : 1066 opts; 1067 if ((cp = getgroupname(stb.st_gid, target, o)) 1068 != NULL) 1069 if (strcmp(group, cp)) 1070 (void) strlcpy(lgroup, cp, 1071 sizeof(lgroup)); 1072 } 1073 1074 /* 1075 * Need to set owner and/or group 1076 */ 1077 #define PRN(n) ((n[0] == ':') ? n+1 : n) 1078 if (lowner[0] != CNULL || lgroup[0] != CNULL) { 1079 if (lowner[0] == CNULL && 1080 (cp = getusername(stb.st_uid, 1081 target, opts))) 1082 (void) strlcpy(lowner, cp, 1083 sizeof(lowner)); 1084 if (lgroup[0] == CNULL && 1085 (cp = getgroupname(stb.st_gid, 1086 target, opts))) 1087 (void) strlcpy(lgroup, cp, 1088 sizeof(lgroup)); 1089 1090 if (IS_ON(opts, DO_VERIFY)) 1091 message(MT_NOTICE, 1092 "%s: need to chown from %s:%s to %s:%s", 1093 target, 1094 PRN(lowner), PRN(lgroup), 1095 PRN(owner), PRN(group)); 1096 else { 1097 if (fchog(-1, target, owner, 1098 group, -1) == 0) 1099 message(MT_NOTICE, 1100 "%s: chown from %s:%s to %s:%s", 1101 target, 1102 PRN(lowner), 1103 PRN(lgroup), 1104 PRN(owner), 1105 PRN(group)); 1106 } 1107 } 1108 #undef PRN 1109 ack(); 1110 return; 1111 } 1112 } 1113 1114 if (IS_ON(opts, DO_VERIFY)) { 1115 ack(); 1116 return; 1117 } 1118 1119 /* 1120 * Create the directory 1121 */ 1122 if (s < 0) { 1123 if (errno == ENOENT) { 1124 if (mkdir(target, mode) == 0 || 1125 (chkparent(target, opts) == 0 && 1126 mkdir(target, mode) == 0)) { 1127 message(MT_NOTICE, "%s: mkdir", target); 1128 (void) fchog(-1, target, owner, group, mode); 1129 ack(); 1130 } else { 1131 error("%s: mkdir failed: %s", target, SYSERR); 1132 ptarget = sptarget[--catname]; 1133 *ptarget = CNULL; 1134 } 1135 return; 1136 } 1137 } 1138 error("%s: lstat failed: %s", target, SYSERR); 1139 ptarget = sptarget[--catname]; 1140 *ptarget = CNULL; 1141 } 1142 1143 /* 1144 * Receive a link 1145 */ 1146 static void 1147 recvlink(char *new, opt_t opts, int mode, off_t size) 1148 { 1149 char tbuf[MAXPATHLEN], dbuf[BUFSIZ]; 1150 struct stat stb; 1151 char *optarget; 1152 int uptodate; 1153 off_t i; 1154 1155 /* 1156 * Read basic link info 1157 */ 1158 ack(); 1159 (void) remline(buf, sizeof(buf), TRUE); 1160 1161 if (response() < 0) { 1162 err(); 1163 return; 1164 } 1165 1166 if (DECODE(dbuf, buf) == -1) { 1167 error("recvlink: cannot decode symlink target"); 1168 return; 1169 } 1170 1171 uptodate = 0; 1172 if ((i = readlink(target, tbuf, sizeof(tbuf)-1)) != -1) { 1173 tbuf[i] = '\0'; 1174 if (i == size && strncmp(dbuf, tbuf, (int) size) == 0) 1175 uptodate = 1; 1176 } 1177 mode &= 0777; 1178 1179 if (IS_ON(opts, DO_VERIFY) || uptodate) { 1180 if (uptodate) 1181 message(MT_REMOTE|MT_INFO, ""); 1182 else 1183 message(MT_REMOTE|MT_INFO, "%s: need to update", 1184 target); 1185 if (IS_ON(opts, DO_COMPARE)) 1186 return; 1187 (void) sendcmd(C_END, NULL); 1188 (void) response(); 1189 return; 1190 } 1191 1192 /* 1193 * Make new symlink using a temporary name 1194 */ 1195 if (mktemp(new) == NULL || symlink(dbuf, new) < 0) { 1196 if (errno != ENOENT || chkparent(new, opts) < 0 || 1197 mktemp(new) == NULL || symlink(dbuf, new) < 0) { 1198 error("%s -> %s: symlink failed: %s", new, dbuf, 1199 SYSERR); 1200 return; 1201 } 1202 } 1203 1204 /* 1205 * See if target is a directory and remove it if it is 1206 */ 1207 if (lstat(target, &stb) == 0) { 1208 if (S_ISDIR(stb.st_mode)) { 1209 optarget = ptarget; 1210 for (ptarget = target; *ptarget; ptarget++); 1211 if (removefile(&stb, 0) < 0) { 1212 ptarget = optarget; 1213 (void) unlink(new); 1214 (void) sendcmd(C_END, NULL); 1215 (void) response(); 1216 return; 1217 } 1218 ptarget = optarget; 1219 } 1220 } 1221 1222 /* 1223 * Install link as the target 1224 */ 1225 if (rename(new, target) < 0) { 1226 error("%s -> %s: symlink rename failed: %s", 1227 new, target, SYSERR); 1228 (void) unlink(new); 1229 (void) sendcmd(C_END, NULL); 1230 (void) response(); 1231 return; 1232 } 1233 1234 message(MT_REMOTE|MT_CHANGE, "%s: updated", target); 1235 1236 /* 1237 * Indicate end of receive operation 1238 */ 1239 (void) sendcmd(C_END, NULL); 1240 (void) response(); 1241 } 1242 1243 /* 1244 * Creat a hard link to existing file. 1245 */ 1246 static void 1247 hardlink(char *cmd) 1248 { 1249 struct stat stb; 1250 int exists = 0; 1251 char *xoldname, *xnewname; 1252 char *cp = cmd; 1253 static char expbuf[BUFSIZ]; 1254 char oldname[BUFSIZ], newname[BUFSIZ]; 1255 1256 /* Skip over opts */ 1257 (void) strtol(cp, &cp, 8); 1258 if (*cp++ != ' ') { 1259 error("hardlink: options not delimited"); 1260 return; 1261 } 1262 1263 xoldname = strtok(cp, " "); 1264 if (xoldname == NULL) { 1265 error("hardlink: oldname name not delimited"); 1266 return; 1267 } 1268 1269 if (DECODE(oldname, xoldname) == -1) { 1270 error("hardlink: Cannot decode oldname"); 1271 return; 1272 } 1273 1274 xnewname = strtok(NULL, " "); 1275 if (xnewname == NULL) { 1276 error("hardlink: new name not specified"); 1277 return; 1278 } 1279 1280 if (DECODE(newname, xnewname) == -1) { 1281 error("hardlink: Cannot decode newname"); 1282 return; 1283 } 1284 1285 if (exptilde(expbuf, oldname, sizeof(expbuf)) == NULL) { 1286 error("hardlink: tilde expansion failed"); 1287 return; 1288 } 1289 1290 if (catname && cattarget(newname) < 0) { 1291 error("Cannot set newname target."); 1292 return; 1293 } 1294 1295 if (lstat(target, &stb) == 0) { 1296 int mode = stb.st_mode & S_IFMT; 1297 1298 if (mode != S_IFREG && mode != S_IFLNK) { 1299 error("%s: not a regular file", target); 1300 return; 1301 } 1302 exists = 1; 1303 } 1304 1305 if (chkparent(target, options) < 0 ) { 1306 error("%s: no parent: %s ", target, SYSERR); 1307 return; 1308 } 1309 if (exists && (unlink(target) < 0)) { 1310 error("%s: unlink failed: %s", target, SYSERR); 1311 return; 1312 } 1313 if (link(expbuf, target) < 0) { 1314 error("%s: cannot link to %s: %s", target, oldname, SYSERR); 1315 return; 1316 } 1317 ack(); 1318 } 1319 1320 /* 1321 * Set configuration information. 1322 * 1323 * A key letter is followed immediately by the value 1324 * to set. The keys are: 1325 * SC_FREESPACE - Set minimium free space of filesystem 1326 * SC_FREEFILES - Set minimium free number of files of filesystem 1327 */ 1328 static void 1329 setconfig(char *cmd) 1330 { 1331 char *cp = cmd; 1332 char *estr; 1333 const char *errstr; 1334 1335 switch (*cp++) { 1336 case SC_HOSTNAME: /* Set hostname */ 1337 /* 1338 * Only use info if we don't know who this is. 1339 */ 1340 if (!fromhost) { 1341 fromhost = xstrdup(cp); 1342 message(MT_SYSLOG, "startup for %s", fromhost); 1343 #if defined(SETARGS) || defined(HAVE_SETPROCTITLE) 1344 setproctitle("serving %s", cp); 1345 #endif /* SETARGS || HAVE_SETPROCTITLE */ 1346 } 1347 break; 1348 1349 case SC_FREESPACE: /* Minimium free space */ 1350 min_freespace = (int64_t)strtonum(cp, 0, LLONG_MAX, &errstr); 1351 if (errstr) 1352 fatalerr("Minimum free space is %s: '%s'", errstr, 1353 optarg); 1354 break; 1355 1356 case SC_FREEFILES: /* Minimium free files */ 1357 min_freefiles = (int64_t)strtonum(cp, 0, LLONG_MAX, &errstr); 1358 if (errstr) 1359 fatalerr("Minimum free files is %s: '%s'", errstr, 1360 optarg); 1361 break; 1362 1363 case SC_LOGGING: /* Logging options */ 1364 if ((estr = msgparseopts(cp, TRUE)) != NULL) { 1365 fatalerr("Bad message option string (%s): %s", 1366 cp, estr); 1367 return; 1368 } 1369 break; 1370 1371 case SC_DEFOWNER: 1372 (void) strlcpy(defowner, cp, sizeof(defowner)); 1373 break; 1374 1375 case SC_DEFGROUP: 1376 (void) strlcpy(defgroup, cp, sizeof(defgroup)); 1377 break; 1378 1379 default: 1380 message(MT_NOTICE, "Unknown config command \"%s\".", cp-1); 1381 return; 1382 } 1383 } 1384 1385 /* 1386 * Receive something 1387 */ 1388 static void 1389 recvit(char *cmd, int type) 1390 { 1391 int mode; 1392 opt_t opts; 1393 off_t size; 1394 time_t mtime, atime; 1395 char *owner, *group, *file; 1396 char new[MAXPATHLEN]; 1397 char fileb[MAXPATHLEN]; 1398 int64_t freespace = -1, freefiles = -1; 1399 char *cp = cmd; 1400 1401 /* 1402 * Get rdist option flags 1403 */ 1404 opts = strtol(cp, &cp, 8); 1405 if (*cp++ != ' ') { 1406 error("recvit: options not delimited"); 1407 return; 1408 } 1409 1410 /* 1411 * Get file mode 1412 */ 1413 mode = strtol(cp, &cp, 8); 1414 if (*cp++ != ' ') { 1415 error("recvit: mode not delimited"); 1416 return; 1417 } 1418 1419 /* 1420 * Get file size 1421 */ 1422 size = (off_t) strtoll(cp, &cp, 10); 1423 if (*cp++ != ' ') { 1424 error("recvit: size not delimited"); 1425 return; 1426 } 1427 1428 /* 1429 * Get modification time 1430 */ 1431 mtime = (time_t) strtol(cp, &cp, 10); 1432 if (*cp++ != ' ') { 1433 error("recvit: mtime not delimited"); 1434 return; 1435 } 1436 1437 /* 1438 * Get access time 1439 */ 1440 atime = strtol(cp, &cp, 10); 1441 if (*cp++ != ' ') { 1442 error("recvit: atime not delimited"); 1443 return; 1444 } 1445 1446 /* 1447 * Get file owner name 1448 */ 1449 owner = strtok(cp, " "); 1450 if (owner == NULL) { 1451 error("recvit: owner name not delimited"); 1452 return; 1453 } 1454 1455 /* 1456 * Get file group name 1457 */ 1458 group = strtok(NULL, " "); 1459 if (group == NULL) { 1460 error("recvit: group name not delimited"); 1461 return; 1462 } 1463 1464 /* 1465 * Get file name. Can't use strtok() since there could 1466 * be white space in the file name. 1467 */ 1468 if (DECODE(fileb, group + strlen(group) + 1) == -1) { 1469 error("recvit: Cannot decode file name"); 1470 return; 1471 } 1472 1473 if (fileb[0] == '\0') { 1474 error("recvit: no file name"); 1475 return; 1476 } 1477 file = fileb; 1478 1479 debugmsg(DM_MISC, 1480 "recvit: opts = %04o mode = %04o size = %lld mtime = %d", 1481 opts, mode, (long long) size, mtime); 1482 debugmsg(DM_MISC, 1483 "recvit: owner = '%s' group = '%s' file = '%s' catname = %d isdir = %d", 1484 owner, group, file, catname, (type == S_IFDIR) ? 1 : 0); 1485 1486 if (type == S_IFDIR) { 1487 if ((size_t) catname >= sizeof(sptarget)) { 1488 error("%s: too many directory levels", target); 1489 return; 1490 } 1491 sptarget[catname] = ptarget; 1492 if (catname++) { 1493 *ptarget++ = '/'; 1494 while ((*ptarget++ = *file++) != '\0') 1495 continue; 1496 ptarget--; 1497 } 1498 } else { 1499 /* 1500 * Create name of temporary file 1501 */ 1502 if (catname && cattarget(file) < 0) { 1503 error("Cannot set file name."); 1504 return; 1505 } 1506 file = strrchr(target, '/'); 1507 if (file == NULL) 1508 (void) strlcpy(new, tempname, sizeof(new)); 1509 else if (file == target) 1510 (void) snprintf(new, sizeof(new), "/%s", tempname); 1511 else { 1512 *file = CNULL; 1513 (void) snprintf(new, sizeof(new), "%s/%s", target, 1514 tempname); 1515 *file = '/'; 1516 } 1517 } 1518 1519 /* 1520 * Check to see if there is enough free space and inodes 1521 * to install this file. 1522 */ 1523 if (min_freespace || min_freefiles) { 1524 /* Convert file size to kilobytes */ 1525 int64_t fsize = (int64_t)size / 1024; 1526 1527 if (getfilesysinfo(target, &freespace, &freefiles) != 0) 1528 return; 1529 1530 /* 1531 * filesystem values < 0 indicate unsupported or unavailable 1532 * information. 1533 */ 1534 if (min_freespace && (freespace >= 0) && 1535 (freespace - fsize < min_freespace)) { 1536 error( 1537 "%s: Not enough free space on filesystem: min %lld " 1538 "free %lld", target, min_freespace, freespace); 1539 return; 1540 } 1541 if (min_freefiles && (freefiles >= 0) && 1542 (freefiles - 1 < min_freefiles)) { 1543 error( 1544 "%s: Not enough free files on filesystem: min %lld free " 1545 "%lld", target, min_freefiles, freefiles); 1546 return; 1547 } 1548 } 1549 1550 /* 1551 * Call appropriate receive function to receive file 1552 */ 1553 switch (type) { 1554 case S_IFDIR: 1555 recvdir(opts, mode, owner, group); 1556 break; 1557 1558 case S_IFLNK: 1559 recvlink(new, opts, mode, size); 1560 break; 1561 1562 case S_IFREG: 1563 recvfile(new, opts, mode, owner, group, mtime, atime, size); 1564 break; 1565 1566 default: 1567 error("%d: unknown file type", type); 1568 break; 1569 } 1570 } 1571 1572 /* 1573 * Chmog something 1574 */ 1575 static void 1576 dochmog(char *cmd) 1577 { 1578 int mode; 1579 opt_t opts; 1580 char *owner, *group, *file; 1581 char *cp = cmd; 1582 char fileb[MAXPATHLEN]; 1583 1584 /* 1585 * Get rdist option flags 1586 */ 1587 opts = strtol(cp, &cp, 8); 1588 if (*cp++ != ' ') { 1589 error("dochmog: options not delimited"); 1590 return; 1591 } 1592 1593 /* 1594 * Get file mode 1595 */ 1596 mode = strtol(cp, &cp, 8); 1597 if (*cp++ != ' ') { 1598 error("dochmog: mode not delimited"); 1599 return; 1600 } 1601 1602 /* 1603 * Get file owner name 1604 */ 1605 owner = strtok(cp, " "); 1606 if (owner == NULL) { 1607 error("dochmog: owner name not delimited"); 1608 return; 1609 } 1610 1611 /* 1612 * Get file group name 1613 */ 1614 group = strtok(NULL, " "); 1615 if (group == NULL) { 1616 error("dochmog: group name not delimited"); 1617 return; 1618 } 1619 1620 /* 1621 * Get file name. Can't use strtok() since there could 1622 * be white space in the file name. 1623 */ 1624 if (DECODE(fileb, group + strlen(group) + 1) == -1) { 1625 error("dochmog: Cannot decode file name"); 1626 return; 1627 } 1628 1629 if (fileb[0] == '\0') { 1630 error("dochmog: no file name"); 1631 return; 1632 } 1633 file = fileb; 1634 1635 debugmsg(DM_MISC, 1636 "dochmog: opts = %04o mode = %04o", opts, mode); 1637 debugmsg(DM_MISC, 1638 "dochmog: owner = '%s' group = '%s' file = '%s' catname = %d", 1639 owner, group, file, catname); 1640 1641 if (catname && cattarget(file) < 0) { 1642 error("Cannot set newname target."); 1643 return; 1644 } 1645 1646 (void) fchog(-1, target, owner, group, mode); 1647 1648 ack(); 1649 } 1650 1651 /* 1652 * Set target information 1653 */ 1654 static void 1655 settarget(char *cmd, int isdir) 1656 { 1657 char *cp = cmd; 1658 opt_t opts; 1659 char file[BUFSIZ]; 1660 1661 catname = isdir; 1662 1663 /* 1664 * Parse options for this target 1665 */ 1666 opts = strtol(cp, &cp, 8); 1667 if (*cp++ != ' ') { 1668 error("settarget: options not delimited"); 1669 return; 1670 } 1671 options = opts; 1672 1673 if (DECODE(file, cp) == -1) { 1674 error("settarget: Cannot decode target name"); 1675 return; 1676 } 1677 1678 /* 1679 * Handle target 1680 */ 1681 if (exptilde(target, cp, sizeof(target)) == NULL) 1682 return; 1683 ptarget = target; 1684 while (*ptarget) 1685 ptarget++; 1686 1687 ack(); 1688 } 1689 1690 /* 1691 * Cleanup in preparation for exiting. 1692 */ 1693 void 1694 cleanup(int dummy) 1695 { 1696 /* We don't need to do anything */ 1697 } 1698 1699 /* 1700 * Server routine to read requests and process them. 1701 */ 1702 void 1703 server(void) 1704 { 1705 static char cmdbuf[BUFSIZ]; 1706 char *cp; 1707 int n; 1708 extern jmp_buf finish_jmpbuf; 1709 1710 if (setjmp(finish_jmpbuf)) 1711 return; 1712 (void) signal(SIGHUP, sighandler); 1713 (void) signal(SIGINT, sighandler); 1714 (void) signal(SIGQUIT, sighandler); 1715 (void) signal(SIGTERM, sighandler); 1716 (void) signal(SIGPIPE, sighandler); 1717 (void) umask(oumask = umask(0)); 1718 (void) strlcpy(tempname, _RDIST_TMP, sizeof(tempname)); 1719 if (fromhost) { 1720 message(MT_SYSLOG, "Startup for %s", fromhost); 1721 #if defined(SETARGS) 1722 setproctitle("Serving %s", fromhost); 1723 #endif /* SETARGS */ 1724 } 1725 1726 /* 1727 * Let client know we want it to send it's version number 1728 */ 1729 (void) sendcmd(S_VERSION, NULL); 1730 1731 if (remline(cmdbuf, sizeof(cmdbuf), TRUE) < 0) { 1732 error("server: expected control record"); 1733 return; 1734 } 1735 1736 if (cmdbuf[0] != S_VERSION || !isdigit((unsigned char)cmdbuf[1])) { 1737 error("Expected version command, received: \"%s\".", cmdbuf); 1738 return; 1739 } 1740 1741 proto_version = atoi(&cmdbuf[1]); 1742 if (proto_version != VERSION) { 1743 error("Protocol version %d is not supported.", proto_version); 1744 return; 1745 } 1746 1747 /* Version number is okay */ 1748 ack(); 1749 1750 /* 1751 * Main command loop 1752 */ 1753 for ( ; ; ) { 1754 n = remline(cp = cmdbuf, sizeof(cmdbuf), TRUE); 1755 if (n == -1) /* EOF */ 1756 return; 1757 if (n == 0) { 1758 error("server: expected control record"); 1759 continue; 1760 } 1761 1762 switch (*cp++) { 1763 case C_SETCONFIG: /* Configuration info */ 1764 setconfig(cp); 1765 ack(); 1766 continue; 1767 1768 case C_DIRTARGET: /* init target file/directory name */ 1769 settarget(cp, TRUE); 1770 continue; 1771 1772 case C_TARGET: /* init target file/directory name */ 1773 settarget(cp, FALSE); 1774 continue; 1775 1776 case C_RECVREG: /* Transfer a regular file. */ 1777 recvit(cp, S_IFREG); 1778 continue; 1779 1780 case C_RECVDIR: /* Transfer a directory. */ 1781 recvit(cp, S_IFDIR); 1782 continue; 1783 1784 case C_RECVSYMLINK: /* Transfer symbolic link. */ 1785 recvit(cp, S_IFLNK); 1786 continue; 1787 1788 case C_RECVHARDLINK: /* Transfer hard link. */ 1789 hardlink(cp); 1790 continue; 1791 1792 case C_END: /* End of transfer */ 1793 *ptarget = CNULL; 1794 if (catname <= 0) { 1795 error("server: too many '%c's", C_END); 1796 continue; 1797 } 1798 ptarget = sptarget[--catname]; 1799 *ptarget = CNULL; 1800 ack(); 1801 continue; 1802 1803 case C_CLEAN: /* Clean. Cleanup a directory */ 1804 clean(cp); 1805 continue; 1806 1807 case C_QUERY: /* Query file/directory */ 1808 query(cp); 1809 continue; 1810 1811 case C_SPECIAL: /* Special. Execute commands */ 1812 dospecial(cp); 1813 continue; 1814 1815 case C_CMDSPECIAL: /* Cmd Special. Execute commands */ 1816 docmdspecial(); 1817 continue; 1818 1819 case C_CHMOG: /* Set owner, group, mode */ 1820 dochmog(cp); 1821 continue; 1822 1823 case C_ERRMSG: /* Normal error message */ 1824 if (cp && *cp) 1825 message(MT_NERROR|MT_NOREMOTE, "%s", cp); 1826 continue; 1827 1828 case C_FERRMSG: /* Fatal error message */ 1829 if (cp && *cp) 1830 message(MT_FERROR|MT_NOREMOTE, "%s", cp); 1831 return; 1832 1833 default: 1834 error("server: unknown command '%s'", cp - 1); 1835 case CNULL: 1836 continue; 1837 } 1838 } 1839 } 1840