diff uip/pgpshow.c @ 0:bce86c4163a3

Initial revision
author kono
date Mon, 18 Apr 2005 23:46:02 +0900
parents
children 441a2190cfae
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uip/pgpshow.c	Mon Apr 18 23:46:02 2005 +0900
@@ -0,0 +1,614 @@
+/* pgpshow.c - PGP viewer */
+#ifndef lint
+static char ident[] = "@(#)$Id$";
+#endif /* lint */
+
+#include "../h/mh.h"
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/stat.h>
+#ifdef UNISTD
+#include <unistd.h>
+#endif /* UNISTD */
+#ifdef LOCALE
+#include <locale.h>
+#endif /* LOCALE */
+
+void pgp_show();
+void pgp_store();
+void pgp_mime();
+int  tee();
+static TYPESIG goodbye();
+
+/*  */
+
+static struct swit switches[] = {
+#define PGPPROC 0
+    {"pgpproc program", -7},
+
+#define SHOWSW 1
+    {"show", 0},
+#define NSHOWSW 2
+    {"noshow", 0},
+
+#define STORESW 3
+    {"store", 0},
+#define NSTORESW 4
+    {"nostore", 0},
+
+#define MIMESW 5
+    {"mime", 0},
+#define NMIMESW 6
+    {"nomime", 0},
+
+#define HELPSW 7
+    {"help", 4},
+
+    {NULL, 0}
+};
+
+/*  */
+
+static int showsw = 0;
+static int storesw = 0;
+static int mimesw = 0;
+
+static char *pgpproc = ""; /* "pgp"; */
+static char *showprog = "show"; /* not showproc */
+extern char *moreproc;
+
+static char tmpfil1[BUFSIZ];
+static char tmpfil2[BUFSIZ];
+static FILE *out = NULL;
+
+#define PGP_SIGN    1
+#define PGP_ENCRYPT 2
+
+#define PGP_VER2 (int)1
+#define PGP_VER5 (int)2
+
+#define PGP2_GOOD_SIGNATURE "Good signature from user"
+#define PGP5_GOOD_SIGNATURE "Good signature made"
+
+#define NOT_INSTALLED 127
+
+/*  */
+
+main(argc, argv)
+int argc;
+char *argv[];
+{
+    int i, paramp = 0;
+    char *cp, buf[BUFSIZ];
+    char **ap, **argp, *arguments[MAXARGS], *param[MAXARGS];
+
+#ifdef LOCALE
+    setlocale(LC_ALL, "");
+#endif /* LOCALE */
+#ifdef JAPAN
+    ml_init();
+#endif /* JAPAN */
+    invo_name = r1bindex(argv[0], '/');
+    if ((cp = m_find(invo_name)) != NULL) {
+	ap = brkstring(cp = getcpy(cp), " ", "\n");
+	ap = copyip(ap, arguments);
+    }
+    else
+	ap = arguments;
+    (void) copyip(argv + 1, ap);
+    argp = arguments;
+
+/*  */
+
+    while ((cp = *argp++)) {
+	if (*cp == '-')
+	    switch (smatch(++cp, switches)) {
+	    case AMBIGSW: 
+		ambigsw(cp, switches);
+		done(1);
+	    case UNKWNSW: 
+		adios(NULLCP, "-%s unknown", cp);
+	    case HELPSW: 
+		(void) sprintf(buf, "%s [switches] file .. [parameters]",
+			       invo_name);
+		help(buf, switches);
+		done(1);
+
+	    case SHOWSW:
+		showsw++;
+		continue;
+	    case NSHOWSW:
+		showsw = 0;
+		continue;
+
+	    case STORESW:
+		storesw++;
+		continue;
+	    case NSTORESW:
+		storesw = 0;
+		continue;
+
+	    case MIMESW:
+		mimesw++;
+		continue;
+	    case NMIMESW:
+		mimesw = 0;
+		continue;
+
+	    case PGPPROC:
+		if (!(pgpproc = *argp++) || *pgpproc == '-')
+		    adios(NULLCP, "missing argument to %s", argp[-2]);
+		continue;
+	    }
+	else
+	    param[paramp++] = cp;
+    }
+    param[paramp] = NULLCP;
+    if ((!showsw && !storesw) || paramp < (mimesw ? 2 : 1))
+	adios(NULLCP, "usage: %s [switches] file .. [parameters]", invo_name);
+    tmpfil1[0] = tmpfil2[0] = '\0';
+
+/*  */
+
+    if (mimesw) {
+	int protocol = 0;
+	char *micalg = NULLCP;
+	for (i = 2; param[i]; i++) {
+	    if (uprf(param[i], "protocol=")) {
+		if (uleq(param[i] + 9, "application/pgp-signature"))
+		    protocol = PGP_SIGN;
+		else if (uleq(param[i] + 9, "application/pgp-encrypted"))
+		    protocol = PGP_ENCRYPT;
+		else
+		    adios(NULLCP,
+			  "protocol \"%s\" is unsupported", param[i] + 9);
+	    }
+	    if (uprf(param[i], "micalg=")) {
+		micalg = param[i] + 7;
+		if (!uleq(micalg, "pgp-md5") && !uleq(micalg, "pgp-sha1"))
+		    adios(NULLCP, "micalg \"%s\" is unsupported", micalg);
+	    }
+	}
+	if (!protocol)
+	    adios(NULLCP, "protocol parameter is required");
+
+	pgp_mime(param[0], param[1], protocol, micalg, showsw);
+    } else {
+	int fmtmime = 0;
+	for (i = 1; param[i]; i++) {
+	    if (uleq(param[i], "format=mime")) {
+		fmtmime = 1;
+		break;
+	    }
+	}
+	if (showsw)
+	    pgp_show(param[0], fmtmime);
+	else
+	    pgp_store(param[0], fmtmime);
+    }
+
+    done(0);
+}
+
+void
+pgp_show(file, fmtmime)
+char *file;
+int fmtmime;
+{
+    int pid, nopgp = 0;
+    char *ap[5];
+
+    (void) signal(SIGHUP, goodbye);
+    (void) signal(SIGINT, goodbye);
+    (void) signal(SIGQUIT, goodbye);
+    (void) signal(SIGPIPE, goodbye);
+    (void) signal(SIGTERM, goodbye);
+
+    (void) strcpy(tmpfil1, m_scratch("", m_maildir(invo_name)));
+    if ((out = fopen(tmpfil1, "w")) == NULL) {
+	(void) strcpy(tmpfil1, m_tmpfil(invo_name));
+	if ((out = fopen(tmpfil1, "w")) == NULL) {
+	    advise(tmpfil1, "unable to create");
+	    goodbye();
+	}
+    }
+    (void) chmod(tmpfil1, 0600);
+    fclose(out);
+    out = NULL;
+    unlink(tmpfil1);
+
+    if (! *pgpproc) {
+	/* for PGP5 */
+	ap[0] = pgpproc = "pgpv";
+	ap[1] = file;
+	ap[2] = "-o";
+	ap[3] = tmpfil1;
+	ap[4] = NULLCP;
+	if (tee(ap, PGP_VER5) == NOTOK)
+	    /* Let's try old PGP */
+	    pgpproc = "pgp";
+	else
+	    pgpproc = "";
+    }
+    if (*pgpproc) {
+	/* for PGP2 */
+	ap[0] = r1bindex(pgpproc, '/');
+	if (tee(ap, PGP_VER2) == NOTOK) {
+	    advise(pgpproc, "unable to exec");
+	    nopgp = 1;
+	}
+    }
+
+    if (fmtmime) {
+	ap[0] = r1bindex(showprog, '/');
+	ap[1] = "-file";
+	ap[2] = nopgp ? file : tmpfil1;
+	ap[3] = NULLCP;
+    } else {
+	ap[0] = r1bindex(moreproc, '/');
+	ap[1] = nopgp ? file : tmpfil1;
+	ap[2] = NULLCP;
+    }
+
+    switch (pid = fork()) {
+    case NOTOK:
+	advise("fork", "unable to");
+	goodbye();
+
+    case OK:
+	execvp(fmtmime ? showprog : moreproc, ap);
+	adios(fmtmime ? showprog : moreproc, "unable to exec");
+
+    default:
+	if (pidXwait(pid, fmtmime ? showprog : r1bindex(moreproc, '/')))
+	    goodbye();
+	break;
+    }
+    unlink(tmpfil1);
+}
+
+void
+pgp_store(file, fmtmime)
+char *file;
+int fmtmime;
+{
+    int pid, state;
+    char *ap[5];
+
+    (void) signal(SIGHUP, goodbye);
+    (void) signal(SIGINT, goodbye);
+    (void) signal(SIGQUIT, goodbye);
+    (void) signal(SIGPIPE, goodbye);
+    (void) signal(SIGTERM, goodbye);
+
+    (void) strcpy(tmpfil1, m_scratch("", m_maildir(invo_name)));
+    if ((out = fopen(tmpfil1, "w")) == NULL) {
+	(void) strcpy(tmpfil1, m_tmpfil(invo_name));
+	if ((out = fopen(tmpfil1, "w")) == NULL) {
+	    advise(tmpfil1, "unable to create");
+	    goodbye();
+	}
+    }
+    (void) chmod(tmpfil1, 0600);
+    cpydata(fileno(stdin), fileno(out), "stdin", tmpfil1);
+    fclose(out);
+    out = NULL;
+
+    if (! *pgpproc) {
+	/* for PGP5 */
+	ap[0] = "pgpv";
+	ap[1] = tmpfil1;
+	ap[2] = "-o";
+	ap[3] = file;
+	ap[4] = NULLCP;
+
+	switch (pid = fork()) {
+	case NOTOK:
+	    advise("fork", "unable to");
+	    goodbye();
+
+	case OK:
+	    execvp("pgpv", ap);
+	    /* maybe PGP5 is not installed. */
+	    _exit(NOT_INSTALLED);
+
+	default:
+#if 0
+	    state = pidwait(pid, OK);
+	    if (WIFEXITED(state) && WEXITSTATUS(state) == NOT_INSTALLED)
+#else
+	    if ((state = pidwait(pid, OK)) == (NOT_INSTALLED << 8))
+#endif
+		/* Let's try old PGP */
+		pgpproc = "pgp";
+	    else if (pidstatus(state, stdout, "pgpv"))
+		goodbye();
+	    break;
+	}
+    }
+    if (*pgpproc) {
+	/* for PGP2 */
+	ap[0] = r1bindex(pgpproc, '/');
+
+	switch (pid = fork()) {
+	case NOTOK:
+	    advise("fork", "unable to");
+	    goodbye();
+
+	case OK:
+	    execvp(pgpproc, ap);
+	    adios(pgpproc, "unable to exec");
+
+	default:
+	    if (pidXwait(pid, r1bindex(pgpproc, '/')))
+		goodbye();
+	    break;
+	}
+    }
+    unlink(tmpfil1);
+
+    if (fmtmime) {
+	if (!m_find("path"))
+	    free(path("./", TFOLDER));
+	if (!(ap[0] = m_find(inbox)))
+	    ap[0] = defalt;
+	if (*ap[0] != '+' && *ap[0] != '@')
+	    ap[0] = add(ap[0], add("+", NULLCP));
+	ap[1] = NULL;
+	refile(ap, file);
+    }
+}
+
+void
+pgp_mime(file1, file2, protocol, micalg, showsw)
+char *file1, *file2, *micalg;
+int protocol, showsw;
+{
+    int pid;
+    char *cp, *ap[6], buf[BUFSIZ];
+    FILE *in;
+
+    (void) signal(SIGHUP, goodbye);
+    (void) signal(SIGINT, goodbye);
+    (void) signal(SIGQUIT, goodbye);
+    (void) signal(SIGPIPE, goodbye);
+    (void) signal(SIGTERM, goodbye);
+
+    (void) strcpy(tmpfil1, m_scratch("", m_maildir(invo_name)));
+    if ((out = fopen(tmpfil1, "w")) == NULL) {
+	(void) strcpy(tmpfil1, m_tmpfil(invo_name));
+	if ((out = fopen(tmpfil1, "w")) == NULL) {
+	    advise(tmpfil1, "unable to create");
+	    goodbye();
+	}
+    }
+    (void) chmod(tmpfil1, 0600);
+
+    if (protocol == PGP_SIGN) {
+	if ((in = fopen(file1, "r")) == NULL) {
+	    advise(file1, "unable to open");
+	    goodbye();
+	}
+
+	while (fgets(buf, sizeof(buf) - 2, in)) {
+	    cp = buf + strlen(buf) - 1;
+	    if (*cp-- == '\n' && *cp != '\r') {
+		*++cp = '\r';
+		*++cp = '\n';
+		*++cp = '\0';
+	    }
+	    fputs(buf, out);
+	}
+	fclose(in);
+	fclose(out);
+	out = NULL;
+
+	ap[1] = "+batchmode=on";
+	ap[2] = file2;
+	ap[3] = "-o";
+	ap[4] = tmpfil1;
+	ap[5] = NULLCP;
+    } else {
+	fclose(out);
+	out = NULL;
+	unlink(tmpfil1);
+
+	ap[1] = file2;
+	ap[2] = "-o";
+	ap[3] = tmpfil1;
+	ap[4] = NULLCP;
+    }
+    if (! *pgpproc) {
+	/* for PGP5 */
+	ap[0] = pgpproc = "pgpv";
+	if (tee(ap, PGP_VER5) == NOTOK) {
+	    if (protocol == PGP_SIGN && !uleq(micalg, "pgp-md5")) {
+		/* PGP2 only support PGP-MD5 */
+		advise(pgpproc, "unable to exec");
+		pgpproc = "";
+	    } else
+		/* Let's try old PGP */
+		pgpproc = "pgp";
+	} else
+	    pgpproc = "";
+    }
+    if (*pgpproc) {
+	/* for PGP2 */
+	ap[0] = r1bindex(pgpproc, '/');
+	if (protocol == PGP_SIGN) {
+	    ap[3] = tmpfil1;
+	    ap[4] = NULLCP;
+	}
+	if (tee(ap, PGP_VER2) == NOTOK) {
+	    advise(pgpproc, "unable to exec");
+	    if (protocol != PGP_SIGN)
+		goodbye();
+	}
+    }
+
+    ap[0] = r1bindex(showprog, '/');
+    ap[1] = "-file";
+    if (protocol == PGP_SIGN)
+	ap[2] = file1;
+    else {
+	if ((in = fopen(tmpfil1, "r")) == NULL) {
+	    advise(tmpfil1, "unable to open");
+	    goodbye();
+	}
+
+	(void) strcpy(tmpfil2, m_scratch("", m_maildir(invo_name)));
+	if ((out = fopen(tmpfil2, "w")) == NULL) {
+	    (void) strcpy(tmpfil2, m_tmpfil(invo_name));
+	    if ((out = fopen(tmpfil2, "w")) == NULL) {
+		advise(tmpfil2, "unable to create");
+		goodbye();
+	    }
+	}
+	(void) chmod(tmpfil2, 0600);
+
+	while (fgets(buf, sizeof(buf) - 1, in)) {
+	    cp = buf + strlen(buf) - 1;
+	    if (*cp-- == '\n' && *cp == '\r') {
+		*cp++ = '\n';
+		*cp = '\0';
+	    }
+	    fputs(buf, out);
+	}
+	fclose(in);
+	fclose(out);
+	out = NULL;
+
+	ap[2] = tmpfil2;
+    }
+    ap[3] = NULLCP;
+    unlink(tmpfil1);
+
+    if (!showsw) {
+	if (!m_find("path"))
+	    free(path("./", TFOLDER));
+	if (!(ap[0] = m_find(inbox)))
+	    ap[0] = defalt;
+	if (*ap[0] != '+' && *ap[0] != '@')
+	    ap[0] = add(ap[0], add("+", NULLCP));
+	ap[1] = NULL;
+	refile(ap, ap[2]);
+	return;
+    }
+
+    switch (pid = fork()) {
+    case NOTOK:
+	advise("fork", "unable to");
+	goodbye();
+
+    case OK:
+	execvp(showprog, ap);
+	adios(showprog, "unable to exec");
+
+    default:
+	if (pidXwait(pid, r1bindex(showprog, '/')))
+	    goodbye();
+	break;
+    }
+    if (tmpfil2[0])
+	unlink(tmpfil2);
+}
+
+int
+tee(ap, pgpver)
+char *ap[];
+int pgpver;
+{
+    int cnt, state, pid, pdes[2];
+    char *cp, *ep, *np, buf[BUFSIZ];
+
+    if (pipe(pdes) == NOTOK) {
+	advise(NULLCP, "unable to open pipe");
+	goodbye();
+    }
+
+    switch (pid = fork()) {
+    case NOTOK:
+	close(pdes[0]);
+	close(pdes[1]);
+	advise("fork", "unable to");
+	goodbye();
+
+    case OK:
+	if (pdes[1] != fileno(stdout))
+	    dup2(pdes[1], fileno(stdout));
+	if (pdes[1] != fileno(stderr)) {
+	    dup2(pdes[1], fileno(stderr));
+	    if (pdes[1] != fileno(stdout))
+		close(pdes[1]);
+	}
+	close(pdes[0]);
+	execvp(pgpproc, ap);
+	/* maybe PGP is not installed. */
+	_exit(NOT_INSTALLED);
+    }
+    close(pdes[1]);
+
+    cp = ep = buf;
+    while ((cnt = read(pdes[0], buf + (ep - cp), sizeof(buf) - (ep - cp) - 1))
+	   > 0) {
+	write(fileno(stdout), buf + (ep - cp), cnt);
+
+	ep = buf + (ep - cp) + cnt;
+	cp = buf;
+	while (cp < ep) {
+	    np = cp;
+	    while (np < ep && *np != '\n')
+		np++;
+	    if (np < ep || (cp == buf && np == buf + sizeof(buf) - 1)) {
+		char *xp, *yp;
+		*np = '\0';
+		if ((pgpver == PGP_VER5
+		     && strncmp(cp, PGP5_GOOD_SIGNATURE,
+				strlen(PGP5_GOOD_SIGNATURE)) == 0)
+		    ||
+		    (pgpver == PGP_VER2
+		     && strncmp(cp, PGP2_GOOD_SIGNATURE,
+				strlen(PGP2_GOOD_SIGNATURE)) == 0)) {
+		    pgpver = -1;
+		}
+		if (pgpver < 0
+		    && (xp = index(cp, '"')) && (yp = rindex(xp + 1, '"'))) {
+		    *yp = '\0';
+		    m_putenv("PGP_SIGNATURE", xp + 1);
+		    pgpver = 0;
+		}
+	    } else {
+		bcopy(cp, buf, ep - cp);
+		break;
+	    }
+	    cp = np + 1;
+	}
+    }
+    close(pdes[0]);
+
+#if 0
+    state = pidwait(pid, OK);
+    if (WIFEXITED(state) && WEXITSTATUS(state) == NOT_INSTALLED)
+#else
+    if ((state = pidwait(pid, OK)) == (NOT_INSTALLED << 8))
+#endif
+	return NOTOK;
+
+    if (pidstatus(state, stdout, r1bindex(pgpproc, '/')))
+	goodbye();
+
+    return OK;
+}
+
+static TYPESIG goodbye()
+{
+    if (out)
+	fclose(out);
+    if (tmpfil1[0])
+	unlink(tmpfil1);
+    if (tmpfil2[0])
+	unlink(tmpfil2);
+    done(1);
+    /* NOT REACHED */
+}