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