⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pgpuserio.c

📁 著名的加密软件的应用于电子邮件中
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * pgpUserIO.c -- PGP TTY user IO interfaces
 *
 * Copyright (C) 1995-1997 Pretty Good Privacy, Inc. All rights reserved.
 *
 * Written by:	Derek Atkins <warlord@MIT.EDU> and Colin Plumb
 * Modified by Brett A. Thomas <quark@baz.com> to use /dev/random
 *
 * $Id: pgpUserIO.c,v 1.5.2.10.2.5 1997/07/15 21:26:32 quark Exp $
 */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <ctype.h>
#include <stdio.h>
#include <string.h>

#if HAVE_SYS_TIME_H
#include <sys/time.h>
#if !TIME_WITH_SYS_TIME
#include <time.h>
#endif
#endif

#include <sys/types.h>
#include <sys/ioctl.h>
#include <fcntl.h>

#if HAVE_UNISTD_H
#include <unistd.h>
#endif

#if HAVE_STDARG_H
#include <stdarg.h>
#endif

#if HAVE_SYS_STAT_H
#include <sys/stat.h> /*for stat() to check for /dev/random*/
#endif

#include "pgpDebug.h"
#include "pgpFileRef.h"
#include "pgpAnnotate.h"
#include "pgpESK.h"
#include "pgpFileMod.h"
#include "pgpFixedKey.h"
#include "pgpMem.h"
#include "pgpPassCach.h"
#include "pgpErr.h"
#include "pgpFile.h"
#include "pgpMsg.h"
#include "pgpUI.h"
#include "pgpPipeline.h"
#include "pgpPubKey.h"
#include "pgpRndPool.h"
#include "pgpRngPub.h"
#include "pgpRngRead.h"
#include "pgpSig.h"
#include "pgpTimeDate.h"
#include "pgpUsuals.h"
#include "pgpEnv.h"
#include "pgpKB.h"
#include "pgpUserIO.h"
#include "pgpOutput.h"
#include "pgpRingUI.h"
#include "pgpMoreMod.h"
#include "pgpTypes.h"

/* Filename for dumping data we don't want to keep */
#ifdef MSDOS
#define NULLNAME "NUL"
#else
#define NULLNAME "/dev/null"
#endif

static unsigned
pgpDevRandomAccum(int fd, unsigned count);

static Boolean
CheckDevRandom(char **RandomDevice, PgpTtyUI *ui);

static Boolean
VerifyRandomDevOSVersion(void);

/*
 * Get a string from the keyboard into the supplied buffer.
 * If echo is true, echos to the InteractionOutput stream.
 * Otherwise prints nothing (and beeps go to stderr).
 * Returns the number of characters read (always <= len-1).
 */
int
pgpTtyGetString(char *buf, int len, int echo)
{
    int c;
    int n = 0;

    kbCbreak();
#ifdef MACINTOSH
    echo = NULL;	/* XXX: For now, the Mac version echoes by itself */
#endif

    for (;;) {
	c = kbGet();
	
	if (c == '\r' || c == '\n') {
	    c = '\n';
	    break;
	}
	else
	    if (c == '\b' || c == 7 || c == 127) {
		if (n > 0) {
		    n--;
		    if (echo)
			InteractionOutputString(FALSE, "\b \b");
		}
		else
		    InteractionOutputString(FALSE, "\a");
	    }
	    else
		if (c < ' ' || c > 256) {
		    InteractionOutputString(FALSE, "\a");
		}
		else
		    if (n + 1 >= len) {
			InteractionOutputString(FALSE, "\a");
				kbFlush(0);
		    }
		    else {
				if (echo)
			    InteractionOutputString(FALSE, "%c", c);
				buf[n++] = (char)c;
		    }
    }
    if (echo) {
	InteractionOutputString(FALSE, "\n");
    }
    buf[n] = '\0';

    kbNorm();
    return n;
}

/*
 * Prompts the user for Y or N (case insensitive), and returns
 * the appropriate boolean value.  If nothing is entered, <def>
 * is returned.  This assumes that a prompt has already been printed.
 */
int
pgpTtyGetBool(int def, int echo)
{
	char buf[2];

	for (;;) {
		if (pgpTtyGetString(buf, sizeof (buf), echo) == 0)
			return def;
		switch (buf[0]) {
			case 'y':
			case 'Y':
				return 1;
			case 'n':
			case 'N':
				return 0;
			default:
				break;
		}
		InteractionOutput(TRUE,
				  "ENTER_Y_OR_N",
				  def ? 'Y' : 'N');
	}
}

