static void scriptexec(struct op *tp, const char **ap) { const char *sh; #ifndef MKSH_SMALL int fd; unsigned char buf[68]; #endif union mksh_ccphack args, cap; sh = str_val(global("EXECSHELL")); if (sh && *sh) sh = search_path(sh, path, X_OK, NULL); if (!sh || !*sh) sh = MKSH_DEFAULT_EXECSHELL; *tp->args-- = tp->str; #ifndef MKSH_SMALL if ((fd = binopen2(tp->str, O_RDONLY)) >= 0) { unsigned char *cp; unsigned short m; ssize_t n; /* read first couple of octets from file */ n = read(fd, buf, sizeof(buf) - 1); close(fd); /* read error or short read? */ if (n < 5) goto nomagic; /* terminate buffer */ buf[n] = '\0'; /* skip UTF-8 Byte Order Mark, if present */ cp = buf + (n = ((buf[0] == 0xEF) && (buf[1] == 0xBB) && (buf[2] == 0xBF)) ? 3 : 0); /* scan for newline or NUL (end of buffer) */ while (*cp && *cp != '\n') ++cp; /* if the shebang line is longer than MAXINTERP, bail out */ if (!*cp) goto noshebang; /* replace newline by NUL */ *cp = '\0'; /* restore begin of shebang position (buf+0 or buf+3) */ cp = buf + n; /* bail out if no shebang magic found */ if (cp[0] == '#' && cp[1] == '!') cp += 2; #ifdef __OS2__ else if (!strncmp(cp, Textproc, 7) && (cp[7] == ' ' || cp[7] == '\t')) cp += 8; #endif else goto noshebang; /* skip whitespace before shell name */ while (*cp == ' ' || *cp == '\t') ++cp; /* just whitespace on the line? */ if (*cp == '\0') goto noshebang; /* no, we actually found an interpreter name */ sh = (char *)cp; /* look for end of shell/interpreter name */ while (*cp != ' ' && *cp != '\t' && *cp != '\0') ++cp; /* any arguments? */ if (*cp) { *cp++ = '\0'; /* skip spaces before arguments */ while (*cp == ' ' || *cp == '\t') ++cp; /* pass it all in ONE argument (historic reasons) */ if (*cp) *tp->args-- = (char *)cp; } goto nomagic; noshebang: m = buf[0] << 8 | buf[1]; if (m == 0x7F45 && buf[2] == 'L' && buf[3] == 'F') errorf("%s: not executable: %d-bit ELF file", tp->str, 32 * buf[4]); if ((m == /* OMAGIC */ 0407) || (m == /* NMAGIC */ 0410) || (m == /* ZMAGIC */ 0413) || (m == /* QMAGIC */ 0314) || (m == /* ECOFF_I386 */ 0x4C01) || (m == /* ECOFF_M68K */ 0x0150 || m == 0x5001) || (m == /* ECOFF_SH */ 0x0500 || m == 0x0005) || (m == /* bzip */ 0x425A) || (m == /* "MZ" */ 0x4D5A) || (m == /* "NE" */ 0x4E45) || (m == /* "LX" */ 0x4C58) || (m == /* xz */ 0xFD37 && buf[2] == 'z' && buf[3] == 'X' && buf[4] == 'Z') || (m == /* 7zip */ 0x377A) || (m == /* gzip */ 0x1F8B) || (m == /* .Z */ 0x1F9D)) errorf("%s: not executable: magic %04X", tp->str, m); nomagic: ; } #endif args.ro = tp->args; *args.ro = sh; cap.ro = ap; execve(args.rw[0], args.rw, cap.rw); /* report both the programme that was run and the bogus interpreter */ errorf("%s: %s: %s", tp->str, sh, cstrerror(errno)); }
static void chvt(const Getopt *go) { const char *dv = go->optarg; char *cp = NULL; int fd; switch (*dv) { case '-': dv = "/dev/null"; break; case '!': ++dv; /* FALLTHROUGH */ default: { struct stat sb; if (stat(dv, &sb)) { cp = shf_smprintf("/dev/ttyC%s", dv); dv = cp; if (stat(dv, &sb)) { memmove(cp + 1, cp, /* /dev/tty */ 8); dv = cp + 1; if (stat(dv, &sb)) { errorf("%s: %s: %s", "chvt", "can't find tty", go->optarg); } } } if (!(sb.st_mode & S_IFCHR)) errorf("%s: %s: %s", "chvt", "not a char device", dv); #ifndef MKSH_DISABLE_REVOKE_WARNING #if HAVE_REVOKE if (revoke(dv)) #endif warningf(false, "%s: %s %s", "chvt", "new shell is potentially insecure, can't revoke", dv); #endif } } if ((fd = binopen2(dv, O_RDWR)) < 0) { sleep(1); if ((fd = binopen2(dv, O_RDWR)) < 0) { errorf("%s: %s %s", "chvt", "can't open", dv); } } if (go->optarg[0] != '!') { switch (fork()) { case -1: errorf("%s: %s %s", "chvt", "fork", "failed"); case 0: break; default: exit(0); } } if (setsid() == -1) errorf("%s: %s %s", "chvt", "setsid", "failed"); if (go->optarg[0] != '-') { if (ioctl(fd, TIOCSCTTY, NULL) == -1) errorf("%s: %s %s", "chvt", "TIOCSCTTY", "failed"); if (tcflush(fd, TCIOFLUSH)) errorf("%s: %s %s", "chvt", "TCIOFLUSH", "failed"); } ksh_dup2(fd, 0, false); ksh_dup2(fd, 1, false); ksh_dup2(fd, 2, false); if (fd > 2) close(fd); rndset((unsigned long)chvt_rndsetup(go, sizeof(Getopt))); chvt_reinit(); }
int main(int argc, char **argv) { const char *tmpdir; size_t tdlen; /* may not be a constant, thus initialising early */ listf = stderr; now = time(NULL); /* * Keep a reference to cwd, so we can always come back home. */ cwdfd = binopen2(BO_CLEXEC, ".", O_RDONLY); if (cwdfd < 0) { syswarn(1, errno, "Cannot open current working directory."); return(exit_val); } /* * Where should we put temporary files? */ if ((tmpdir = getenv("TMPDIR")) == NULL || *tmpdir == '\0') tmpdir = _PATH_TMP; tdlen = strlen(tmpdir); while (tdlen > 0 && tmpdir[tdlen - 1] == '/') tdlen--; tempfile = malloc(tdlen + 1 + sizeof(_TFILE_BASE)); if (tempfile == NULL) { paxwarn(1, "%s for %s", "Out of memory", "temp file name"); return (exit_val); } if (tdlen) memcpy(tempfile, tmpdir, tdlen); tempbase = tempfile + tdlen; *tempbase++ = '/'; #if HAVE_SETPGENT /* * keep passwd and group files open for faster lookups. */ setpassent(1); setgroupent(1); #endif /* * parse options, determine operational mode, general init */ options(argc, argv); if ((gen_init() < 0) || (tty_init() < 0)) return(exit_val); #if HAVE_PLEDGE /* * pmode needs to restore setugid bits when extracting or copying, * so can't pledge at all then. */ if (pmode == 0 || (act != EXTRACT && act != COPY)) { if (pledge("stdio rpath wpath cpath fattr dpath getpw proc exec tape", NULL) == -1) err(1, "pledge"); /* Copy mode, or no gzip -- don't need to fork/exec. */ if (compress_program == NULL || act == COPY) { if (pledge("stdio rpath wpath cpath fattr dpath getpw tape", NULL) == -1) err(1, "pledge"); } } #endif /* make list fd independent and line-buffered */ if ((listfd = dup(fileno(listf))) < 0 || !(listf = fdopen(listfd, "wb"))) { syswarn(1, errno, "Cannot open list file descriptor"); return (exit_val); } if (fcntl(listfd, F_SETFD, FD_CLOEXEC) == -1) syswarn(0, errno, "%s on list file descriptor", "Failed to set the close-on-exec flag"); setlinebuf(listf); /* * select a primary operation mode */ switch (act) { case EXTRACT: extract(); break; case ARCHIVE: archive(); break; case APPND: if (compress_program != NULL) errx(1, "cannot compress while appending"); append(); break; case COPY: copy(); break; default: /* for ar_io.c etc. */ act = LIST; /* FALLTHROUGH */ case LIST: list(); break; } return(exit_val); }