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