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