static void
pgpTtyPutKeyID (byte const *keyid)
{
    InformationOutputString(FALSE,
			    "0x%2.2X%2.2X%2.2X%2.2X\n",
			    keyid[4],
			    keyid[5],
			    keyid[6],
			    keyid[7]);
}

/*
 * Ask the user for a filename.
 * string is the default print string that should be used.  filename is
 * the default that will be used.  buffer is of size buflen, and is
 * used to store the new filename.
 *
 * returns the length of the contents of buffer, which must be a real
 * filename (trailing white space must be stripped) */
static int
pgpTtyNeedFile (char *buffer, int buflen)
{
	char *p;

	*buffer = '\0';
	pgpTtyGetString (buffer, buflen, 1);

	p = buffer + strlen(buffer) - 1;
	while (p >= buffer && isspace (*p))
		*p-- = '\0';

	return (strlen (buffer));
}

static void
pgpTtySigResult (void *arg, union RingObject *key, word32 timestamp,
		 int status)
{
	struct PgpTtyUI *ui = (struct PgpTtyUI *) arg;
	struct RingSet const *set = ui->ringset;
	char timedate[21];

	pgpTimeString (timestamp, timedate);

	/* Status tells us whether the sig is good or bad.  Must also determine
	   if the signing key is valid. */

	if (status > 0) {
	    InformationOutput(TRUE, "GOOD_SIGNATURE", timedate);

	    ringKeyPrint (OUTPUT_INFORMATION, set, key, 1);
	    ringTtyKeyOKToSign(set, key);
	}
	else if (status == 0) {
	    InformationOutput(TRUE, "BAD_SIGNATURE", timedate);
	    ringKeyPrint (OUTPUT_INFORMATION, set, key, 1);
	}
	else {
	    char *ErrorString;
	    if(PGPErrCodeLoadString(&ErrorString, status) == PGPERR_OK) {
		InformationOutput(TRUE,
				  "ERROR_SIGNATURE",
				  status,
				  ErrorString);
		FreeString(&ErrorString);
	    }
	    PGPErrCodeOutput(TRUE, LEVEL_INFORMATION, status);
	}
}

int
pgpTtyGetPass (int showpass, char *buffer, int buflen)
{
	int i;

	InteractionOutput(TRUE, "ENTER_PASSPHRASE");
	i = pgpTtyGetString (buffer, buflen, showpass);
	InteractionOutputString(FALSE, "\n");
	return i;
}

/*
 * Responds to a commit request depending on the TTY UI member "commits"
 * If commits >= 0, then it will process that many levels of scopes.
 * if commits < 0, it will always recurse.
 */
int
pgpTtyDoCommit (void *arg, int scope)
{
	struct PgpTtyUI *ui = (struct PgpTtyUI *)arg;

	(void)scope;
	if (!ui->commits)
		return PGPANN_PARSER_PASSTHROUGH;
	ui->commits--;
	return PGPANN_PARSER_RECURSE;
}

/*
 * Performs an accumulation of random bits. As long as there are
 * fewer bits in the buffer than are needed, prompt for more.
 * (kbGet is known to call pgpRandPoolKeystroke() which increments
 * trueRandBits.)
 */
