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