static char rcsid[] = "@(#)$Id: pgp_decode.c,v 1.51 2007/08/18 06:48:24 hurtta Exp $";
/******************************************************************************
* The Elm (ME+) Mail System - $Revision: 1.51 $ $State: Exp $
*
* Modified by: Kari Hurtta <hurtta+elm@posti.FMI.FI>
* (was hurtta+elm@ozone.FMI.FI)
*
* Initially written by: Michael Elkins <elkins@aero.org>, 1995
*****************************************************************************/
#include "def_melib.h"
#include "s_me.h"
#include "s_elm.h"
DEBUG_VAR(Debug,__FILE__,"pgp");
#ifdef USE_PGP
#include <sys/time.h>
#include <errno.h>
#ifndef ANSI_C
extern int errno;
#endif
extern int pgp_keeppassfor; /* 5 minutes */
char pgp_passphrase[PGP_NUM][STRING];
int pgp_expires;
static CONST char * pgp_names[PGP_NUM] = {
"*none*",
"PGP 2",
"PGP 5",
"GnuPG"
};
/* if v >= pgp2 returns gives available pgp version */
enum pgp_version have_pgp (v)
enum pgp_version v;
{
enum pgp_version return_value = v;
switch(v) {
case pgp_none:
return_value = pgp_none;
;;
case pgp2: {
char * pgp2_path_val = give_dt_estr_as_str(&pgp2_path_e, "pgp2");
if (! pgp2_path_val ||
strcmp(pgp2_path_val,"none") == 0 ||
pgp2_path_val[0] == '\0') {
return_value = pgp_none;
} else if (pgp2_path_val[0] == '/') {
if (-1 == access(pgp2_path_val,EXECUTE_ACCESS)) {
int err = errno;
lib_error(CATGETS(elm_msg_cat, MeSet, MePgpCantExecute,
"Can't execute pgp: %.50s: %.30s"),
pgp2_path_val, error_description(err));
DPRINT(Debug,5,(&Debug,
"have_pgp: no access %s: %s\n",pgp2_path_val,
error_description(err)));
return_value = pgp_none;
}
} else {
lib_error(CATGETS(elm_msg_cat, MeSet, MePgpPath,
"PGP path must start with '/': %.60s"),
pgp2_path_val);
DPRINT(Debug,5,(&Debug,
"have_pgp: bad path: %s\n",pgp2_path_val));
return_value = pgp_none;
}
if (return_value != pgp_none)
break;
return_value = pgp5;
/* FALLTROUGH */
}
case pgp5: try_pgp5: {
/* give_dt_estr_as_str adds / to end */
char * pgp5_dir_val = give_dt_estr_as_str(&pgp5_dir_e, "pgp5-dir");
if (! pgp5_dir_val ||
strcmp(pgp5_dir_val,"none") == 0 ||
pgp5_dir_val[0] == '\0') {
return_value = pgp_none;
} else if (pgp5_dir_val[0] == '/') {
char * path = elm_message(FRM("%spgpv"),pgp5_dir_val);
if (-1 == access(path,EXECUTE_ACCESS)) {
int err = errno;
lib_error(CATGETS(elm_msg_cat, MeSet, MePgpCantExecute,
"Can't execute pgp: %.50s: %.30s"),
path, error_description(err));
DPRINT(Debug,5,(&Debug,
"have_pgp: no access %s: %s\n",path,
error_description(err)));
return_value = pgp_none;
}
free(path);
} else {
lib_error(CATGETS(elm_msg_cat, MeSet, MePgpPath,
"PGP path must start with '/': %.60s"),
pgp5_dir_val);
DPRINT(Debug,5,(&Debug,
"have_pgp: bad path: %s\n",pgp5_dir_val));
return_value = pgp_none;
}
}
break;
case gpg: {
char * gpg_path_val = give_dt_estr_as_str(&gpg_path_e, "gpg");
if (! gpg_path_val ||
strcmp(gpg_path_val,"none") == 0 ||
gpg_path_val[0] == '\0') {
return_value = pgp_none;
} else if (gpg_path_val[0] == '/') {
if (-1 == access(gpg_path_val,EXECUTE_ACCESS)) {
int err = errno;
lib_error(CATGETS(elm_msg_cat, MeSet, MePgpCantExecute,
"Can't execute pgp: %.50s: %.30s"),
gpg_path_val, error_description(err));
DPRINT(Debug,5,(&Debug,
"have_pgp: no access %s: %s\n",gpg_path_val,
error_description(err)));
return_value = pgp_none;
}
} else {
lib_error(CATGETS(elm_msg_cat, MeSet, MePgpPath,
"PGP path must start with '/': %.60s"),
gpg_path_val);
DPRINT(Debug,5,(&Debug,
"have_pgp: bad path: %s\n",gpg_path_val));
return_value = pgp_none;
}
if (return_value != pgp_none)
break;
return_value = pgp5;
goto try_pgp5;
}
}
DPRINT(Debug,5,(&Debug,
"have_pgp(%d)=%d\n",v,return_value));
return return_value;
}
int pgp_void_passphrase ()
{
int i;
enum pgp_version v;
int X = 0;
for (v = pgp_none; v < PGP_NUM; v++) {
if (pgp_passphrase[v][0])
X++;
for (i = 0 ; i < sizeof pgp_passphrase[v] ; i++)
pgp_passphrase[v][i] = '\0';
pgp_expires = 0;
}
return X;
}
static int QueryExpirePassphrase P_((void));
static int QueryExpirePassphrase()
{
struct timeval now;
/* negative implies never expire */
if (pgp_keeppassfor < 0)
return(0);
gettimeofday(&now, 0);
if (now.tv_sec < pgp_expires) {
pgp_expires = now.tv_sec + pgp_keeppassfor;
return(0);
}
pgp_void_passphrase ();
return(1);
}
static int GetPassphrase P_((enum pgp_version v));
static int GetPassphrase (v)
enum pgp_version v;
{
char * buffer;
struct timeval now;
int r;
DPRINT(Debug,2,(&Debug,
"GetPassphrase(%d) -- pgp_names[%d]=%s\n",
v,v,pgp_names[v]));
buffer = lib_prompt(1,
CATGETS(elm_msg_cat, MeSet, MePgpEnterPassphrase,
"Please enter your %s passphrase: "),
pgp_names[v]);
if (!buffer) {
DPRINT(Debug,2,(&Debug,
"GetPassphrase=0 -- lib_prompt failed\n"));
return 0;
}
strfcpy(pgp_passphrase[v],buffer,sizeof pgp_passphrase[v]);
gettimeofday(&now, 0);
if (pgp_keeppassfor > 0)
pgp_expires = now.tv_sec + pgp_keeppassfor;
free(buffer);
r = pgp_passphrase[v][0] != '\0';
DPRINT(Debug,2,(&Debug,
"GetPassphrase=%d\n",r));
return(r);
}
int pgp_goodPassphrase(v)
enum pgp_version v;
{
if (pgp_passphrase[v][0] == '\0' || QueryExpirePassphrase())
return(GetPassphrase(v));
else
return(1);
}
static void close_them P_((struct run_state *rs));
static void close_them(rs)
struct run_state *rs;
{
int *array = rs->ext_init_data;
close(array[0]);
close(array[1]);
if (array[2] != -1)
close(array[2]);
}
/* opens up a PGP process as a child and returns its stdin and stdout */
int pgp_decrypt_init (fpin, fpout, opts, v, rs)
FILE **fpin, **fpout;
int opts; /* PGP_MESSAGE, PGP_SIGNED_MESSAGE, or
PGP_PUBLIC_KEY */
enum pgp_version v; /* 'minimum version' */
struct run_state *rs;
{
int pgp_child_in[2];
int pgp_child_out[2];
int array[3];
CONST char * argv[10];
char * env[2];
int passpipe[2];
int usepass=FALSE;
int code;
DPRINT(Debug,2,(&Debug,
"pgp_descrypt_init() called with opts=%d\n", opts));
rs->save_errno = 0;
if (pipe(pgp_child_in) == -1) {
rs->save_errno = errno;
return(0);
}
if (pipe(pgp_child_out) == -1) {
rs->save_errno = errno;
close(pgp_child_in[0]);
close(pgp_child_in[1]);
return(0);
}
if ((opts & PGP_MESSAGE) && pgp_keeppass) {
if (pipe(passpipe) == -1) {
rs->save_errno = errno;
close(pgp_child_in[0]);
close(pgp_child_out[0]);
close(pgp_child_in[1]);
close(pgp_child_out[1]);
return(0);
}
usepass = TRUE;
}
DPRINT(Debug,3,(&Debug,
"usepass = %d.\n", usepass));
sr_call_Raw(OFF);
sr_call_ClearScreen();
/* Tell the user why they are waiting */
if (opts & PGP_MESSAGE) {
sr_call_Write_to_screen(CATGETS(elm_msg_cat, MeSet, MePgpDecryptMes,
"Running pgp: Decrypting message...\n"));
} else if (opts & PGP_SIGNED_MESSAGE) {
sr_call_Write_to_screen(CATGETS(elm_msg_cat, MeSet, MePgpCheckSig,
"Running pgp: Checking signature...\n"));
} else if (opts & PGP_PUBLIC_KEY) {
sr_call_Write_to_screen(CATGETS(elm_msg_cat, MeSet, MePgpExtractKeys,
"Running pgp: Extracting keys...\n"));
} else {
sr_call_Write_to_screen(CATGETS(elm_msg_cat, MeSet, MePgpRun,
"Running pgp ...\n"));
}
array[0] = pgp_child_in[1];
array[1] = pgp_child_out[0];
array[2] = -1;
rs->ext_init_data = array;
rs->ext_init = close_them;
env[0] = NULL;
rs->ext_env = env;
switch(v) {
case pgp2:
case pgp5:
if (usepass) {
static char buffer[20];
elm_sfprintf(buffer, sizeof buffer,FRM("PGPPASSFD=%d"),
passpipe[0]);
env[0] = buffer;
array[2] = passpipe[1];
}
env[1] = NULL;
}
switch(v) {
static char path[1000];
int n;
case pgp2:
n = 0;
{
char * pgp2_path_val = give_dt_estr_as_str(&pgp2_path_e, "pgp2");
if (! pgp2_path_val)
return 0;
argv[n++] = pgp2_path_val;
}
argv[n++] = "-f";
argv[n++] = "+verbose=0";
argv[n++] = "+KEEPBINARY=OFF";
if (usepass || opts == PGP_SIGNED_MESSAGE || opts == PGP_PUBLIC_KEY)
argv[n++] = "+batchmode";
if (opts == PGP_PUBLIC_KEY)
argv[n++] = "-ka";
argv[n] = NULL;
break;
case pgp5:
n = 0;
{
/* give_dt_estr_as_str adds / to end */
char * pgp5_dir_val = give_dt_estr_as_str(&pgp5_dir_e,
"pgp5-dir");
if (! pgp5_dir_val)
return 0;
elm_sfprintf(path, sizeof path,FRM("%spgpv"),pgp5_dir_val);
}
argv[n++] = path;
if (opts != PGP_PUBLIC_KEY)
argv[n++] = "-f";
argv[n++] = "+verbose=0";
if (usepass || opts == PGP_SIGNED_MESSAGE || opts == PGP_PUBLIC_KEY)
argv[n++] = "+batchmode";
argv[n] = NULL;
break;
case gpg:
n = 0;
{
char * gpg_path_val = give_dt_estr_as_str(&gpg_path_e, "gpg");
if (! gpg_path_val)
return 0;
argv[n++] = gpg_path_val;
}
if (usepass) {
static char buffer[10];
argv[n++] = "--passphrase-fd";
elm_sfprintf(buffer, sizeof buffer,FRM("%d"),
passpipe[0]);
argv[n++] = buffer;
array[2] = passpipe[1];
}
if (usepass || opts == PGP_SIGNED_MESSAGE || opts == PGP_PUBLIC_KEY)
argv[n++] = "--batch";
if (opts == PGP_PUBLIC_KEY)
argv[n++] = "--import";
else
argv[n++] = "--decrypt";
argv[n] = NULL;
break;
}
code = start_run(rs, SY_RUN_STATE_INIT|SY_RUN_STATE_ENV , argv ,
pgp_child_in[0],pgp_child_out[1]);
close (pgp_child_in[0]);
close (pgp_child_out[1]);
if (!code)
return 0;
/* now send the passphrase if needed */
if (usepass) {
DPRINT(Debug,3,(&Debug,
"pgp_decrypt_init: sending pgp passphrase.\n"));
close (passpipe[0]);
write (passpipe[1], pgp_passphrase[v],
strlen(pgp_passphrase[v]));
write (passpipe[1], "\n", 1);
close (passpipe[1]);
}
if ((*fpin = fdopen(pgp_child_out[0], "r")) == 0) {
int tmp;
int err = errno;
DPRINT(Debug,3,(&Debug,
"pgp_decrypt_init: fdopen(%d) failed, errno=%d\n",
pgp_child_out[0],err));
kill(rs->pid,SIGTERM);
wait_end(rs,&tmp);
rs->save_errno = err;
sr_call_Raw(ON);
return(0);
}
if ((*fpout = fdopen(pgp_child_in[1], "w")) == 0) {
int err = errno;
int tmp;
DPRINT(Debug,3,(&Debug,
"pgp_decrypt_init: fdopen(%d) failed, errno=%d\n",
pgp_child_out[0],err));
kill(rs->pid,SIGTERM);
wait_end(rs,&tmp);
rs->save_errno = err;
sr_call_Raw(ON);
return(0);
}
return(code);
}
static int pgp_mime_opts P_((struct mime_param *s));
static int pgp_mime_opts (s)
struct mime_param *s;
{
if (s) {
CONST char *pv;
pv = get_mime_param_compat(s,"format");
if (pv) {
if (istrcmp (pv, "keys-only") == 0)
return PGP_PUBLIC_KEY;
}
pv = get_mime_param_compat(s,"x-action");
if (pv) {
if (istrcmp (pv, "encryptsign") == 0)
return (PGP_MESSAGE | PGP_SIGNED_MESSAGE);
else if (istrcmp (pv, "encrypt") == 0)
return PGP_MESSAGE;
else if (istrcmp (pv, "sign") == 0)
return PGP_SIGNED_MESSAGE;
else if (istrcmp (pv, "signclear") == 0)
return PGP_SIGNED_MESSAGE;
}
}
return PGP_MESSAGE;
}
enum pgp_version decode_pgp_version(c)
char * c;
{
int se = give_dt_enumerate_as_int(&send_pgp_version);
if (0 == strncmp(c,"2.",2)) {
DPRINT(Debug,4,(&Debug,
"decode_pgp_version: Version -- PGP 2\n"));
return pgp2;
} else if (0 == strncmp(c,"GnuPG",5)) {
DPRINT(Debug,4,(&Debug,
"decode_pgp_version: Version -- GnuPG\n"));
return gpg;
} else {
/* give_dt_estr_as_str adds / to end */
char * pgp5_dir_val = give_dt_estr_as_str(&pgp5_dir_e, "pgp5-dir");
DPRINT(Debug,4,(&Debug,
"decode_pgp_version: Version -- PGP 5?\n"));
if (pgp5_dir_val &&
'/' == pgp5_dir_val[0])
return pgp5;
else
return (enum pgp_version) se;
}
}
/* Returns -1 on failure otherwise same mask than mime_classify_media() */
#if ANSI_C
mime_run_selector pgp_selector;
#endif
int pgp_selector(p,hdr)
mime_t *p;
struct header_rec * hdr;
{
int flags = 0;
DPRINT(Debug,11,(&Debug,
"pgp_selector(%p) -- type: %p=%s/%s\n",
p,
p->TYPE,
get_major_type_name(p->TYPE),
get_subtype_name(p->TYPE)));
DPRINT(Debug,11,(&Debug,
"pgp_selector(%p) = %d\n",
p,
flags));
return flags;
}
void pgp_decode (m, s_in, s_out, defcharset, mss, badtype)
mime_t *m;
in_state_t *s_in;
out_state_t *s_out;
charset_t defcharset;
struct header_rec * mss;
type_mismatch_prompt *badtype;
{
/* This procedure implements the de-facto standard for using PGP with MIME.
* Content-Type: application/pgp
* Required-Parameters: none
* Optional parameters: format, x-action
* format = mime | text | keys-only
* mime : indicates that the signed/encrypted body contains a MIME
* compliant body and should be parsed recursively.
* text : [DEFAULT if there is no format option]. This option
* means that the encrypted/signed data should be presented
* to the user after processing, no additional processing
* needed.
* keys-only:
* The data in the body represents public key data only
* x-action = encryptsign | encrypt | sign
* This keyword is meant to be helpful to the application, but is
* not required, and may not even be necessary to look at.
*
* encryptsign : the application/pgp data is both signed and
* encrypted.
* encrypt : the data is encrypted only
* sign : the data is signed only
*/
char buffer[LONG_STRING];
FILE *pgpout, *pgpin, *tmpfp=NULL, *decode_fp = NULL;
int
code = 0,
inbody = FALSE,
opts,
len,
raw,
stat = -1,
bytes = 0,
nested = FALSE; /* PGP output should be parsed as a MIME body */
int skip_flag = 0;
mime_t *tmpmt;
enum pgp_version v = pgp2;
int armor_header = 0;
struct run_state RS;
int was_binary = 0;
in_state_t newstate2;
enum pgp_version version;
char *tmp;
CONST char *pv;
int was_text = 0;
tmp = give_dt_estr_as_str(&temp_dir_e,"tmpdir");
if (!tmp)
return;
in_state_clear(&newstate2,STATE_in_file);
raw = sr_call_RawState ();
if (
(pv = get_mime_param_compat(m->TYPE_opts,"format")) &&
(istrcmp (pv, "mime") == 0)) {
char * tempfile = elm_message(FRM("%selmPT%d"),
tmp, getpid ());
nested = TRUE;
DPRINT(Debug,3,(&Debug,
"pgp_decode: format=mime\n"));
if (NULL == (tmpfp = safeopen_rdwr(tempfile))) {
lib_error(CATGETS(elm_msg_cat, MeSet, MePgpCantCreate,
"Failed to create file for decoding."));
state_puts("[ ",s_out);
state_printf(s_out,
CATGETS(elm_msg_cat, MeSet, MePgpCantCreate,
"Failed to create file for decoding."));
state_puts(" ]\n",s_out);
free(tempfile);
return;
}
unlink (tempfile); /* Filename is no longer needed ... */
free(tempfile);
}
else
tmpfp = NULL;
opts = pgp_mime_opts(m->TYPE_opts);
buffer[0] = '\0';
if (opts & PGP_PUBLIC_KEY) {
state_printf (s_out,
CATGETS(elm_msg_cat, MeSet, MePgpPublicKeys,
"(** This message contains PGP public key(s) **)\n"));
state_putc('\n',s_out);
}
/* Decode Content-transfer-encoding */
if (NULL != (decode_fp =
arrange_decoded(m,s_in,s_out,&newstate2,NULL))) {
/* If arrange_decoded was treated this as text, don't consider
* about binary PGP files -- that happens when type is text/x-pgp
*/
if (check_type_pattern) {
if (!check_type_magic(m,&newstate2, s_out, badtype)) {
DPRINT(Debug,11,(&Debug,
"pgp_decode: mime_type_rejected\n"));
goto FAILTYPE;
}
}
/* 7bit and 8bit are only allowed for line orienteed types */
if (m->encoding == ENCODING_NONE ||
m->encoding == ENCODING_7BIT ||
m->encoding == ENCODING_8BIT) {
DPRINT(Debug,11,(&Debug,
"pgp_decode: textual encoding (%s)\n",
ENCODING(m->encoding)));
was_text = 1;
} else
was_text = give_text_type_code(m->TYPE);
DPRINT(Debug,4,(&Debug,
"pgp_decode: was_text = %d\n", was_text));
/* Print text before PGP armor
*
*/
len = state_getl (buffer, sizeof (buffer), &newstate2);
if ( len < 1) {
state_printf(s_out,
CATGETS(elm_msg_cat, MeSet, MePgpNoText1,
"[ No text in PGP section. ]\n"));
} else {
int c = (unsigned char) buffer[0],i;
if (!pgp_noarmor && opts != PGP_PUBLIC_KEY) {
was_binary = 1; /* default assumption */
goto pgp_found;
}
if (!was_text) {
/* Check if that is binary PGP file */
if (c & 0x80) {
/* In PGP block have type byte which have higgest bit set
* always. so if in first byte have higgest bit set assume
* PGP binary file.
*/
DPRINT(Debug,4,(&Debug,
"pgp_decode: first byte = %d -- assume binary PGP file\n",
c));
was_binary = 1;
goto pgp_found;
}
/* Another check */
for (i = 0; i < len; i++) {
if (buffer[i] == 0) {
DPRINT(Debug,4,(&Debug,
"pgp_decode: byte idx=%d is zero -- binary file?\n",
i));
state_printf(s_out,
CATGETS(elm_msg_cat, MeSet, MePgpBinary,
"[ Binary file, but does not look like PGP ]\n"));
was_binary = 1;
goto pgp_found;
}
}
}
if (strncmp(buffer, "-----BEGIN PGP", 14) == 0)
goto pgp_found;
state_printf(s_out,
CATGETS(elm_msg_cat, MeSet, MePgpBefore,
"[ There is text before PGP section. ]\n"));
if (set_filter(m,s_out,NULL,
mss ? mss->override_charset : NULL)
) { /* Character set filtering */
do {
state_add_prefix(s_out);
/* Take care of CRLF => LF conversion in here because
* arrange_decoded() is treating application/pgp as
* binary type (it need to treate it as binary because
* it may be binary)
*/
if (!was_text &&
len > 1 &&
buffer[len - 1] == '\n' &&
buffer[len - 2] == '\r') {
buffer[len - 2] = '\n';
buffer[len - 1] = '\0';
len--;
}
state_put(buffer,len,s_out);
} while ((len = state_getl (buffer, sizeof (buffer),
&newstate2)) > 0
&& strncmp(buffer, "-----BEGIN PGP", 14) != 0);
} else {
DPRINT(Debug,4,(&Debug,
"pgp_decode: Unsupported character set?\n"));
}
pgp_found:
s_out -> filter = NULL;
}
} else {
char * msg = NULL;
if (opts & PGP_MESSAGE)
msg = elm_message(CATGETS(elm_msg_cat, MeSet,
MePgpEncodedCantEncoding,
"-- Start of PGP encoded section -- can't decode content-transfer-encoding\n"));
else if (opts & PGP_SIGNED_MESSAGE)
msg = elm_message(CATGETS(elm_msg_cat, MeSet,
MePgpSignedCantEncoding,
"-- Start of PGP signed section -- can't decode content-transfer-encoding\n"));
else
msg = elm_message(CATGETS(elm_msg_cat, MeSet, MePgpCantEncoding,
"-- Start of PGP section -- can't decode content-transfer-encoding\n"));
state_puts(msg,s_out);
free(msg);
return;
}
if ( len < 1) {
char * msg = NULL;
if (opts & PGP_MESSAGE)
msg = elm_message(CATGETS(elm_msg_cat, MeSet, MePgpNoTextEncoded,
"[ No text in PGP encoded section ]\n"));
else if (opts & PGP_SIGNED_MESSAGE)
msg = elm_message(CATGETS(elm_msg_cat, MeSet, MePgpNoTextSigned,
"[ No text in PGP signed section ]\n"));
else
msg = elm_message(CATGETS(elm_msg_cat, MeSet, MePgpNoText,
"[ No text in PGP section ]\n"));
state_puts(msg,s_out);
free(msg);
return;
}
if (!was_binary) {
int l = in_state_ftell(&newstate2);
int len1;
char buf[STRING];
/*
* On PGP 2 messages these is empty line immediately after
* -----BEGIN PGP SIGNED MESSAGE----
*
* If there is something other such as
* Hash: SHA1
* PGP 2 does not understand message.
*/
while ((len1 = state_getl (buf, sizeof (buf), &newstate2)) > 0) {
if ((len1 == 1 && buf[0] == '\n') ||
(len1 == 2 && buf[0] == '\r' && buf[1] == '\n'))
break;
if (opts == PGP_SIGNED_MESSAGE) {
DPRINT(Debug,4,(&Debug,
"pgp_decode: peek: Header on armor -- requires PGP 5 or GnuPG\n" ));
v = gpg;
armor_header++;
break;
}
if (0 == strncmp("Version: ",buf,9)) {
char *c = buf+9;
v = decode_pgp_version(c);
if (armor_header && pgp2 == v)
v = gpg;
}
}
/* Look also for -----BEGIN PGP SIGNATURE----- ... */
if (opts == PGP_SIGNED_MESSAGE && len1 > 0) {
DPRINT(Debug,4,(&Debug,
"pgp_decode: Looking for -----BEGIN PGP SIGNATURE\n"));
while ((len1 = state_getl (buf, sizeof (buf), &newstate2)) > 0) {
if (len1 > 24 &&
0 == strncmp(buf,
"-----BEGIN PGP SIGNATURE",24))
break;
}
while ((len1 = state_getl (buf, sizeof (buf),
&newstate2)) > 0) {
if ((len1 == 1 && buf[0] == '\n') ||
(len1 == 2 && buf[0] == '\r' && buf[1] == '\n'))
break;
if (0 == strncmp("Version: ",buf,9)) {
char *c = buf+9;
v = decode_pgp_version(c);
if (armor_header && pgp2 == v)
v = gpg;
}
}
}
in_state_fseek(&newstate2,l);
}
version = have_pgp(v);
if (!version) {
if (was_binary) {
state_printf(s_out,
CATGETS(elm_msg_cat, MeSet, MePgpNotAvailSkipping,
"[ PGP not available, skipping... ]\n"));
return;
} else
state_printf (s_out,
CATGETS(elm_msg_cat, MeSet, MePgpNotAvailRawdata,
"[ PGP not available, raw data follows ]\n"));
goto fail;
}
if ((opts & PGP_MESSAGE) && pgp_keeppass) {
if (!pgp_goodPassphrase(version)) {
lib_error(CATGETS(elm_msg_cat, MeSet, MePgpBadPassphrase,
"Decrypting message... Bad PGP passphrase."));
state_putc('[',s_out);
state_printf(s_out,
CATGETS(elm_msg_cat, MeSet, MePgpBadPassphrase,
"Decrypting message... Bad PGP passphrase."));
state_puts("]\n",s_out);
return;
}
}
if (!pgp_decrypt_init (&pgpout, &pgpin, opts, version, &RS)) {
if (was_binary)
state_printf(s_out,
CATGETS(elm_msg_cat, MeSet, MePgpInternalSkipping,
"[ Internal error while calling pgp, skipping... ]\n"));
else {
state_printf(s_out,
CATGETS(elm_msg_cat, MeSet, MePgpInternalRawdata,
"[ Internal error while calling pgp, raw data follows ]\n"));
fail:
do {
state_add_prefix(s_out);
if (len > 1 &&
buffer[len - 1] == '\n' &&
buffer[len - 2] == '\r') {
buffer[len - 2] = '\n';
buffer[len - 1] = '\0';
len--;
}
state_put(buffer,len,s_out);
bytes += len;
} while ((len = state_getl (buffer, sizeof (buffer),
&newstate2)) > 0);
state_printf(s_out,
CATGETS(elm_msg_cat, MeSet, MePgpRawEnd,
"[ End of raw data. ]\n"));
}
return;
}
do {
fwrite(buffer,1,len,pgpin);
bytes += len;
} while ((len = state_getl (buffer, sizeof (buffer),
&newstate2)) > 0);
fclose (pgpin);
code = run_already_done(&RS,&stat);
if (code != 0) {
char * msg = NULL;
if (opts & PGP_MESSAGE)
msg = elm_message(CATGETS(elm_msg_cat, MeSet, MePgpStartEncoded1,
"-- Start of PGP encoded section%s\n"),
code < 0 || stat ? catgets(elm_msg_cat, MeSet,
MePgpFail,
", PGP failed!") : ".");
else if (opts & PGP_SIGNED_MESSAGE)
msg = elm_message(CATGETS(elm_msg_cat, MeSet, MePgpStartSigned1,
"-- Start of PGP signed section%s\n"),
code < 0 || stat ? catgets(elm_msg_cat, MeSet,
MePgpFail,
", PGP failed!") : ".");
else if (opts & PGP_PUBLIC_KEY)
msg = elm_message(CATGETS(elm_msg_cat, MeSet, MePgpStartOutput1,
"-- Start of PGP output%s\n"),
code < 0 || stat ? catgets(elm_msg_cat, MeSet,
MePgpFail,
", PGP failed!") : ".");
else
msg = elm_message(CATGETS(elm_msg_cat, MeSet, MePgpStart1,
"-- Start of PGP section%s\n"),
code < 0 || stat ? catgets(elm_msg_cat, MeSet,
MePgpFail,
", PGP failed!") : ".");
state_puts(msg,s_out);
free(msg);
} else {
if (opts & PGP_MESSAGE)
state_printf(s_out,
CATGETS(elm_msg_cat, MeSet, MePgpStartEncoded,
"-- Start of PGP encoded section.\n"));
else if (opts & PGP_SIGNED_MESSAGE)
state_printf(s_out,
CATGETS(elm_msg_cat, MeSet, MePgpStartSigned,
"-- Start of PGP signed section.\n"));
else if (opts & PGP_PUBLIC_KEY)
state_printf(s_out,
CATGETS(elm_msg_cat, MeSet, MePgpStartOutput,
"-- Start of PGP output.\n"));
else
state_printf(s_out,
CATGETS(elm_msg_cat, MeSet, MePgpStart,
"-- Start of PGP section.\n"));
}
bytes = 0;
if (was_text && !nested) {
if (set_filter(m,s_out,NULL,
mss ? mss->override_charset : NULL)) {
DPRINT(Debug,4,(&Debug,
"pgp_decode: Filtering according of charset enabled.\n"));
} else {
DPRINT(Debug,4,(&Debug,
"pgp_decode: Unsupported character set?\n"));
skip_flag++;
}
}
retry:
while ((len = mail_gets (buffer, sizeof (buffer), pgpout)) > 0) {
if (nested) {
if (buffer[0] == '\n' || (buffer[0] == '\r' && buffer[1] == '\n'))
inbody = TRUE;
fputs (buffer, tmpfp);
if (inbody)
bytes += len;
} else if (!skip_flag) {
state_add_prefix(s_out);
state_puts(buffer,s_out);
}
}
s_out -> filter = NULL;
if (ferror(pgpout) && EINTR == errno) {
clearerr(pgpout);
DPRINT(Debug,5,(&Debug,
"Reading of result interrupted (EINTR) -- retrying\n"));
if (0 == code) {
code = run_already_done(&RS,&stat);
if (0 != code) {
DPRINT(Debug,5,(&Debug,
"now pgp/gpg is completing\n"));
}
}
goto retry;
}
fclose (pgpout); pgpout = NULL;
if (nested) {
struct in_state s2_in;
in_state_clear(&s2_in,STATE_in_file);
DPRINT(Debug,3,(&Debug,
"pgp_decode: parsing decrypted data as MIME\n"));
if (EOF == fflush(tmpfp)) {
lib_error(CATGETS(elm_msg_cat, MeSet, MePgpErrorFlush,
"Error when flushing temporary file."));
state_putc('[',s_out);
state_printf(s_out,
CATGETS(elm_msg_cat, MeSet, MePgpErrorFlush,
"Error when flushing temporary file."));
state_puts("]\n",s_out);
}
rewind(tmpfp); /* Rewind it for reading */
tmpmt = mime_read_header (tmpfp, 0, defcharset, & (mss->header_error));
tmpmt->length = bytes;
mime_parser_parse(tmpmt,defcharset,tmpfp, & (mss->header_error));
set_in_state_file(tmpfp,&s2_in);
/* Pass NULL as message, because this is decryoted contetnt */
mime_decode (tmpmt, &s2_in, s_out, defcharset, NULL, badtype);
mime_t_clear(tmpmt);
in_state_destroy(&s2_in);
fclose (tmpfp);
}
if (0 == code)
code = wait_end(&RS,&stat);
call_print_status_cooked(&RS,code < 0 ? -code : 0,stat);
if (raw)
sr_call_Raw (ON);
if (opts & PGP_MESSAGE)
elm_sfprintf(buffer,sizeof buffer,
CATGETS(elm_msg_cat, MeSet, MePgpEndEncoded,
"-- End of PGP encoded section%s\n"),
code < 0 || stat ? catgets(elm_msg_cat, MeSet, MePgpFail,
", PGP failed!") : ".");
else if (opts & PGP_SIGNED_MESSAGE)
elm_sfprintf(buffer,sizeof buffer,
CATGETS(elm_msg_cat, MeSet, MePgpEndSigned,
"-- End of PGP signed section%s\n"),
code < 0 || stat ? catgets(elm_msg_cat, MeSet, MePgpFail,
", PGP failed!") : ".");
else if (opts & PGP_PUBLIC_KEY)
elm_sfprintf(buffer,sizeof buffer,
CATGETS(elm_msg_cat, MeSet, MePgpEndOutput,
"-- End of PGP output%s\n"),
code < 0 || stat ? catgets(elm_msg_cat, MeSet, MePgpFail,
", PGP failed!") : ".");
else
elm_sfprintf(buffer,sizeof buffer,
CATGETS(elm_msg_cat, MeSet, MePgpEnd,
"-- End of PGP section%s\n"),
code < 0 || stat ? catgets(elm_msg_cat, MeSet, MePgpFail,
", PGP failed!") : ".");
state_puts(buffer,s_out);
FAILTYPE:
in_state_destroy(&newstate2);
if (decode_fp) /* in_state_destroy does not close file!! */
fclose(decode_fp);
}
void pgp_SG_decoder(body,sign,state_in,state_out,micalg, defcharset, mss,
badtype)
mime_t *body;
mime_t *sign;
in_state_t *state_in;
out_state_t *state_out;
const char *micalg;
charset_t defcharset;
struct header_rec *mss;
type_mismatch_prompt *badtype;
{
int exit_code = -1;
FILE *binary_fp;
char *body_name = NULL;
in_state_t newstate2;
char * buffer;
enum pgp_version v = pgp2;
enum pgp_version version;
in_state_clear(&newstate2,STATE_in_file);
if (0 == istrcmp(micalg,"pgp-md5")) {
DPRINT(Debug,4,(&Debug,
"pgp_SG_decoder: micalg=%s, PGP 2\n",
micalg));
v = pgp2;
} else {
DPRINT(Debug,4,(&Debug,
"pgp_SG_decoder: micalg=%s, GPG\n",
micalg));
v = gpg;
}
if (NULL != (binary_fp = arrange_binary(body,state_in,state_out,&newstate2,
&body_name))) {
in_state_t newstate3;
FILE *decode_fp = NULL;
char *sign_name = NULL;
in_state_clear(&newstate3,STATE_in_file);
if (in_state_fseek(state_in,sign->offset) != 0) {
lib_error(CATGETS(elm_msg_cat, MeSet, MePgpSGSeekFail,
"pgp_SG_decoder: seek failed"));
state_putc('[',state_out);
state_printf(state_out,
CATGETS(elm_msg_cat, MeSet, MePgpSGSeekFail,
"pgp_SG_decoder: seek failed"));
state_puts("]\n",state_out);
}
if (NULL != (decode_fp =
arrange_decoded(sign,state_in,state_out,&newstate3,
&sign_name))) {
int i = 0;
int len1;
char buf[STRING];
while ((len1 = state_getl (buf, sizeof (buf), &newstate3)) > 0) {
if (i == 0) {
if (strncmp(buf, "-----BEGIN PGP", 14) != 0)
break;
i++;
continue;
}
if ((len1 == 1 && buf[0] == '\n') ||
(len1 == 2 && buf[0] == '\r' && buf[1] == '\n'))
break;
if (0 == strncmp("Version: ",buf,9)) {
char *c = buf+9;
v = decode_pgp_version(c);
}
}
in_state_fseek(&newstate3,0);
if ((version=have_pgp(v))) {
struct run_state RS;
int stat;
CONST char * argv[10];
int raw = sr_call_RawState ();
switch(version) {
static char path[1000];
case pgp2:
{
char * pgp2_path_val =
give_dt_estr_as_str(&pgp2_path_e, "pgp2");
if (! pgp2_path_val)
return;
argv[0] = pgp2_path_val;
}
argv[1] = "+batchmode";
argv[2] = "+TEXTMODE=off";
argv[3] = "+CHARSET=noconv";
argv[4] = sign_name;
argv[5] = body_name;
argv[6] = NULL;
break;
case pgp5:
{
/* give_dt_estr_as_str adds / to end */
char * pgp5_dir_val = give_dt_estr_as_str(&pgp5_dir_e,
"pgp5-dir");
if (! pgp5_dir_val)
return;
elm_sfprintf(path, sizeof path,FRM("%spgpv"),
pgp5_dir_val);
}
argv[0] = path;
argv[1] = "+batchmode";
argv[2] = "+TEXTMODE=off";
argv[3] = "+CHARSET=noconv";
argv[4] = sign_name;
argv[5] = body_name;
argv[6] = NULL;
break;
case gpg:
{
char * gpg_path_val = give_dt_estr_as_str(&gpg_path_e,
"gpg");
if (! gpg_path_val)
return;
argv[0] = gpg_path_val;
}
argv[1] = "--batch";
argv[2] = "--verify";
argv[3] = sign_name;
argv[4] = body_name;
argv[5] = NULL;
break;
}
sr_call_Raw(OFF);
sr_call_ClearScreen();
sr_call_Write_to_screen(CATGETS(elm_msg_cat, MeSet, MePgpCheckSig,
"Running pgp: Checking signature...\n"));
stat = start_run(&RS,0,argv,-1,-1);
if (stat)
stat = wait_end(&RS,&exit_code);
call_print_status_cooked(&RS,stat < 0 ? -stat : 0,exit_code);
if (raw)
sr_call_Raw (ON);
if (stat) {
if (state_out->displaying) {
state_puts("\n[",state_out);
if (exit_code == 0)
state_printf(state_out,
CATGETS(elm_msg_cat, MeSet,MePgpSigOK,
"Checking application/pgp-signature: OK"));
else
state_printf(state_out,
CATGETS(elm_msg_cat, MeSet,MePgpSigFAILURE,
"Checking application/pgp-signature: FAILURE"));
state_puts("]\n\n",state_out);
} else if (exit_code != 0) {
state_puts("\n",state_out);
state_printf(state_out,
CATGETS(elm_msg_cat, MeSet,MePgpSigFAILURE,
"Checking application/pgp-signature: FAILURE"));
state_puts("\n",state_out);
}
} else {
if (RS.save_errno) {
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmFailErrno,
"Failed: %.30s: %.40s"),
argv[0],error_description(RS.save_errno));
} else
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCantStart,
"Can't start %.30s"),
argv[0]);
}
}
unlink(sign_name);
free(sign_name);
in_state_destroy(&newstate3);
if (decode_fp) /* in_state_destroy does not close file!! */
fclose(decode_fp);
}
unlink(body_name);
free(body_name);
in_state_destroy(&newstate2);
if (binary_fp) /* in_state_destroy does not close file!! */
fclose(binary_fp);
}
state_printf(state_out,
CATGETS(elm_msg_cat, MeSet, MePgpStartSigned,
"-- Start of PGP signed section.\n"));
/* Pass mss as message, because this is NOT decrypted (only signed) */
mime_decode(body,state_in,state_out, defcharset, mss,
badtype);
buffer = elm_message(CATGETS(elm_msg_cat, MeSet, MePgpEnd,
"-- End of PGP section%s\n"),
exit_code ? catgets(elm_msg_cat, MeSet, MePgpFail,
", PGP failed!") : ".");
state_puts(buffer,state_out);
free(buffer);
}
void pgp_EC_decoder(init,data,state_in,state_out, defcharset, mss, badtype)
mime_t *init;
mime_t *data;
in_state_t *state_in;
out_state_t *state_out;
charset_t defcharset;
struct header_rec *mss;
type_mismatch_prompt *badtype;
{
char * tempfile = NULL;
FILE *decode_fp;
FILE *tmpfp;
in_state_t newstate2;
char *tmp;
tmp = give_dt_estr_as_str(&temp_dir_e,"tmpdir");
in_state_clear(&newstate2,STATE_in_file);
if (in_state_fseek(state_in,data->offset) != 0) {
lib_error(CATGETS(elm_msg_cat, MeSet, MePgpECSeekFail,
"pgp_EC_decoder: seek failed"));
state_putc('[',state_out);
state_printf(state_out,
CATGETS(elm_msg_cat, MeSet, MePgpECSeekFail,
"pgp_EC_decoder: seek failed"));
state_puts("]\n",state_out);
}
tempfile = elm_message(FRM("%selmPT%d"),
tmp, getpid ());
if (NULL == (tmpfp = safeopen_rdwr(tempfile))) {
lib_error(CATGETS(elm_msg_cat, MeSet, MePgpCantCreate,
"Failed to create file for decoding."));
state_putc('[',state_out);
state_printf(state_out,
CATGETS(elm_msg_cat, MeSet, MePgpCantCreate,
"Failed to create file for decoding."));
state_puts("]\n",state_out);
free(tempfile);
return;
}
unlink (tempfile); /* Filename is no longer needed ... */
free(tempfile); tempfile = NULL;
if (NULL != (decode_fp =
arrange_decoded(data,state_in,state_out,&newstate2,NULL))) {
int i = 0,len1;
char buf[STRING];
enum pgp_version v = pgp2;
enum pgp_version version;
struct in_state s2_in;
struct run_state RS;
FILE *pgpout,*pgpin;
int code;
mime_t *tmpmt;
int stat;
long bytes = 0;
int inbody = FALSE;
int raw = sr_call_RawState ();
in_state_clear(&s2_in,STATE_in_file);
while ((len1 = state_getl (buf, sizeof (buf), &newstate2)) > 0) {
if (i == 0) {
if (strncmp(buf, "-----BEGIN PGP", 14) != 0)
break;
i++;
continue;
}
if ((len1 == 1 && buf[0] == '\n') ||
(len1 == 2 && buf[0] == '\r' && buf[1] == '\n'))
break;
if (0 == strncmp("Version: ",buf,9)) {
char *c = buf+9;
v = decode_pgp_version(c);
}
}
in_state_fseek(&newstate2,0);
version = have_pgp(v);
if (!version) {
state_printf(state_out,
CATGETS(elm_msg_cat, MeSet, MePgpNotAvailSkipping,
"[ PGP not available, skipping... ]\n"));
return;
}
if (!pgp_goodPassphrase(version)) {
lib_error(CATGETS(elm_msg_cat, MeSet, MePgpBadPassphrase,
"Decrypting message... Bad PGP passphrase."));
state_puts("[ ",state_out);
state_printf(state_out,
CATGETS(elm_msg_cat, MeSet, MePgpBadPassphrase,
"Decrypting message... Bad PGP passphrase."));
state_puts(" ]\n",state_out);
return;
}
if (!pgp_decrypt_init (&pgpout, &pgpin, PGP_MESSAGE, version, &RS)) {
state_printf(state_out,
CATGETS(elm_msg_cat, MeSet, MePgpInternalSkipping,
"[ Internal error while calling pgp, skipping... ]\n"));
}
while ((len1 = state_getl (buf, sizeof (buf),
&newstate2)) > 0) {
fwrite(buf,1,len1,pgpin);
}
fclose (pgpin);
code = run_already_done(&RS,&stat);
if (code != 0) {
char * msg = elm_message(CATGETS(elm_msg_cat, MeSet,
MePgpStartEncoded1,
"-- Start of PGP encoded section%s\n"),
code < 0 || stat ? catgets(elm_msg_cat,
MeSet,
MePgpFail,
", PGP failed!")
: ".");
state_puts(msg,state_out);
free(msg);
} else
state_printf(state_out,
CATGETS(elm_msg_cat, MeSet, MePgpStartEncoded,
"-- Start of PGP encoded section.\n"));
bytes = 0;
retry:
while ((len1 = mail_gets (buf, sizeof (buf), pgpout)) > 0) {
if (buf[0] == '\n' || (buf[0] == '\r' && buf[1] == '\n'))
inbody = TRUE;
fputs (buf, tmpfp);
if (inbody)
bytes += len1;
}
if (ferror(pgpout) && EINTR == errno) {
clearerr(pgpout);
DPRINT(Debug,5,(&Debug,
"Reading of result interrupted (EINTR) -- retrying\n"));
if (0 == code) {
code = run_already_done(&RS,&stat);
if (0 != code) {
DPRINT(Debug,5,(&Debug,
"now pgp/gpg is completing\n"));
}
}
goto retry;
}
fclose(pgpout);
if (EOF == fflush(tmpfp)) {
lib_error(CATGETS(elm_msg_cat, MeSet, MePgpErrorFlush,
"Error when flushing temporary file."));
state_puts(" [",state_out);
state_printf(state_out,
CATGETS(elm_msg_cat, MeSet, MePgpErrorFlush,
"Error when flushing temporary file."));
state_puts(" ]\n",state_out);
}
rewind(tmpfp); /* Rewind it for reading */
tmpmt = mime_read_header (tmpfp, 0, defcharset, &(mss->header_error));
tmpmt->length = bytes;
mime_parser_parse(tmpmt,defcharset,tmpfp, & (mss->header_error));
set_in_state_file(tmpfp,&s2_in);
/* Pass NULL as message, because this is encrypted section */
mime_decode (tmpmt, &s2_in, state_out, defcharset, NULL,
badtype);
mime_t_clear(tmpmt);
in_state_destroy(&s2_in);
if (0 == code)
code = wait_end(&RS,&stat);
call_print_status_cooked(&RS,code < 0 ? -code : 0,stat);
if (raw)
sr_call_Raw (ON);
elm_sfprintf(buf,sizeof buf,
CATGETS(elm_msg_cat, MeSet, MePgpEndEncoded,
"-- End of PGP encoded section%s\n"),
code < 0 || stat ? catgets(elm_msg_cat, MeSet, MePgpFail,
", PGP failed!") : ".");
state_puts(buf,state_out);
in_state_destroy(&newstate2);
if (decode_fp) /* in_state_destroy does not close file!! */
fclose(decode_fp);
} else {
char * msg = elm_message(CATGETS(elm_msg_cat, MeSet,
MePgpEncodedCantEncoding,
"-- Start of PGP encoded section -- can't decode content-transfer-encoding\n"));
state_puts(msg,state_out);
free(msg);
}
fclose (tmpfp);
}
#endif /* USE_PGP */
/*
* Local Variables:
* mode:c
* c-basic-offset:4
* buffer-file-coding-system: iso-8859-1
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1