|
|
1.1.1.6 ! root 1: /* config.c - config file parser by Peter Gutmann ! 2: Parses config file for PGP ! 3: ! 4: (c) Copyright 1990-1994 by Philip Zimmermann. All rights reserved. ! 5: The author assumes no liability for damages resulting from the use ! 6: of this software, even if the damage results from defects in this ! 7: software. No warranty is expressed or implied. ! 8: ! 9: Note that while most PGP source modules bear Philip Zimmermann's ! 10: copyright notice, many of them have been revised or entirely written ! 11: by contributors who frequently failed to put their names in their ! 12: code. Code that has been incorporated into PGP from other authors ! 13: was either originally published in the public domain or is used with ! 14: permission from the various authors. ! 15: ! 16: PGP is available for free to the public under certain restrictions. ! 17: See the PGP User's Guide (included in the release package) for ! 18: important information about licensing, patent restrictions on ! 19: certain algorithms, trademarks, copyrights, and export controls. ! 20: ! 21: Modified 24 Jun 92 - HAJK ! 22: Misc fixes for VAX C restrictions. ! 23: ! 24: */ ! 25: ! 26: #include <ctype.h> ! 27: #include <string.h> ! 28: #include <stdio.h> ! 29: #include <stdlib.h> ! 30: #include "usuals.h" ! 31: #include "fileio.h" ! 32: #include "pgp.h" ! 33: #include "config.h" ! 34: #include "charset.h" ! 35: ! 36: static int lookup( char *key, int keyLength, char *keyWords[], int range ); ! 37: static int extractToken( char *buffer, int *endIndex, int *length ); ! 38: static int getaString( char *buffer, int *endIndex ); ! 39: static int getAssignment( char *buffer, int *endIndex, INPUT_TYPE settingType ); ! 40: static void processAssignment( int intrinsicIndex ); ! 41: ! 42: /* The external config variables we can set here are referenced in pgp.h */ ! 43: ! 44: /* Return values */ ! 45: ! 46: #define ERROR -1 ! 47: #define OK 0 ! 48: ! 49: /* The types of error we check for */ ! 50: ! 51: enum { NO_ERROR, ILLEGAL_CHAR_ERROR, LINELENGTH_ERROR }; ! 52: ! 53: #define CPM_EOF 0x1A /* ^Z = CPM EOF char */ ! 54: ! 55: #define MAX_ERRORS 3 /* Max.no.errors before we give up */ ! 56: ! 57: #define LINEBUF_SIZE 100 /* Size of input buffer */ ! 58: ! 59: static int line; /* The line on which an error occurred */ ! 60: static int errCount; /* Total error count */ ! 61: static boolean hasError; /* Whether this line has an error in it */ ! 62: ! 63: /* The settings parsed out by getAssignment() */ ! 64: ! 65: static char str[ LINEBUF_SIZE ]; ! 66: static int value; ! 67: static boolean flag; ! 68: static char *errtag; /* prefix for printing error messages */ ! 69: static char optstr[100]; /* option being processed */ ! 70: ! 71: /* A .CFG file roughly follows the format used in the world-famous HPACK ! 72: archiver and is as follows: ! 73: ! 74: - Leading spaces/tabs (whitespace) are ignored. ! 75: ! 76: - Lines with a '#' as the first non-whitespace character are treated as ! 77: comment lines. ! 78: ! 79: - All other lines are treated as config options for the program. ! 80: ! 81: - Lines may be terminated by either linefeeds, carriage returns, or ! 82: carriage return/linefeed pairs (the latter being the DOS default ! 83: method of storing text files). ! 84: ! 85: - Config options have the form: ! 86: ! 87: <option> '=' <setting> ! 88: ! 89: where <setting> may be 'on', 'off', a numeric value, or a string ! 90: value. ! 91: ! 92: - If strings have spaces or the '#' character inside them they must be ! 93: surrounded by quote marks '"' */ ! 94: ! 95: /* Intrinsic variables */ ! 96: ! 97: #define NO_INTRINSICS (sizeof(intrinsics) / sizeof(intrinsics[0])) ! 98: ! 99: enum ! 100: { ARMOR, COMPRESS, SHOWPASS, KEEPBINARY, LANGUAGE, ! 101: MYNAME, TEXTMODE, TMP, TZFIX, VERBOSE, BAKRING, ! 102: ARMORLINES, COMPLETES_NEEDED, MARGINALS_NEEDED, PAGER, ! 103: CERT_DEPTH, CHARSET, CLEAR, SELF_ENCRYPT, ! 104: INTERACTIVE, PKCS_COMPAT, PUBRING, SECRING, RANDSEED, ! 105: COMMENT, ! 106: /* options below this line can only be used as command line ! 107: * "long" options */ ! 108: #define CONFIG_INTRINSICS BATCHMODE ! 109: BATCHMODE, FORCE, LEGAL_KLUDGE, NOMANUAL ! 110: }; ! 111: ! 112: static char *intrinsics[] = ! 113: { "ARMOR", "COMPRESS", "SHOWPASS", "KEEPBINARY", "LANGUAGE", ! 114: "MYNAME", "TEXTMODE", "TMP", "TZFIX", "VERBOSE", "BAKRING", ! 115: "ARMORLINES", "COMPLETES_NEEDED", "MARGINALS_NEEDED", "PAGER", ! 116: "CERT_DEPTH", "CHARSET", "CLEARSIG", "ENCRYPTTOSELF", ! 117: "INTERACTIVE", "PKCS_COMPAT", "PUBRING", "SECRING", "RANDSEED", ! 118: "COMMENT", ! 119: /* command line only */ ! 120: "BATCHMODE", "FORCE", "LEGAL_KLUDGE", "NOMANUAL" ! 121: }; ! 122: ! 123: static INPUT_TYPE intrinsicType[] = ! 124: { BOOL, BOOL, BOOL, BOOL, STRING, ! 125: STRING, BOOL, STRING, NUMERIC, NUMERIC, STRING, ! 126: NUMERIC, NUMERIC, NUMERIC, STRING, ! 127: NUMERIC, STRING, BOOL, BOOL, ! 128: BOOL, NUMERIC, STRING, STRING, STRING, ! 129: STRING, ! 130: /* command line only */ ! 131: BOOL, BOOL, BOOL, BOOL ! 132: }; ! 133: ! 134: /* Possible settings for variables */ ! 135: ! 136: #define NO_SETTINGS 2 ! 137: ! 138: static char *settings[] = { "OFF", "ON" }; ! 139: ! 140: ! 141: /* Search a list of keywords for a match */ ! 142: ! 143: static int lookup( char *key, int keyLength, char *keyWords[], int range ) ! 144: { ! 145: int indx, pos = 0, matches = 0; ! 146: ! 147: strncpy(optstr, key, keyLength); ! 148: optstr[keyLength] = '\0'; ! 149: /* Make the search case insensitive */ ! 150: for( indx = 0; indx < keyLength; indx++ ) ! 151: key[ indx ] = to_upper( key[ indx ] ); ! 152: ! 153: for( indx = 0; indx < range; indx++ ) ! 154: if( !strncmp( key, keyWords[ indx ], keyLength ) ) { ! 155: if (strlen(keyWords[indx]) == keyLength) ! 156: return indx; /* exact match */ ! 157: pos = indx; ! 158: ++matches; ! 159: } ! 160: ! 161: switch (matches) { ! 162: case 0: ! 163: fprintf(stderr, "%s: unknown keyword: \"%s\"\n", errtag, optstr); ! 164: break; ! 165: case 1: ! 166: return pos; ! 167: default: ! 168: fprintf(stderr, "%s: \"%s\" is ambiguous\n", errtag, optstr); ! 169: } ! 170: return ERROR; ! 171: } ! 172: ! 173: /* Extract a token from a buffer */ ! 174: static int extractToken( char *buffer, int *endIndex, int *length ) ! 175: { ! 176: int indx = 0, tokenStart; ! 177: char ch; ! 178: ! 179: /* Skip whitespace */ ! 180: for( ch = buffer[ indx ]; ch && ( ch == ' ' || ch == '\t' ); ch = buffer[ indx ] ) ! 181: indx++; ! 182: tokenStart = indx; ! 183: ! 184: /* Find end of setting */ ! 185: while( indx < LINEBUF_SIZE && ( ch = buffer[ indx ] ) != '\0' && ch != ' ' && ch != '\t' ) ! 186: indx++; ! 187: *endIndex += indx; ! 188: *length = indx - tokenStart; ! 189: ! 190: /* Return start position of token in buffer */ ! 191: return tokenStart; ! 192: } ! 193: ! 194: ! 195: /* Get a string constant */ ! 196: static int getaString( char *buffer, int *endIndex ) ! 197: { ! 198: boolean noQuote = FALSE; ! 199: int stringIndex = 0, bufIndex = 1; ! 200: char ch = *buffer; ! 201: ! 202: /* Skip whitespace */ ! 203: while( ch && ( ch == ' ' || ch == '\t' ) ) ! 204: ch = buffer[ bufIndex++ ]; ! 205: ! 206: /* Check for non-string */ ! 207: if( ch != '\"' ) { ! 208: *endIndex += bufIndex; ! 209: ! 210: /* Check for special case of null string */ ! 211: if( !ch ) { ! 212: *str = '\0'; ! 213: return OK; ! 214: } ! 215: ! 216: /* Use nasty non-rigorous string format */ ! 217: noQuote = TRUE; ! 218: } ! 219: ! 220: /* Get first char of string */ ! 221: if( !noQuote ) ! 222: ch = buffer[ bufIndex++ ]; ! 223: ! 224: /* Get string into string */ ! 225: while( ch && ch != '\"' ) { ! 226: /* Exit on '#' if using non-rigorous format */ ! 227: if( noQuote && ch == '#' ) ! 228: break; ! 229: ! 230: str[ stringIndex++ ] = ch; ! 231: ch = buffer[ bufIndex++ ]; ! 232: } ! 233: ! 234: /* If using the non-rigorous format, stomp trailing spaces */ ! 235: if( noQuote ) ! 236: while( stringIndex > 0 && str[ stringIndex - 1 ] == ' ' ) ! 237: stringIndex--; ! 238: ! 239: str[ stringIndex++ ] = '\0'; ! 240: *endIndex += bufIndex; ! 241: ! 242: /* Check for missing string terminator */ ! 243: if( ch != '\"' && !noQuote ) { ! 244: if (line) ! 245: fprintf(stderr, "%s: unterminated string in line %d\n", errtag, line ); ! 246: else ! 247: fprintf(stderr, "unterminated string: '\"%s'\n", str ); ! 248: hasError = TRUE; ! 249: errCount++; ! 250: return ERROR; ! 251: } ! 252: ! 253: return OK; ! 254: } ! 255: ! 256: /* Get an assignment to an intrinsic */ ! 257: static int getAssignment( char *buffer, int *endIndex, INPUT_TYPE settingType ) ! 258: { ! 259: int settingIndex = 0, length; ! 260: ! 261: buffer += extractToken( buffer, endIndex, &length ); ! 262: ! 263: /* Check for an assignment operator */ ! 264: if ( *buffer != '=' ) { ! 265: if (line) ! 266: fprintf(stderr, "%s: expected '=' in line %d\n", errtag, line ); ! 267: else ! 268: fprintf(stderr, "%s: expected '=' after \"%s\"\n", errtag, optstr); ! 269: hasError = TRUE; ! 270: errCount++; ! 271: return ERROR; ! 272: } ! 273: buffer++; /* Skip '=' */ ! 274: ! 275: buffer += extractToken( buffer, endIndex, &length ); ! 276: ! 277: switch( settingType ) { ! 278: case BOOL: ! 279: /* Check for known intrinsic - really more general than just ! 280: checking for TRUE or FALSE */ ! 281: if( ( settingIndex = lookup( buffer, length, settings, NO_SETTINGS ) ) == ERROR ) ! 282: { ! 283: hasError = TRUE; ! 284: errCount++; ! 285: return ERROR; ! 286: } ! 287: ! 288: flag = ( settingIndex == 0 ) ? FALSE : TRUE; ! 289: break; ! 290: ! 291: case STRING: ! 292: /* Get a string */ ! 293: getaString( buffer, &length ); ! 294: break; ! 295: ! 296: case NUMERIC: ! 297: /* Get numeric input. Error checking is a pain since atoi() ! 298: has no real equivalent of NAN */ ! 299: value = atoi( buffer ); ! 300: break; ! 301: } ! 302: ! 303: return settingIndex; ! 304: } ! 305: ! 306: /* Process an assignment */ ! 307: ! 308: static void processAssignment( int intrinsicIndex ) ! 309: { ! 310: if( !hasError ) ! 311: switch( intrinsicIndex ) { ! 312: case ARMOR: ! 313: emit_radix_64 = flag; ! 314: break; ! 315: ! 316: case COMPRESS: ! 317: compress_enabled = flag; ! 318: break; ! 319: ! 320: case SHOWPASS: ! 321: showpass = flag; ! 322: break; ! 323: ! 324: case KEEPBINARY: ! 325: keepctx = flag; ! 326: break; ! 327: ! 328: case LANGUAGE: ! 329: strncpy(language, str, 15); ! 330: break; ! 331: ! 332: case BAKRING: ! 333: strcpy(floppyring, str); ! 334: break; ! 335: ! 336: case MYNAME: ! 337: strcpy(my_name, str); ! 338: break; ! 339: ! 340: case TEXTMODE: ! 341: if( flag ) ! 342: literal_mode = MODE_TEXT; ! 343: else ! 344: literal_mode = MODE_BINARY; ! 345: break; ! 346: ! 347: case TMP: ! 348: /* directory pathname to store temp files */ ! 349: settmpdir(str); ! 350: break; ! 351: ! 352: case TZFIX: ! 353: /* How many hours to add to time() to get GMT. */ ! 354: /* Compute seconds from hours to shift to GMT: */ ! 355: timeshift = 3600L * (long) value; ! 356: break; ! 357: ! 358: case VERBOSE: ! 359: if (value < 1) { ! 360: quietmode = TRUE; verbose = FALSE; ! 361: } else if (value == 1) { ! 362: quietmode = FALSE; verbose = FALSE; ! 363: } else { /* value > 1 */ ! 364: quietmode = FALSE; verbose = TRUE; ! 365: } ! 366: break; ! 367: ! 368: case ARMORLINES: ! 369: pem_lines = value; ! 370: break; ! 371: ! 372: case MARGINALS_NEEDED: ! 373: marg_min = value; ! 374: if (marg_min < 1) ! 375: marg_min = 1; ! 376: break; ! 377: ! 378: case COMPLETES_NEEDED: ! 379: compl_min = value; ! 380: if (compl_min < 1) ! 381: compl_min = 1; ! 382: if (compl_min > 4) ! 383: compl_min = 4; ! 384: break; ! 385: ! 386: case CERT_DEPTH: ! 387: max_cert_depth = value; ! 388: if (max_cert_depth < 0) ! 389: max_cert_depth = 0; ! 390: if (max_cert_depth > 8) ! 391: max_cert_depth = 8; ! 392: break; ! 393: ! 394: case PAGER: ! 395: strcpy(pager, str); ! 396: break; ! 397: ! 398: case CHARSET: ! 399: strcpy(charset, str); ! 400: break; ! 401: ! 402: case CLEAR: ! 403: clear_signatures = flag; ! 404: break; ! 405: ! 406: case SELF_ENCRYPT: ! 407: encrypt_to_self = flag; ! 408: break; ! 409: ! 410: case INTERACTIVE: ! 411: interactive_add = flag; ! 412: break; ! 413: ! 414: case BATCHMODE: batchmode = flag; break; ! 415: case FORCE: force_flag = flag; break; ! 416: case PKCS_COMPAT: pkcs_compat = value; break; ! 417: ! 418: /* Undocumented flag to test contractually-mandated time bomb */ ! 419: case LEGAL_KLUDGE: ! 420: legal_kludge = value; ! 421: break; ! 422: ! 423: case NOMANUAL: nomanual = value; break; ! 424: ! 425: case PUBRING: ! 426: strcpy(globalPubringName, str); ! 427: break; ! 428: ! 429: case SECRING: ! 430: strcpy(globalSecringName, str); ! 431: break; ! 432: ! 433: case RANDSEED: ! 434: strcpy(globalRandseedName, str); ! 435: break; ! 436: ! 437: case COMMENT: ! 438: strcpy(globalCommentString, str); ! 439: break; ! 440: } ! 441: } ! 442: ! 443: /* Process an option on a line by itself. This expects options which are ! 444: taken from the command-line, and is less finicky about errors than the ! 445: config-file version */ ! 446: ! 447: int processConfigLine( char *option ) ! 448: { ! 449: int indx, intrinsicIndex; ! 450: char ch; ! 451: ! 452: /* Give it a pseudo-linenumber of 0 */ ! 453: line = 0; ! 454: ! 455: errtag = "pgp"; ! 456: errCount = 0; ! 457: for( indx = 0; ! 458: indx < LINEBUF_SIZE && ( ch = option[ indx ] ) != '\0' && ! 459: ch != ' ' && ch != '\t' && ch != '='; ! 460: indx++ ); ! 461: if( ( intrinsicIndex = lookup( ( char * ) option, indx, intrinsics, NO_INTRINSICS ) ) == ERROR ) ! 462: return -1; ! 463: if (option[indx] == '\0' && intrinsicType[intrinsicIndex] == BOOL) ! 464: { ! 465: /* boolean option, no '=' means TRUE */ ! 466: flag = TRUE; ! 467: processAssignment(intrinsicIndex); ! 468: } else /* Get the value to set to, either as a string, a ! 469: numeric value, or a boolean flag */ ! 470: if (getAssignment( ( char * ) option + indx, &indx, intrinsicType[ intrinsicIndex ] ) != ERROR) ! 471: processAssignment( intrinsicIndex ); ! 472: return errCount ? -1 : 0; ! 473: } ! 474: ! 475: /* Process a config file */ ! 476: int processConfigFile( char *configFileName ) ! 477: { ! 478: FILE *configFilePtr; ! 479: int ch = 0, theCh; ! 480: int errType, errPos = 0, lineBufCount, intrinsicIndex; ! 481: int indx; ! 482: char inBuffer[ LINEBUF_SIZE ]; ! 483: ! 484: line = 1; ! 485: errCount = 0; ! 486: errtag = "config.txt"; ! 487: ! 488: if( ( configFilePtr = fopen( configFileName, FOPRTXT ) ) == NULL ) { ! 489: fprintf(stderr, "Cannot open configuration file %s\n", configFileName ); ! 490: return OK; /* treat like empty config file */ ! 491: } ! 492: ! 493: /* Process each line in the configFile */ ! 494: while( ch != EOF ) { ! 495: /* Skip whitespace */ ! 496: while( ( ( ch = getc( configFilePtr ) ) == ' ' || ch == '\t' ) && ch != EOF ) ! 497: ; ! 498: ! 499: /* Get a line into the inBuffer */ ! 500: hasError = FALSE; ! 501: lineBufCount = 0; ! 502: errType = NO_ERROR; ! 503: while( ch != '\r' && ch != '\n' && ch != CPM_EOF && ch != EOF ) ! 504: { ! 505: /* Check for an illegal char in the data */ ! 506: if( ( ch < ' ' || ch > '~' ) && ch != '\r' && ch != '\n' && ! 507: ch != ' ' && ch != '\t' && ch != CPM_EOF && ch != EOF ) ! 508: { ! 509: if( errType == NO_ERROR ) ! 510: /* Save position of first illegal char */ ! 511: errPos = lineBufCount; ! 512: errType = ILLEGAL_CHAR_ERROR; ! 513: } ! 514: ! 515: /* Make sure the path is of the correct length. Note that the ! 516: code is ordered so that a LINELENGTH_ERROR takes precedence over ! 517: an ILLEGAL_CHAR_ERROR */ ! 518: if( lineBufCount > LINEBUF_SIZE ) ! 519: errType = LINELENGTH_ERROR; ! 520: else ! 521: inBuffer[ lineBufCount++ ] = ch; ! 522: ! 523: if( ( ch = getc( configFilePtr ) ) == '#' ) ! 524: { ! 525: /* Skip comment section and trailing whitespace */ ! 526: while( ch != '\r' && ch != '\n' && ch != CPM_EOF && ch != EOF ) ! 527: ch = getc( configFilePtr ); ! 528: break; ! 529: } ! 530: } ! 531: ! 532: /* Skip trailing whitespace and add der terminador */ ! 533: while(lineBufCount && (( theCh = inBuffer[ lineBufCount - 1 ] ) == ' ' || theCh == '\t' )) ! 534: lineBufCount--; ! 535: ! 536: inBuffer[ lineBufCount ] = '\0'; ! 537: ! 538: /* Process the line unless its a blank or comment line */ ! 539: if( lineBufCount && *inBuffer != '#' ) ! 540: { ! 541: switch( errType ) ! 542: { ! 543: case LINELENGTH_ERROR: ! 544: fprintf(stderr, "%s: line '%.30s...' too long\n", errtag, inBuffer ); ! 545: errCount++; ! 546: break; ! 547: ! 548: case ILLEGAL_CHAR_ERROR: ! 549: fprintf(stderr, "> %s\n ", inBuffer ); ! 550: fprintf(stderr, "%*s^\n", errPos, ""); ! 551: fprintf(stderr, "%s: bad character in command on line %d\n", errtag, line ); ! 552: errCount++; ! 553: break; ! 554: ! 555: default: ! 556: for( indx = 0; ! 557: indx < LINEBUF_SIZE && ( ch = inBuffer[ indx ] ) != '\0' ! 558: && ch != ' ' && ch != '\t' && ch != '='; ! 559: indx++ ) ! 560: ; ! 561: if( ( intrinsicIndex = lookup( inBuffer, indx, intrinsics, CONFIG_INTRINSICS ) ) == ERROR ) ! 562: { ! 563: errCount++; ! 564: } else { ! 565: /* Get the value to set to, either as a string, a ! 566: numeric value, or a boolean flag */ ! 567: getAssignment( inBuffer + indx, &indx, intrinsicType[ intrinsicIndex ] ); ! 568: processAssignment( intrinsicIndex ); ! 569: } ! 570: } ! 571: } ! 572: ! 573: /* Handle special-case of ^Z if configFile came off an MSDOS system */ ! 574: if( ch == CPM_EOF ) ! 575: ch = EOF; ! 576: ! 577: /* Exit if there are too many errors */ ! 578: if( errCount >= MAX_ERRORS ) ! 579: break; ! 580: ! 581: line++; ! 582: } ! 583: ! 584: fclose( configFilePtr ); ! 585: ! 586: /* Exit if there were errors */ ! 587: if( errCount ) { ! 588: fprintf(stderr, "%s: %s%d error(s) detected\n\n", configFileName, ( errCount >= MAX_ERRORS ) ? ! 589: "Maximum level of " : "", errCount ); ! 590: return ERROR; ! 591: } ! 592: ! 593: return OK; ! 594: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.