Annotation of pgp/src/config.c, revision 1.1.1.4

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

unix.superglobalmegacorp.com

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