--- pgp/src/config.c 2018/04/24 16:37:53 1.1 +++ pgp/src/config.c 2018/04/24 16:41:09 1.1.1.5 @@ -1,6 +1,23 @@ /* config.c - config file parser by Peter Gutmann Parses config file for PGP + (c) Copyright 1990-1994 by Philip Zimmermann. All rights reserved. + The author assumes no liability for damages resulting from the use + of this software, even if the damage results from defects in this + software. No warranty is expressed or implied. + + Note that while most PGP source modules bear Philip Zimmermann's + copyright notice, many of them have been revised or entirely written + by contributors who frequently failed to put their names in their + code. Code that has been incorporated into PGP from other authors + was either originally published in the public domain or is used with + permission from the various authors. + + PGP is available for free to the public under certain restrictions. + See the PGP User's Guide (included in the release package) for + important information about licensing, patent restrictions on + certain algorithms, trademarks, copyrights, and export controls. + Modified 24 Jun 92 - HAJK Misc fixes for VAX C restrictions. @@ -11,7 +28,17 @@ #include #include #include "usuals.h" +#include "fileio.h" #include "pgp.h" +#include "config.h" +#include "charset.h" + +static int lookup( char *key, int keyLength, char *keyWords[], int range ); +static int extractToken( char *buffer, int *endIndex, int *length ); +static int getaString( char *buffer, int *endIndex ); +static int getAssignment( char *buffer, int *endIndex, INPUT_TYPE settingType ); +static void processAssignment( int intrinsicIndex ); + /* The external config variables we can set here are referenced in pgp.h */ /* Return values */ @@ -29,15 +56,17 @@ enum { NO_ERROR, ILLEGAL_CHAR_ERROR, LIN #define LINEBUF_SIZE 100 /* Size of input buffer */ -int line; /* The line on which an error occurred */ -int errCount; /* Total error count */ -boolean hasError; /* Whether this line has an error in it */ +static int line; /* The line on which an error occurred */ +static int errCount; /* Total error count */ +static boolean hasError; /* Whether this line has an error in it */ /* The settings parsed out by getAssignment() */ -char str[ LINEBUF_SIZE ]; -int value; -boolean flag; +static char str[ LINEBUF_SIZE ]; +static int value; +static boolean flag; +static char *errtag; /* prefix for printing error messages */ +static char optstr[100]; /* option being processed */ /* A .CFG file roughly follows the format used in the world-famous HPACK archiver and is as follows: @@ -50,8 +79,8 @@ boolean flag; - All other lines are treated as config options for the program. - Lines may be terminated by either linefeeds, carriage returns, or - carriage return/linefeed pairs (the latter being the DOS default method - of storing text files). + carriage return/linefeed pairs (the latter being the DOS default + method of storing text files). - Config options have the form: @@ -63,84 +92,108 @@ boolean flag; - If strings have spaces or the '#' character inside them they must be surrounded by quote marks '"' */ -/* The types of input we can expect */ - -typedef enum { BOOL, NUMERIC, STRING } INPUT_TYPE; - /* Intrinsic variables */ -#define NO_INTRINSICS 17 +#define NO_INTRINSICS (sizeof(intrinsics) / sizeof(intrinsics[0])) enum { ARMOR, COMPRESS, SHOWPASS, KEEPBINARY, LANGUAGE, MYNAME, TEXTMODE, TMP, TZFIX, VERBOSE, BAKRING, ARMORLINES, COMPLETES_NEEDED, MARGINALS_NEEDED, PAGER, - CERT_DEPTH, CHARSET + CERT_DEPTH, CHARSET, CLEAR, SELF_ENCRYPT, + INTERACTIVE, PKCS_COMPAT, PUBRING, SECRING, RANDSEED, + COMMENT, + /* options below this line can only be used as command line + * "long" options */ +#define CONFIG_INTRINSICS BATCHMODE + BATCHMODE, FORCE }; -char *intrinsics[] = +static char *intrinsics[] = { "ARMOR", "COMPRESS", "SHOWPASS", "KEEPBINARY", "LANGUAGE", "MYNAME", "TEXTMODE", "TMP", "TZFIX", "VERBOSE", "BAKRING", "ARMORLINES", "COMPLETES_NEEDED", "MARGINALS_NEEDED", "PAGER", - "CERT_DEPTH", "CHARSET" + "CERT_DEPTH", "CHARSET", "CLEARSIG", "ENCRYPTTOSELF", + "INTERACTIVE", "PKCS_COMPAT", "PUBRING", "SECRING", "RANDSEED", + "COMMENT", + /* command line only */ + "BATCHMODE", "FORCE", }; -INPUT_TYPE intrinsicType[] = +static INPUT_TYPE intrinsicType[] = { BOOL, BOOL, BOOL, BOOL, STRING, - STRING, BOOL, STRING, NUMERIC, BOOL, STRING, + STRING, BOOL, STRING, NUMERIC, NUMERIC, STRING, NUMERIC, NUMERIC, NUMERIC, STRING, - NUMERIC, STRING + NUMERIC, STRING, BOOL, BOOL, + BOOL, NUMERIC, STRING, STRING, STRING, + STRING, + /* command line only */ + BOOL, BOOL, }; /* Possible settings for variables */ #define NO_SETTINGS 2 -char *settings[] = { "OFF", "ON" }; +static char *settings[] = { "OFF", "ON" }; /* Search a list of keywords for a match */ -int lookup( char *key, int keyLength, char *keyWords[], int range ) - { - int index; +static int lookup( char *key, int keyLength, char *keyWords[], int range ) +{ + int indx, pos = 0, matches = 0; + strncpy(optstr, key, keyLength); + optstr[keyLength] = '\0'; /* Make the search case insensitive */ - for( index = 0; index < keyLength; index++ ) - key[ index ] = toupper( key[ index ] ); + for( indx = 0; indx < keyLength; indx++ ) + key[ indx ] = to_upper( key[ indx ] ); - for( index = 0; index < range; index++ ) - if( !strncmp( key, keyWords[ index ], keyLength ) ) - return( index ); - - /* Key not found */ - return( ERROR ); + for( indx = 0; indx < range; indx++ ) + if( !strncmp( key, keyWords[ indx ], keyLength ) ) { + if (strlen(keyWords[indx]) == keyLength) + return indx; /* exact match */ + pos = indx; + ++matches; + } + + switch (matches) { + case 0: + fprintf(stderr, "%s: unknown keyword: \"%s\"\n", errtag, optstr); + break; + case 1: + return pos; + default: + fprintf(stderr, "%s: \"%s\" is ambiguous\n", errtag, optstr); } + return ERROR; +} /* Extract a token from a buffer */ -int extractToken( char *buffer, int *endIndex, int *length ) +static int extractToken( char *buffer, int *endIndex, int *length ) { - int index = 0, tokenStart; + int indx = 0, tokenStart; char ch; /* Skip whitespace */ - for( ch = buffer[ index ]; ch && ( ch == ' ' || ch == '\t' ); ch = buffer[ index ] ) - index++; - tokenStart = index; + for( ch = buffer[ indx ]; ch && ( ch == ' ' || ch == '\t' ); ch = buffer[ indx ] ) + indx++; + tokenStart = indx; /* Find end of setting */ - while( index < LINEBUF_SIZE && ( ch = buffer[ index ] ) != '\0' && ch != ' ' && ch != '\t' ) - index++; - *endIndex += index; - *length = index - tokenStart; + while( indx < LINEBUF_SIZE && ( ch = buffer[ indx ] ) != '\0' && ch != ' ' && ch != '\t' ) + indx++; + *endIndex += indx; + *length = indx - tokenStart; /* Return start position of token in buffer */ - return( tokenStart ); + return tokenStart; } /* Get a string constant */ -int getaString( char *buffer, int *endIndex ) +static int getaString( char *buffer, int *endIndex ) { boolean noQuote = FALSE; int stringIndex = 0, bufIndex = 1; @@ -151,35 +204,32 @@ int getaString( char *buffer, int *endIn ch = buffer[ bufIndex++ ]; /* Check for non-string */ - if( ch != '\"' ) - { + if( ch != '\"' ) { *endIndex += bufIndex; /* Check for special case of null string */ - if( !ch ) - { + if( !ch ) { *str = '\0'; - return( OK ); - } + return OK; + } /* Use nasty non-rigorous string format */ noQuote = TRUE; - } + } /* Get first char of string */ if( !noQuote ) ch = buffer[ bufIndex++ ]; /* Get string into string */ - while( ch && ch != '\"' ) - { + while( ch && ch != '\"' ) { /* Exit on '#' if using non-rigorous format */ if( noQuote && ch == '#' ) break; str[ stringIndex++ ] = ch; ch = buffer[ bufIndex++ ]; - } + } /* If using the non-rigorous format, stomp trailing spaces */ if( noQuote ) @@ -190,67 +240,230 @@ int getaString( char *buffer, int *endIn *endIndex += bufIndex; /* Check for missing string terminator */ - if( ch != '\"' && !noQuote ) - { - printf( "Unterminated string in line %d\n", line ); + if( ch != '\"' && !noQuote ) { + if (line) + fprintf(stderr, "%s: unterminated string in line %d\n", errtag, line ); + else + fprintf(stderr, "unterminated string: '\"%s'\n", str ); hasError = TRUE; errCount++; - return( ERROR ); - } - - return( OK ); + return ERROR; } + return OK; +} + /* Get an assignment to an intrinsic */ -int getAssignment( char *buffer, int *endIndex, INPUT_TYPE settingType ) +static int getAssignment( char *buffer, int *endIndex, INPUT_TYPE settingType ) { int settingIndex = 0, length; buffer += extractToken( buffer, endIndex, &length ); /* Check for an assignment operator */ - if ( *buffer != '=' ) - { - printf( "Expected '=' in line %d\n", line ); + if ( *buffer != '=' ) { + if (line) + fprintf(stderr, "%s: expected '=' in line %d\n", errtag, line ); + else + fprintf(stderr, "%s: expected '=' after \"%s\"\n", errtag, optstr); hasError = TRUE; errCount++; - return( ERROR ); + return ERROR; } buffer++; /* Skip '=' */ buffer += extractToken( buffer, endIndex, &length ); - switch( settingType ) - { - case BOOL: - /* Check for known intrinsic - really more general than just - checking for TRUE or FALSE */ - if( ( settingIndex = lookup( buffer, length, settings, NO_SETTINGS ) ) == ERROR ) - { - printf( "Unknown setting '%s' in line %d\n", buffer, line ); - hasError = TRUE; - errCount++; - return( ERROR ); + switch( settingType ) { + case BOOL: + /* Check for known intrinsic - really more general than just + checking for TRUE or FALSE */ + if( ( settingIndex = lookup( buffer, length, settings, NO_SETTINGS ) ) == ERROR ) + { + hasError = TRUE; + errCount++; + return ERROR; + } + + flag = ( settingIndex == 0 ) ? FALSE : TRUE; + break; + + case STRING: + /* Get a string */ + getaString( buffer, &length ); + break; + + case NUMERIC: + /* Get numeric input. Error checking is a pain since atoi() + has no real equivalent of NAN */ + value = atoi( buffer ); + break; + } + + return settingIndex; +} + +/* Process an assignment */ + +static void processAssignment( int intrinsicIndex ) +{ + if( !hasError ) + switch( intrinsicIndex ) { + case ARMOR: + emit_radix_64 = flag; + break; + + case COMPRESS: + compress_enabled = flag; + break; + + case SHOWPASS: + showpass = flag; + break; + + case KEEPBINARY: + keepctx = flag; + break; + + case LANGUAGE: + strncpy(language, str, 15); + break; + + case BAKRING: + strcpy(floppyring, str); + break; + + case MYNAME: + strcpy(my_name, str); + break; + + case TEXTMODE: + if( flag ) + literal_mode = MODE_TEXT; + else + literal_mode = MODE_BINARY; + break; + + case TMP: + /* directory pathname to store temp files */ + settmpdir(str); + break; + + case TZFIX: + /* How many hours to add to time() to get GMT. */ + /* Compute seconds from hours to shift to GMT: */ + timeshift = 3600L * (long) value; + break; + + case VERBOSE: + if (value < 1) { + quietmode = TRUE; verbose = FALSE; + } else if (value == 1) { + quietmode = FALSE; verbose = FALSE; + } else { /* value > 1 */ + quietmode = FALSE; verbose = TRUE; } + break; - flag = ( settingIndex == 0 ) ? FALSE : TRUE; + case ARMORLINES: + pem_lines = value; break; - case STRING: - /* Get a string */ - getaString( buffer, &length ); + case MARGINALS_NEEDED: + marg_min = value; + if (marg_min < 1) + marg_min = 1; break; - case NUMERIC: - /* Get numeric input. Error checking is a pain since atoi() - has no real equivalent of NAN */ - value = atoi( buffer ); + case COMPLETES_NEEDED: + compl_min = value; + if (compl_min < 1) + compl_min = 1; + if (compl_min > 4) + compl_min = 4; + break; + + case CERT_DEPTH: + max_cert_depth = value; + if (max_cert_depth < 0) + max_cert_depth = 0; + if (max_cert_depth > 8) + max_cert_depth = 8; + break; + + case PAGER: + strcpy(pager, str); + break; + + case CHARSET: + strcpy(charset, str); + break; + + case CLEAR: + clear_signatures = flag; + break; + + case SELF_ENCRYPT: + encrypt_to_self = flag; + break; + + case INTERACTIVE: + interactive_add = flag; + break; + + case BATCHMODE: batchmode = flag; break; + case FORCE: force_flag = flag; break; + case PKCS_COMPAT: pkcs_compat = value; break; + + case PUBRING: + strcpy(globalPubringName, str); + break; + + case SECRING: + strcpy(globalSecringName, str); break; - } - return( settingIndex ); + case RANDSEED: + strcpy(globalRandseedName, str); + break; + + case COMMENT: + strcpy(globalCommentString, str); + break; + } } +/* Process an option on a line by itself. This expects options which are + taken from the command-line, and is less finicky about errors than the + config-file version */ + +int processConfigLine( char *option ) +{ + int indx, intrinsicIndex; + char ch; + + /* Give it a pseudo-linenumber of 0 */ + line = 0; + + errtag = "pgp"; + errCount = 0; + for( indx = 0; + indx < LINEBUF_SIZE && ( ch = option[ indx ] ) != '\0' && + ch != ' ' && ch != '\t' && ch != '='; + indx++ ); + if( ( intrinsicIndex = lookup( ( char * ) option, indx, intrinsics, NO_INTRINSICS ) ) == ERROR ) + return -1; + if (option[indx] == '\0' && intrinsicType[intrinsicIndex] == BOOL) + { + /* boolean option, no '=' means TRUE */ + flag = TRUE; + processAssignment(intrinsicIndex); + } else /* Get the value to set to, either as a string, a + numeric value, or a boolean flag */ + if (getAssignment( ( char * ) option + indx, &indx, intrinsicType[ intrinsicIndex ] ) != ERROR) + processAssignment( intrinsicIndex ); + return errCount ? -1 : 0; +} /* Process a config file */ int processConfigFile( char *configFileName ) @@ -258,23 +471,23 @@ int processConfigFile( char *configFileN FILE *configFilePtr; int ch = 0, theCh; int errType, errPos = 0, lineBufCount, intrinsicIndex; - int index; + int indx; char inBuffer[ LINEBUF_SIZE ]; line = 1; errCount = 0; + errtag = "config.txt"; - if( ( configFilePtr = fopen( configFileName, "r" ) ) == NULL ) - { - printf( "Cannot open configuration file %s\n", configFileName ); - return( OK ); /* treat like empty config file */ + if( ( configFilePtr = fopen( configFileName, FOPRTXT ) ) == NULL ) { + fprintf(stderr, "Cannot open configuration file %s\n", configFileName ); + return OK; /* treat like empty config file */ } /* Process each line in the configFile */ - while( ch != EOF ) - { + while( ch != EOF ) { /* Skip whitespace */ - while( ( ( ch = getc( configFilePtr ) ) == ' ' || ch == '\t' ) && ch != EOF ); + while( ( ( ch = getc( configFilePtr ) ) == ' ' || ch == '\t' ) && ch != EOF ) + ; /* Get a line into the inBuffer */ hasError = FALSE; @@ -310,8 +523,9 @@ int processConfigFile( char *configFileN } /* Skip trailing whitespace and add der terminador */ - while( ( theCh = inBuffer[ lineBufCount - 1 ] ) == ' ' || theCh == '\t' ) + while(lineBufCount && (( theCh = inBuffer[ lineBufCount - 1 ] ) == ' ' || theCh == '\t' )) lineBufCount--; + inBuffer[ lineBufCount ] = '\0'; /* Process the line unless its a blank or comment line */ @@ -319,123 +533,33 @@ int processConfigFile( char *configFileN { switch( errType ) { - case LINELENGTH_ERROR: - inBuffer[ 80 - strlen( "Line '%s...' too long\n" ) - 3 ] = '\0'; - /* Truncate to fit screen size (3 = '%s' + 1) */ - printf( "Line '%s...' too long\n", inBuffer ); - errCount++; - break; - - case ILLEGAL_CHAR_ERROR: - printf( "> %s\n ", inBuffer ); - while( errPos-- ) - putchar( ' ' ); - printf( "^ Bad character in command on line %d\n", line ); - errCount++; - break; + case LINELENGTH_ERROR: + fprintf(stderr, "%s: line '%.30s...' too long\n", errtag, inBuffer ); + errCount++; + break; - default: - for( index = 0; - index < LINEBUF_SIZE && ( ch = inBuffer[ index ] ) != '\0' && ch != ' ' && ch != '\t'; - index++ ); - if( ( intrinsicIndex = lookup( inBuffer, index, intrinsics, NO_INTRINSICS ) ) == ERROR ) - { - printf( "Unknown command '%s' in line %d\n", inBuffer, line ); - errCount++; - } - else - { - /* Get the value to set to, either as a string, a - numeric value, or a boolean flag */ - getAssignment( inBuffer + index, &index, intrinsicType[ intrinsicIndex ] ); - - if( !hasError ) - switch( intrinsicIndex ) - { - case ARMOR: - emit_radix_64 = flag; - break; - - case COMPRESS: - compress_enabled = flag; - break; - - case SHOWPASS: - showpass = flag; - break; - - case KEEPBINARY: - keepctx = flag; - break; - - case LANGUAGE: - strncpy(language, str, 15); - break; - - case BAKRING: - strcpy(floppyring, str); - break; - - case MYNAME: - strcpy(my_name, str); - break; - - case TEXTMODE: - if( flag ) - lit_mode = MODE_TEXT; - break; - - case TMP: - /* directory pathname to store temp files */ - strcpy(tmpdir, str); - break; - - case TZFIX: - /* How many hours to add to time() to get GMT. */ - /* Compute seconds from hours to shift to GMT: */ - timeshift = 3600L * (long) value; - break; - - case VERBOSE: - verbose = flag; - break; - - case ARMORLINES: - pem_lines = value; - break; - - case MARGINALS_NEEDED: - marg_min = value; - if (marg_min < 1) - marg_min = 1; - break; - - case COMPLETES_NEEDED: - compl_min = value; - if (compl_min < 1) - compl_min = 1; - if (compl_min > 4) - compl_min = 4; - break; - - case CERT_DEPTH: - max_cert_depth = value; - if (max_cert_depth < 0) - max_cert_depth = 0; - if (max_cert_depth > 8) - max_cert_depth = 8; - break; - - case PAGER: - strcpy(pager, str); - break; - - case CHARSET: - strcpy(charset, str); - break; + case ILLEGAL_CHAR_ERROR: + fprintf(stderr, "> %s\n ", inBuffer ); + fprintf(stderr, "%*s^\n", errPos, ""); + fprintf(stderr, "%s: bad character in command on line %d\n", errtag, line ); + errCount++; + break; - } - } + default: + for( indx = 0; + indx < LINEBUF_SIZE && ( ch = inBuffer[ indx ] ) != '\0' + && ch != ' ' && ch != '\t' && ch != '='; + indx++ ) + ; + if( ( intrinsicIndex = lookup( inBuffer, indx, intrinsics, CONFIG_INTRINSICS ) ) == ERROR ) + { + errCount++; + } else { + /* Get the value to set to, either as a string, a + numeric value, or a boolean flag */ + getAssignment( inBuffer + indx, &indx, intrinsicType[ intrinsicIndex ] ); + processAssignment( intrinsicIndex ); + } } } @@ -453,12 +577,11 @@ int processConfigFile( char *configFileN fclose( configFilePtr ); /* Exit if there were errors */ - if( errCount ) - { - printf( "%s%d errors detected\n", ( errCount >= MAX_ERRORS ) ? + if( errCount ) { + fprintf(stderr, "%s: %s%d error(s) detected\n\n", configFileName, ( errCount >= MAX_ERRORS ) ? "Maximum level of " : "", errCount ); - return( ERROR ); + return ERROR; } - return( OK ); + return OK; }