V10/cmd/asd/unseal.c

Compare this file to the similar file:
Show the results in this format:

/*
 *	unseal - disclose and verify the contents of a sealed package
 */

#include "asd.h"
#include "seal.h"
#include <ctype.h>

static FILE *outfd;
static char outf[] = "/usr/tmp/usXXXXXX";
static char line[MAXULINE];

main (argc, argv)
	int argc;
	char **argv;
{
	int rc = 0;
	int c;
	char *keyfile;
	static char stdbuf[BUFSIZ];

	setbuf (stdout, stdbuf);

	umask (077);
	mktemp (outf);
	outfd = fopen (outf, "w+");
	if (outfd == NULL) {
		fprintf (stderr, "unseal: can't create temp file\n");
		exit (1);
	}

	/* don't leave dregs */
	unlink (outf);

	rc = getargs (argc, argv, "kK:", unseal);
	
	/* if successful, copy the temp file to the output */
	if (rc == 0) {
		register FILE *in = outfd, *out = stdout;
		register int ch;

		rewind (in);

		while ((ch = getc (in)) != EOF)
			putc (ch, out);
		
		fflush (out);
		
		if (ferror (in)) {
			fprintf (stderr, "unseal: error reading temp file\n");
			rc++;
		}

		if (ferror (out)) {
			fprintf (stderr, "unseal: error writing stdout\n");
			rc++;
		}
	}

	return rc;
}

static unsigned long length, checksum;

unseal (f, fname)
	FILE *f;
	char *fname;
{
	int intext = 0, rc = 0, nulltext = 1;

	length = checksum = 0;
	resetN12();

	while (fgets (line, MAXULINE, f) != NULL) {

		/* check for a control line, which starts with "!" */
		if (line[0] == '!') {
			if (intext) {
				/* only thing allowed is !end */
				if (strncmp (line + 1, "end ", 4) == 0) {
					rc += docksum (line, length, checksum);
					intext = 0;
				} else {
					fprintf (stderr, "invalid control line %s", line);
					rc++;
				}
			} else {
				/* look for header, else quietly ignore */
				if (strcmp (line + 1, "<seal>\n") == 0) {
					intext++;
					nulltext = 0;
				}
			}
		/* data lines are quietly ignored if not in text */
		} else if (intext) {
			rc += dodata (line);
		}
	}

	if (nulltext) {
		fprintf (stderr, "unseal: no contents\n");
		rc++;
	}

	if (intext) {
		fprintf (stderr, "unseal: no checksum\n");
		rc++;
	}

	return rc;
}

static char *
csverify (p, value)
	register char *p;
	register unsigned long value;
{
	register unsigned long n = 0;

	while (isspace (*p))
		p++;

	if (!isdigit (*p))
		return NULL;

	do	n = n * 10 + *p++ - '0';
	while (isdigit (*p));

	if (!isspace (*p))
		return NULL;

	if (n != value)
		return NULL;

	return p;
}

docksum (line, length, checksum)
	char *line;
	unsigned long length, checksum;
{
	register char *p = line + 5;

	p = csverify (p, length);
	if (p == NULL) {
		fprintf (stderr, "unseal: invalid length\n");
		return 1;
	}
	p = csverify (p, checksum);
	if (p == NULL) {
		fprintf (stderr, "unseal: invalid checksum\n");
		return 1;
	}
	return 0;
}

dodata (line)
	char *line;
{
	int hrout(), mrout();
	char out[MAXULINE * 2];
	int r;

	r = (*(line[0] == '.'? mrout: hrout)) (line, out);
	if (r < 0)
		return 1;
	fwrite (out, sizeof(*out), r, outfd);
	length += r;

	if (kflag || Kflag)
		mangle (out, out + r);

	checksum = mkcsum (checksum, out, out + r);

	return 0;
}

int
hrout (line, out)
	char *line, *out;
{
	register char *p, *q;
	register int ch;

	p = line;
	q = out;

	while ((ch = *p++) != '\0') {
		if (ch != '\\') {
			*q++ = ch;
		} else {
			ch = *p++;
			if (ch == '\\' || ch == '.' || ch == '!' || ch == 'F') {
				*q++ = ch;
			} else if (ch != '\n') {
				register int n = 0, i = 1;

				do {
					ch = unhex (ch);
					if (ch < 0) {
						fprintf (stderr,
							"bad hex char: %s", line);
						return -1;
					}
					n = (n << 4) | ch;
					if (i)
						ch = *p++;
				} while (--i >= 0);

				*q++ = n;
			}
		}
	}

	return q - out;
}

int
unhex (c)
	register int c;
{
	register char *p;

	p = hextab;
	while (*p && *p != c)
		p++;
	if (*p)
		return p - hextab;
	return -1;
}

int
mrout (line, out)
	char *line, *out;
{
	register char *p = line + 1;
	char *q = out;

	while (*p != '\n' && *p != '\0') {
		register unsigned long bits;
		register int n;
		register char *rq;

		n = 0;
		bits = 0;
		do {
			register int ch = *p++;
			if (ch == '\n')
				break;
			if (ch < RADBASE || ch >= RADBASE + RADIX) {
				fprintf (stderr, "bad input char: %s", line);
				return -1;
			}
			bits = bits * RADIX + ch - RADBASE;
			n++;
		} while (n < OUTCPW);

		n -= OUTCPW - INCPW;
		if (n <= 0) {
			fprintf (stderr, "non-positive output count: %s", line);
			return -1;
		}

		rq = q = q + n;
		do {
			*--rq = bits;
			bits >>= BPC;
		} while (--n > 0);
	}

	return q - out;
}