Beyond shar (Re: shars and security concerns.)
Warren Toomey
wkt at rodos2.cs.adfa.oz.au
Fri Jun 1 14:54:27 AEST 1990
In article [...], xanthian at 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 at cs.adfa.oz.au@munnari.oz at 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 <stdio.h>
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!'
More information about the Alt.sources.d
mailing list