void
pgpTtyRandAccum (void *arg, unsigned count)
/* Get this many random bits ready */
{
	struct PgpTtyUI *ui = (struct PgpTtyUI *)arg;
	word32 randbits = pgpRandPoolEntropy ();
	Boolean HasDevRandom = FALSE, UseDevRandom = TRUE;
	char *RandomDevice = NULL;
	int fdDevRandom = -1, fdKB = -1, LargestFD = -1, SelectReturn = 0;
	fd_set AllDevicesSet;

	if (count > (unsigned)pgpRandPoolSize ())
		count = pgpRandPoolSize ();

	if (randbits >= count)
		return;

	/*Open the keyboard so that we can do a select on it:*/
	fdKB = kbOpenKbd(O_RDONLY); /*Can't fail*/
	FD_SET(fdKB, &AllDevicesSet);
	LargestFD = fdKB;

	if((HasDevRandom = CheckDevRandom(&RandomDevice, ui))) {
	    /*
	     *XXX Need to add support for ForceRandomDevice to pgp.cfg.
	     */
	    if(VerifyRandomDevOSVersion()) {
		if((fdDevRandom = open(RandomDevice, O_RDONLY)) >= 0) {
		    FD_SET(fdDevRandom, &AllDevicesSet);
		    if(fdDevRandom > LargestFD)
			LargestFD = fdDevRandom;
		    HasDevRandom = TRUE;
		}
		else
		    HasDevRandom = FALSE;

		}
		else {
		    UseDevRandom = FALSE;
		}
	}

	if(HasDevRandom) {
	    if(UseDevRandom) {
		InteractionOutput(TRUE,
				  "RANDOM_BITS_FROM_DEVICE",
				  count - (randbits), RandomDevice);
	    }
	    else {
		InteractionOutput(TRUE, "RANDOM_BITS_FROM_DEVICE_OLD_KERNEL");
	    }
	}

	if(!HasDevRandom || !UseDevRandom) {
	    InteractionOutput(TRUE,
			      "RANDOM_BITS_FROM_KEYBOARD",
			      count - (randbits));
	}

	kbCbreak ();

	do {
	    /* display counter to show progress */
	    InteractionOutputString(FALSE,
				    "\r%4u",
				    count-(unsigned)(randbits));

	    FD_ZERO(&AllDevicesSet);
	    FD_SET(fdKB, &AllDevicesSet);

	    if(HasDevRandom && UseDevRandom && fdDevRandom >= 0) {
		FD_SET(fdDevRandom, &AllDevicesSet);
	    }

	    kbFlush (0); /* Typeahead is illegal */

	    SelectReturn =
		select(LargestFD + 1, &AllDevicesSet, NULL, NULL, NULL);

	    /*If the waiting input is on stdin, or there was some kind of
	     *error, grab input from the keyboard:
	     */
	    if(SelectReturn < 0 ||
	       (SelectReturn >= 0 && FD_ISSET(fdKB, &AllDevicesSet))) {
		   (void)kbGet (); /* Wait for next char */
	    }
	    else { /*The waiting data is in /dev/random*/
		pgpDevRandomAccum(fdDevRandom, 1);
	    }
	    fputc (pgpRandPoolEntropy () == randbits ? '?' : '.', ui->fp);
	    randbits = pgpRandPoolEntropy ();

	} while (randbits < count);

    /* Do final display update */
    fputs ("\r   0 *", ui->fp);
    fputs ("\a -Enough, thank you.\n", ui->fp);

    /* Do an extra-thorough flush to absorb extra typing. */
    kbFlush (1);

    kbNorm ();

    if(RandomDevice) {
	pgpFree(RandomDevice);
    }

    if(fdDevRandom >= 0) {
	close(fdDevRandom);
	}

	kbCloseKbd(fdKB); /*Doesn't close if we're on stdin*/
}


int
pgpTtyNeedInput (void *arg, struct PgpPipeline *head)
{
    struct PgpTtyUI *ui = (struct PgpTtyUI *) arg;
    struct PgpFileRead *fileread;
    FILE *file = NULL;
    unsigned i, err;
    char namebuf[256], suggested_name[256];

    if (pgpenvGetInt (ui->env, PGPENV_BATCHMODE, NULL, NULL)) {
	if (ui->outname &&
	    (file = fopen (ui->outname, "rb")) != NULL) {
	    ui->outname = NULL;
	}
	else {
	    ErrorOutput(TRUE, LEVEL_CRITICAL, "NO_INPUT_FILE_IN_BATCHMODE");
	    return PGPERR_NO_FILE;
	}
    } else {
	if (ui->outname) {
	    strncpy (suggested_name, ui->outname,
		     sizeof(suggested_name));
	}
	else {
	    suggested_name[0] = '\0';
	}
	
	for (;;) {
	    InteractionOutput(TRUE, "NEED_SIG_FILE", suggested_name);
	    i = pgpTtyNeedFile (namebuf, sizeof(namebuf));
	    if (!i) {
		if (suggested_name[0])
		    strcpy (namebuf, suggested_name);
		else
		    return PGPERR_NO_FILE;
	    }
	    file = fopen (namebuf, "rb");
	    if (file)
		break;
	    ErrorOutput(TRUE, LEVEL_CRITICAL, "UNABLE_TO_OPEN_FILE", namebuf);
	    suggested_name[0] = 0;
	}
	/* Only use ui->outname once */
	if (strcmp (namebuf, ui->outname) == 0)
	    ui->outname = NULL;
    }

    fileread = pgpFileReadCreate (file, 1);

⌨️ 快捷键说明

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