Path: utzoo!attcan!uunet!cs.utexas.edu!samsung!munnari.oz.au!metro!usage.csd.unsw.oz.au!ccadfa!rodos2!wkt From: wkt@rodos2.cs.adfa.oz.au (Warren Toomey) Newsgroups: alt.sources.d Subject: Re: Beyond shar (Re: shars and security concerns.) Summary: code fast Message-ID: <1586@ccadfa.adfa.oz.au> Date: 1 Jun 90 04:54:27 GMT References: <15520@bfmny0.UU.NET> <18123@well.sf.ca.us> <1990May29.043552.15964@zorch.SF-Bay.ORG> Sender: news@ccadfa.adfa.oz.au Lines: 366 In article [...], xanthian@zorch.SF-Bay.ORG (Kent Paul Dolan) writes: > > Beyond that, shar is widely used to port sources away from Unix (granted > zoo is more appropriate, shar's _are_ human readable), and "tar" is not > often available on the target systems. > > I have, for example, many files ported to my Amiga in shar format, and > an "unshar" program that imitates the actions of "sh" well enough to unpack > most common shar output. Sorry, I just stumbled onto this thread, viz. shar files being a security hole. Below is a quick little hack of an unshar, which can unshar files that used cat, sed & gres, but doesn't invoke a shell. There are two main options: -t to show a table of contents (nice) & -x to extract a particular file. It was originally posted in the [comp.os.minix] newsgroup, but compiles under Unix & QuickC aka MS-DOS (you need getopt!). It's primitive, but security holes are minimal. Warren Toomey ------ echo x - unshar.c sed '/^X/s///' > unshar.c << '/' X/* unshar - extract files from a shell archive Author: Warren Toomey */ X X X/* Unshar - extract files from shell archive X * X * Written by Warren Toomey [wkt@cs.adfa.oz.au@munnari.oz@uunet.uu.net] You may X * freely copy or give away this source as long as this notice remains X * intact. X * X * Definitions used by unshar X */ X X X#include X X/* Methods of unsharing */ X#define UNKNOWN 0 X#define BRUTAL 1 X X/* Whitespace indicators */ X#define WHITE 0 X#define NOWHITE 1 X X/* Leading character indicators */ X#define NOX 0 X#define YESX 1 X X/* Emulation types available */ X X#define NUMTOKS 4 /* Must change NUMTOKS to equal the */ X /* Define UNKNOWN 0 *//* number of emulation types */ X#define SED 1 X#define GRES 2 X#define CAT 3 X X/* The list of emulation types. */ Xstatic char *token[NUMTOKS]= X{ X "", X "sed", X "gres", X "cat" X}; X X X/* Misc. constants */ X#define BUFSIZE 512 /* Size of line buffer */ X X/* Global variables */ Xint table; /* Generate a table, or extract */ Xint verbose; /* Unshar verbosely - debugging */ Xint numext; /* Number of files to extract */ Xint binfile; /* Binary file - err indicator */ Xchar *exfile[100]; /* Files to extract */ X X X#define getline(x,y) fgetline(stdin,x,y) X Xint fgetline(zin, how, buf) /* Get a line from a file */ XFILE *zin; Xint how; /* Ignore leading whitespace if */ Xchar *buf; /* how == NOWHITE */ X{ X int ch = 0; X X *buf = 0; /* Null the buffer */ X if (how == NOWHITE) { /* If skip any whitespace */ X while (((ch = fgetc(zin)) == ' ') || (ch == '\t')); X if (ch == EOF) return(EOF); /* Returning EOF or 0 */ X if (ch == '\n') return (0); X *buf++ = ch; /* Put char in buffer */ X } X while ((ch = fgetc(zin)) != '\n') { /* Now get the line */ X if (ch == EOF) { X *buf = 0; X return(EOF); X } X if (ch > 127) { X binfile = 1; X return(0); X } X *buf++ = ch; X } X X *buf = 0; /* Finally null-terminate the buffer */ X return(0); /* and return */ X} X X X Xchar *getstring(buf) /* Get the next string from the buffer */ Xchar *buf; /* ignoring any quotes */ X{ X char out[BUFSIZE]; X char *temp = out; X char inquotes = 0, ok = 1; X while ((*buf == ' ') || (*buf == '\t')) X buf++; /* Skip whitespace */ X X if (verbose) printf("In getstring...\n"); X *temp = 0; X while (ok) { /* Parse line */ X switch (*buf) { X case '\"': X case '\'': X buf++; X inquotes = !inquotes; /* Toggle inquotes */ X break; X case 0: X case '\n': /* Stop on <, >, NULL */ X case '>': /* \n, and sometimes */ X case '<': ok = 0; break; /* space & tab */ X case '\t': X case ' ': X if (!inquotes) ok = 0; X case '\\': X if (!inquotes) {/* Ignore backquotes */ X buf++; X break; X } X default: X *temp++ = *buf++; /* Copy chars :-) */ X } X } X *temp = 0; X if (verbose) printf("Returning *%s*\n", out); X return(out); X} X X Xint firstword(buf) /* Return token value of first word */ Xchar *buf; /* in the buffer. Assume no leading */ X{ /* whitespace in the buffer */ X int i; X X for (i = 1; i < NUMTOKS; i++) X if (strncmp(buf, token[i], strlen(token[i])) == 0) return(i); X X return(UNKNOWN); X} X X Xint mustget(s1) /* Return 1 if s1 is in the list of */ Xchar *s1; /* files to extract. Return 0 if not */ X{ X int i; X X if (numext == 0) return(0); X for (i = 0; i < numext; i++) X if (!strcmp(s1, exfile[i])) return(1); X return(0); X} X X Xvoid extract(how, file, end, lead) /* Extract file, up until end word */ Xint how; /* If how==YESX, then ignore lead */ Xchar *file; /* character on every line */ Xchar *end; Xint lead; X{ X FILE *zout; X char line[BUFSIZE]; X char *temp; X int ch; X X zout = fopen(file, "w"); /* Open output file */ X if (zout == NULL) { X perror("unshar1"); X return; X } X while (1) { X binfile = 0; X ch = getline(WHITE, line); /* Get a line of file */ X temp = line; X if (binfile || (ch == EOF)) { X fprintf(zout, "%s\n", line); X fclose(zout); X return; X } X if ((how == YESX) && (*temp == lead)) temp++; /* Skip any lead */ X X if (strcmp(temp, end) == 0) { /* If end word */ X fclose(zout); /* close the file */ X return; X } X fprintf(zout, "%s\n", temp); X } X} X X Xvoid getnames(buf, file, word) /* Get the file & end word */ Xchar *buf, *file, *word; /* from the buffer */ X{ X char *temp; X X temp = buf; X if (verbose) printf("Getnames: buf is %s\n", buf); X X while (*temp != 0) { /* Scan along buffer */ X switch (*temp) { /* Get file or end word */ X case '>': X strcpy(file, getstring(++temp)); /* Get the file name */ X break; X case '<': X if (*(++temp) == '<') ++temp; /* Skip 2nd < */ X strcpy(word, getstring(temp)); /* Get next word */ X break; X default: X temp++; X } X } X} X X X Xvoid disembowel() X{ /* Unshar brutally! */ X char buf[BUFSIZE]; /* Line buffer */ X char file[BUFSIZE]; /* File name */ X char word[BUFSIZE]; /* Word buffer */ X int ch, x; X X if (verbose) printf("Entering disembowel\n"); X x = 'X'; /* Leading X character */ X while (1) { X binfile = 0; X ch = getline(NOWHITE, buf); /* Get a line from file */ X if (ch == EOF) return; X if (binfile) continue; X X switch (firstword(buf)) { /* Extract, depending on first word */ X case CAT: X if (verbose) printf("About to do getnames\n"); X getnames(buf, file, word); X if (table == 0) { X if ((numext == 0) || (mustget(file))) { X printf("unshar: Extracting %s\n", file); X if (verbose) X printf(" stopping at %s\n", word); X extract(NOX, file, word, x); X } X } else X printf(" %s\n", file); X break; X case GRES: X case SED: X if (verbose) printf("About to do getnames\n"); X getnames(buf, file, word); X if (table == 0) { X if ((numext == 0) || (mustget(file))) { X printf("unshar: Extracting %s\n", file); X if (verbose) X printf(" stopping at %s\n", word); X extract(YESX, file, word, x); X } X } else X printf(" %s\n", file); X break; X default: X break; X } X } X} X X X Xusage() X{ X fprintf(stderr, "Usage: unshar [-t] [-b] [-v] [-xfile] [file(s)]\n"); X exit(0); X} X X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X extern int optind; X extern char *optarg; X int i, c, first; X X FILE *zin; /* Dummy file descriptor */ X int method; /* Method of unsharing */ X X method = BRUTAL; /* Only BRUTAL currently available */ X table = 0; /* Don't generate a table */ X verbose = 0; /* Nor be very verbose */ X numext = 0; /* Initially no files to extract */ X X X while ((c = getopt(argc, argv, "x:tbv")) != EOF) switch (c) { X case 't': X table = 1; /* Get the various options */ X break; X case 'b': method = BRUTAL; break; X case 'v': verbose = 1; break; X case 'x': X exfile[numext] = (char *) malloc(strlen(optarg) + 1); X strcpy(exfile[numext++], optarg); X break; X default: X usage(); X } X X if (argc == 1) X first = argc; /* Find first file argument */ X else X for (first = 1; first < argc; first++) X if (argv[first][0] != '-') break; X X if (first == argc) { /* If no file argument *//* use stdin only */ X switch (method) { X case BRUTAL: X disembowel(); /* Unshar brutally! */ X break; X default: X fprintf(stderr, "unshar: Unknown method of unsharing\n"); X exit(1); X } X } else X for (i = first; i < argc; i++) { /* open stdio with every X * file */ X if (table) printf("%s:\n", argv[i]); X fclose(stdin); X if ((zin = fopen(argv[i], "r")) == NULL) { X perror("unshar2"); X exit(1); X } X switch (method) { X case BRUTAL: X disembowel(); /* Unshar brutally! */ X break; X default: X fprintf(stderr, "unshar: Unknown method of unsharing\n"); X exit(1); X } X } X exit(0); X} / Warren Toomey VK2XWT, really enjoying this. Deep in the bowels of ADFA Comp Science. `Happy birthday to you, Happy birthday to you!'