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