|
|
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
65: carriage return/linefeed pairs (the latter being the DOS default method
66: of storing text files).
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,
! 87: INTERACTIVE,
! 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",
! 99: "INTERACTIVE",
! 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,
! 109: BOOL,
! 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.2 root 326: break;
327:
328: case TMP:
329: /* directory pathname to store temp files */
330: settmpdir(str);
331: break;
332:
333: case TZFIX:
334: /* How many hours to add to time() to get GMT. */
335: /* Compute seconds from hours to shift to GMT: */
336: timeshift = 3600L * (long) value;
337: break;
338:
339: case VERBOSE:
1.1.1.3 ! root 340: switch (value)
! 341: {
! 342: case 0: quietmode = TRUE; verbose = FALSE; break;
! 343: case 1: quietmode = FALSE; verbose = FALSE; break;
! 344: case 2: quietmode = FALSE; verbose = TRUE; break;
! 345: default: quietmode = FALSE; verbose = FALSE;
! 346: }
1.1.1.2 root 347: break;
348:
349: case ARMORLINES:
350: pem_lines = value;
351: break;
352:
353: case MARGINALS_NEEDED:
354: marg_min = value;
355: if (marg_min < 1)
356: marg_min = 1;
357: break;
358:
359: case COMPLETES_NEEDED:
360: compl_min = value;
361: if (compl_min < 1)
362: compl_min = 1;
363: if (compl_min > 4)
364: compl_min = 4;
365: break;
366:
367: case CERT_DEPTH:
368: max_cert_depth = value;
369: if (max_cert_depth < 0)
370: max_cert_depth = 0;
371: if (max_cert_depth > 8)
372: max_cert_depth = 8;
373: break;
374:
375: case PAGER:
376: strcpy(pager, str);
377: break;
378:
379: case CHARSET:
380: strcpy(charset, str);
381: break;
382:
383: case CLEAR:
384: clear_signatures = flag;
385: break;
1.1.1.3 ! root 386:
! 387: case SELF_ENCRYPT:
! 388: encrypt_to_self = flag;
! 389: break;
! 390:
! 391: case INTERACTIVE:
! 392: interactive_add = flag;
! 393: break;
! 394:
! 395: case BATCHMODE: batchmode = flag; break;
! 396: case FORCE: force_flag = flag; break;
1.1.1.2 root 397: }
398: }
399:
400: /* Process an option on a line by itself. This expects options which are
401: taken from the command-line, and is less finicky about errors than the
402: config-file version */
403:
404: int processConfigLine( char *option )
405: {
1.1.1.3 ! root 406: int indx, intrinsicIndex;
1.1.1.2 root 407: char ch;
408:
409: /* Give it a pseudo-linenumber of 0 */
410: line = 0;
411:
412: errtag = "pgp";
413: errCount = 0;
1.1.1.3 ! root 414: for( indx = 0;
! 415: indx < LINEBUF_SIZE && ( ch = option[ indx ] ) != '\0' &&
1.1.1.2 root 416: ch != ' ' && ch != '\t' && ch != '=';
1.1.1.3 ! root 417: indx++ );
! 418: if( ( intrinsicIndex = lookup( ( char * ) option, indx, intrinsics, NO_INTRINSICS ) ) == ERROR )
1.1.1.2 root 419: return -1;
1.1.1.3 ! root 420: if (option[indx] == '\0' && intrinsicType[intrinsicIndex] == BOOL)
1.1.1.2 root 421: { /* boolean option, no '=' means TRUE */
422: flag = TRUE;
423: processAssignment(intrinsicIndex);
424: }
425: else /* Get the value to set to, either as a string, a
426: numeric value, or a boolean flag */
1.1.1.3 ! root 427: if (getAssignment( ( char * ) option + indx, &indx, intrinsicType[ intrinsicIndex ] ) != ERROR)
1.1.1.2 root 428: processAssignment( intrinsicIndex );
429: return(errCount ? -1 : 0);
430: }
431:
432: /* Process a config file */
433: int processConfigFile( char *configFileName )
434: {
435: FILE *configFilePtr;
436: int ch = 0, theCh;
437: int errType, errPos = 0, lineBufCount, intrinsicIndex;
1.1.1.3 ! root 438: int indx;
1.1.1.2 root 439: char inBuffer[ LINEBUF_SIZE ];
440:
441: line = 1;
442: errCount = 0;
443: errtag = "config.txt";
444:
445: if( ( configFilePtr = fopen( configFileName, FOPRTXT ) ) == NULL )
446: {
447: fprintf(stderr, "Cannot open configuration file %s\n", configFileName );
448: return( OK ); /* treat like empty config file */
449: }
450:
451: /* Process each line in the configFile */
452: while( ch != EOF )
453: {
454: /* Skip whitespace */
1.1.1.3 ! root 455: while( ( ( ch = getc( configFilePtr ) ) == ' ' || ch == '\t' ) && ch != EOF )
! 456: ;
1.1.1.2 root 457:
458: /* Get a line into the inBuffer */
459: hasError = FALSE;
460: lineBufCount = 0;
461: errType = NO_ERROR;
462: while( ch != '\r' && ch != '\n' && ch != CPM_EOF && ch != EOF )
463: {
464: /* Check for an illegal char in the data */
465: if( ( ch < ' ' || ch > '~' ) && ch != '\r' && ch != '\n' &&
466: ch != ' ' && ch != '\t' && ch != CPM_EOF && ch != EOF )
467: {
468: if( errType == NO_ERROR )
469: /* Save position of first illegal char */
470: errPos = lineBufCount;
471: errType = ILLEGAL_CHAR_ERROR;
472: }
473:
474: /* Make sure the path is of the correct length. Note that the
475: code is ordered so that a LINELENGTH_ERROR takes precedence over
476: an ILLEGAL_CHAR_ERROR */
477: if( lineBufCount > LINEBUF_SIZE )
478: errType = LINELENGTH_ERROR;
479: else
480: inBuffer[ lineBufCount++ ] = ch;
481:
482: if( ( ch = getc( configFilePtr ) ) == '#' )
483: {
484: /* Skip comment section and trailing whitespace */
485: while( ch != '\r' && ch != '\n' && ch != CPM_EOF && ch != EOF )
486: ch = getc( configFilePtr );
487: break;
488: }
489: }
490:
491: /* Skip trailing whitespace and add der terminador */
492: while(lineBufCount && (( theCh = inBuffer[ lineBufCount - 1 ] ) == ' ' || theCh == '\t' ))
493: lineBufCount--;
494:
495: inBuffer[ lineBufCount ] = '\0';
496:
497: /* Process the line unless its a blank or comment line */
498: if( lineBufCount && *inBuffer != '#' )
499: {
500: switch( errType )
501: {
502: case LINELENGTH_ERROR:
503: fprintf(stderr, "%s: line '%.30s...' too long\n", errtag, inBuffer );
504: errCount++;
505: break;
506:
507: case ILLEGAL_CHAR_ERROR:
508: fprintf(stderr, "> %s\n ", inBuffer );
509: fprintf(stderr, "%*s^\n", errPos, "");
510: fprintf(stderr, "%s: bad character in command on line %d\n", errtag, line );
511: errCount++;
512: break;
513:
514: default:
1.1.1.3 ! root 515: for( indx = 0;
! 516: indx < LINEBUF_SIZE && ( ch = inBuffer[ indx ] ) != '\0'
1.1.1.2 root 517: && ch != ' ' && ch != '\t' && ch != '=';
1.1.1.3 ! root 518: indx++ )
! 519: ;
! 520: if( ( intrinsicIndex = lookup( inBuffer, indx, intrinsics, CONFIG_INTRINSICS ) ) == ERROR )
1.1.1.2 root 521: {
522: errCount++;
523: }
524: else
525: {
526: /* Get the value to set to, either as a string, a
527: numeric value, or a boolean flag */
1.1.1.3 ! root 528: getAssignment( inBuffer + indx, &indx, intrinsicType[ intrinsicIndex ] );
1.1.1.2 root 529: processAssignment( intrinsicIndex );
530: }
531: }
532: }
533:
534: /* Handle special-case of ^Z if configFile came off an MSDOS system */
535: if( ch == CPM_EOF )
536: ch = EOF;
537:
538: /* Exit if there are too many errors */
539: if( errCount >= MAX_ERRORS )
540: break;
541:
542: line++;
543: }
544:
545: fclose( configFilePtr );
546:
547: /* Exit if there were errors */
548: if( errCount )
549: {
550: fprintf(stderr, "%s: %s%d error(s) detected\n\n", configFileName, ( errCount >= MAX_ERRORS ) ?
551: "Maximum level of " : "", errCount );
552: return( ERROR );
553: }
554:
555: return( OK );
556: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.