1 /* $OpenBSD: common.c,v 1.11 2001/07/09 07:04:51 deraadt 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. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #ifndef lint 37 #if 0 38 static char RCSid[] = 39 "$From: common.c,v 6.82 1998/03/23 23:27:33 michaelc Exp $"; 40 #else 41 static char RCSid[] = 42 "$OpenBSD: common.c,v 1.11 2001/07/09 07:04:51 deraadt Exp $"; 43 #endif 44 45 static char sccsid[] = "@(#)common.c"; 46 47 static char copyright[] = 48 "@(#) Copyright (c) 1983 Regents of the University of California.\n\ 49 All rights reserved.\n"; 50 #endif /* !lint */ 51 52 /* 53 * Things common to both the client and server. 54 */ 55 56 #include "defs.h" 57 #if defined(NEED_UTIME_H) 58 #include <utime.h> 59 #endif /* defined(NEED_UTIME_H) */ 60 #include <sys/socket.h> 61 #include <sys/wait.h> 62 63 /* 64 * Variables common to both client and server 65 */ 66 char host[MAXHOSTNAMELEN]; /* Name of this host */ 67 UID_T userid = (UID_T)-1; /* User's UID */ 68 GID_T groupid = (GID_T)-1; /* User's GID */ 69 char *homedir = NULL; /* User's $HOME */ 70 char *locuser = NULL; /* Local User's name */ 71 int isserver = FALSE; /* We're the server */ 72 int amchild = 0; /* This PID is a child */ 73 int do_fork = 1; /* Fork child process */ 74 char *currenthost = NULL; /* Current client hostname */ 75 char *progname = NULL; /* Name of this program */ 76 int rem_r = -1; /* Client file descriptor */ 77 int rem_w = -1; /* Client file descriptor */ 78 struct passwd *pw = NULL; /* Local user's pwd entry */ 79 int contimedout = FALSE; /* Connection timed out */ 80 int proto_version = -1; /* Protocol version */ 81 int rtimeout = RTIMEOUT; /* Response time out */ 82 jmp_buf finish_jmpbuf; /* Finish() jmp buffer */ 83 int setjmp_ok = FALSE; /* setjmp()/longjmp() status */ 84 char **realargv; /* Real main() argv */ 85 int realargc; /* Real main() argc */ 86 opt_t options = 0; /* Global install options */ 87 88 /* 89 * Front end to write() that handles partial write() requests. 90 */ 91 extern WRITE_RETURN_T xwrite(fd, buf, len) 92 int fd; 93 void *buf; 94 WRITE_AMT_T len; 95 { 96 WRITE_AMT_T nleft = len; 97 WRITE_RETURN_T nwritten; 98 register char *ptr = buf; 99 100 while (nleft > 0) { 101 if ((nwritten = write(fd, ptr, nleft)) <= 0) { 102 return nwritten; 103 } 104 nleft -= nwritten; 105 ptr += nwritten; 106 } 107 108 return len; 109 } 110 111 /* 112 * Set program name 113 */ 114 extern void setprogname(argv) 115 char **argv; 116 { 117 register char *cp; 118 119 if (!progname) { 120 progname = xstrdup(argv[0]); 121 if ((cp = strrchr(progname, '/'))) 122 progname = cp + 1; 123 } 124 } 125 126 /* 127 * Do run-time initialization 128 */ 129 extern int init(argc, argv, envp) 130 /*ARGSUSED*/ 131 int argc; 132 char **argv; 133 char **envp; 134 { 135 register int i; 136 register char *cp; 137 138 if (!isserver) 139 (void) signal(SIGSEGV, sighandler); 140 141 setprogname(argv); 142 143 /* 144 * Save a copy of our argc and argv before setargs() overwrites them 145 */ 146 realargc = argc; 147 realargv = (char **) xmalloc(sizeof(char *) * (argc+1)); 148 for (i = 0; i < argc; i++) 149 realargv[i] = xstrdup(argv[i]); 150 151 #if defined(SETARGS) 152 setargs_settup(argc, argv, envp); 153 #endif /* SETARGS */ 154 155 pw = getpwuid(userid = getuid()); 156 if (pw == NULL) { 157 error("Your user id (%d) is not known to this system.", 158 getuid()); 159 return(-1); 160 } 161 162 debugmsg(DM_MISC, "UserID = %d pwname = '%s' home = '%s'\n", 163 userid, pw->pw_name, pw->pw_dir); 164 homedir = xstrdup(pw->pw_dir); 165 locuser = xstrdup(pw->pw_name); 166 groupid = pw->pw_gid; 167 gethostname(host, sizeof(host)); 168 if ((cp = strchr(host, '.')) != NULL) 169 *cp = CNULL; 170 171 /* 172 * If we're not root, disable paranoid ownership checks 173 * since normal users cannot chown() files. 174 */ 175 if (!isserver && userid != 0) { 176 FLAG_ON(options, DO_NOCHKOWNER); 177 FLAG_ON(options, DO_NOCHKGROUP); 178 } 179 180 return(0); 181 } 182 183 /* 184 * Finish things up before ending. 185 */ 186 extern void finish() 187 { 188 extern jmp_buf finish_jmpbuf; 189 190 debugmsg(DM_CALL, 191 "finish() called: do_fork = %d amchild = %d isserver = %d", 192 do_fork, amchild, isserver); 193 cleanup(); 194 195 /* 196 * There's no valid finish_jmpbuf for the rdist master parent. 197 */ 198 if (!do_fork || amchild || isserver) { 199 200 if (!setjmp_ok) { 201 #ifdef DEBUG_SETJMP 202 error("attemping longjmp() without target"); 203 abort(); 204 #else 205 exit(1); 206 #endif 207 } 208 209 longjmp(finish_jmpbuf, 1); 210 /*NOTREACHED*/ 211 error("Unexpected failure of longjmp() in finish()"); 212 exit(2); 213 } else 214 exit(1); 215 } 216 217 /* 218 * Handle lost connections 219 */ 220 extern void lostconn() 221 { 222 /* Prevent looping */ 223 (void) signal(SIGPIPE, SIG_IGN); 224 225 rem_r = rem_w = -1; /* Ensure we don't try to send to server */ 226 checkhostname(); 227 error("Lost connection to %s", 228 (currenthost) ? currenthost : "(unknown)"); 229 230 finish(); 231 } 232 233 /* 234 * Do a core dump 235 */ 236 extern void coredump() 237 { 238 error("Segmentation violation - dumping core [PID = %d, %s]", 239 getpid(), 240 (isserver) ? "isserver" : ((amchild) ? "amchild" : "parent")); 241 abort(); 242 /*NOTREACHED*/ 243 fatalerr("Abort failed - no core dump. Exiting..."); 244 } 245 246 /* 247 * General signal handler 248 */ 249 extern void sighandler(sig) 250 int sig; 251 { 252 int save_errno = errno; 253 254 debugmsg(DM_CALL, "sighandler() received signal %d\n", sig); 255 256 switch (sig) { 257 case SIGALRM: 258 contimedout = TRUE; 259 checkhostname(); 260 error("Response time out"); 261 finish(); 262 break; 263 264 case SIGPIPE: 265 lostconn(); 266 break; 267 268 case SIGFPE: 269 debug = !debug; 270 break; 271 272 case SIGSEGV: 273 coredump(); 274 break; 275 276 case SIGHUP: 277 case SIGINT: 278 case SIGQUIT: 279 case SIGTERM: 280 finish(); 281 break; 282 283 default: 284 fatalerr("No signal handler defined for signal %d.", sig); 285 } 286 errno = save_errno; 287 } 288 289 /* 290 * Function to actually send the command char and message to the 291 * remote host. 292 */ 293 static int sendcmdmsg(cmd, msg) 294 char cmd; 295 char *msg; 296 { 297 int len; 298 299 if (rem_w < 0) 300 return(-1); 301 302 /* 303 * All commands except C_NONE should have a newline 304 */ 305 if (cmd != C_NONE && !strchr(msg + 1, '\n')) 306 (void) strcat(msg + 1, "\n"); 307 308 if (cmd == C_NONE) 309 len = strlen(msg); 310 else { 311 len = strlen(msg + 1) + 1; 312 msg[0] = cmd; 313 } 314 315 debugmsg(DM_PROTO, ">>> Cmd = %c (\\%3.3o) Msg = \"%.*s\"", 316 cmd, cmd, 317 (cmd == C_NONE) ? len-1 : len-2, 318 (cmd == C_NONE) ? msg : msg + 1); 319 320 return(!(xwrite(rem_w, msg, len) == len)); 321 } 322 323 /* 324 * Send a command message to the remote host. 325 * Called as sendcmd(char cmdchar, char *fmt, arg1, arg2, ...) 326 * The fmt and arg? arguments are optional. 327 */ 328 #if defined(ARG_TYPE) && ARG_TYPE == ARG_STDARG 329 /* 330 * Stdarg frontend to sendcmdmsg() 331 */ 332 extern int sendcmd(char cmd, char *fmt, ...) 333 { 334 static char buf[BUFSIZ]; 335 va_list args; 336 337 va_start(args, fmt); 338 if (fmt) 339 (void) vsprintf((cmd == C_NONE) ? buf : buf + 1, fmt, args); 340 else 341 buf[1] = CNULL; 342 va_end(args); 343 344 return(sendcmdmsg(cmd, buf)); 345 } 346 #endif /* ARG_TYPE == ARG_STDARG */ 347 348 #if defined(ARG_TYPE) && ARG_TYPE == ARG_VARARGS 349 /* 350 * Varargs frontend to sendcmdmsg() 351 */ 352 extern int sendcmd(va_alist) 353 va_dcl 354 { 355 static char buf[BUFSIZ]; 356 va_list args; 357 char cmd; 358 char *fmt; 359 360 va_start(args); 361 /* XXX The "int" is necessary as a workaround for broken varargs */ 362 cmd = (char) va_arg(args, int); 363 fmt = va_arg(args, char *); 364 if (fmt) 365 (void) vsprintf((cmd == C_NONE) ? buf : buf + 1, fmt, args); 366 else 367 buf[1] = CNULL; 368 va_end(args); 369 370 return(sendcmdmsg(cmd, buf)); 371 } 372 #endif /* ARG_TYPE == ARG_VARARGS */ 373 374 #if !defined(ARG_TYPE) 375 /* 376 * Stupid frontend to sendcmdmsg() 377 */ 378 /*VARARGS2*/ 379 extern int sendcmd(cmd, fmt, a1, a2, a3, a4, a5, a6, a7, a8) 380 char cmd; 381 char *fmt; 382 { 383 static char buf[BUFSIZ]; 384 385 if (fmt) 386 (void) sprintf((cmd == C_NONE) ? buf : buf + 1, 387 fmt, a1, a2, a3, a4, a5, a6, a7, a8); 388 else 389 buf[1] = CNULL; 390 391 return(sendcmdmsg(cmd, buf)); 392 } 393 #endif /* !ARG_TYPE */ 394 395 /* 396 * Internal variables and routines for reading lines from the remote. 397 */ 398 static u_char rembuf[BUFSIZ]; 399 static u_char *remptr; 400 static int remleft; 401 402 #define remc() (--remleft < 0 ? remmore() : *remptr++) 403 404 /* 405 * Back end to remote read() 406 */ 407 static int remread(fd, buf, bufsiz) 408 int fd; 409 u_char *buf; 410 int bufsiz; 411 { 412 return(read(fd, (char *)buf, bufsiz)); 413 } 414 415 static int remmore() 416 { 417 (void) signal(SIGALRM, sighandler); 418 (void) alarm(rtimeout); 419 420 remleft = remread(rem_r, rembuf, sizeof(rembuf)); 421 422 (void) alarm(0); 423 424 if (remleft < 0) 425 return (-2); /* error */ 426 if (remleft == 0) 427 return (-1); /* EOF */ 428 remptr = rembuf; 429 remleft--; 430 return (*remptr++); 431 } 432 433 /* 434 * Read an input line from the remote. Return the number of bytes 435 * stored (equivalent to strlen(p)). If `cleanup' is set, EOF at 436 * the beginning of a line is returned as EOF (-1); other EOFs, or 437 * errors, call cleanup() or lostconn(). In other words, unless 438 * the third argument is nonzero, this routine never returns failure. 439 */ 440 extern int remline(buffer, space, doclean) 441 register u_char *buffer; 442 int space; 443 int doclean; 444 { 445 register int c, left = space; 446 register u_char *p = buffer; 447 448 if (rem_r < 0) { 449 error("Cannot read remote input: Remote descriptor not open."); 450 return(-1); 451 } 452 453 while (left > 0) { 454 if ((c = remc()) < -1) { /* error */ 455 if (doclean) { 456 finish(); 457 /*NOTREACHED*/ 458 } 459 lostconn(); 460 /*NOTREACHED*/ 461 } 462 if (c == -1) { /* got EOF */ 463 if (doclean) { 464 if (left == space) 465 return (-1);/* signal proper EOF */ 466 finish(); /* improper EOF */ 467 /*NOTREACHED*/ 468 } 469 lostconn(); 470 /*NOTREACHED*/ 471 } 472 if (c == '\n') { 473 *p = CNULL; 474 475 if (debug) { 476 static char mbuf[BUFSIZ]; 477 478 (void) sprintf(mbuf, 479 "<<< Cmd = %c (\\%3.3o) Msg = \"%s\"", 480 buffer[0], buffer[0], 481 buffer + 1); 482 483 debugmsg(DM_PROTO, "%s", mbuf); 484 } 485 486 return (space - left); 487 } 488 *p++ = c; 489 left--; 490 } 491 492 /* this will probably blow the entire session */ 493 error("remote input line too long"); 494 p[-1] = CNULL; /* truncate */ 495 return (space); 496 } 497 498 /* 499 * Non-line-oriented remote read. 500 */ 501 int 502 readrem(p, space) 503 char *p; 504 register int space; 505 { 506 if (remleft <= 0) { 507 /* 508 * Set remote time out alarm. 509 */ 510 (void) signal(SIGALRM, sighandler); 511 (void) alarm(rtimeout); 512 513 remleft = remread(rem_r, rembuf, sizeof(rembuf)); 514 515 (void) alarm(0); 516 remptr = rembuf; 517 } 518 519 if (remleft <= 0) 520 return (remleft); 521 if (remleft < space) 522 space = remleft; 523 524 bcopy((char *) remptr, p, space); 525 526 remptr += space; 527 remleft -= space; 528 529 return (space); 530 } 531 532 /* 533 * Get the user name for the uid. 534 */ 535 extern char *getusername(uid, file, opts) 536 UID_T uid; 537 char *file; 538 opt_t opts; 539 { 540 static char buf[100]; 541 static UID_T lastuid = (UID_T)-1; 542 struct passwd *pwd = NULL; 543 544 /* 545 * The value of opts may have changed so we always 546 * do the opts check. 547 */ 548 if (IS_ON(opts, DO_NUMCHKOWNER)) { 549 (void) sprintf(buf, ":%d", uid); 550 return(buf); 551 } 552 553 /* 554 * Try to avoid getpwuid() call. 555 */ 556 if (lastuid == uid && buf[0] != '\0' && buf[0] != ':') 557 return(buf); 558 559 lastuid = uid; 560 561 if ((pwd = getpwuid(uid)) == NULL) { 562 message(MT_WARNING, 563 "%s: No password entry for uid %d", file, uid); 564 (void) sprintf(buf, ":%d", uid); 565 } else 566 (void) strcpy(buf, pwd->pw_name); 567 568 return(buf); 569 } 570 571 /* 572 * Get the group name for the gid. 573 */ 574 extern char *getgroupname(gid, file, opts) 575 GID_T gid; 576 char *file; 577 opt_t opts; 578 { 579 static char buf[100]; 580 static GID_T lastgid = (GID_T)-1; 581 struct group *grp = NULL; 582 583 /* 584 * The value of opts may have changed so we always 585 * do the opts check. 586 */ 587 if (IS_ON(opts, DO_NUMCHKGROUP)) { 588 (void) sprintf(buf, ":%d", gid); 589 return(buf); 590 } 591 592 /* 593 * Try to avoid getgrgid() call. 594 */ 595 if (lastgid == gid && buf[0] != '\0' && buf[0] != ':') 596 return(buf); 597 598 lastgid = gid; 599 600 if ((grp = (struct group *)getgrgid(gid)) == NULL) { 601 message(MT_WARNING, "%s: No name for group %d", file, gid); 602 (void) sprintf(buf, ":%d", gid); 603 } else 604 (void) strcpy(buf, grp->gr_name); 605 606 return(buf); 607 } 608 609 /* 610 * Read a response from the remote host. 611 */ 612 extern int response() 613 { 614 static u_char resp[BUFSIZ]; 615 u_char *s; 616 int n; 617 618 debugmsg(DM_CALL, "response() start\n"); 619 620 n = remline(s = resp, sizeof(resp), 0); 621 622 n--; 623 switch (*s++) { 624 case C_ACK: 625 debugmsg(DM_PROTO, "received ACK\n"); 626 return(0); 627 case C_LOGMSG: 628 if (n > 0) { 629 message(MT_CHANGE, "%s", s); 630 return(1); 631 } 632 debugmsg(DM_PROTO, "received EMPTY logmsg\n"); 633 return(0); 634 case C_NOTEMSG: 635 if (s) 636 message(MT_NOTICE, "%s", s); 637 return(response()); 638 639 default: 640 s--; 641 n++; 642 /* fall into... */ 643 644 case C_ERRMSG: /* Normal error message */ 645 if (s) 646 message(MT_NERROR, "%s", s); 647 return(-1); 648 649 case C_FERRMSG: /* Fatal error message */ 650 if (s) 651 message(MT_FERROR, "%s", s); 652 finish(); 653 } 654 /*NOTREACHED*/ 655 } 656 657 /* 658 * This should be in expand.c but the other routines call other modules 659 * that we don't want to load in. 660 * 661 * Expand file names beginning with `~' into the 662 * user's home directory path name. Return a pointer in buf to the 663 * part corresponding to `file'. 664 */ 665 extern char *exptilde(ebuf, file) 666 char *ebuf; 667 register char *file; 668 { 669 register char *s1, *s2, *s3; 670 extern char *homedir; 671 672 if (*file != '~') { 673 (void) strcpy(ebuf, file); 674 return(ebuf); 675 } 676 if (*++file == CNULL) { 677 s2 = homedir; 678 s3 = NULL; 679 } else if (*file == '/') { 680 s2 = homedir; 681 s3 = file; 682 } else { 683 s3 = file; 684 while (*s3 && *s3 != '/') 685 s3++; 686 if (*s3 == '/') 687 *s3 = CNULL; 688 else 689 s3 = NULL; 690 if (pw == NULL || strcmp(pw->pw_name, file) != 0) { 691 if ((pw = getpwnam(file)) == NULL) { 692 error("%s: unknown user name", file); 693 if (s3 != NULL) 694 *s3 = '/'; 695 return(NULL); 696 } 697 } 698 if (s3 != NULL) 699 *s3 = '/'; 700 s2 = pw->pw_dir; 701 } 702 for (s1 = ebuf; (*s1++ = *s2++); ) 703 ; 704 s2 = --s1; 705 if (s3 != NULL) { 706 s2++; 707 while ((*s1++ = *s3++)) 708 ; 709 } 710 return(s2); 711 } 712 713 #if defined(DIRECT_RCMD) 714 /* 715 * Set our effective user id to the user running us. 716 * This should be the uid we do most of our work as. 717 */ 718 extern int becomeuser() 719 { 720 int r = 0; 721 722 #if defined(HAVE_SAVED_IDS) 723 r = seteuid(userid); 724 #else 725 r = setreuid(0, userid); 726 #endif /* HAVE_SAVED_IDS */ 727 728 if (r < 0) 729 error("becomeuser %d failed: %s (ruid = %d euid = %d)", 730 userid, SYSERR, getuid(), geteuid()); 731 732 return(r); 733 } 734 #endif /* DIRECT_RCMD */ 735 736 #if defined(DIRECT_RCMD) 737 /* 738 * Set our effective user id to "root" (uid = 0) 739 */ 740 extern int becomeroot() 741 { 742 int r = 0; 743 744 #if defined(HAVE_SAVED_IDS) 745 r = seteuid(0); 746 #else 747 r = setreuid(userid, 0); 748 #endif /* HAVE_SAVED_IDS */ 749 750 if (r < 0) 751 error("becomeroot failed: %s (ruid = %d euid = %d)", 752 SYSERR, getuid(), geteuid()); 753 754 return(r); 755 } 756 #endif /* DIRECT_RCMD */ 757 758 /* 759 * Set access and modify times of a given file 760 */ 761 extern int setfiletime(file, atime, mtime) 762 char *file; 763 time_t atime; 764 time_t mtime; 765 { 766 #if SETFTIME_TYPE == SETFTIME_UTIMES 767 struct timeval tv[2]; 768 769 if (atime != 0 && mtime != 0) { 770 tv[0].tv_sec = atime; 771 tv[1].tv_sec = mtime; 772 tv[0].tv_usec = tv[1].tv_usec = (time_t) 0; 773 return(utimes(file, tv)); 774 } else /* Set to current time */ 775 return(utimes(file, NULL)); 776 777 #endif /* SETFTIME_UTIMES */ 778 779 #if SETFTIME_TYPE == SETFTIME_UTIME 780 struct utimbuf utbuf; 781 782 if (atime != 0 && mtime != 0) { 783 utbuf.actime = atime; 784 utbuf.modtime = mtime; 785 return(utime(file, &utbuf)); 786 } else /* Set to current time */ 787 return(utime(file, NULL)); 788 #endif /* SETFTIME_UTIME */ 789 790 #if !defined(SETFTIME_TYPE) 791 There is no "SETFTIME_TYPE" defined! 792 #endif /* SETFTIME_TYPE */ 793 } 794 795 /* 796 * Get version info 797 */ 798 extern char *getversion() 799 { 800 static char buff[BUFSIZ]; 801 802 (void) sprintf(buff, 803 "Version %s.%d (%s) - Protocol Version %d, Release %s, Patch level %d", 804 DISTVERSION, PATCHLEVEL, DISTSTATUS, 805 VERSION, DISTVERSION, PATCHLEVEL); 806 807 return(buff); 808 } 809 810 /* 811 * Execute a shell command to handle special cases. 812 * This is now common to both server and client 813 */ 814 void runcommand(cmd) 815 char *cmd; 816 { 817 int fd[2], pid, i; 818 int status; 819 register char *cp, *s; 820 char sbuf[BUFSIZ], buf[BUFSIZ]; 821 822 if (pipe(fd) < 0) { 823 error("pipe of %s failed: %s", cmd, SYSERR); 824 return; 825 } 826 827 if ((pid = fork()) == 0) { 828 /* 829 * Return everything the shell commands print. 830 */ 831 (void) close(0); 832 (void) close(1); 833 (void) close(2); 834 (void) open(_PATH_DEVNULL, O_RDONLY); 835 (void) dup(fd[PIPE_WRITE]); 836 (void) dup(fd[PIPE_WRITE]); 837 (void) close(fd[PIPE_READ]); 838 (void) close(fd[PIPE_WRITE]); 839 (void) execl(_PATH_BSHELL, "sh", "-c", cmd, (char *)NULL); 840 _exit(127); 841 } 842 (void) close(fd[PIPE_WRITE]); 843 s = sbuf; 844 *s++ = C_LOGMSG; 845 while ((i = read(fd[PIPE_READ], buf, sizeof(buf))) > 0) { 846 cp = buf; 847 do { 848 *s++ = *cp++; 849 if (cp[-1] != '\n') { 850 if (s < (char *) &sbuf[sizeof(sbuf)-1]) 851 continue; 852 *s++ = '\n'; 853 } 854 /* 855 * Throw away blank lines. 856 */ 857 if (s == &sbuf[2]) { 858 s--; 859 continue; 860 } 861 if (isserver) 862 (void) xwrite(rem_w, sbuf, s - sbuf); 863 else { 864 *s = CNULL; 865 message(MT_INFO, "%s", sbuf+1); 866 } 867 s = &sbuf[1]; 868 } while (--i); 869 } 870 if (s > (char *) &sbuf[1]) { 871 *s++ = '\n'; 872 if (isserver) 873 (void) xwrite(rem_w, sbuf, s - sbuf); 874 else { 875 *s = CNULL; 876 message(MT_INFO, "%s", sbuf+1); 877 } 878 } 879 while ((i = wait(&status)) != pid && i != -1) 880 ; 881 if (i == -1) 882 status = -1; 883 (void) close(fd[PIPE_READ]); 884 if (status) 885 error("shell returned %d", status); 886 else if (isserver) 887 ack(); 888 } 889 890 /* 891 * Malloc with error checking 892 */ 893 char *xmalloc(amt) 894 int amt; 895 { 896 char *ptr; 897 extern POINTER *malloc(); 898 899 if ((ptr = (char *)malloc(amt)) == NULL) 900 fatalerr("Cannot malloc %d bytes of memory.", amt); 901 902 return(ptr); 903 } 904 905 /* 906 * realloc with error checking 907 */ 908 char *xrealloc(baseptr, amt) 909 char *baseptr; 910 unsigned int amt; 911 { 912 char *new; 913 extern POINTER *realloc(); 914 915 if ((new = (char *)realloc(baseptr, amt)) == NULL) 916 fatalerr("Cannot realloc %d bytes of memory.", amt); 917 918 return(new); 919 } 920 921 /* 922 * calloc with error checking 923 */ 924 char *xcalloc(num, esize) 925 unsigned num; 926 unsigned esize; 927 { 928 char *ptr; 929 extern POINTER *calloc(); 930 931 if ((ptr = (char *)calloc(num, esize)) == NULL) 932 fatalerr("Cannot calloc %d * %d = %d bytes of memory.", 933 num, esize, num * esize); 934 935 return(ptr); 936 } 937 938 /* 939 * Strdup with error checking 940 */ 941 char *xstrdup(str) 942 char *str; 943 { 944 char *nstr; 945 946 if ((nstr = strdup(str)) == NULL) 947 fatalerr("Cannot malloc %d bytes of memory.", strlen(str) + 1); 948 949 return(nstr); 950 } 951 952 /* 953 * Private version of basename() 954 */ 955 extern char *xbasename(path) 956 char *path; 957 { 958 register char *cp; 959 960 if ((cp = strrchr(path, '/'))) 961 return(cp+1); 962 else 963 return(path); 964 } 965 966 /* 967 * Take a colon (':') separated path to a file and 968 * search until a component of that path is found and 969 * return the found file name. 970 */ 971 extern char *searchpath(path) 972 char *path; 973 { 974 register char *cp; 975 register char *file; 976 struct stat statbuf; 977 978 for (; ;) { 979 if (!path) 980 return(NULL); 981 file = path; 982 cp = strchr(path, ':'); 983 if (cp) { 984 path = cp + 1; 985 *cp = CNULL; 986 } else 987 path = NULL; 988 if (stat(file, &statbuf) == 0) 989 return(file); 990 /* Put back what we zapped */ 991 if (path) 992 *cp = ':'; 993 } 994 } 995 996 /* 997 * Set line buffering. 998 */ 999 extern void 1000 mysetlinebuf(fp) 1001 FILE *fp; 1002 { 1003 #if SETBUF_TYPE == SETBUF_SETLINEBUF 1004 setlinebuf(fp); 1005 #endif /* SETBUF_SETLINEBUF */ 1006 #if SETBUF_TYPE == SETBUF_SETVBUF 1007 setvbuf(stdout, NULL, _IOLBF, BUFSIZ); 1008 #endif /* SETBUF_SETVBUF */ 1009 #if !defined(SETBUF_TYPE) 1010 No SETBUF_TYPE is defined! 1011 #endif /* SETBUF_TYPE */ 1012 } 1013 1014 /* 1015 * Our interface to system call to get a socket pair. 1016 */ 1017 int 1018 getsocketpair(domain, type, protocol, sv) 1019 int domain; 1020 int type; 1021 int protocol; 1022 int sv[]; 1023 { 1024 #if SOCKPAIR_TYPE == SOCKPAIR_SOCKETPAIR 1025 return(socketpair(domain, type, protocol, sv)); 1026 #endif /* SOCKPAIR_SOCKETPAIR */ 1027 #if SOCKPAIR_TYPE == SOCKPAIR_SPIPE 1028 return(spipe(sv)); 1029 #endif /* SOCKPAIR_SPIPE */ 1030 #if !defined(SOCKPAIR_TYPE) 1031 No SOCKPAIR_TYPE is defined! 1032 #endif /* SOCKPAIR_TYPE */ 1033 } 1034