1 /* $OpenBSD: common.c,v 1.33 2014/07/12 03:32:00 guenther 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 "defs.h" 33 34 /* 35 * Things common to both the client and server. 36 */ 37 38 #if defined(NEED_UTIME_H) 39 #include <utime.h> 40 #endif /* defined(NEED_UTIME_H) */ 41 #include <sys/wait.h> 42 #include <sys/socket.h> 43 44 /* 45 * Variables common to both client and server 46 */ 47 char host[MAXHOSTNAMELEN]; /* Name of this host */ 48 uid_t userid = (uid_t)-1; /* User's UID */ 49 gid_t groupid = (gid_t)-1; /* User's GID */ 50 char *homedir = NULL; /* User's $HOME */ 51 char *locuser = NULL; /* Local User's name */ 52 int isserver = FALSE; /* We're the server */ 53 int amchild = 0; /* This PID is a child */ 54 int do_fork = 1; /* Fork child process */ 55 char *currenthost = NULL; /* Current client hostname */ 56 char *progname = NULL; /* Name of this program */ 57 int rem_r = -1; /* Client file descriptor */ 58 int rem_w = -1; /* Client file descriptor */ 59 struct passwd *pw = NULL; /* Local user's pwd entry */ 60 volatile sig_atomic_t contimedout = FALSE; /* Connection timed out */ 61 int proto_version = -1; /* Protocol version */ 62 int rtimeout = RTIMEOUT; /* Response time out */ 63 jmp_buf finish_jmpbuf; /* Finish() jmp buffer */ 64 int setjmp_ok = FALSE; /* setjmp()/longjmp() status */ 65 char **realargv; /* Real main() argv */ 66 int realargc; /* Real main() argc */ 67 opt_t options = 0; /* Global install options */ 68 char defowner[64] = "bin"; /* Default owner */ 69 char defgroup[64] = "bin"; /* Default group */ 70 71 static int sendcmdmsg(int, char *, size_t); 72 static ssize_t remread(int, u_char *, size_t); 73 static int remmore(void); 74 75 /* 76 * Front end to write() that handles partial write() requests. 77 */ 78 ssize_t 79 xwrite(int fd, void *buf, size_t len) 80 { 81 size_t nleft = len; 82 ssize_t nwritten; 83 char *ptr = buf; 84 85 while (nleft > 0) { 86 if ((nwritten = write(fd, ptr, nleft)) <= 0) { 87 return nwritten; 88 } 89 nleft -= nwritten; 90 ptr += nwritten; 91 } 92 93 return len; 94 } 95 96 /* 97 * Do run-time initialization 98 */ 99 int 100 init(int argc, char **argv, char **envp) 101 { 102 int i; 103 104 /* 105 * Save a copy of our argc and argv before setargs() overwrites them 106 */ 107 realargc = argc; 108 realargv = (char **) xmalloc(sizeof(char *) * (argc+1)); 109 for (i = 0; i < argc; i++) 110 realargv[i] = xstrdup(argv[i]); 111 112 pw = getpwuid(userid = getuid()); 113 if (pw == NULL) { 114 error("Your user id (%u) is not known to this system.", 115 getuid()); 116 return(-1); 117 } 118 119 debugmsg(DM_MISC, "UserID = %u pwname = '%s' home = '%s'\n", 120 userid, pw->pw_name, pw->pw_dir); 121 homedir = xstrdup(pw->pw_dir); 122 locuser = xstrdup(pw->pw_name); 123 groupid = pw->pw_gid; 124 gethostname(host, sizeof(host)); 125 #if 0 126 if ((cp = strchr(host, '.')) != NULL) 127 *cp = CNULL; 128 #endif 129 130 /* 131 * If we're not root, disable paranoid ownership checks 132 * since normal users cannot chown() files. 133 */ 134 if (!isserver && userid != 0) { 135 FLAG_ON(options, DO_NOCHKOWNER); 136 FLAG_ON(options, DO_NOCHKGROUP); 137 } 138 139 return(0); 140 } 141 142 /* 143 * Finish things up before ending. 144 */ 145 void 146 finish(void) 147 { 148 extern jmp_buf finish_jmpbuf; 149 150 debugmsg(DM_CALL, 151 "finish() called: do_fork = %d amchild = %d isserver = %d", 152 do_fork, amchild, isserver); 153 cleanup(0); 154 155 /* 156 * There's no valid finish_jmpbuf for the rdist master parent. 157 */ 158 if (!do_fork || amchild || isserver) { 159 160 if (!setjmp_ok) { 161 #ifdef DEBUG_SETJMP 162 error("attemping longjmp() without target"); 163 abort(); 164 #else 165 exit(1); 166 #endif 167 } 168 169 longjmp(finish_jmpbuf, 1); 170 /*NOTREACHED*/ 171 error("Unexpected failure of longjmp() in finish()"); 172 exit(2); 173 } else 174 exit(1); 175 } 176 177 /* 178 * Handle lost connections 179 */ 180 void 181 lostconn(void) 182 { 183 /* Prevent looping */ 184 (void) signal(SIGPIPE, SIG_IGN); 185 186 rem_r = rem_w = -1; /* Ensure we don't try to send to server */ 187 checkhostname(); 188 error("Lost connection to %s", 189 (currenthost) ? currenthost : "(unknown)"); 190 191 finish(); 192 } 193 194 /* 195 * General signal handler 196 */ 197 void 198 sighandler(int sig) 199 { 200 int save_errno = errno; 201 202 /* XXX signal race */ 203 debugmsg(DM_CALL, "sighandler() received signal %d\n", sig); 204 205 switch (sig) { 206 case SIGALRM: 207 contimedout = TRUE; 208 /* XXX signal race */ 209 checkhostname(); 210 error("Response time out"); 211 finish(); 212 break; 213 214 case SIGPIPE: 215 /* XXX signal race */ 216 lostconn(); 217 break; 218 219 case SIGFPE: 220 debug = !debug; 221 break; 222 223 case SIGHUP: 224 case SIGINT: 225 case SIGQUIT: 226 case SIGTERM: 227 /* XXX signal race */ 228 finish(); 229 break; 230 231 default: 232 /* XXX signal race */ 233 fatalerr("No signal handler defined for signal %d.", sig); 234 } 235 errno = save_errno; 236 } 237 238 /* 239 * Function to actually send the command char and message to the 240 * remote host. 241 */ 242 static int 243 sendcmdmsg(int cmd, char *msg, size_t msgsize) 244 { 245 int len; 246 247 if (rem_w < 0) 248 return(-1); 249 250 /* 251 * All commands except C_NONE should have a newline 252 */ 253 if (cmd != C_NONE && !strchr(msg + 1, '\n')) 254 (void) strlcat(msg + 1, "\n", msgsize - 1); 255 256 if (cmd == C_NONE) 257 len = strlen(msg); 258 else { 259 len = strlen(msg + 1) + 1; 260 msg[0] = cmd; 261 } 262 263 debugmsg(DM_PROTO, ">>> Cmd = %c (\\%3.3o) Msg = \"%.*s\"", 264 cmd, cmd, 265 (cmd == C_NONE) ? len-1 : len-2, 266 (cmd == C_NONE) ? msg : msg + 1); 267 268 return(!(xwrite(rem_w, msg, len) == len)); 269 } 270 271 /* 272 * Send a command message to the remote host. 273 * Called as sendcmd(char cmdchar, char *fmt, arg1, arg2, ...) 274 * The fmt may be NULL, in which case there are no args. 275 */ 276 int 277 sendcmd(char cmd, const char *fmt, ...) 278 { 279 static char buf[BUFSIZ]; 280 va_list args; 281 282 va_start(args, fmt); 283 if (fmt) 284 (void) vsnprintf(buf + (cmd != C_NONE), 285 sizeof(buf) - (cmd != C_NONE), fmt, args); 286 else 287 buf[1] = CNULL; 288 va_end(args); 289 290 return(sendcmdmsg(cmd, buf, sizeof(buf))); 291 } 292 293 /* 294 * Internal variables and routines for reading lines from the remote. 295 */ 296 static u_char rembuf[BUFSIZ]; 297 static u_char *remptr; 298 static ssize_t remleft; 299 300 #define remc() (--remleft < 0 ? remmore() : *remptr++) 301 302 /* 303 * Back end to remote read() 304 */ 305 static ssize_t 306 remread(int fd, u_char *buf, size_t bufsiz) 307 { 308 return(read(fd, (char *)buf, bufsiz)); 309 } 310 311 static int 312 remmore(void) 313 { 314 (void) signal(SIGALRM, sighandler); 315 (void) alarm(rtimeout); 316 317 remleft = remread(rem_r, rembuf, sizeof(rembuf)); 318 319 (void) alarm(0); 320 321 if (remleft < 0) 322 return (-2); /* error */ 323 if (remleft == 0) 324 return (-1); /* EOF */ 325 remptr = rembuf; 326 remleft--; 327 return (*remptr++); 328 } 329 330 /* 331 * Read an input line from the remote. Return the number of bytes 332 * stored (equivalent to strlen(p)). If `cleanup' is set, EOF at 333 * the beginning of a line is returned as EOF (-1); other EOFs, or 334 * errors, call cleanup() or lostconn(). In other words, unless 335 * the third argument is nonzero, this routine never returns failure. 336 */ 337 int 338 remline(u_char *buffer, int space, int doclean) 339 { 340 int c, left = space; 341 u_char *p = buffer; 342 343 if (rem_r < 0) { 344 error("Cannot read remote input: Remote descriptor not open."); 345 return(-1); 346 } 347 348 while (left > 0) { 349 if ((c = remc()) < -1) { /* error */ 350 if (doclean) { 351 finish(); 352 /*NOTREACHED*/ 353 } 354 lostconn(); 355 /*NOTREACHED*/ 356 } 357 if (c == -1) { /* got EOF */ 358 if (doclean) { 359 if (left == space) 360 return (-1);/* signal proper EOF */ 361 finish(); /* improper EOF */ 362 /*NOTREACHED*/ 363 } 364 lostconn(); 365 /*NOTREACHED*/ 366 } 367 if (c == '\n') { 368 *p = CNULL; 369 370 if (debug) { 371 static char mbuf[BUFSIZ]; 372 373 (void) snprintf(mbuf, sizeof(mbuf), 374 "<<< Cmd = %c (\\%3.3o) Msg = \"%s\"", 375 buffer[0], buffer[0], 376 buffer + 1); 377 378 debugmsg(DM_PROTO, "%s", mbuf); 379 } 380 381 return (space - left); 382 } 383 *p++ = c; 384 left--; 385 } 386 387 /* this will probably blow the entire session */ 388 error("remote input line too long"); 389 p[-1] = CNULL; /* truncate */ 390 return (space); 391 } 392 393 /* 394 * Non-line-oriented remote read. 395 */ 396 ssize_t 397 readrem(char *p, ssize_t space) 398 { 399 if (remleft <= 0) { 400 /* 401 * Set remote time out alarm. 402 */ 403 (void) signal(SIGALRM, sighandler); 404 (void) alarm(rtimeout); 405 406 remleft = remread(rem_r, rembuf, sizeof(rembuf)); 407 408 (void) alarm(0); 409 remptr = rembuf; 410 } 411 412 if (remleft <= 0) 413 return (remleft); 414 if (remleft < space) 415 space = remleft; 416 417 memcpy(p, remptr, space); 418 419 remptr += space; 420 remleft -= space; 421 422 return (space); 423 } 424 425 /* 426 * Get the user name for the uid. 427 */ 428 char * 429 getusername(uid_t uid, char *file, opt_t opts) 430 { 431 static char buf[100]; 432 static uid_t lastuid = (uid_t)-1; 433 struct passwd *pwd = NULL; 434 435 /* 436 * The value of opts may have changed so we always 437 * do the opts check. 438 */ 439 if (IS_ON(opts, DO_NUMCHKOWNER)) { 440 (void) snprintf(buf, sizeof(buf), ":%u", uid); 441 return(buf); 442 } 443 444 /* 445 * Try to avoid getpwuid() call. 446 */ 447 if (lastuid == uid && buf[0] != '\0' && buf[0] != ':') 448 return(buf); 449 450 lastuid = uid; 451 452 if ((pwd = getpwuid(uid)) == NULL) { 453 if (IS_ON(opts, DO_DEFOWNER) && !isserver) 454 (void) strlcpy(buf, defowner, sizeof(buf)); 455 else { 456 message(MT_WARNING, 457 "%s: No password entry for uid %u", file, uid); 458 (void) snprintf(buf, sizeof(buf), ":%u", uid); 459 } 460 } else { 461 (void) strlcpy(buf, pwd->pw_name, sizeof(buf)); 462 } 463 464 return(buf); 465 } 466 467 /* 468 * Get the group name for the gid. 469 */ 470 char * 471 getgroupname(gid_t gid, char *file, opt_t opts) 472 { 473 static char buf[100]; 474 static gid_t lastgid = (gid_t)-1; 475 struct group *grp = NULL; 476 477 /* 478 * The value of opts may have changed so we always 479 * do the opts check. 480 */ 481 if (IS_ON(opts, DO_NUMCHKGROUP)) { 482 (void) snprintf(buf, sizeof(buf), ":%u", gid); 483 return(buf); 484 } 485 486 /* 487 * Try to avoid getgrgid() call. 488 */ 489 if (lastgid == gid && buf[0] != '\0' && buf[0] != ':') 490 return(buf); 491 492 lastgid = gid; 493 494 if ((grp = (struct group *)getgrgid(gid)) == NULL) { 495 if (IS_ON(opts, DO_DEFGROUP) && !isserver) 496 (void) strlcpy(buf, defgroup, sizeof(buf)); 497 else { 498 message(MT_WARNING, "%s: No name for group %u", 499 file, gid); 500 (void) snprintf(buf, sizeof(buf), ":%u", gid); 501 } 502 } else 503 (void) strlcpy(buf, grp->gr_name, sizeof(buf)); 504 505 return(buf); 506 } 507 508 /* 509 * Read a response from the remote host. 510 */ 511 int 512 response(void) 513 { 514 static u_char resp[BUFSIZ]; 515 u_char *s; 516 int n; 517 518 debugmsg(DM_CALL, "response() start\n"); 519 520 n = remline(s = resp, sizeof(resp), 0); 521 522 n--; 523 switch (*s++) { 524 case C_ACK: 525 debugmsg(DM_PROTO, "received ACK\n"); 526 return(0); 527 case C_LOGMSG: 528 if (n > 0) { 529 message(MT_CHANGE, "%s", s); 530 return(1); 531 } 532 debugmsg(DM_PROTO, "received EMPTY logmsg\n"); 533 return(0); 534 case C_NOTEMSG: 535 if (s) 536 message(MT_NOTICE, "%s", s); 537 return(response()); 538 539 default: 540 s--; 541 n++; 542 /* fall into... */ 543 544 case C_ERRMSG: /* Normal error message */ 545 if (s) 546 message(MT_NERROR, "%s", s); 547 return(-1); 548 549 case C_FERRMSG: /* Fatal error message */ 550 if (s) 551 message(MT_FERROR, "%s", s); 552 finish(); 553 return(-1); 554 } 555 /*NOTREACHED*/ 556 } 557 558 /* 559 * This should be in expand.c but the other routines call other modules 560 * that we don't want to load in. 561 * 562 * Expand file names beginning with `~' into the 563 * user's home directory path name. Return a pointer in buf to the 564 * part corresponding to `file'. 565 */ 566 char * 567 exptilde(char *ebuf, char *file, size_t ebufsize) 568 { 569 char *pw_dir, *rest; 570 size_t len; 571 extern char *homedir; 572 573 if (*file != '~') { 574 notilde: 575 (void) strlcpy(ebuf, file, ebufsize); 576 return(ebuf); 577 } 578 if (*++file == CNULL) { 579 pw_dir = homedir; 580 rest = NULL; 581 } else if (*file == '/') { 582 pw_dir = homedir; 583 rest = file; 584 } else { 585 rest = file; 586 while (*rest && *rest != '/') 587 rest++; 588 if (*rest == '/') 589 *rest = CNULL; 590 else 591 rest = NULL; 592 if (pw == NULL || strcmp(pw->pw_name, file) != 0) { 593 if ((pw = getpwnam(file)) == NULL) { 594 error("%s: unknown user name", file); 595 if (rest != NULL) 596 *rest = '/'; 597 return(NULL); 598 } 599 } 600 if (rest != NULL) 601 *rest = '/'; 602 pw_dir = pw->pw_dir; 603 } 604 if ((len = strlcpy(ebuf, pw_dir, ebufsize)) >= ebufsize) 605 goto notilde; 606 pw_dir = ebuf + len; 607 if (rest != NULL) { 608 pw_dir++; 609 if ((len = strlcat(ebuf, rest, ebufsize)) >= ebufsize) 610 goto notilde; 611 } 612 return(pw_dir); 613 } 614 615 616 617 /* 618 * Set access and modify times of a given file 619 */ 620 int 621 setfiletime(char *file, time_t atime, time_t mtime) 622 { 623 struct timeval tv[2]; 624 625 if (atime != 0 && mtime != 0) { 626 tv[0].tv_sec = atime; 627 tv[1].tv_sec = mtime; 628 tv[0].tv_usec = tv[1].tv_usec = 0; 629 return (utimes(file, tv)); 630 } else /* Set to current time */ 631 return (utimes(file, NULL)); 632 } 633 634 /* 635 * Get version info 636 */ 637 char * 638 getversion(void) 639 { 640 static char buff[BUFSIZ]; 641 642 (void) snprintf(buff, sizeof(buff), 643 "Version %s.%d (%s) - Protocol Version %d, Release %s, Patch level %d", 644 DISTVERSION, PATCHLEVEL, DISTSTATUS, 645 VERSION, DISTVERSION, PATCHLEVEL); 646 647 return(buff); 648 } 649 650 /* 651 * Execute a shell command to handle special cases. 652 * This is now common to both server and client 653 */ 654 void 655 runcommand(char *cmd) 656 { 657 ssize_t nread; 658 pid_t pid, wpid; 659 char *cp, *s; 660 char sbuf[BUFSIZ], buf[BUFSIZ]; 661 int fd[2], status; 662 663 if (pipe(fd) < 0) { 664 error("pipe of %s failed: %s", cmd, SYSERR); 665 return; 666 } 667 668 if ((pid = fork()) == 0) { 669 /* 670 * Return everything the shell commands print. 671 */ 672 (void) close(0); 673 (void) close(1); 674 (void) close(2); 675 (void) open(_PATH_DEVNULL, O_RDONLY); 676 (void) dup(fd[PIPE_WRITE]); 677 (void) dup(fd[PIPE_WRITE]); 678 (void) close(fd[PIPE_READ]); 679 (void) close(fd[PIPE_WRITE]); 680 (void) execl(_PATH_BSHELL, "sh", "-c", cmd, (char *)NULL); 681 _exit(127); 682 } 683 (void) close(fd[PIPE_WRITE]); 684 s = sbuf; 685 *s++ = C_LOGMSG; 686 while ((nread = read(fd[PIPE_READ], buf, sizeof(buf))) > 0) { 687 cp = buf; 688 do { 689 *s++ = *cp++; 690 if (cp[-1] != '\n') { 691 if (s < (char *) &sbuf[sizeof(sbuf)-1]) 692 continue; 693 *s++ = '\n'; 694 } 695 /* 696 * Throw away blank lines. 697 */ 698 if (s == &sbuf[2]) { 699 s--; 700 continue; 701 } 702 if (isserver) 703 (void) xwrite(rem_w, sbuf, s - sbuf); 704 else { 705 *s = CNULL; 706 message(MT_INFO, "%s", sbuf+1); 707 } 708 s = &sbuf[1]; 709 } while (--nread); 710 } 711 if (s > (char *) &sbuf[1]) { 712 *s++ = '\n'; 713 if (isserver) 714 (void) xwrite(rem_w, sbuf, s - sbuf); 715 else { 716 *s = CNULL; 717 message(MT_INFO, "%s", sbuf+1); 718 } 719 } 720 while ((wpid = wait(&status)) != pid && wpid != -1) 721 ; 722 if (wpid == -1) 723 status = -1; 724 (void) close(fd[PIPE_READ]); 725 if (status) 726 error("shell returned %d", status); 727 else if (isserver) 728 ack(); 729 } 730 731 /* 732 * Malloc with error checking 733 */ 734 void * 735 xmalloc(size_t amt) 736 { 737 void *ptr; 738 739 if ((ptr = malloc(amt)) == NULL) 740 fatalerr("Cannot malloc %zu bytes of memory.", amt); 741 742 return (ptr); 743 } 744 745 /* 746 * realloc with error checking 747 */ 748 void * 749 xrealloc(void *baseptr, size_t amt) 750 { 751 void *new; 752 753 if ((new = realloc(baseptr, amt)) == NULL) 754 fatalerr("Cannot realloc %zu bytes of memory.", amt); 755 756 return (new); 757 } 758 759 /* 760 * calloc with error checking 761 */ 762 void * 763 xcalloc(size_t num, size_t esize) 764 { 765 void *ptr; 766 767 if ((ptr = calloc(num, esize)) == NULL) 768 fatalerr("Cannot calloc %zu * %zu = %zu bytes of memory.", 769 num, esize, num * esize); 770 771 return (ptr); 772 } 773 774 /* 775 * Strdup with error checking 776 */ 777 char * 778 xstrdup(const char *str) 779 { 780 size_t len = strlen(str) + 1; 781 char *nstr = xmalloc(len); 782 783 return (memcpy(nstr, str, len)); 784 } 785 786 /* 787 * Private version of basename() 788 */ 789 char * 790 xbasename(char *path) 791 { 792 char *cp; 793 794 if ((cp = strrchr(path, '/')) != NULL) 795 return(cp+1); 796 else 797 return(path); 798 } 799 800 /* 801 * Take a colon (':') separated path to a file and 802 * search until a component of that path is found and 803 * return the found file name. 804 */ 805 char * 806 searchpath(char *path) 807 { 808 char *file; 809 char *space; 810 int found; 811 struct stat statbuf; 812 813 for (found = 0; !found && (file = strsep(&path, ":")) != NULL; ) { 814 if ((space = strchr(file, ' ')) != NULL) 815 *space = CNULL; 816 found = stat(file, &statbuf) == 0; 817 if (space) 818 *space = ' '; /* Put back what we zapped */ 819 } 820 return (file); 821 } 822