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