pgpconf.c

来自「著名的加密软件的应用于电子邮件中」· C语言 代码 · 共 666 行 · 第 1/2 页

C
666
字号
/*
 * pgpConf.c - Parse configuration files and lines.
 *
 * Copyright (C) 1993-1997 Pretty Good Privacy, Inc. All rights reserved.
 *
 * Written by:	Colin Plumb and Derek Atkins <warlord@MIT.EDU>
 *
 * $Id: pgpConf.c,v 1.6.2.3.2.2 1997/07/14 16:44:34 quark Exp $
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>	 /* For strtol() */
#include <string.h>

#include "pgpConf.h"
#include "pgpEnv.h"
#include "pgpErr.h"
#include "pgpMsg.h"
#include "pgpUI.h"

struct Config {
			char const *name;
			int var;
			unsigned flags;
			int min, max;
	};

/* The following are in the flags: */
	#define OPT_TYPEMASK	3
	#define OPT_IGNORE	 0		/* Ignore if encountered */
	#define OPT_BINARY	 1		/* Boolean options: min = false, max = true */
	#define OPT_INT		2		/* Integer option, in range [min,max] */
	#define OPT_STRING	 3		/* String, of length <= max */
/* The following additional flags are also used: */
#define OPT_CMD		4	 /* Command line only */
#define OPT_LOWER	8	/* Lowercase strings before storing */
#define OPT_FUNC	16	/* Call function rather than set conf */

/* Up to this many errors are ignored when reading a config file. */
#define MAX_ERRORS 3	/* Don't give up right away on error. */

#define FUNC_RANDSOURCE	2

/* The options list. Indexes in the left margin are used in configInit. */
static struct Config
EnvOptions[] = {
	{ "armor",            PGPENV_ARMOR,       OPT_BINARY,     0, 1 },
	{ "armorlines",       PGPENV_ARMORLINES,  OPT_INT,        0, INT_MAX },
	{ "bakring",          PGPENV_BAKRING,     OPT_STRING,     0, 0 },
	{ "cert_depth",       PGPENV_CERTDEPTH,   OPT_INT,        0, 8 },
 	{ "charset",          PGPENV_CHARSET,     OPT_STRING,     0, 0 },
	{ "clearsign",        PGPENV_CLEARSIG,    OPT_BINARY,     0, 1 },
	{ "comment",          PGPENV_COMMENT,     OPT_STRING,     0, 70 },
	{ "completes_needed", PGPENV_COMPLETES,   OPT_INT,        1, 4 },
	{ "compress",         PGPENV_COMPRESS,    OPT_BINARY,     0, 1 },
	{ "companykey",       PGPENV_COMPANYKEY,  OPT_STRING,     0, 255 },
	{ "encrypttoself",    PGPENV_ENCRYPTTOSELF,OPT_BINARY,     0, 1 },
/*	{ "interactive",      PGPENV_INTERACTIVE, OPT_BINARY,     0, 1 },*/
/*	{ "keepbinary",       PGPENV_KEEPBINARY,  OPT_BINARY,     0, 1 },*/
	{ "language",         PGPENV_LANGUAGE,  OPT_STRING|OPT_LOWER,  0, 16 },
	{ "languagefile",     PGPENV_LANGUAGEFILE, OPT_STRING,    0, 0},
	{ "marginals_needed", PGPENV_MARGINALS,   OPT_INT,        1, 4 },
	{ "myname",           PGPENV_MYNAME,      OPT_STRING,     0, 255 },
/*	{ "pager",            PGPENV_PAGER,       OPT_STRING,     0, 255 },*/
/*	{ "pkcs_compat",      PGPENV_PKCS_COMPAT, OPT_INT,      0, INT_MAX },*/
	{ "pgp_mime",         PGPENV_PGPMIME,     OPT_BINARY,     0, 1 },
			{ "pgp_mimeparse",	PGPENV_PGPMIMEPARSEBODY, OPT_BINARY,0, 1 },
			{ "pubring",	PGPENV_PUBRING, OPT_STRING, 0, 0 },
			{ "randomdevice",	PGPENV_RANDOMDEVICE, OPT_STRING, 0, 0 },
			{ "randseed",	PGPENV_RANDSEED, OPT_STRING, 0, 0 },
#ifdef UNIX
	/*		{ "randsource",	FUNC_RANDSOURCE, OPT_STRING|OPT_FUNC, 0, 0 },*/
#endif
			{ "secring",	PGPENV_SECRING,	OPT_STRING,	0, 0 },
			{ "showpass",	PGPENV_SHOWPASS,	OPT_BINARY,	0, 1 },
			{ "textmode",	PGPENV_TEXTMODE,	OPT_BINARY,	0, 1 },
			{ "tmp",	PGPENV_TMP,	OPT_STRING,	0, 0 },
/* Temp for new trust - change to something better */
		{ "trusted",		PGPENV_TRUSTED,	OPT_INT,	0, 255 },
		{ "tzfix",		PGPENV_TZFIX,	OPT_INT,	-24, 24 },
		{ "verbose",		PGPENV_VERBOSE,	OPT_INT,	0, INT_MAX },
/* Experimental XXX@@@ */
			{ "version",	PGPENV_VERSION,	OPT_INT,	2, 4 },
			{ "ciphernum",		PGPENV_CIPHER,		OPT_INT,		1, INT_MAX },
			{ "hashnum",		PGPENV_HASH,		OPT_INT,		1, INT_MAX },
			{ "fastkeygen",	PGPENV_FASTKEYGEN, OPT_BINARY,	0, 1 },

			/* command line only */
			{ "batchmode",	PGPENV_BATCHMODE, OPT_BINARY|OPT_CMD, 0, 1 },
			{ "force",	PGPENV_FORCE,		OPT_BINARY|OPT_CMD, 0, 1 },
			{ "magic",	PGPENV_MAGIC,		OPT_BINARY|OPT_CMD, 0, 1 },
			{ "noout",	PGPENV_NOOUT,		OPT_BINARY|OPT_CMD, 0, 1 },
	{ "license",          PGPENV_LICENSE,     OPT_BINARY|OPT_CMD,  0, 1 },
	{ "headers",          PGPENV_HEADERS,     OPT_BINARY|OPT_CMD,  0, 1 },
			/* Null-terminated */
			{ (char const *)0,	0,	0,		0, 0 }
};

