Annotation of pgp/src/armor.c, revision 1.1.1.9

1.1.1.9 ! root        1: /*      armor.c  - ASCII/binary encoding/decoding based partly on
        !             2:    PEM RFC1113 and MIME standards.
        !             3:    PGP: Pretty Good(tm) Privacy - public key cryptography for the masses.
        !             4: 
        !             5:    (c) Copyright 1990-1996 by Philip Zimmermann.  All rights reserved.
        !             6:    The author assumes no liability for damages resulting from the use
        !             7:    of this software, even if the damage results from defects in this
        !             8:    software.  No warranty is expressed or implied.
        !             9: 
        !            10:    Note that while most PGP source modules bear Philip Zimmermann's
        !            11:    copyright notice, many of them have been revised or entirely written
        !            12:    by contributors who frequently failed to put their names in their
        !            13:    code.  Code that has been incorporated into PGP from other authors
        !            14:    was either originally published in the public domain or is used with
        !            15:    permission from the various authors.
        !            16: 
        !            17:    PGP is available for free to the public under certain restrictions.
        !            18:    See the PGP User's Guide (included in the release package) for
        !            19:    important information about licensing, patent restrictions on
        !            20:    certain algorithms, trademarks, copyrights, and export controls.
        !            21:  */
        !            22: #include <ctype.h>
        !            23: #include <stdio.h>
        !            24: #include <string.h>
        !            25: #include "mpilib.h"
        !            26: #include "fileio.h"
        !            27: #include "mpiio.h"
        !            28: #include "language.h"
        !            29: #include "pgp.h"
        !            30: #include "charset.h"
        !            31: #include "crypto.h"
        !            32: #include "armor.h"
        !            33: #include "keymgmt.h"
        !            34: #ifdef MACTC5
        !            35: #include "Macutil2.h"
        !            36: #include "Macutil3.h"
        !            37: #endif
        !            38: 
        !            39: static int darmor_file(char *infile, char *outfile);
        !            40: static crcword crchware(byte ch, crcword poly, crcword accum);
        !            41: static int armordecode(FILE * in, FILE * out, int *warned);
        !            42: static void mk_crctbl(crcword poly);
        !            43: static boolean is_armorfile(char *infile);
        !            44: 
        !            45: /*      Begin ASCII armor routines.
        !            46:    This converts a binary file into printable ASCII characters, in a
        !            47:    radix-64 form mostly compatible with the MIME format.
        !            48:    This makes it easier to send encrypted files over a 7-bit channel.
        !            49:  */
        !            50: 
        !            51: /* Index this array by a 6 bit value to get the character corresponding
        !            52:  * to that value.
        !            53:  */
        !            54: static
        !            55: unsigned char bintoasc[] =
        !            56:        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        !            57: 
        !            58: /* Index this array by a 7 bit value to get the 6-bit binary field
        !            59:  * corresponding to that value.  Any illegal characters return high bit set.
        !            60:  */
        !            61: static
        !            62: unsigned char asctobin[] =
        !            63: {
        !            64: #ifdef EBCDIC
        !            65:     128,128,128,128,128,128,128,128, 128,128,128,128,128,128,128,128,
        !            66:     128,128,128,128,128,128,128,128, 128,128,128,128,128,128,128,128,
        !            67:     128,128,128,128,128,128,128,128, 128,128,128,128,128,128,128,128,
        !            68:     128,128,128,128,128,128,128,128, 128,128,128,128,128,128,128,128,
        !            69:     128,128,128,128,128,128,128,128, 128,128,128,128,128,128, 62,128,
        !            70:     128,128,128,128,128,128,128,128, 128,128,128,128,128,128,128,128,
        !            71:     128, 63,128,128,128,128,128,128, 128,128,128,128,128,128,128,128,
        !            72:     128,128,128,128,128,128,128,128, 128,128,128,128,128,128,128,128,
        !            73:     128, 26, 27, 28, 29, 30, 31, 32,  33, 34,128,128,128,128,128,128,
        !            74:     128, 35, 36, 37, 38, 39, 40, 41,  42, 43,128,128,128,128,128,128,
        !            75:     128,128, 44, 45, 46, 47, 48, 49,  50, 51,128,128,128,128,128,128,
        !            76:     128,128,128,128,128,128,128,128, 128,128,128,128,128,128,128,128,
        !            77:     128,  0,  1,  2,  3,  4,  5,  6,   7,  8,128,128,128,128,128,128,
        !            78:     128,  9, 10, 11, 12, 13, 14, 15,  16, 17,128,128,128,128,128,128,
        !            79:     128,128, 18, 19, 20, 21, 22, 23,  24, 25,128,128,128,128,128,128,
        !            80:      52, 53, 54, 55, 56, 57, 58, 59,  60, 61,128,128,128,128,128,128
        !            81: #else
        !            82:     0200, 0200, 0200, 0200, 0200, 0200, 0200, 0200,
        !            83:     0200, 0200, 0200, 0200, 0200, 0200, 0200, 0200,
        !            84:     0200, 0200, 0200, 0200, 0200, 0200, 0200, 0200,
        !            85:     0200, 0200, 0200, 0200, 0200, 0200, 0200, 0200,
        !            86:     0200, 0200, 0200, 0200, 0200, 0200, 0200, 0200,
        !            87:     0200, 0200, 0200, 0076, 0200, 0200, 0200, 0077,
        !            88:     0064, 0065, 0066, 0067, 0070, 0071, 0072, 0073,
        !            89:     0074, 0075, 0200, 0200, 0200, 0200, 0200, 0200,
        !            90:     0200, 0000, 0001, 0002, 0003, 0004, 0005, 0006,
        !            91:     0007, 0010, 0011, 0012, 0013, 0014, 0015, 0016,
        !            92:     0017, 0020, 0021, 0022, 0023, 0024, 0025, 0026,
        !            93:     0027, 0030, 0031, 0200, 0200, 0200, 0200, 0200,
        !            94:     0200, 0032, 0033, 0034, 0035, 0036, 0037, 0040,
        !            95:     0041, 0042, 0043, 0044, 0045, 0046, 0047, 0050,
        !            96:     0051, 0052, 0053, 0054, 0055, 0056, 0057, 0060,
        !            97:     0061, 0062, 0063, 0200, 0200, 0200, 0200, 0200
        !            98: #endif
        !            99: };
        !           100: 
        !           101: /* Current line number for mult decodes */
        !           102: #ifdef MACTC5
        !           103: long   infile_line;            /* Current line number for mult decodes */
        !           104: #else
        !           105: static long infile_line;
        !           106: #endif
        !           107: 
        !           108: /************************************************************************/
        !           109: 
        !           110: /* CRC Routines. */
        !           111: /*      These CRC functions are derived from code in chapter 19 of the book 
        !           112:  *    "C Programmer's Guide to Serial Communications", by Joe Campbell.
        !           113:  *      Generalized to any CRC width by Philip Zimmermann.
        !           114:  */
        !           115: 
        !           116: #define byte unsigned char
        !           117: 
        !           118: #define CRCBITS 24             /* may be 16, 24, or 32 */
        !           119: /* #define maskcrc(crc) ((crcword)(crc)) *//* if CRCBITS is 16 or 32 */
        !           120: #define maskcrc(crc) ((crc) & 0xffffffL)       /* if CRCBITS is 24 */
        !           121: #define CRCHIBIT ((crcword) (1L<<(CRCBITS-1))) /* 0x8000 if CRCBITS is 16 */
        !           122: #define CRCSHIFTS (CRCBITS-8)
        !           123: 
        !           124: /*
        !           125:  * Notes on making a good 24-bit CRC--
        !           126:  * The primitive irreducible polynomial of degree 23 over GF(2),
        !           127:  * 040435651 (octal), comes from Appendix C of "Error Correcting Codes,
        !           128:  * 2nd edition" by Peterson and Weldon, page 490.  This polynomial was
        !           129:  * chosen for its uniform density of ones and zeros, which has better
        !           130:  * error detection properties than polynomials with a minimal number of
        !           131:  * nonzero terms.  Multiplying this primitive degree-23 polynomial by
        !           132:  * the polynomial x+1 yields the additional property of detecting any
        !           133:  * odd number of bits in error, which means it adds parity.  This 
        !           134:  * approach was recommended by Neal Glover.
        !           135:  *
        !           136:  * To multiply the polynomial 040435651 by x+1, shift it left 1 bit and
        !           137:  * bitwise add (xor) the unshifted version back in.  Dropping the unused 
        !           138:  * upper bit (bit 24) produces a CRC-24 generator bitmask of 041446373 
        !           139:  * octal, or 0x864cfb hex.  
        !           140:  *
        !           141:  * You can detect spurious leading zeros or framing errors in the 
        !           142:  * message by initializing the CRC accumulator to some agreed-upon 
        !           143:  * nonzero value, but the value used is a bit nonstandard.  
        !           144:  */
        !           145: 
        !           146: #define CCITTCRC 0x1021                /* CCITT's 16-bit CRC generator polynomial */
        !           147: #define PRZCRC 0x864cfbL       /* PRZ's 24-bit CRC generator polynomial */
        !           148: #define CRCINIT 0xB704CEL      /* Init value for CRC accumulator */
        !           149: 
        !           150: static crcword crctable[256];  /* Table for speeding up CRC's */
        !           151: 
        !           152: /*
        !           153:  * mk_crctbl derives a CRC lookup table from the CRC polynomial.
        !           154:  * The table is used later by the crcbytes function given below.
        !           155:  * mk_crctbl only needs to be called once at the dawn of time.
        !           156:  *
        !           157:  * The theory behind mk_crctbl is that table[i] is initialized
        !           158:  * with the CRC of i, and this is related to the CRC of i>>1,
        !           159:  * so the CRC of i>>1 (pointed to by p) can be used to derive
        !           160:  * the CRC of i (pointed to by q).
        !           161:  */
        !           162: static void
        !           163: mk_crctbl(crcword poly)
        !           164: {
        !           165:     int i;
        !           166:     crcword t, *p, *q;
        !           167:     p = q = crctable;
        !           168:     *q++ = 0;
        !           169:     *q++ = poly;
        !           170:     for (i = 1; i < 128; i++) {
        !           171:        t = *++p;
        !           172:        if (t & CRCHIBIT) {
        !           173:            t <<= 1;
        !           174:            *q++ = t ^ poly;
        !           175:            *q++ = t;
        !           176:        } else {
        !           177:            t <<= 1;
        !           178:            *q++ = t;
        !           179:            *q++ = t ^ poly;
        !           180:        }
        !           181:     }
        !           182: }
        !           183: 
        !           184: /*
        !           185:  * Accumulate a buffer's worth of bytes into a CRC accumulator,
        !           186:  * returning the new CRC value.
        !           187:  */
        !           188: crcword
        !           189: crcbytes(byte * buf, unsigned len, register crcword accum)
        !           190: {
        !           191:     do {
        !           192:        accum = accum << 8 ^ crctable[(byte) (accum >> CRCSHIFTS) ^ *buf++];
        !           193:     } while (--len);
        !           194:     return maskcrc(accum);
        !           195: }                              /* crcbytes */
        !           196: 
        !           197: /* Initialize the CRC table using our codes */
        !           198: void
        !           199: init_crc(void)
        !           200: {
        !           201:     mk_crctbl(PRZCRC);
        !           202: }
        !           203: 
        !           204: 
        !           205: /************************************************************************/
        !           206: 
        !           207: 
        !           208: /* ENC is the basic 1 character encoding function to make a char printing */
        !           209: #define ENC(c) ((int)bintoasc[((c) & 077)])
        !           210: #define PAD            '='
        !           211: 
        !           212: /*
        !           213:  * output one group of up to 3 bytes, pointed at by p, on file f.
        !           214:  * if fewer than 3 are present, the 1 or two extras must be zeros.
        !           215:  */
        !           216: static void
        !           217: outdec(char *p, FILE *f, int count)
        !           218: {
        !           219:     int c1, c2, c3, c4;
        !           220: 
        !           221:     c1 = *p >> 2;
        !           222:     c2 = ((*p << 4) & 060) | ((p[1] >> 4) & 017);
        !           223:     c3 = ((p[1] << 2) & 074) | ((p[2] >> 6) & 03);
        !           224:     c4 = p[2] & 077;
        !           225:     putc(ENC(c1), f);
        !           226:     putc(ENC(c2), f);
        !           227:     if (count == 1) {
        !           228:        putc(PAD, f);
        !           229:        putc(PAD, f);
        !           230:     } else {
        !           231:        putc(ENC(c3), f);
        !           232:        if (count == 2)
        !           233:            putc(PAD, f);
        !           234:        else
        !           235:            putc(ENC(c4), f);
        !           236:     }
        !           237: }                              /* outdec */
        !           238: 
        !           239: 
        !           240: /* Output the CRC value, MSB first per normal CRC conventions */
        !           241: static void
        !           242: outcrc(word32 crc, FILE *outFile)
        !           243: {
        !           244:     char crcbuf[4];
        !           245:     crcbuf[0] = (crc >> 16) & 0xff;
        !           246:     crcbuf[1] = (crc >> 8) & 0xff;
        !           247:     crcbuf[2] = (crc >> 0) & 0xff;
        !           248:     putc(PAD, outFile);
        !           249:     outdec(crcbuf, outFile, 3);
        !           250:     putc('\n', outFile);
        !           251: }                              /* outcrc */
        !           252: 
        !           253: /* Return filename for output (text mode), but replace last letter(s) of
        !           254:  * filename with the ascii for num.  It will use the appropriate number
        !           255:  * of digits for ofnum when converting num, so if ofnum < 10, use 1 digit,
        !           256:  * >= 10 and < 100 use 2 digits, >= 100 and < 1000 use 3 digits.  If its
        !           257:  * >= 1000, then we have other problems to worry about, and this might do
        !           258:  * weird things.
        !           259:  */
        !           260: static char *
        !           261: numFilename(char *fname, int num, int ofnum)
        !           262: {
        !           263:     static char fnamenum[MAX_PATH];
        !           264:     int len;
        !           265:     int offset = 1;
        !           266: 
        !           267:     strcpy(fnamenum, fname);
        !           268:     len = strlen(fnamenum);
        !           269:     do {
        !           270:        fnamenum[len - offset] = '0' + (num % 10);
        !           271:        num /= 10;
        !           272:        ofnum /= 10;
        !           273:        offset++;
        !           274:     } while (ofnum >= 1 && offset < 4);
        !           275:     return fnamenum;
        !           276: }
        !           277: 
        !           278: /*
        !           279:  * Reads and discards a line from the given file.  Returns -1 on error or
        !           280:  * EOF, 0 if the line is blank, and 1 if the line is not blank.
        !           281:  */
        !           282: static int
        !           283: skipline(FILE * f)
        !           284: {
        !           285:     int state, flag, c;
        !           286: 
        !           287:     state = 0;
        !           288:     flag = 0;
        !           289:     for (;;) {
        !           290:        c = getc(f);
        !           291:        if (c == '\n')
        !           292:            return flag;
        !           293:        if (state) {
        !           294:            ungetc(c, f);
        !           295:            return flag;
        !           296:        }
        !           297:        if (c == EOF)
        !           298:            return -1;
        !           299:        if (c == '\r')
        !           300:            state = 1;
        !           301:        else if (c != ' ')
        !           302:            flag = 1;
        !           303:     }
        !           304: }                              /* skipline */
        !           305: 
        !           306: 
        !           307: /*
        !           308:  * Copies a line from the input file to the output.  Does NOT copy the
        !           309:  * trailing newline.  Returns -1 on EOF or error, 0 if the line was terminated
        !           310:  * by EOF, and 1 if the line was terminated with a newline sequence.
        !           311:  */
        !           312: static int
        !           313: copyline(FILE * in, FILE * out)
        !           314: {
        !           315:     int state, flag, c;
        !           316: 
        !           317:     state = 0;
        !           318:     for (;;) {
        !           319:        c = getc(in);
        !           320:        if (c == '\n')
        !           321:            return 1;
        !           322:        if (state) {
        !           323:            ungetc(c, in);
        !           324:            return 1;
        !           325:        }
        !           326:        if (c == EOF)
        !           327:            return 0;
        !           328:        if (c == '\r')
        !           329:            state = 1;
        !           330:        else
        !           331:            putc(c, out);
        !           332:     }
        !           333: }                              /* copyline */
        !           334: 
        !           335: /*
        !           336:  * Reads a line from file f, up to the size of the buffer.  The line in the
        !           337:  * buffer will NOT include line termination, although any of (CR, LF, CRLF)
        !           338:  * is accepted on input.  The return value is -1 on error, 0 if the line
        !           339:  * was terminated abnormally (EOF, error, or out of buffer space), and
        !           340:  * 1 if the line was terminated normally.
        !           341:  *
        !           342:  * Passing in a buffer less than 2 characters long is not a terribly bright
        !           343:  * idea.
        !           344:  */
        !           345: static int
        !           346: getline(char *buf, int n, FILE * f)
        !           347: {
        !           348:     int state;
        !           349:     char *p;
        !           350:     int c;
        !           351: 
        !           352:     state = 0;
        !           353:     p = buf;
        !           354:     for (;;) {
        !           355:        c = getc(f);
        !           356:        if (c == '\n') {
        !           357:            *p = 0;
        !           358:            return 1;           /* Line terminated with \n or \r\n */
        !           359:        }
        !           360:        if (state) {
        !           361:            ungetc(c, f);
        !           362:            *p = 0;
        !           363:            return 1;           /* Line terminated with \r */
        !           364:        }
        !           365:        if (c == EOF) {
        !           366:            *p = 0;
        !           367:            return (p == buf) ? -1 : 0;         /* Error */
        !           368:        }
        !           369:        if (c == '\r')
        !           370:            state = 1;
        !           371:        else if (--n > 0) {
        !           372:            *p++ = c;
        !           373:        } else {
        !           374:            ungetc(c, f);
        !           375:            *p = 0;
        !           376:            return 0;           /* Out of buffer space */
        !           377:        }
        !           378:     }                          /* for (;;) */
        !           379: }                              /* getline */
        !           380: 
        !           381: #if 1
        !           382: /* This limit is advisory only; longer lines are handled properly.
        !           383:  * The only requirement is that this be at least as long as the longest
        !           384:  * delimiter string used by PGP
        !           385:  * (e.g. "-----BEGIN PGP MESSAGE, PART %02d/%02d-----\n")
        !           386:  */
        !           387: #define MAX_LINE_SIZE 80
        !           388: #else
        !           389: #ifdef MSDOS                   /* limited stack space */
        !           390: #define MAX_LINE_SIZE  256
        !           391: #else
        !           392: #define MAX_LINE_SIZE  1024
        !           393: #endif
        !           394: #endif
        !           395: 
        !           396: /*
        !           397:  * Read a line from file f, buf must be able to hold at least MAX_LINE_SIZE
        !           398:  * characters.  Anything after that is ignored.  Strips trailing spaces and
        !           399:  * line terminator, can read LF, CRLF and CR textfiles.  It can't be ASCII
        !           400:  * armor anyway.
        !           401:  */
        !           402: static char *
        !           403: get_armor_line(char *buf, FILE * f)
        !           404: {
        !           405:     int c, n = MAX_LINE_SIZE-1;
        !           406:     char *p = buf;
        !           407: 
        !           408:     do {
        !           409:        c = getc(f);
        !           410:        if (c == '\n' || c == '\r' || c == EOF)
        !           411:            break;
        !           412:        *p++ = c;
        !           413:     } while (--n > 0);
        !           414:     if (p == buf && c == EOF) {
        !           415:        *buf = '\0';
        !           416:        return NULL;
        !           417:     }
        !           418:     /*
        !           419:      * Skip to end of line, setting n to non-zero if anything trailing is
        !           420:      * not a space (meaning that any trailing whitespace in the buffer is
        !           421:      * not trailing whitespace on the line and should not be stripped).
        !           422:      */
        !           423:     n = 0;
        !           424:     while (c != '\n' && c != '\r' && c != EOF) {
        !           425:         n |= c ^ ' ';
        !           426:        c = getc(f);
        !           427:     }
        !           428:     if (c == '\r' && (c = getc(f)) != '\n')
        !           429:        ungetc(c, f);
        !           430:     if (!n) {  /* Skip trailing whitespace, as described above */
        !           431:        while (p > buf && p[-1] == ' ')
        !           432:            --p;
        !           433:     }
        !           434:     *p = '\0';
        !           435:     return buf;
        !           436: }
        !           437: 
        !           438: 
        !           439: /*
        !           440:  * Encode a file in sections.  64 ASCII bytes * 720 lines = 46K, 
        !           441:  * recommended max.  Usenet message size is 50K so this leaves a nice 
        !           442:  * margin for .signature.  In the interests of orthogonality and 
        !           443:  * programmer laziness no check is made for a message containing only 
        !           444:  * a few lines (or even just an 'end')  after a section break. 
        !           445:  */
        !           446: #define LINE_LEN       48L
        !           447: int pem_lines = 720;
        !           448: #define BYTES_PER_SECTION      (LINE_LEN * pem_lines)
        !           449: 
        !           450: #if defined(VMS) || defined(C370)
        !           451: #define FOPRARMOR      FOPRTXT
        !           452: #else
        !           453: /* armored files are opened in binary mode so that CRLF/LF/CR files
        !           454:    can be handled by all systems */
        !           455: #define        FOPRARMOR       FOPRBIN
        !           456: #endif
        !           457: 
        !           458: extern boolean verbose;                /* Undocumented command mode in PGP.C */
        !           459: extern boolean filter_mode;
        !           460: 
        !           461: /*
        !           462:  * Copy from infilename to outfilename, ASCII armoring as you go along,
        !           463:  * and with breaks every pem_lines lines.
        !           464:  * If clearfilename is non-NULL, first output that file preceded by a
        !           465:  * special delimiter line.  filename is the original filename, used
        !           466:  * only for debugging.
        !           467:  */
        !           468: int
        !           469: armor_file(char *infilename, char *outfilename, char *filename,
        !           470:        char *clearfilename, boolean kv_label)
        !           471: {
        !           472:     char buffer[MAX_LINE_SIZE];
        !           473:     int i, rc, bytesRead, lines = 0;
        !           474:     int noSections, currentSection = 1;
        !           475:     long fileLen;
        !           476:     crcword crc;
        !           477:     FILE *inFile, *outFile, *clearFile;
        !           478:     char *tempf;
        !           479:     char *blocktype = "MESSAGE";
        !           480: #ifdef MACTC5
        !           481:     char curOutFile[256]="";
        !           482: #endif
        !           483: 
        !           484:     if (verbose)
        !           485:        fprintf(pgpout,
        !           486: "armor_file: infile = %s, outfile = %s, filename = %s, clearname = %s\n",
        !           487:                infilename, outfilename, filename,
        !           488:                clearfilename == NULL ? "" : clearfilename);
        !           489: 
        !           490:     /* open input file as binary */
        !           491:     if ((inFile = fopen(infilename, FOPRBIN)) == NULL)
        !           492:        return 1;
        !           493: 
        !           494:     if (!outfilename || pem_lines == 0) {
        !           495:        noSections = 1;
        !           496:     } else {
        !           497:        /* Evaluate how many parts this file will comprise */
        !           498:        fseek(inFile, 0L, SEEK_END);
        !           499:        fileLen = ftell(inFile);
        !           500:        rewind(inFile);
        !           501:        noSections = (fileLen + BYTES_PER_SECTION - 1) /
        !           502:            BYTES_PER_SECTION;
        !           503:        if (noSections > 99) {
        !           504:            pem_lines = ((fileLen + LINE_LEN - 1) / LINE_LEN + 98) / 99;
        !           505:            noSections = (fileLen + BYTES_PER_SECTION - 1) /
        !           506:                BYTES_PER_SECTION;
        !           507:            fprintf(pgpout,
        !           508:            "value for \"armorlines\" is too low, using %d\n", pem_lines);
        !           509:        }
        !           510:     }
        !           511: 
        !           512:     if (clearfilename)
        !           513:       tempf = tempfile(TMP_WIPE);
        !           514:     else
        !           515:       tempf = outfilename;
        !           516: 
        !           517:     if (outfilename == NULL) {
        !           518:        outFile = stdout;
        !           519:     } else {
        !           520:        if (noSections > 1) {
        !           521:             do {
        !           522:                 char *t;
        !           523:                 force_extension(outfilename, ASC_EXTENSION);
        !           524:                 strcpy(outfilename, numFilename(outfilename, 1, noSections));
        !           525:                 if (!file_exists(outfilename)) break;
        !           526:                 t = ck_dup_output(outfilename, TRUE, TRUE);
        !           527:                 if (t==NULL) user_error();
        !           528:                 strcpy(outfilename,t);
        !           529:             } while (TRUE);
        !           530:             outFile = fopen(tempf, FOPWTXT);
        !           531:        } else
        !           532:            outFile = fopen(tempf, FOPWTXT);
        !           533: #ifdef MACTC5
        !           534:                strcpy(curOutFile,outfilename);
        !           535: #endif
        !           536:     }
        !           537: 
        !           538:     if (outFile == NULL) {
        !           539:        fclose(inFile);
        !           540:        return 1;
        !           541:     }
        !           542:     if (clearfilename) {
        !           543:        if ((clearFile = fopen(clearfilename, FOPRTXT)) == NULL) {
        !           544:            fclose(inFile);
        !           545:            if (outFile != stdout)
        !           546:                fclose(outFile);
        !           547:            return 1;
        !           548:        }
        !           549:        fprintf(outFile, "-----BEGIN PGP SIGNED MESSAGE-----\n\n");
        !           550:        while ((i = getline(buffer, sizeof buffer, clearFile)) >= 0) {
        !           551:            /* Quote lines beginning with '-' as per RFC1113;
        !           552:             * Also quote lines beginning with "From "; this is
        !           553:             * for Unix mailers which add ">" to such lines.
        !           554:             */
        !           555:            if (buffer[0] == '-' || strncmp(buffer, "From ", 5) == 0)
        !           556:                fputs("- ", outFile);
        !           557:            fputs(buffer, outFile);
        !           558:            /* If there is more on this line, copy it */
        !           559:            if (i == 0)
        !           560:                if (copyline(clearFile, outFile) <= 0)
        !           561:                    break;
        !           562:            fputc('\n', outFile);
        !           563:        }
        !           564:        fclose(clearFile);
        !           565:        putc('\n', outFile);
        !           566:        blocktype = "SIGNATURE";
        !           567:     }
        !           568:     if (noSections == 1) {
        !           569:        byte ctb = 0;
        !           570:         int keycounter = 0;
        !           571:         int status;
        !           572:        ctb = getc(inFile);
        !           573:        if (is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE)) {
        !           574:            blocktype = "PUBLIC KEY BLOCK";
        !           575:             if (kv_label) {
        !           576:                 kv_title(outFile);     /* Title line */
        !           577:                 rewind(inFile);        /* Back over CTB */
        !           578:                 status = kvformat_keypacket(inFile, outFile, TRUE, "", infilename,
        !           579:                                             FALSE, FALSE, &keycounter);
        !           580:                fprintf(outFile, "\n");
        !           581:             }
        !           582:        } else if (is_ctb_type(ctb, CTB_CERT_SECKEY_TYPE)) {
        !           583:             blocktype = "SECRET KEY BLOCK";
        !           584:             if (kv_label) {
        !           585:                 kv_title(outFile);     /* Title line */
        !           586:                 rewind(inFile);        /* Back over CTB */
        !           587:                 status = kvformat_keypacket(inFile, outFile, TRUE, "", infilename,
        !           588:                                             FALSE, FALSE, &keycounter);
        !           589:                fprintf(outFile, "\n");
        !           590:             }
        !           591:        }
        !           592:        fprintf(outFile, "-----BEGIN PGP %s-----\n", blocktype);
        !           593:        rewind(inFile);
        !           594:     } else {
        !           595:        fprintf(outFile,
        !           596:                "-----BEGIN PGP MESSAGE, PART %02d/%02d-----\n",
        !           597:                1, noSections);
        !           598:     }
        !           599:     fprintf(outFile, "Version: %s\n", LANG(rel_version));
        !           600:     if (clearfilename)
        !           601:        fprintf(outFile, "Charset: %s\n", charset);
        !           602:     if (globalCommentString[0])
        !           603:        fprintf(outFile, "Comment: %s\n", globalCommentString);
        !           604:     fprintf(outFile, "\n");
        !           605: 
        !           606:     init_crc();
        !           607:     crc = CRCINIT;
        !           608: 
        !           609:     while ((bytesRead = fread(buffer, 1, LINE_LEN, inFile)) > 0) {
        !           610:        /* Munge up LINE_LEN characters */
        !           611:        if (bytesRead < LINE_LEN)
        !           612:            fill0(buffer + bytesRead, LINE_LEN - bytesRead);
        !           613: 
        !           614:        crc = crcbytes((byte *) buffer, bytesRead, crc);
        !           615:        for (i = 0; i < bytesRead - 3; i += 3)
        !           616:            outdec(buffer + i, outFile, 3);
        !           617:        outdec(buffer + i, outFile, bytesRead - i);
        !           618:        putc('\n', outFile);
        !           619: #ifdef MACTC5
        !           620:                mac_poll_for_break();
        !           621: #endif
        !           622: 
        !           623:        if (++lines == pem_lines && currentSection < noSections) {
        !           624:            lines = 0;
        !           625:            outcrc(crc, outFile);
        !           626:            fprintf(outFile,
        !           627:                    "-----END PGP MESSAGE, PART %02d/%02d-----\n\n",
        !           628:                    currentSection, noSections);
        !           629:            if (write_error(outFile)) {
        !           630:                fclose(outFile);
        !           631:                return -1;
        !           632:            }
        !           633:            fclose(outFile);
        !           634: #ifdef MACTC5
        !           635:                PGPSetFinfo(curOutFile,'TEXT','MPGP');
        !           636: #endif
        !           637:            outFile = fopen(numFilename(outfilename,
        !           638:                                        ++currentSection,
        !           639:                                        noSections), FOPWTXT);
        !           640: #ifdef MACTC5
        !           641:                strcpy(curOutFile,numFilename (outfilename,currentSection,noSections));
        !           642: #endif
        !           643:            if (outFile == NULL) {
        !           644:                fclose(inFile);
        !           645:                return -1;
        !           646:            }
        !           647:            fprintf(outFile,
        !           648:                    "-----BEGIN PGP MESSAGE, PART %02d/%02d-----\n",
        !           649:                    currentSection, noSections);
        !           650:            fprintf(outFile, "\n");
        !           651:            crc = CRCINIT;
        !           652:        }
        !           653:     }
        !           654:     outcrc(crc, outFile);
        !           655: 
        !           656:     if (noSections == 1)
        !           657:        fprintf(outFile, "-----END PGP %s-----\n", blocktype);
        !           658:     else
        !           659:        fprintf(outFile, "-----END PGP MESSAGE, PART %02d/%02d-----\n",
        !           660:                noSections, noSections);
        !           661: 
        !           662:     /* Done */
        !           663:     fclose(inFile);
        !           664:     rc = write_error(outFile);
        !           665:     if (outFile == stdout)
        !           666:        return rc;
        !           667: #ifdef MACTC5
        !           668:        PGPSetFinfo(curOutFile,'TEXT','MPGP');
        !           669: #endif
        !           670:     fclose(outFile);
        !           671:     if (clearfilename) {
        !           672:         remove(outfilename);
        !           673:         savetemp(tempf,outfilename);
        !           674:     }
        !           675: 
        !           676:     if (rc)
        !           677:        return -1;
        !           678: 
        !           679:     if (clearfilename) {
        !           680:        fprintf(pgpout,
        !           681:                LANG("\nClear signature file: %s\n"), outfilename);
        !           682:     } else if (noSections == 1) {
        !           683:        fprintf(pgpout,
        !           684:                LANG("\nTransport armor file: %s\n"), outfilename);
        !           685:     } else {
        !           686:        fprintf(pgpout, LANG("\nTransport armor files: "));
        !           687:        for (i = 1; i <= noSections; ++i)
        !           688:            fprintf(pgpout, "%s%s",
        !           689:                    numFilename(outfilename, i, noSections),
        !           690:                    i == noSections ? "\n" : ", ");
        !           691:     }
        !           692:     return 0;
        !           693: }                              /* armor_file */
        !           694: 
        !           695: /*      End ASCII armor encode routines. */
        !           696: 
        !           697: 
        !           698: /*
        !           699:  * ASCII armor decode routines.
        !           700:  */
        !           701: static int
        !           702: darmor_buffer(char *inbuf, char *outbuf, int *outlength)
        !           703: {
        !           704:     unsigned char *bp;
        !           705:     int length;
        !           706:     unsigned int c1, c2, c3, c4;
        !           707:     register int j;
        !           708: 
        !           709:     length = 0;
        !           710:     bp = (unsigned char *) inbuf;
        !           711: 
        !           712:     /* FOUR input characters go into each THREE output charcters */
        !           713: 
        !           714:     while (*bp != '\0') {
        !           715: #ifdef EBCDIC
        !           716:        if ((c1 = asctobin[*bp]) & 0x80)
        !           717:            return -1;
        !           718:        ++bp;
        !           719:        if ((c2 = asctobin[*bp]) & 0x80)
        !           720:            return -1;
        !           721: #else
        !           722:        if (*bp & 0x80 || (c1 = asctobin[*bp]) & 0x80)
        !           723:            return -1;
        !           724:        ++bp;
        !           725:        if (*bp & 0x80 || (c2 = asctobin[*bp]) & 0x80)
        !           726:            return -1;
        !           727: #endif
        !           728:        if (*++bp == PAD) {
        !           729:            c3 = c4 = 0;
        !           730:            length += 1;
        !           731:            if (c2 & 15)
        !           732:                return -1;
        !           733:            if (strcmp((char *) bp, "==") == 0)
        !           734:                bp += 1;
        !           735:            else if (strcmp((char *) bp, "=3D=3D") == 0)
        !           736:                bp += 5;
        !           737:            else
        !           738:                return -1;
        !           739: #ifdef EBCDIC
        !           740:        } else if ((c3 = asctobin[*bp]) & 0x80) {
        !           741: #else
        !           742:        } else if (*bp & 0x80 || (c3 = asctobin[*bp]) & 0x80) {
        !           743: #endif
        !           744:            return -1;
        !           745:        } else {
        !           746:            if (*++bp == PAD) {
        !           747:                c4 = 0;
        !           748:                length += 2;
        !           749:                if (c3 & 3)
        !           750:                    return -1;
        !           751:                if (strcmp((char *) bp, "=") == 0);     /* All is well */
        !           752:                else if (strcmp((char *) bp, "=3D") == 0)
        !           753:                    bp += 2;
        !           754:                else
        !           755:                    return -1;
        !           756: #ifdef EBCDIC
        !           757:            } else if ((c4 = asctobin[*bp]) & 0x80) {
        !           758: #else
        !           759:            } else if (*bp & 0x80 || (c4 = asctobin[*bp]) & 0x80) {
        !           760: #endif
        !           761:                return -1;
        !           762:            } else {
        !           763:                length += 3;
        !           764:            }
        !           765:        }
        !           766:        ++bp;
        !           767:        j = (c1 << 2) | (c2 >> 4);
        !           768:        *outbuf++ = j;
        !           769:        j = (c2 << 4) | (c3 >> 2);
        !           770:        *outbuf++ = j;
        !           771:        j = (c3 << 6) | c4;
        !           772:        *outbuf++ = j;
        !           773:     }
        !           774: 
        !           775:     *outlength = length;
        !           776:     return 0;                  /* normal return */
        !           777: 
        !           778: }                              /* darmor_buffer */
        !           779: 
        !           780: static char armorfilename[MAX_PATH];
        !           781: /*
        !           782:  * try to open the next file of a multi-part armored file
        !           783:  * the sequence number is expected at the end of the file name
        !           784:  */
        !           785: static FILE *
        !           786: open_next(void)
        !           787: {
        !           788:     char *p, *s, c;
        !           789:     FILE *fp;
        !           790: 
        !           791:     p = armorfilename + strlen(armorfilename);
        !           792:     while (--p >= armorfilename && isdigit(*p)) {
        !           793:        if (*p != '9') {
        !           794:            ++*p;
        !           795:            return fopen(armorfilename, FOPRARMOR);
        !           796:        }
        !           797:        *p = '0';
        !           798:     }
        !           799: 
        !           800:     /* need an extra digit */
        !           801:     if (p >= armorfilename) {
        !           802:        /* try replacing character ( .as0 -> .a10 ) */
        !           803:        c = *p;
        !           804:        *p = '1';
        !           805:        if ((fp = fopen(armorfilename, FOPRARMOR)) != NULL)
        !           806:            return fp;
        !           807:        *p = c;                 /* restore original character */
        !           808:     }
        !           809:     ++p;
        !           810:     for (s = p + strlen(p); s >= p; --s)
        !           811:        s[1] = *s;
        !           812:     *p = '1';                  /* insert digit ( fn0 -> fn10 ) */
        !           813: 
        !           814: #if defined(MSDOS) && !defined(BUG)
        !           815:     /* if the resulting filename has more than three
        !           816:        characters after the first dot, don't even try to open it */
        !           817:     s = strchr(armorfilename, '.');
        !           818:     if (s != NULL)
        !           819:        if (strlen(s) > 3)
        !           820:           return NULL;
        !           821: #endif /* MSDOS */
        !           822: 
        !           823:     return fopen(armorfilename, FOPRARMOR);
        !           824: }
        !           825: 
        !           826: /*
        !           827:  * Returns -1 if the line given is does not begin as a valid ASCII
        !           828:  * armor header line (something of the form "Label: ", where "Label"
        !           829:  * must begin with a letter followed by letters, numbers, or hyphens,
        !           830:  * followed immediately by a colon and a space), 0 if it is a familiar
        !           831:  * label, and the length of the label if it is an unfamiliar label
        !           832:  * (E.g. not "Version" or "Comment");
        !           833:  */
        !           834: static int
        !           835: isheaderline(char const *buf)
        !           836: {
        !           837:        int i;
        !           838: 
        !           839:        if (!isalpha(*buf))
        !           840:                return -1;      /* Not a label */
        !           841: 
        !           842:        for (i = 1; isalnum(buf[i]) || i == '-'; i++)
        !           843:                ;
        !           844:        if (buf[i] != ':' || buf[i+1] != ' ')
        !           845:                return -1;      /* Not a label */
        !           846: 
        !           847:        if (memcmp(buf, "Charset", i) == 0) {
        !           848:                if (use_charset_header) strcpy(charset_header,buf+9);
        !           849:                return 0;
        !           850:        }
        !           851:        if (memcmp(buf, "Version", i) == 0 ||
        !           852:            memcmp(buf, "Comment", i) == 0)
        !           853:                return 0;       /* Familiar label */
        !           854:        return i;       /* Unfamiliar label */
        !           855: }
        !           856: 
        !           857: /* 
        !           858:  * Skips a bunch of headers, either returning 0, or printing
        !           859:  * an error message and returning -1.
        !           860:  * If it encounters an unfamiliar label and *warned is not set,
        !           861:  * prints a warning and sets *warned.
        !           862:  * NOTE that file read errors are NOT printed or reported in the
        !           863:  * return code.  It is assumed that the following read will
        !           864:  * notice the error and do something appropriate.
        !           865:  */
        !           866: static int
        !           867: skipheaders(FILE *in, char *buf, int *warned, int armorfollows)
        !           868: {
        !           869:     int label_seen = 0;
        !           870:     int i;
        !           871: #ifndef STRICT_ARMOR   /* Allow no space */
        !           872:     long fpos;
        !           873:     char outbuf[(MAX_LINE_SIZE*3+3)/4];
        !           874:     int n;
        !           875: #endif
        !           876: 
        !           877:     for (;;) {
        !           878:        ++infile_line;
        !           879: #ifndef STRICT_ARMOR
        !           880:        fpos = ftell(in);
        !           881: #endif
        !           882:        if (get_armor_line(buf, in) == NULL)    /* Error */
        !           883:            return 0;   /* See comment above */
        !           884:        if (buf[0] == '\0')     /* Blank line */
        !           885:            return 0;   /* Success */
        !           886:        if (label_seen && (buf[0] == ' ' || buf[0] == '\t'))
        !           887:            continue;   /* RFC-822-style continuation line */
        !           888:        i = isheaderline(buf);
        !           889:        if (i < 0) {    /* Not a legal header line */
        !           890: #ifndef STRICT_ARMOR   /* If it's as ASCII armor line, accept it */
        !           891:            if (armorfollows && darmor_buffer(buf, outbuf, &n) == 0 && n == 48)
        !           892:            {
        !           893:                fseek(in, fpos, SEEK_SET);
        !           894:                --infile_line;
        !           895:                return 0;       /* Consider this acceptable */
        !           896:            }
        !           897: #else
        !           898:            (void)armorfollows; /* Stop compiler complaints */
        !           899: #endif
        !           900:            fprintf(pgpout,
        !           901: LANG("Invalid ASCII armor header line: \"%.40s\"\n\
        !           902: ASCII armor corrupted.\n"), buf);
        !           903:            return -1;
        !           904:        }
        !           905:        if (i > 0 && !*warned) {
        !           906:                fprintf(pgpout,
        !           907: LANG("Warning: Unrecognized ASCII armor header label \"%.*s:\" ignored.\n"),
        !           908:                        i, buf);
        !           909:                *warned = 1;
        !           910:        }
        !           911:        label_seen = 1; /* Continuation lines are now legal */
        !           912:     }
        !           913: }
        !           914: 
        !           915: /*
        !           916:  * Copy from in to out, decoding as you go, with handling for multiple
        !           917:  * 500-line blocks of encoded data.  This function also knows how to
        !           918:  * go past the end of one part to the beginning of the next in a multi-part
        !           919:  * file.  (As you can see from some ugliness below, this is not the best
        !           920:  * place to do it, since the caller is responsible for closing the
        !           921:  * "original_in" file.)
        !           922:  */
        !           923: static int
        !           924: armordecode(FILE *original_in, FILE *out, int *warned)
        !           925: {
        !           926:     char inbuf[MAX_LINE_SIZE];
        !           927:     char outbuf[MAX_LINE_SIZE];
        !           928: 
        !           929:     int i, n, status;
        !           930:     int line;
        !           931:     int section, currentSection = 1;
        !           932:     int noSections = 0;
        !           933:     int gotcrc = 0;
        !           934:     long crc = CRCINIT, chkcrc = -1;
        !           935:     char crcbuf[4];
        !           936:     int ret_code = 0;
        !           937:     int end_of_message;
        !           938:     FILE *in = original_in;
        !           939: 
        !           940:     init_crc();
        !           941: 
        !           942:     for (line = 1;; line++) {  /* for each input line */
        !           943:        if (get_armor_line(inbuf, in) == NULL) {
        !           944:            end_of_message = 1;
        !           945:        } else {
        !           946:            end_of_message =
        !           947:                (strncmp(inbuf, "-----END PGP MESSAGE,", 21) == 0);
        !           948:            ++infile_line;
        !           949:        }
        !           950: 
        !           951:        if (currentSection != noSections && end_of_message) {
        !           952:            /* End of this section */
        !           953:            if (gotcrc) {
        !           954:                if (chkcrc != crc) {
        !           955:                    fprintf(pgpout,
        !           956:  LANG("ERROR: Bad ASCII armor checksum in section %d.\n"), currentSection);
        !           957: /* continue with decoding to see if there are other bad parts */
        !           958:                    ret_code = -1;
        !           959:                }
        !           960:            }
        !           961:            gotcrc = 0;
        !           962:            crc = CRCINIT;
        !           963:            section = 0;
        !           964: 
        !           965:            /* Try and find start of next section */
        !           966:            do {
        !           967:                if (get_armor_line(inbuf, in) == NULL) {
        !           968:                    if (in != original_in)
        !           969:                        fclose(in);
        !           970:                    if ((in = open_next()) != NULL)
        !           971:                        continue;       /* Keep working on new in */
        !           972:                    fprintf(pgpout,
        !           973:                    LANG("Can't find section %d.\n"), currentSection + 1);
        !           974:                    return -1;
        !           975:                }
        !           976:                ++infile_line;
        !           977:            }
        !           978:            while (strncmp(inbuf, "-----BEGIN PGP MESSAGE", 22));
        !           979: 
        !           980:            /* Make sure this section is the correct one */
        !           981:            if (2 != sscanf(inbuf,
        !           982:                            "-----BEGIN PGP MESSAGE, PART %d/%d",
        !           983:                            &section, &noSections)) {
        !           984:                fprintf(pgpout,
        !           985:                        LANG("Badly formed section delimiter, part %d.\n"),
        !           986:                        currentSection + 1);
        !           987:                goto error;
        !           988:            }
        !           989:            if (section != ++currentSection) {
        !           990:                fprintf(pgpout,
        !           991: LANG("Sections out of order, expected part %d"), currentSection);
        !           992:                if (section)
        !           993:                    fprintf(pgpout,
        !           994:                            LANG(", got part %d\n"), section);
        !           995:                else
        !           996:                    fputc('\n', pgpout);
        !           997:                goto error;
        !           998:            }
        !           999:            /* Skip header after BEGIN line */
        !          1000:            if (skipheaders(in, inbuf, warned, 1) < 0)
        !          1001:                goto error;
        !          1002:            if (feof(in)) {
        !          1003:                fprintf(pgpout,
        !          1004:                   LANG("ERROR: Hit EOF in header of section %d.\n"),
        !          1005:                        currentSection);
        !          1006:                goto error;
        !          1007:            }
        !          1008:                
        !          1009:            /* Continue decoding */
        !          1010:            continue;
        !          1011:        }
        !          1012: #ifdef MACTC5
        !          1013:        mac_poll_for_break();
        !          1014: #endif
        !          1015: 
        !          1016: /* Quit when hit the -----END PGP MESSAGE----- line or a blank,
        !          1017:  * or handle checksum
        !          1018:  */
        !          1019:        if (inbuf[0] == PAD) {  /* Checksum lines start
        !          1020:                                   with PAD char */
        !          1021:            /* If the already-armored file is sent through MIME
        !          1022:             * and gets armored again, '=' will become '=3D'.
        !          1023:             * To make life easier, we detect and work around this
        !          1024:             * idiosyncracy.
        !          1025:             */
        !          1026:            if (strlen(inbuf) == 7 &&
        !          1027:                inbuf[1] == '3' && inbuf[2] == 'D')
        !          1028:                status = darmor_buffer(inbuf + 3, crcbuf, &n);
        !          1029:            else
        !          1030:                status = darmor_buffer(inbuf + 1, crcbuf, &n);
        !          1031:            if (status < 0 || n != 3) {
        !          1032:                fprintf(pgpout,
        !          1033: LANG("ERROR: Badly formed ASCII armor checksum, line %d.\n"), line);
        !          1034:                 goto error;
        !          1035:            }
        !          1036:            chkcrc = (((long) crcbuf[0] << 16) & 0xff0000L) +
        !          1037:                ((crcbuf[1] << 8) & 0xff00L) + (crcbuf[2] & 0xffL);
        !          1038:            gotcrc = 1;
        !          1039:            continue;
        !          1040:        }
        !          1041:        if (inbuf[0] == '\0') {
        !          1042:            fprintf(pgpout,
        !          1043:                    LANG("WARNING: No ASCII armor `END' line.\n"));
        !          1044:            break;
        !          1045:        }
        !          1046:        if (strncmp(inbuf, "-----END PGP ", 13) == 0)
        !          1047:            break;
        !          1048: 
        !          1049:        status = darmor_buffer(inbuf, outbuf, &n);
        !          1050: 
        !          1051:        if (status == -1) {
        !          1052:            fprintf(pgpout,
        !          1053:             LANG("ERROR: Bad ASCII armor character, line %d.\n"), line);
        !          1054:            gotcrc = 1;         /* this will print part number,
        !          1055:                                   continue with next part */
        !          1056:            ret_code = -1;
        !          1057:        }
        !          1058:        if (n > sizeof outbuf) {
        !          1059:            fprintf(pgpout,
        !          1060:             LANG("ERROR: Bad ASCII armor line length %d on line %d.\n"),
        !          1061:                    n, line);
        !          1062:            goto error;
        !          1063:        }
        !          1064:        crc = crcbytes((byte *) outbuf, n, crc);
        !          1065:        if (fwrite(outbuf, 1, n, out) != n) {
        !          1066:            ret_code = -1;
        !          1067:            break;
        !          1068:        }
        !          1069:     }                          /* line */
        !          1070: 
        !          1071:     if (gotcrc) {
        !          1072:        if (chkcrc != crc) {
        !          1073:            fprintf(pgpout,
        !          1074:                    LANG("ERROR: Bad ASCII armor checksum"));
        !          1075:            if (noSections > 0)
        !          1076:                fprintf(pgpout,
        !          1077:                        LANG(" in section %d"), noSections);
        !          1078:            fputc('\n', pgpout);
        !          1079:            goto error;
        !          1080:        }
        !          1081:     } else {
        !          1082:        fprintf(pgpout,
        !          1083:                LANG("Warning: Transport armor lacks a checksum.\n"));
        !          1084:     }
        !          1085: 
        !          1086:     if (in != original_in)
        !          1087:        fclose(in);
        !          1088:     return ret_code;           /* normal return */
        !          1089: error:
        !          1090:     if (in != original_in)
        !          1091:        fclose(in);
        !          1092:     return -1;                 /* error return */
        !          1093: }                              /* armordecode */
        !          1094: 
        !          1095: static boolean
        !          1096: is_armorfile(char *infile)
        !          1097: {
        !          1098:     FILE *in;
        !          1099:     char inbuf[MAX_LINE_SIZE];
        !          1100:     char outbuf[MAX_LINE_SIZE];
        !          1101:     int n;
        !          1102:     long il;
        !          1103: 
        !          1104:     in = fopen(infile, FOPRARMOR);
        !          1105:     if (in == NULL)
        !          1106:        return FALSE;   /* can't open file */
        !          1107:    
        !          1108:     /* Read to infile_line before we begin looking */
        !          1109:     for (il = 0; il < infile_line; ++il) {
        !          1110:        if (get_armor_line(inbuf, in) == NULL) {
        !          1111:            fclose(in);
        !          1112:            return FALSE;
        !          1113:        }
        !          1114:     }
        !          1115: 
        !          1116:     /* search file for delimiter line */
        !          1117:     for (;;) {
        !          1118:        if (get_armor_line(inbuf, in) == NULL)
        !          1119:            break;
        !          1120:        if (strncmp(inbuf, "-----BEGIN PGP ", 15) == 0) {
        !          1121:            if (strncmp(inbuf,
        !          1122:                    "-----BEGIN PGP SIGNED MESSAGE-----", 34) == 0) {
        !          1123:                fclose(in);
        !          1124:                return TRUE;
        !          1125:            }
        !          1126:            n = 1;      /* Don't print warnings yet */
        !          1127:            if (skipheaders(in, inbuf, &n, 1) < 0 ||
        !          1128:                get_armor_line(inbuf, in) == NULL ||
        !          1129:                darmor_buffer(inbuf, outbuf, &n) < 0)
        !          1130:                break;
        !          1131:            fclose(in);
        !          1132:            return TRUE;
        !          1133:        }
        !          1134:     }
        !          1135: 
        !          1136:     fclose(in);
        !          1137:     return FALSE;
        !          1138: }                              /* is_armorfile */
        !          1139: 
        !          1140: static int
        !          1141: darmor_file(char *infile, char *outfile)
        !          1142: {
        !          1143:     FILE *in, *out;
        !          1144:     char buf[MAX_LINE_SIZE];
        !          1145:     char outbuf[(MAX_LINE_SIZE*3+3)/4];
        !          1146:     int status, n;
        !          1147:     long il, fpos;
        !          1148:     char *litfile = NULL;
        !          1149:     int header_warned = 0;     /* Complained about unknown header */
        !          1150: 
        !          1151:     if ((in = fopen(infile, FOPRARMOR)) == NULL) {
        !          1152:        fprintf(pgpout, LANG("ERROR: Can't find file %s\n"), infile);
        !          1153:        return 10;
        !          1154:     }
        !          1155:     strcpy(armorfilename, infile);     /* store filename for multi-parts */
        !          1156: 
        !          1157:     /* Skip to infile_line */
        !          1158:     for (il = 0; il < infile_line; ++il) {
        !          1159:        if (get_armor_line(buf, in) == NULL) {
        !          1160:            fclose(in);
        !          1161:            return -1;
        !          1162:        }
        !          1163:     }
        !          1164: 
        !          1165:     /* Loop through file, searching for delimiter.  Decode anything with a
        !          1166:        delimiter, complain if there were no delimiter. */
        !          1167: 
        !          1168:     /* search file for delimiter line */
        !          1169:     for (;;) {
        !          1170:        ++infile_line;
        !          1171:        if (get_armor_line(buf, in) == NULL) {
        !          1172:            fprintf(pgpout,
        !          1173:                    LANG("ERROR: No ASCII armor `BEGIN' line!\n"));
        !          1174:            fclose(in);
        !          1175:            return 12;
        !          1176:        }
        !          1177:        if (strncmp(buf, "-----BEGIN PGP ", 15) == 0)
        !          1178:            break;
        !          1179:     }
        !          1180:     if (strncmp(buf, "-----BEGIN PGP SIGNED MESSAGE-----", 34) == 0) {
        !          1181:        FILE *litout;
        !          1182:        char *p;
        !          1183:        int nline;
        !          1184: 
        !          1185:        /*
        !          1186:         * It would be nice to allow headers here, as we could add
        !          1187:         * additional information to PGP messages, but it appears to
        !          1188:         * be too easy to spoof, given standard text viewers.  So,
        !          1189:         * forbid it outright until we sit down and figure out how to
        !          1190:         * thwart all the ways of faking an end-of-headers.  The
        !          1191:         * possibilities are:
        !          1192:         * - Enough trailing whitespace on a valid-looking line to force a
        !          1193:         *   line wrap.  The 80 column case is tricky, as the classical
        !          1194:         *   Big Iron IBM mainframe pads to 80 columns, and some terminal
        !          1195:         *   and text viewer combinations cause a blank line, while others
        !          1196:         *   don't.  A line that is exactly 80 columns wide but ends in
        !          1197:         *   a non-blank would do, too.
        !          1198:         * - A big pile of whitespace within a line, enough to 
        !          1199:         *   produce something that looks like a blank line between
        !          1200:         *   the beginning and end parts.
        !          1201:         * - Various cursor-control sequences.
        !          1202:         * Basically, it's a nasty problem.  A very strong case can be made
        !          1203:         * for the argument that it's the text viewer's problem, and outside
        !          1204:         * PGP's jurisdiction, but that has a few conflicts with reality.
        !          1205:         */
        !          1206:        charset_header[0] = '\0';
        !          1207:        if (get_armor_line(buf, in) == NULL) {
        !          1208:                fprintf(pgpout,
        !          1209: LANG("ERROR: ASCII armor decode input ended unexpectedly!\n"));
        !          1210:                fclose(in);
        !          1211:                return 12;
        !          1212:        }
        !          1213:        if (buf[0] != '\0') {
        !          1214:                fprintf(pgpout,
        !          1215: LANG("ERROR: Header line added to ASCII armor: \"%s\"\n\
        !          1216: ASCII armor corrupted.\n"), buf);
        !          1217:                fclose(in);
        !          1218:                return -1;
        !          1219:                
        !          1220:        }
        !          1221:                
        !          1222:        litfile = tempfile(TMP_WIPE | TMP_TMPDIR);
        !          1223:        if ((litout = fopen(litfile, FOPWTXT)) == NULL) {
        !          1224:            fprintf(pgpout,
        !          1225: LANG("\n\007Unable to write ciphertext output file '%s'.\n"), litfile);
        !          1226:            fclose(in);
        !          1227:            return -1;
        !          1228:        }
        !          1229: 
        !          1230:        status = 0;
        !          1231:        for (;;) {
        !          1232:            ++infile_line;
        !          1233:            nline = status;
        !          1234:            status = getline(buf, sizeof buf, in);
        !          1235:            if (status < 0) {
        !          1236:                fprintf(pgpout,
        !          1237: LANG("ERROR: ASCII armor decode input ended unexpectedly!\n"));
        !          1238:                fclose(in);
        !          1239:                fclose(litout);
        !          1240:                rmtemp(litfile);
        !          1241:                return 12;
        !          1242:            }
        !          1243:            if (strncmp(buf, "-----BEGIN PGP ", 15) == 0)
        !          1244:                break;
        !          1245:            if (nline)
        !          1246:                putc('\n', litout);
        !          1247:            /* De-quote lines starting with '- ' */
        !          1248:            fputs(buf + ((buf[0] == '-' && buf[1] == ' ') ? 2 : 0), litout);
        !          1249:            /* Copy trailing part of line, if any. */
        !          1250:            if (!status)
        !          1251:                status = copyline(in, litout);
        !          1252:            /* Ignore error; getline will discover it again */
        !          1253:        }
        !          1254:        fflush(litout);
        !          1255:        if (ferror(litout)) {
        !          1256:            fclose(litout);
        !          1257:            fclose(in);
        !          1258:            rmtemp(litfile);
        !          1259:            return -1;
        !          1260:        }
        !          1261:        fclose(litout);
        !          1262:     }
        !          1263:     /* Skip header after BEGIN line */
        !          1264:     if (skipheaders(in, buf, &header_warned, 1) < 0) {
        !          1265:        fclose(in);
        !          1266:        return -1;
        !          1267:     }
        !          1268:     if (feof(in)) {
        !          1269:        fprintf(pgpout, LANG("ERROR: Hit EOF in header.\n"));
        !          1270:        fclose(in);
        !          1271:        return 13;
        !          1272:     }
        !          1273: 
        !          1274:     if ((out = fopen(outfile, FOPWBIN)) == NULL) {
        !          1275:        fprintf(pgpout,
        !          1276: LANG("\n\007Unable to write ciphertext output file '%s'.\n"), outfile);
        !          1277:        fclose(in);
        !          1278:        return -1;
        !          1279:     }
        !          1280:     status = armordecode(in, out, &header_warned);
        !          1281: 
        !          1282:     if (litfile) {
        !          1283:        char *canonfile, hold_charset[16];
        !          1284:        char lit_mode = MODE_TEXT;
        !          1285:        word32 dummystamp = 0;
        !          1286:        FILE *f;
        !          1287: 
        !          1288:        /* Convert clearsigned message to internal character set */
        !          1289:        canonfile = tempfile(TMP_WIPE | TMP_TMPDIR);
        !          1290:        strip_spaces = TRUE;
        !          1291:         if (charset_header[0]) {
        !          1292:             strcpy(hold_charset, charset);
        !          1293:             strcpy(charset, charset_header);
        !          1294:             init_charset();
        !          1295:         }
        !          1296:        make_canonical(litfile, canonfile);
        !          1297:        rmtemp(litfile);
        !          1298:        litfile = canonfile;
        !          1299:         if (charset_header[0]) {
        !          1300:             strcpy(charset, hold_charset);
        !          1301:             init_charset();
        !          1302:        }
        !          1303:        /* Glue the literal file read above to the signature */
        !          1304:         f = fopen(litfile, FOPRBIN);
        !          1305: 
        !          1306:        write_ctb_len(out, CTB_LITERAL2_TYPE, fsize(f) + 6, FALSE);
        !          1307:        fwrite(&lit_mode, 1, 1, out);   /* write lit_mode */
        !          1308:        fputc('\0', out);       /* No filename */
        !          1309:        fwrite(&dummystamp, 1, sizeof(dummystamp), out);
        !          1310:        /* dummy timestamp */
        !          1311:        copyfile(f, out, -1L);  /* Append literal file */
        !          1312:        fclose(f);
        !          1313:        rmtemp(litfile);
        !          1314:     }
        !          1315:     if (write_error(out))
        !          1316:        status = -1;
        !          1317:     fclose(out);
        !          1318:     fclose(in);
        !          1319:     return status;
        !          1320: }                              /* darmor_file */
        !          1321: 
        !          1322: /* Entry points for generic interface names */
        !          1323: 
        !          1324: int de_armor_file(char *infile, char *outfile, long *curline)
        !          1325: {
        !          1326:     int status;
        !          1327: 
        !          1328:     if (verbose)
        !          1329:        fprintf(pgpout,
        !          1330:             "de_armor_file: infile = %s, outfile = %s, curline = %ld\n",
        !          1331:                infile, outfile, *curline);
        !          1332:     infile_line = (curline ? *curline : 0);
        !          1333:     status = darmor_file(infile, outfile);
        !          1334:     if (curline)
        !          1335:        *curline = infile_line;
        !          1336:     return status;
        !          1337: }
        !          1338: 
        !          1339: boolean
        !          1340: is_armor_file(char *infile, long startline)
        !          1341: {
        !          1342:     infile_line = startline;
        !          1343:     return is_armorfile(infile);
        !          1344: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.