/* Case-insensitive memory compare */
static int
xmemicmp (char const *in1, char const *in2, int len)
	{
			while (len--) {
					if (tolower(*in1) != tolower(*in2))
							return 1;
					in1++;
					in2++;
			}
			return 0;
	}

/*
 * Find a keyword in a null-terminated options list.
 * Returns the option, or NULL if the option is ambiguous,
 * or a pointer to the null option if it is not found.
 * optmask is a mask of bits in the opt->flags list which cause
 * entries with any of those bits set to be ignored.
 */
static struct Config const *
configLookup (struct PgpUICb const *ui, void *arg, unsigned linenum,
			char const *key, unsigned keylen, int optmask)
	{
			struct Config *hit = NULL;
			int i;
			struct PgpUICbArg msgarg1, msgarg2, msgarg3, msgarg4;

			for (i=0; EnvOptions[i].name; i++) {
					if ((EnvOptions[i].flags & optmask) != 0)
						continue;
					if (xmemicmp(EnvOptions[i].name, key, keylen) != 0)
						continue;
					/* We have a match! */
					if (strlen(EnvOptions[i].name) == keylen)
						return (&(EnvOptions[i])); /* exact match */
					/* Do we have a double match? */
					if (hit) {
							msgarg1.type = PGP_UI_ARG_UNSIGNED;
							msgarg1.val.u = linenum;
							msgarg2.type = PGP_UI_ARG_BUFFER;
							msgarg2.val.buf.buf = (byte *)key;
							msgarg2.val.buf.len = keylen;
							msgarg3.type = PGP_UI_ARG_STRING;
							msgarg3.val.s = hit->name;
							msgarg4.type = PGP_UI_ARG_STRING;
							msgarg4.val.s = EnvOptions[i].name;
							ui->message (arg, PGPERR_CONFIG,
								 PGPMSG_CONFIG_AMBIGUOUS, 4, &msgarg1,
								 &msgarg2, &msgarg3, &msgarg4);

							return (struct Config const *)0;
					}
					/* Remember this match */
					hit = &(EnvOptions[i]);
					/* Keep looking for an exact match or ambiguity. */
			}

			if (hit) {
				 return hit;
			}

			msgarg1.type = PGP_UI_ARG_UNSIGNED;
			msgarg1.val.u = linenum;
			msgarg2.type = PGP_UI_ARG_BUFFER;
			msgarg2.val.buf.buf = (byte *)key;
			msgarg2.val.buf.len = keylen;
			ui->message (arg, PGPERR_CONFIG, PGPMSG_CONFIG_UNKNOWN_KEYWORD,
				 2, &msgarg1, &msgarg2);

			return (&EnvOptions[i]);
}

static int
configCallFunci (struct PgpEnv *env, int varnum, int val, int pri)
	{
			(void)env;
			(void)val;
			(void)pri;
			switch (varnum) {
			default:
				 return PGPERR_CONFIG_BADFUNC;
			}
	}

static int
configCallFuncs (struct PgpEnv *env, int varnum, char const *string, int len,
				 int pri)
	{
			(void)env;
			(void)string;
			(void)len;
			(void)pri;
			switch (varnum) {
			case FUNC_RANDSOURCE:
			default:
				 return PGPERR_CONFIG_BADFUNC;
			}
	}

/* Return the number of leading whitespace characters in a buffer */
static unsigned
skipWhite(char const *buf)
	{
			unsigned i = 0;

while (isspace(buf[i]))
	i++;

return i;
}

/*
 * Reduce "len" by the amount of trailing whitespace characters in the
 * string starting at buf and len characters long.
 */
static unsigned
unskipWhite(char const *buf, unsigned len)
	{
			while (len && isspace(buf[len-1]))
				 --len;

return len;
}

/*
 * Get a word up to the next non-graphic character, comment symbol (#)
 * or delimiter (such as '='). Set delimiter to a non-graphic character
 * (0 works well) to not use it.
 * Returns the length of the word found.
 */
static unsigned
getWord(char const *buf, char delimiter)
	{
			char c;
			int i = 0;

			do {
				 c = buf[i++];
			} while (isgraph(c) && c != '#' && c != delimiter);

			return i-1;
}

/*
 * Get a string in the nasty non-quoted format.
 * Spaces are allowed, but the string ends at a comment and
 * trailing whitespace is suppresed.
 * Returns the length of the string found.
 */
static unsigned
getString(char const *buf)
	{
			char c;
			unsigned i = 0;

			do
				 c = buf[i++];
			while (isprint(c) && c != '#');

			return unskipWhite(buf, i-1);
}

/*
 * Get a quoted string. Anything is allowed up to a trailing double
 * quote. Returns the length of the string found, or -1 on error.
 */
static unsigned
getQString(struct PgpUICb const *ui, void *arg, unsigned linenum,
			char const *buf)
{
			char c;
			unsigned i = 0;
			struct PgpUICbArg msgarg1, msgarg2;

			do
				 c = buf[i++];
			while (c && c != '"');

			--i;

if (c == '"')
	return i;

			/* Error case - drop trailing whitespace (like NL) when printing */
			msgarg1.type = PGP_UI_ARG_UNSIGNED;
			msgarg1.val.u = linenum;
			msgarg2.type = PGP_UI_ARG_BUFFER;
			msgarg2.val.buf.buf = (byte *)buf;
			msgarg2.val.buf.len = unskipWhite (buf, i);
	ui->message (arg, PGPERR_CONFIG, PGPMSG_CONFIG_STRINGEND,
		2, &msgarg1, &msgarg2);

	return (unsigned)-1;
}


/*
 * Parse a line of input. linenum == 0 indicates the command line,
 * and causes a few changes in activity:
 * - some extra parameters are recognized (OPT_CMD)
 * - "=ON" is implicit for boolean options
 * - error messages are printed differently
 * - Unknown keywords are fatal
 * - Strings need not be copied, since the argv array isn't going away
 *
 * Note that the input "line" array is not permanently modified, but it
 * is occasionally modified in place temporarily to install a trailing
 * null character in the middle.
 *
 * Returns 0 on success, a PGPERR_* on failure.
 */
static int
configLineParse(struct PgpUICb const *ui, void *arg, struct PgpEnv *env,
				 unsigned linenum, char *line, int pri)
	{
			char const *key;
			unsigned keylen;
			unsigned i;
			struct Config const *opt;
			long val;
			char *p;
			struct PgpUICbArg msgarg1, msgarg2, msgarg3, msgarg4, msgarg5;

			line += skipWhite (line);

			keylen = getWord (line, '=');
			if (!keylen)
				 return 0;	/* Blank line */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?