summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEduardo Chappa <chappa@washington.edu>2014-04-25 17:31:25 -0600
committerEduardo Chappa <chappa@washington.edu>2014-04-25 17:31:25 -0600
commite797af007ccac26651f003bcead095f79994d5a0 (patch)
treeb291d66106dcbfba990b6a8f4f9d0986fb76abe1
parent06525250787f8f774afa7f25901a8a805f2a29db (diff)
downloadalpine-e797af007ccac26651f003bcead095f79994d5a0.tar.xz
* When downloading a signed message, and processing it, we use
body->nested.part instead of b->nested.part in the do_detached_signature_verify function, and save its body and mime headers in create_local_cache. Now all signed messages should verify correctly. * Protect against potential crash bug in write_passfile function by checking if text != NULL. text can only be null if there are no passwords to save. We assume we could get write_passfile called with null arguments, so this is just to protect that. * Add handling of corner cases to several functions by initializing some variables. Reported and patched by James Jerkins. * When selecting the certificate/key pair to encrypt/decrypt the password file choose it in this order: - if -pwdcertdir is given look for certificates there, if nothing there, we bail out; - otherwise we look in the default directory, if anything there and it matches to be a key/cert pair, we use it; - otherwise we check if smime_init() has been called. If not we call it; - we check if a key/cert pair has been found with smime initialized, if so, use it and copy it to the default directory; - if not, check if there is anything in the default smime directories (.alpine-smime/private and .alpine-smime/public), and in this case copy it to the default. - otherwise we bail. We will eventually create a certificate/key pair for the user; - finally, if we called smime_init(), we call smime_deinit(). Throughout this process, if smime_init() was not called before we tried to get the cert/key pair we exit this process without ps_global->smime->inited set, so that other process that need to call smime_init() get the right structure initialized. This is done because we might pick a cert/key pair to decrypt the password file.
-rw-r--r--alpine/folder.c15
-rw-r--r--alpine/help.c2
-rw-r--r--alpine/imap.c38
-rw-r--r--alpine/mailcmd.c10
-rw-r--r--alpine/mailindx.c10
-rw-r--r--alpine/mailview.c6
-rw-r--r--alpine/smime.c16
-rw-r--r--pico/browse.c2
-rw-r--r--pico/word.c2
-rw-r--r--pith/adrbklib.c2
-rw-r--r--pith/conf.c5
-rw-r--r--pith/conftype.h11
-rw-r--r--pith/filter.c8
-rw-r--r--pith/help.c2
-rw-r--r--pith/imap.c2
-rw-r--r--pith/pine.hlp2
-rw-r--r--pith/send.c1
-rw-r--r--pith/smime.c601
-rw-r--r--pith/smkeys.c62
-rw-r--r--pith/smkeys.h2
-rw-r--r--pith/state.c7
-rw-r--r--pith/state.h3
-rw-r--r--pith/string.c6
-rw-r--r--pith/thread.c2
-rw-r--r--po/Makefile.in2
-rw-r--r--web/src/alpined.d/alpined.c2
-rw-r--r--web/src/alpined.d/imap.c1
27 files changed, 459 insertions, 363 deletions
diff --git a/alpine/folder.c b/alpine/folder.c
index 3286d1cf..6890b6f2 100644
--- a/alpine/folder.c
+++ b/alpine/folder.c
@@ -907,10 +907,10 @@ context_edit_screen(struct pine *ps, char *func, char *def_nick,
char *def_serv, char *def_path, char *def_view)
{
int editor_result, i, j;
- char nickpart[MAILTMPLEN], servpart[MAILTMPLEN], new_cntxt[MAILTMPLEN];
+ char servpart[MAILTMPLEN], new_cntxt[MAILTMPLEN];
char pathpart[MAILTMPLEN], allbutnick[MAILTMPLEN];
char tmp[MAILTMPLEN], *nick, *serv, *path, *view,
- *return_cntxt = NULL, *val, *p, new[MAILTMPLEN];
+ *return_cntxt = NULL, *val, *p;
char nickpmt[100], servpmt[100], pathpmt[100], viewpmt[100];
int indent;
PICO pbf;
@@ -4491,10 +4491,10 @@ get_folder_name:
/* for non-local folders, transform UTF-8 to MUTF7 */
if(offset > 0 && add_folder[0] == '{'){
- unsigned char *mutf7 = utf8_to_mutf7(&add_folder[offset]);
+ unsigned char *mutf7 = utf8_to_mutf7((unsigned char *)&add_folder[offset]);
if(mutf7 != NULL){
strncpy(orig_folder, &add_folder[offset], 2*MAXFOLDER+10);
- strncpy(&add_folder[offset], mutf7, add_folderlen-offset);
+ strncpy(&add_folder[offset], (char *) mutf7, add_folderlen-offset);
add_folder[add_folderlen-1] = '\0';
fs_give((void **)&mutf7);
}
@@ -4615,10 +4615,10 @@ skip_over_folder_input:
/* for non-local folders, transform UTF-8 to MUTF7 */
if(offset > 0 && add_folder[0] == '{'){
- unsigned char *mutf7 = utf8_to_mutf7(&add_folder[offset]);
+ unsigned char *mutf7 = utf8_to_mutf7((unsigned char *)&add_folder[offset]);
if(mutf7 != NULL){
strncpy(orig_folder, &add_folder[offset], 2*MAXFOLDER+10);
- strncpy(&add_folder[offset], mutf7, add_folderlen-offset);
+ strncpy(&add_folder[offset], (char *) mutf7, add_folderlen-offset);
add_folder[add_folderlen-1] = '\0';
fs_give((void **)&mutf7);
}
@@ -6166,7 +6166,8 @@ folder_select_count(long int *count, int *cmp)
continue;
case 14 : /* toggle comparison */
- *cmp = ++(*cmp) % 3;
+ ++(*cmp);
+ *cmp = *cmp % 3;
continue;
case -1 : /* cancel */
diff --git a/alpine/help.c b/alpine/help.c
index 0fe06b43..aa7a8d70 100644
--- a/alpine/help.c
+++ b/alpine/help.c
@@ -634,7 +634,7 @@ url_local_config(char *url)
{
if(!struncmp(url, "x-alpine-config:", 16)){
char **config;
- int rv;
+ int rv = MC_NONE;
config = get_supported_options();
if(config){
diff --git a/alpine/imap.c b/alpine/imap.c
index 6db0a0bc..009a9036 100644
--- a/alpine/imap.c
+++ b/alpine/imap.c
@@ -2061,8 +2061,8 @@ line_get(char *tmp, size_t len, char **textp)
if(*(s-1) == '\r')
*(s-1) = '\0';
- strcpy(tmp, *textp);
- strcat(tmp, "\n");
+ snprintf(tmp, len, "%s\n", *textp);
+ tmp[len-1] = '\0';
*textp = s+1;
return 1;
@@ -2373,14 +2373,25 @@ read_passfile(pinerc, l)
};
#ifdef SMIME
- smime_init();
- if(ps_global->smime->pwdcert == NULL)
- setup_pwdcert(&ps_global->smime->pwdcert);
+ /* the next call initializes the key/certificate pair used to
+ * encrypt and decrypt a password file. The details of how this is
+ * done is in the file pith/smime.c. During this setup we might call
+ * smime_init(), but no matter what happens we must call smime_deinit()
+ * there. The reason why this is so is because we can not assume that
+ * the .pinerc file has been read by this time, so this code might not
+ * know about the ps_global->smime structure or any of its components,
+ * and it shouldn't because it only needs ps_global->pwdcert, so
+ * do not init smime here, because the .pinerc might not have been
+ * read and we do not really know where the keys and certificates really
+ * are.
+ */
+ if(ps_global->pwdcert == NULL)
+ setup_pwdcert(&ps_global->pwdcert);
tmp2[0] = '\0';
fgets(tmp2, sizeof(tmp2), fp);
fclose(fp);
if(strcmp(tmp2, "-----BEGIN PKCS7-----\n")){
- if(encrypt_file((char *)tmp, NULL, (PERSONAL_CERT *)ps_global->smime->pwdcert))
+ if(encrypt_file((char *)tmp, NULL, (PERSONAL_CERT *)ps_global->pwdcert))
encrypted++;
}
else
@@ -2399,7 +2410,7 @@ read_passfile(pinerc, l)
* unencrypted and rewritten again.
*/
if(encrypted){
- text = text2 = decrypt_file((char *)tmp, &i, (PERSONAL_CERT *)ps_global->smime->pwdcert);
+ text = text2 = decrypt_file((char *)tmp, &i, (PERSONAL_CERT *)ps_global->pwdcert);
switch(i){
case 1 : save_password = 1;
break;
@@ -2623,7 +2634,7 @@ write_passfile(pinerc, l)
len = strlen(text) + strlen(tmp) + 1;
fs_resize((void **)&text, len*sizeof(char));
}
- strcat(text, tmp);
+ strncat(text, tmp, strlen(tmp));
#else /* SMIME */
fputs(tmp, fp);
#endif /* SMIME */
@@ -2631,13 +2642,15 @@ write_passfile(pinerc, l)
fclose(fp);
#ifdef SMIME
- if(encrypt_file((char *)tmp2, text, (PERSONAL_CERT *) ps_global->smime->pwdcert) == 0){
- if((fp = our_fopen(tmp2, "wb")) != NULL){
+ if(text != NULL){
+ if(encrypt_file((char *)tmp2, text, ps_global->pwdcert) == 0){
+ if((fp = our_fopen(tmp2, "wb")) != NULL){
fputs(text, fp);
fclose(fp);
- }
+ }
+ }
+ fs_give((void **)&text);
}
- fs_give((void **)&text);
#endif /* SMIME */
#endif /* PASSFILE */
}
@@ -2940,7 +2953,6 @@ update_passfile_hostlist(pinerc, user, hostlist, altflag)
return;
#else /* !WINCRED */
MMLOGIN_S *l;
- STRLIST_S *h1, *h2;
for(l = passfile_cache; l; l = l->next)
if(imap_same_host(l->hosts, hostlist)
diff --git a/alpine/mailcmd.c b/alpine/mailcmd.c
index 0ea1617c..bde099c6 100644
--- a/alpine/mailcmd.c
+++ b/alpine/mailcmd.c
@@ -438,7 +438,7 @@ view_text:
: (in_index == View)
? MH_ANYTHD : MH_NONE);
if(i == mn_get_cur(msgmap)){
- PINETHRD_S *thrd, *topthrd;
+ PINETHRD_S *thrd = NULL, *topthrd = NULL;
if(THRD_INDX_ENABLED()){
mn_dec_cur(stream, msgmap, MH_ANYTHD);
@@ -5537,20 +5537,20 @@ broach_folder(int qline, int allow_list, int *notrealinbox, CONTEXT_S **context)
* newfolder, including content and size. f2 is copy of f1
* that has to freed. Sigh!
*/
- f3 = cpystr(newfolder);
+ f3 = (unsigned char *) cpystr(newfolder);
f1 = fs_get(sizeof(newfolder));
f2 = folder_name_decoded(f3);
if(f3) fs_give((void **)&f3);
- strncpy(f1, f2, sizeof(newfolder));
+ strncpy((char *)f1, (char *)f2, sizeof(newfolder));
f1[sizeof(newfolder)-1] = '\0';
if(f2) fs_give((void **)&f2);
flags = OE_APPEND_CURRENT;
rc = optionally_enter(f1, qline, 0, sizeof(newfolder),
- prompt, ekey, help, &flags);
+ (char *) prompt, ekey, help, &flags);
f2 = folder_name_encoded(f1);
- strncpy(newfolder, f2, sizeof(newfolder));
+ strncpy(newfolder, (char *)f2, sizeof(newfolder));
if(f1) fs_give((void **)&f1);
if(f2) fs_give((void **)&f2);
diff --git a/alpine/mailindx.c b/alpine/mailindx.c
index 276fe727..c60ef38c 100644
--- a/alpine/mailindx.c
+++ b/alpine/mailindx.c
@@ -1956,12 +1956,10 @@ paint_index_line(ICE_S *argice, int line, long int msgno, IndexColType sfld,
for(ielem = ifield->ielem; ielem; ielem = ielem->next){
char *src;
- size_t bytes_added;
src = ielem->data;
- bytes_added = utf8_pad_to_width(draw, src,
- (n+1) * sizeof(char),
- ielem->wid, ifield->leftadj);
+ utf8_pad_to_width(draw, src, (n+1) * sizeof(char),
+ ielem->wid, ifield->leftadj);
draw[n] = '\0';
/*
@@ -3625,7 +3623,7 @@ view_in_new_window(void)
void *text;
long len;
int format;
- MSWIN_TEXTWINDOW *mswin_tw;
+ MSWIN_TEXTWINDOW *mswin_tw = NULL;
/* Launch text in alt window. */
if(index_gettext_callback(title, sizeof (title), &text, &len, &format)){
@@ -3636,7 +3634,7 @@ view_in_new_window(void)
mswin_tw = mswin_displaytext(title, NULL, 0, text,
NULL, MSWIN_DT_USEALTWINDOW);
- if(mswin_tw)
+ if(mswin_tw != NULL)
mswin_set_readonly(mswin_tw, FALSE);
}
}
diff --git a/alpine/mailview.c b/alpine/mailview.c
index 566f06c8..639d5c89 100644
--- a/alpine/mailview.c
+++ b/alpine/mailview.c
@@ -835,8 +835,8 @@ scroll_handle_prompt(HANDLE_S *handle, int force)
if(force
|| (handle->type == URL
- && !struncmp(handle->h.url.path, "x-alpine-", 9)
- || !struncmp(handle->h.url.path, "x-pine-help", 11)))
+ && (!struncmp(handle->h.url.path, "x-alpine-", 9)
+ || !struncmp(handle->h.url.path, "x-pine-help", 11))))
return(1);
while(1){
@@ -1396,7 +1396,7 @@ url_launch(HANDLE_S *handle)
#define URL_MAX_LAUNCH (2 * MAILTMPLEN)
if(handle->h.url.tool){
- char *toolp, *cmdp, *p, *q, cmd[URL_MAX_LAUNCH + 4];
+ char *toolp, *cmdp, *p, cmd[URL_MAX_LAUNCH + 4];
int mode, copied = 0;
PIPE_S *syspipe;
diff --git a/alpine/smime.c b/alpine/smime.c
index c2484108..135ab3cf 100644
--- a/alpine/smime.c
+++ b/alpine/smime.c
@@ -880,6 +880,11 @@ smime_config_init_display(struct pine *ps, CONF_S **ctmp, CONF_S **first_line)
#endif /* APPLEKEYCHAIN */
+ if(SMHOLDERTYPE(Private) == Keychain
+ && SMHOLDERTYPE(Public) == Keychain
+ && SMHOLDERTYPE(CACert) == Keychain)
+ return;
+
new_confline(ctmp)->var = vtmp;
(*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
@@ -927,7 +932,7 @@ void display_certificate_information(struct pine *ps, X509 *cert, char *email, W
{
STORE_S *store;
SCROLL_S scrollargs;
- int cmd, offset, i;
+ int cmd, offset;
int pub_cert, priv_cert, new_store;
long error;
BIO *out = NULL;
@@ -942,14 +947,14 @@ void display_certificate_information(struct pine *ps, X509 *cert, char *email, W
switch(cmd){
case MC_PRIVATE:
pub_cert = 0;
- priv_cert = ++priv_cert % 2;
+ priv_cert = 1 - priv_cert;
smime_certificate_info_keymenu.keys[PUBLIC_KEY].label = N_("Public Key");
smime_certificate_info_keymenu.keys[PRIVATE_KEY].label = priv_cert ? N_("No Priv Key") : N_("Pivate Key");
break;
case MC_PUBLIC:
priv_cert = 0;
- pub_cert = ++pub_cert % 2;
+ pub_cert = 1 - pub_cert;
smime_certificate_info_keymenu.keys[PRIVATE_KEY].label = priv_cert ? N_("No Priv Key") : N_("Pivate Key");
smime_certificate_info_keymenu.keys[PUBLIC_KEY].label = N_("Public Key");
break;
@@ -1032,7 +1037,7 @@ void display_certificate_information(struct pine *ps, X509 *cert, char *email, W
gf_puts(NEWLINE, view_writec);
ch[1] = '\0';
while(BIO_read(out, ch, 1) >= 1)
- gf_puts(ch, view_writec);
+ gf_puts((char *)ch, view_writec);
gf_puts(NEWLINE, view_writec);
q_status_message1(SM_ORDER, 1, 3, _("%s information shown at bottom of certificate information"), pub_cert ? _("Public") : _("Private"));
BIO_free_all(out);
@@ -1240,7 +1245,6 @@ void smime_manage_certs_init(struct pine *ps, CONF_S **ctmp, CONF_S **first_line
if(data){
CertList *cl; int i;
- PERSONAL_CERT *pc;
for(cl = data, i = 0; cl; cl = cl->next)
if(cl->name){
@@ -1277,7 +1281,7 @@ void smime_manage_certs_init(struct pine *ps, CONF_S **ctmp, CONF_S **first_line
void manage_certificates(struct pine *ps, WhichCerts ctype)
{
OPT_SCREEN_S screen;
- int ew, readonly_warning = 0, rv = 10, fline;
+ int readonly_warning = 0, rv = 10, fline;
dprint((9, "manage_certificates(ps, %s)", ctype == Public ? _("Public") : (ctype == Private ? _("Private") : (ctype == CACert ? _("certificate authority") : _("unknown")))));
ps->next_screen = SCREEN_FUN_NULL;
diff --git a/pico/browse.c b/pico/browse.c
index 1c171db9..dd8ef336 100644
--- a/pico/browse.c
+++ b/pico/browse.c
@@ -1611,7 +1611,7 @@ FileBrowse(char *dir, size_t dirlen, char *fn, size_t fnlen,
PaintBrowser(gmp, 0, &crow, &ccol);
break;
case (CTRL|'P'):
- bsearch = ++bsearch % 2;
+ bsearch = bsearch == 0 ? 1 : 0;
break;
case (CTRL|'Y'): /* first first cell */
for(tp = gmp->top; tp->prev; tp = tp->prev)
diff --git a/pico/word.c b/pico/word.c
index 52805efb..2de9f287 100644
--- a/pico/word.c
+++ b/pico/word.c
@@ -434,7 +434,7 @@ is_user_separator(UCS c)
void
do_quote_match(UCS *q, LINE *l, UCS *buf, size_t buflen)
{
- register int i, j, qb;
+ register int i, j;
int qstart, qend, k;
/*
diff --git a/pith/adrbklib.c b/pith/adrbklib.c
index 1ccca637..51979bdc 100644
--- a/pith/adrbklib.c
+++ b/pith/adrbklib.c
@@ -3469,7 +3469,7 @@ io_error:
writing = 0;
- if(ab_stream){
+ if(ab_stream != NULL){
fclose(ab_stream);
ab_stream = (FILE *)NULL;
}
diff --git a/pith/conf.c b/pith/conf.c
index 1b216d3a..4bc9481b 100644
--- a/pith/conf.c
+++ b/pith/conf.c
@@ -5935,11 +5935,11 @@ write_pinerc(struct pine *ps, EditWhich which, int flags)
if(basep == NULL){
*basep = '\0';
slpath = (char *) fs_get((strlen(filename) + strlen(slink) + 2)*sizeof(char));
- sprintf(slpath, "%s/%s", filename, slink);
+ snprintf(slpath, sizeof(slpath), "%s/%s", filename, slink);
*basep = '/';
} else {
slpath = (char *) fs_get((strlen(ps_global->home_dir) + strlen(slink) + 2)*sizeof(char));
- sprintf(slpath, "%s/%s", ps_global->home_dir, slink);
+ snprintf(slpath, sizeof(slpath), "%s/%s", ps_global->home_dir, slink);
}
}
file_attrib_copy(tmp, slpath);
@@ -5964,6 +5964,7 @@ write_pinerc(struct pine *ps, EditWhich which, int flags)
char datebuf[200];
datebuf[0] = '\0';
+ we_cancel = 0;
if(!(flags & WRP_NOUSER))
we_cancel = busy_cue(_("Copying to remote config"), NULL, 1);
diff --git a/pith/conftype.h b/pith/conftype.h
index d8636b48..16e8de25 100644
--- a/pith/conftype.h
+++ b/pith/conftype.h
@@ -673,8 +673,8 @@ typedef enum {Directory, Container, Keychain, Nada} SmimeHolderType;
typedef enum {Public, Private, CACert} WhichCerts;
typedef struct certdata {
- unsigned deleted:1; /* certificate is marked deleted */
- unsigned renew:1; /* we must renew this list, set at top cert */
+ unsigned deleted:1; /* certificate is marked deleted */
+ unsigned renew:1; /* we must renew this list, set at top cert */
} CertData;
typedef struct certlist {
@@ -693,9 +693,6 @@ typedef struct smime_stuff {
unsigned already_auto_asked:1; /* asked for passphrase automatically, not again */
volatile char passphrase[100]; /* storage for the entered passphrase */
char **passphrase_emailaddr; /* pointer to allocated storage */
-#ifdef PASSFILE
- void *pwdcert; /* this has type (PERSONAL_CERT *) */
-#endif /* PASSFILE */
/*
* If we are using the Container type it is easiest if we
@@ -724,7 +721,7 @@ typedef struct smime_stuff {
#define DATACERT(X) (((X) == Public ? ps_global->smime->publiccertlist \
: ((X) == Private ? ps_global->smime->privatecertlist \
- : ((X) == CACert ? ps_global->smime->cacertlist : NULL))))
+ : ps_global->smime->cacertlist)))
#define PATHCERTDIR(X) (((X) == Public ? ps_global->smime->publicpath \
: ((X) == Private ? ps_global->smime->privatepath \
@@ -740,7 +737,7 @@ typedef struct smime_stuff {
#define EXTCERT(X) (((X) == Public ? ".crt" \
: ((X) == Private ? ".key" \
- : ((X) == CACert ? ".crt" : NULL))))
+ : ((X) == CACert ? ".crt" : ""))))
#define DELETEDCERT(X) ((X)->data.deleted)
#define RENEWCERT(X) ((X)->data.renew)
diff --git a/pith/filter.c b/pith/filter.c
index d22b1215..c60416b1 100644
--- a/pith/filter.c
+++ b/pith/filter.c
@@ -3696,7 +3696,6 @@ html_pop(FILTER_S *fd, ELPROP_S *ep)
for(tp = HANDLERS(fd); tp && ep != EL(tp); tp = tp->below){
HANDLER_S *tp2;
- ELPROP_S *ep2;
dprint((3, "-- html error: bad nesting: given /%s expected /%s", ep->element, EL(tp)->element));
/* if no evidence of opening tag, ignore given closing tag */
@@ -6931,7 +6930,7 @@ rss_title(HANDLER_S *hd, int ch, int cmd)
RSS_ITEM_S *rip;
if(feed){
- if(rip = feed->items){
+ if((rip = feed->items) != NULL){
for(; rip->next; rip = rip->next)
;
@@ -7025,7 +7024,7 @@ rss_link(HANDLER_S *hd, int ch, int cmd)
RSS_ITEM_S *rip;
if(feed){
- if(rip = feed->items){
+ if((rip = feed->items) != NULL){
for(; rip->next; rip = rip->next)
;
@@ -7078,7 +7077,7 @@ rss_description(HANDLER_S *hd, int ch, int cmd)
RSS_ITEM_S *rip;
if(feed){
- if(rip = feed->items){
+ if((rip = feed->items) != NULL){
for(; rip->next; rip = rip->next)
;
@@ -8886,7 +8885,6 @@ void *
gf_html2plain_rss_opt(RSS_FEED_S **feedp, int flags)
{
HTML_OPT_S *op;
- int margin_l, margin_r;
op = (HTML_OPT_S *) fs_get(sizeof(HTML_OPT_S));
memset(op, 0, sizeof(HTML_OPT_S));
diff --git a/pith/help.c b/pith/help.c
index f92cab4f..6f61e885 100644
--- a/pith/help.c
+++ b/pith/help.c
@@ -216,7 +216,7 @@ debugjournal_to_file(FILE *dfile)
p = NULL;
}
- if(p){
+ if(p != NULL){
if(p->timestamp && p->timestamp[0]
&& (fputs(p->timestamp, dfile) == EOF
|| fputs(": ", dfile) == EOF))
diff --git a/pith/imap.c b/pith/imap.c
index 21732411..90219992 100644
--- a/pith/imap.c
+++ b/pith/imap.c
@@ -206,7 +206,7 @@ necessary.
void
mm_expunged(MAILSTREAM *stream, long unsigned int rawno)
{
- MESSAGECACHE *mc;
+ MESSAGECACHE *mc = NULL;
long i;
int is_current = 0;
MSGNO_S *msgmap;
diff --git a/pith/pine.hlp b/pith/pine.hlp
index 8e9120ba..70cf2041 100644
--- a/pith/pine.hlp
+++ b/pith/pine.hlp
@@ -140,7 +140,7 @@ with help text for the config screen and the composer that didn't have any
reasonable place to be called from.
Dummy change to get revision in pine.hlp
============= h_revision =================
-Alpine Commit 58 2014-04-21 01:23:26
+Alpine Commit 59 2014-04-25 17:31:16
============= h_news =================
<HTML>
<HEAD>
diff --git a/pith/send.c b/pith/send.c
index 3f21f1f3..bd99d49a 100644
--- a/pith/send.c
+++ b/pith/send.c
@@ -1563,6 +1563,7 @@ set_priority_header(METAENV *header, char *value)
pf->textbuf = cpystr(value);
}
}
+ return pf;
}
diff --git a/pith/smime.c b/pith/smime.c
index b4ec7150..566e2be5 100644
--- a/pith/smime.c
+++ b/pith/smime.c
@@ -53,7 +53,7 @@ static void openssl_extra_randomness(void);
static int app_RAND_write_file(const char *file);
static const char *openssl_error_string(void);
static int load_private_key(PERSONAL_CERT *pcert);
-static void create_local_cache(char *h, char *base, BODY *b);
+static void create_local_cache(char *h, char *base, BODY *b, int type);
static long rfc822_output_func(void *b, char *string);
static void setup_pkcs7_body_for_signature(BODY *b, char *description,
char *type, char *filename);
@@ -74,7 +74,7 @@ int smime_extract_and_save_cert(PKCS7 *p7);
int same_cert(X509 *, X509 *);
CertList * certlist_from_personal_certs(PERSONAL_CERT *pc);
#ifdef PASSFILE
-void load_key_and_cert(char *pathdir, char **keyfile, char **certfile, EVP_PKEY **pkey, X509 **pcert);
+void load_key_and_cert(char *pathkeydir, char *pathcertdir, char **keyfile, char **certfile, EVP_PKEY **pkey, X509 **pcert);
#endif /* PASSFILE */
STACK_OF(X509) *get_chain_for_cert(X509 *cert, int *error);
EVP_PKEY *load_pkey_with_prompt(char *fpath, char *text, char *prompt);
@@ -91,54 +91,57 @@ static int egdsocket = 0;
#ifdef PASSFILE
+/*
+ * load key from pathkeydir and cert from pathcertdir. It chooses the first
+ * key/certificate pair that matches. Delete pairs that you do not want used,
+ * if you do not want them selected. All parameters must be non-null.
+ * Memory freed by caller.
+ */
void
-load_key_and_cert(char *pathdir, char **keyfile,
+load_key_and_cert(char *pathkeydir, char *pathcertdir, char **keyfile,
char **certfile, EVP_PKEY **pkey, X509 **pcert)
{
- BIO *in;
char buf[MAXPATH+1], pathkey[MAXPATH+1], prompt[MAILTMPLEN];
DIR *dirp;
struct dirent *d;
+ int b = 0;
- if(keyfile) *keyfile = NULL;
- if(certfile) *certfile = NULL;
- if(pkey) *pkey = NULL;
- if(pcert) *pcert = NULL;
+ if(pathkeydir == NULL || pathcertdir == NULL || keyfile == NULL
+ || pkey == NULL || certfile == NULL || pcert == NULL)
+ return;
- if(pathdir == NULL) return;
+ *keyfile = NULL;
+ *certfile = NULL;
+ *pkey = NULL;
+ *pcert = NULL;
- if((dirp = opendir(pathdir)) != NULL){
- while((d=readdir(dirp)) != NULL){
+ if((dirp = opendir(pathkeydir)) != NULL){
+ while(b == 0 && (d=readdir(dirp)) != NULL){
size_t ll;
if((ll=strlen(d->d_name)) && ll > 4){
- if(pkey && *pkey == NULL && keyfile && !strcmp(d->d_name+ll-4, ".key")){
+ if(!strcmp(d->d_name+ll-4, ".key")){
strncpy(buf, d->d_name, sizeof(buf));
buf[sizeof(buf)-1] = '\0';
- build_path(pathkey, pathdir, buf, sizeof(pathkey));
- buf[strlen(buf)-4] = '\0';
+ build_path(pathkey, pathkeydir, buf, sizeof(pathkey));
+ buf[strlen(buf)-4] = '\0';
snprintf(prompt, sizeof(prompt),
_("Enter password of key <%s> to unlock password file: "), buf);
- if((*pkey = load_pkey_with_prompt(pathkey, NULL, prompt)) != NULL)
- *keyfile = cpystr(buf);
- }
-
- if(pcert && *pcert == NULL && certfile && !strcmp(d->d_name+ll-4, ".crt")){
- strncpy(buf, d->d_name, sizeof(buf));
- buf[sizeof(buf)-1] = '\0';
- build_path(pathkey, pathdir, buf, sizeof(pathkey));
- if((in = BIO_new_file(pathkey, "r")) != NULL){
- if((*pcert = PEM_read_bio_X509(in, NULL, NULL, NULL)) != NULL)
- *certfile = cpystr(buf);
- else{
- q_status_message1(SM_ORDER, 0, 2,
- _("loading public certificate %s failed. Continuing..."), buf);
- }
- BIO_free(in);
+ if((*pkey = load_pkey_with_prompt(pathkey, NULL, prompt)) != NULL){
+ if(load_cert_for_key(pathcertdir, *pkey, certfile, pcert)){
+ b = 1; /* break */
+ *keyfile = cpystr(buf);
+ } else {
+ EVP_PKEY_free(*pkey);
+ *pkey = NULL;
+ q_status_message1(SM_ORDER, 0, 2,
+ _("Cannot find certificate that matches key <%s>. Continuing..."), buf);
+ }
}
}
}
}
+ closedir(dirp);
}
}
@@ -151,32 +154,36 @@ load_key_and_cert(char *pathdir, char **keyfile,
* Check if the .alpine-smime/.pwd (or -pwdcertdir directory) exists,
* if not create it. If we are successful, move to the next step
*
- * - If the user has a key/cert pair, setup is successful;
- * - if the used does not have a key/cert pair, or one cannot be found
- * create one, setup is successful; (TODO: implement this)
+ * - If the user has a key/cert pair, in the .alpine-smime/.pwd dir
+ * setup is successful;
+ * - if the user does not have a key/cert pair, look to see if
+ * ps_global->smime->personal_certs is already setup, if so, use it.
+ * - if ps_global->smime->personal_certs is not set up, see if we can
+ * find a certificate/cert pair in the default locations at compilation
+ * time. (~/.alpine-smime/private and ~/.alpine-smime/public
+ * - if none of this is successful, create a key/certificate pair
+ * (TODO: implement this)
* - in any other case, setup is not successful.
*
- * If setup is successful, setup ps_global->smime->pwdcert.
- * If any of this fails, ps_global->smime->pwdcert will be null.
+ * If setup is successful, setup ps_global->pwdcert.
+ * If any of this fails, ps_global->pwdcert will be null.
* Ok, that should do it.
*/
void
setup_pwdcert(void **pwdcert)
{
+ int we_inited = 0;
int setup_dir = 0; /* make it non zero if we know which dir to use */
- int i,j,k;
struct stat sbuf;
- char pathdir[MAXPATH+1], pathkey[MAXPATH+1], fpath[MAXPATH+1];
- char prompt[MAILTMPLEN], buf[MAXPATH+1];
+ char pathdir[MAXPATH+1], pathkey[MAXPATH+1], fpath[MAXPATH+1], pathcert[MAXPATH+1];
+ char fpath2[MAXPATH+1], prompt[MAILTMPLEN];
char *keyfile, *certfile, *text;
- DIR *dirp;
- struct dirent *d;
EVP_PKEY *pkey = NULL;
X509 *pcert = NULL;
- BIO *in = NULL;
PERSONAL_CERT *pc, *pc2 = NULL;
- smime_init();
+ if(pwdcert == NULL)
+ return;
if(ps_global->pwdcertdir){
if(our_stat(ps_global->pwdcertdir, &sbuf) == 0
@@ -190,91 +197,52 @@ setup_pwdcert(void **pwdcert)
if(our_stat(pathdir, &sbuf) == 0){
if((sbuf.st_mode & S_IFMT) == S_IFDIR)
setup_dir++;
- } else {
- if(can_access(pathdir, ACCESS_EXISTS) != 0
+ } else if(can_access(pathdir, ACCESS_EXISTS) != 0
&& our_mkpath(pathdir, 0700) == 0)
setup_dir++;
- }
}
if(setup_dir == 0)
return;
- /* reuse setup dir to mean setup_key */
- setup_dir = 0;
-
- /* BUG: add container support */
- load_key_and_cert(pathdir, &keyfile, &certfile, &pkey, &pcert);
-
- if(certfile && keyfile)
- setup_dir++;
-
- if(setup_dir == 0){
- if(keyfile == NULL){
- /* PATHCERTDIR(Private) must be null, so create a path */
- set_current_val(&ps_global->vars[V_PRIVATEKEY_DIR], TRUE, TRUE);
- smime_path(ps_global->VAR_PRIVATEKEY_DIR, pathkey, MAXPATH);
- load_key_and_cert(pathkey, &keyfile, NULL, &pkey, NULL);
- }
- if(certfile == NULL){
- /* PATHCERTDIR(Public) must be null, so create a path */
- set_current_val(&ps_global->vars[V_PUBLICCERT_DIR], TRUE, TRUE);
- smime_path(ps_global->VAR_PUBLICCERT_DIR, pathkey, MAXPATH);
- load_key_and_cert(pathkey, NULL, &certfile, NULL, &pcert);
- }
- smime_reinit();
- if(certfile && keyfile){
- build_path(fpath, pathdir, keyfile, sizeof(fpath));
- strncat(fpath, ".key", 4);
- fpath[sizeof(fpath)-1] = '\0';
-
- smime_path(ps_global->VAR_PRIVATEKEY_DIR, pathkey, MAXPATH);
- strncat(pathkey, "/", 1);
- strncat(pathkey, keyfile, strlen(keyfile));
- strncat(pathkey, ".key", 4);
- pathkey[sizeof(pathkey)-1] = '\0';
-
- if(our_copy(fpath, pathkey) == 0)
- setup_dir++;
-
- if(setup_dir){
- setup_dir = 0;
-
- build_path(fpath, pathdir, certfile, sizeof(fpath));
-
- smime_path(ps_global->VAR_PUBLICCERT_DIR, pathkey, MAXPATH);
- strncat(pathkey, "/", 1);
- strncat(pathkey, keyfile, strlen(keyfile));
- strncat(pathkey, ".crt", 4);
- pathkey[sizeof(pathkey)-1] = '\0';
-
- if(our_copy(fpath, pathkey) == 0)
- setup_dir++;
- }
- }
+ load_key_and_cert(pathdir, pathdir, &keyfile, &certfile, &pkey, &pcert);
+
+ if(certfile && keyfile){
+ pc = (PERSONAL_CERT *) fs_get(sizeof(PERSONAL_CERT));
+ memset((void *)pc, 0, sizeof(PERSONAL_CERT));
+ pc->name = keyfile;
+ pc->key = pkey;
+ pc->cert = pcert;
+ *pwdcert = (void *) pc;
+ fs_give((void **)&certfile);
+ return;
}
- if(setup_dir > 0){
- pc2 = (PERSONAL_CERT *) fs_get(sizeof(PERSONAL_CERT));
- memset((void *)pc2, 0, sizeof(PERSONAL_CERT));
- pc2->name = keyfile;
- pc2->key = pkey;
- pc2->cert = pcert;
- if(pwdcert) *pwdcert = (void *) pc2;
- }
+ /* if the user gave a pwdcertdir and there is nothing there, do not
+ * continue. Let the user initialize on their own this directory.
+ */
+ if(ps_global->pwdcertdir != NULL)
+ return;
- if(certfile)
- fs_give((void **)&certfile);
+ /* look to see if there are any certificates lying around, first
+ * we try to load ps_global->smime to see if that has information
+ * we can use. If we are the process filling the smime structure
+ * we deinit at the end, since this might not do a full init.
+ */
+ if(ps_global && ps_global->smime && !ps_global->smime->inited){
+ we_inited++;
+ smime_init();
+ }
- if(setup_dir == 0){ /* try looking for an existent key */
- if(ps_global->smime->personal_certs){
- pc = (PERSONAL_CERT *) ps_global->smime->personal_certs;
- if(ps_global->smime->privatetype == Directory){
+ /* at this point ps_global->smime->inited == 1 */
+ if(ps_global->smime && ps_global->smime->personal_certs != NULL){
+ pc = (PERSONAL_CERT *) ps_global->smime->personal_certs;
+ if(ps_global->smime->privatetype == Directory){
build_path(pathkey, ps_global->smime->privatepath, pc->name, sizeof(pathkey));
strncat(pathkey, ".key", 4);
pathkey[sizeof(pathkey)-1] = '\0';
text = NULL;
- } else { /* ps_global->smime->privatetype == Container */
+ } else if (ps_global->smime->privatetype == Container){
if(pc->keytext == NULL){ /* we should *never* be here, but just in case */
if(ps_global->smime->privatecontent != NULL){
char tmp[MAILTMPLEN], *s, *t, c;
@@ -294,85 +262,138 @@ setup_pwdcert(void **pwdcert)
}
if(pc->keytext != NULL) /* we should go straigth here */
text = pc->keytext;
- }
- if((pathkey && *pathkey) || text){
- snprintf(prompt, sizeof(prompt),
- _("Enter password of key <%s> to unlock password file: "), pc->name);
-
- if((pkey = load_pkey_with_prompt(pathkey, text, prompt)) != NULL){
- pc2 = (PERSONAL_CERT *) fs_get(sizeof(PERSONAL_CERT));
- memset((void *)pc2, 0, sizeof(PERSONAL_CERT));
- pc2->name = cpystr(pc->name);
- pc2->key = pkey;
- pc2->cert = X509_dup(pc->cert);
-
- /* now copy the keys and certs, starting by the key... */
- build_path(fpath, pathdir, pc->name, sizeof(fpath));
- strncat(fpath, ".key", 4);
- fpath[sizeof(fpath)-1] = '\0';
- if(our_stat(fpath, &sbuf) == 0){
- if((sbuf.st_mode & S_IFMT) == S_IFREG)
- setup_dir++;
- }
- else { if(ps_global->smime->privatetype == Directory){
- if(our_copy(fpath, pathkey) == 0)
- setup_dir++;
- } else { /* ps_global->smime->privatetype == Container */
+ } else if (ps_global->smime->privatetype == Keychain){
+ pathkey[0] = '\0'; /* no apple key chain support yet */
+ text = NULL;
+ }
+ if((pathkey && *pathkey) || text){
+ snprintf(prompt, sizeof(prompt),
+ _("Enter password of key <%s> to unlock password file: "), pc->name);
+
+ if((pkey = load_pkey_with_prompt(pathkey, text, prompt)) != NULL){
+ pc2 = (PERSONAL_CERT *) fs_get(sizeof(PERSONAL_CERT));
+ memset((void *)pc2, 0, sizeof(PERSONAL_CERT));
+ pc2->name = cpystr(pc->name);
+ pc2->key = pkey;
+ pc2->cert = X509_dup(pc->cert);
+
+ /* now copy the keys and certs, starting by the key... */
+ build_path(fpath, pathdir, pc->name, sizeof(fpath));
+ strncat(fpath, ".key", 4);
+ fpath[sizeof(fpath)-1] = '\0';
+ if(our_stat(fpath, &sbuf) == 0){ /* if fpath exists */
+ if((sbuf.st_mode & S_IFMT) == S_IFREG) /* and is a regular file */
+ setup_dir++; /* we are done */
+ } else if(ps_global->smime->privatetype == Directory){
+ if(our_copy(fpath, pathkey) == 0)
+ setup_dir++;
+ } else if(ps_global->smime->privatetype == Container){
BIO *out;
if((out = BIO_new_file(fpath, "w")) != NULL){
if(BIO_puts(out, pc->keytext) > 0)
setup_dir++;
BIO_free(out);
}
- }
- }
+ } else if(ps_global->smime->privatetype == Keychain){
+ /* add support for Apple Mac OS X */
+ }
+ }
- /* successful copy of key, now continue with certificate */
- if(setup_dir){
- setup_dir = 0;
+ /* successful copy of key, now continue with certificate */
+ if(setup_dir){
+ setup_dir = 0;
- build_path(pathkey, ps_global->smime->publicpath, pc->name, sizeof(pathkey));
- strncat(pathkey, ".crt", 4);
- pathkey[sizeof(pathkey)-1] = '\0';
+ build_path(pathkey, ps_global->smime->publicpath, pc->name, sizeof(pathkey));
+ strncat(pathkey, ".crt", 4);
+ pathkey[sizeof(pathkey)-1] = '\0';
- build_path(fpath, pathdir, pc->name, sizeof(fpath));
- strncat(fpath, ".crt", 4);
- fpath[sizeof(fpath)-1] = '\0';
+ build_path(fpath, pathdir, pc->name, sizeof(fpath));
+ strncat(fpath, ".crt", 4);
+ fpath[sizeof(fpath)-1] = '\0';
- if(our_stat(fpath, &sbuf) == 0){
- if((sbuf.st_mode & S_IFMT) == S_IFREG)
- setup_dir++;
- }
- else{ if(ps_global->smime->privatetype == Directory){
- if(our_copy(fpath, pathkey) == 0)
- setup_dir++;
- } else { /* ps_global->smime->privatetype == Container */
- BIO *out;
- if((out = BIO_new_file(fpath, "w")) != NULL){
- if(PEM_write_bio_X509(out, pc->cert))
- setup_dir++;
+ if(our_stat(fpath, &sbuf) == 0){
+ if((sbuf.st_mode & S_IFMT) == S_IFREG)
+ setup_dir++;
+ }
+ else if(ps_global->smime->privatetype == Directory){
+ if(our_copy(fpath, pathkey) == 0)
+ setup_dir++;
+ } else if(ps_global->smime->privatetype == Container) {
+ BIO *out;
+ if((out = BIO_new_file(fpath, "w")) != NULL){
+ if(PEM_write_bio_X509(out, pc->cert))
+ setup_dir++;
BIO_free(out);
- }
- }
- }
- }
+ }
+ } else if (ps_global->smime->privatetype == Keychain) {
+ /* add support for Mac OS X */
+ }
+ }
- if(setup_dir)
- if(pwdcert) *pwdcert = (void *) pc2;
- else{
- free_personal_certs(&pc2);
- return;
- }
- } /* end of if(pkey != NULL) */
- BIO_free(in);
- } /* end of if(in != NULL) */
- } /* end of if(ps_global->personal_certs) */
+ if(setup_dir){
+ *pwdcert = (void *) pc2;
+ return;
+ }
+ else if(pc2 != NULL)
+ free_personal_certs(&pc2);
+ } /* if (pathkey...) */
+ } /* if(ps_global->smime->personal_certs) */
+
+
+ if(setup_dir == 0){
+ /* PATHCERTDIR(Private) must be null, so create a path */
+ set_current_val(&ps_global->vars[V_PRIVATEKEY_DIR], TRUE, TRUE);
+ smime_path(ps_global->VAR_PRIVATEKEY_DIR, pathkey, sizeof(pathkey));
+
+ /* PATHCERTDIR(Public) must be null, so create a path */
+ set_current_val(&ps_global->vars[V_PUBLICCERT_DIR], TRUE, TRUE);
+ smime_path(ps_global->VAR_PUBLICCERT_DIR, pathcert, sizeof(pathcert));
+
+ /* BUG: this does not support local containers */
+ load_key_and_cert(pathkey, pathcert, &keyfile, &certfile, &pkey, &pcert);
+
+ if(certfile && keyfile){
+ build_path(fpath, pathdir, keyfile, sizeof(fpath));
+ strncat(fpath, ".key", 4);
+ fpath[sizeof(fpath)-1] = '\0';
+
+ build_path(fpath2, pathkey, keyfile, sizeof(fpath));
+ strncat(fpath2, ".key", 4);
+ fpath2[sizeof(fpath2)-1] = '\0';
+
+ if(our_copy(fpath, fpath2) == 0)
+ setup_dir++;
+
+ if(setup_dir){
+ setup_dir = 0;
+
+ build_path(fpath, pathdir, certfile, sizeof(fpath));
+ build_path(fpath2, pathcert, certfile, sizeof(fpath2));
+
+ if(our_copy(fpath, fpath2) == 0)
+ setup_dir++;
+ }
+ }
}
- /* TODO: create self signed certificate */
- if(setup_dir == 0)
- q_status_message(SM_ORDER, 0, 2,
- _("No key/certificate pair found. Password file not encrypted!"));
+ if(keyfile && certfile){
+ pc = (PERSONAL_CERT *) fs_get(sizeof(PERSONAL_CERT));
+ memset((void *)pc, 0, sizeof(PERSONAL_CERT));
+ pc->name = keyfile;
+ pc->key = pkey;
+ pc->cert = pcert;
+ *pwdcert = (void *) pc;
+ fs_give((void **)&certfile);
+ return;
+ }
+
+/* TODO: create self signed certificate
+ q_status_message(SM_ORDER, 2, 2,
+ _("No key/certificate pair found for password file encryption support"));
+*/
+
+ if(we_inited)
+ smime_deinit();
}
#endif /* PASSFILE */
@@ -385,20 +406,20 @@ smime_expunge_cert(WhichCerts ctype)
{
int count, removed;
CertList *cl, *dummy, *data;
- char *path, *ext, buf[MAXPATH+1];
+ char *path, buf[MAXPATH+1];
char *contents;
if(DATACERT(ctype)== NULL)
return -1;
- /* data cert is the way we unify certificate management across functions, but it is
- * not where we really save the information in the case ctype is equal to Private.
- * What we will do is to update the datacert, and in the case of ctype equal to Private
- * use the updated certdata to update the personal_certs data.
+ /* data cert is the way we unify certificate management across
+ * functions, but it is not where we really save the information in the
+ * case ctype is equal to Private. What we will do is to update the
+ * datacert, and in the case of ctype equal to Private use the updated
+ * certdata to update the personal_certs data.
*/
path = PATHCERTDIR(ctype);
- ext = EXTCERT(ctype);
if(path){
/* add a fake certificate at the beginning of the list */
@@ -415,8 +436,10 @@ smime_expunge_cert(WhichCerts ctype)
removed = 1; /* assume success */
if(SMHOLDERTYPE(ctype) == Directory){
build_path(buf, path, cl->next->name, sizeof(buf));
- if(ctype == Private && strlen(buf) + strlen(EXTCERT(Private)) < sizeof(buf))
- strcat(buf, EXTCERT(Private));
+ if(ctype == Private && strlen(buf) + strlen(EXTCERT(Private)) < sizeof(buf)){
+ strncat(buf, EXTCERT(Private), 4);
+ buf[sizeof(buf)-1] = '\0';
+ }
if(our_unlink(buf) < 0){
q_status_message1(SM_ORDER, 3, 3, _("Error removing certificate %s"), cl->next->name);
@@ -503,7 +526,6 @@ load_pkey_with_prompt(char *fpath, char *text, char *prompt)
{
EVP_PKEY *pkey;
int rc = 0; /* rc == 1, cancel, rc == 0 success */
- int we_clear = 0;
char pass[MAILTMPLEN+1];
BIO *in;
@@ -556,9 +578,7 @@ import_certificate(WhichCerts ctype)
return r;
else if (ctype == Private){
char prompt[500], *s, *t;
- BIO *in;
EVP_PKEY *key = NULL;
- PERSONAL_CERT *pc;
if(!ps_global->smime->privatecertlist){
ps_global->smime->privatecertlist = fs_get(sizeof(CertList));
@@ -569,11 +589,14 @@ import_certificate(WhichCerts ctype)
if(s) *(s-1) = 0;
snprintf(prompt, sizeof(prompt), _("Enter passphrase for <%s>: "), filename);
+ prompt[sizeof(prompt)-1] = '\0';
if((key = load_pkey_with_prompt(full_filename, NULL, prompt)) != NULL){
if(SMHOLDERTYPE(ctype) == Directory){
build_path(buf, PATHCERTDIR(ctype), filename, sizeof(buf));
- if(strcmp(buf + strlen(buf) - 4, EXTCERT(ctype)) != 0 && strlen(buf) + 4 < sizeof(buf))
- strcat(buf, EXTCERT(ctype));
+ if(strcmp(buf + strlen(buf) - 4, EXTCERT(ctype)) != 0 && strlen(buf) + 4 < sizeof(buf)){
+ strncat(buf, EXTCERT(ctype), 4);
+ buf[sizeof(buf)-1] = '\0';
+ }
rc = our_copy(buf, full_filename);
}
else /* if(SMHOLDERTYPE(ctype) == Container){ */
@@ -595,8 +618,10 @@ import_certificate(WhichCerts ctype)
if((cert = PEM_read_bio_X509(ins, NULL, NULL, NULL)) != NULL){
if(SMHOLDERTYPE(ctype) == Directory){
build_path(buf, PATHCERTDIR(ctype), filename, sizeof(buf));
- if(strcmp(buf + strlen(buf) - 4, ".crt") != 0 && strlen(buf) + 4 < sizeof(buf))
- strcat(buf, EXTCERT(ctype));
+ if(strcmp(buf + strlen(buf) - 4, ".crt") != 0 && strlen(buf) + 4 < sizeof(buf)){
+ strncat(buf, EXTCERT(ctype), 4);
+ buf[sizeof(buf)-1] = '\0';
+ }
rc = our_copy(buf, full_filename);
}
@@ -887,23 +912,23 @@ renew_cert_data(CertList **data, WhichCerts ctype)
X509_LOOKUP *lookup = NULL;
X509_STORE *store = NULL;
- if((store = X509_STORE_new()) != NULL)
+ if((store = X509_STORE_new()) != NULL){
if((lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) == NULL){
X509_STORE_free(store);
store = NULL;
- }
- else{
- free_certlist(data);
- if(SMHOLDERTYPE(ctype) == Directory)
- add_certs_in_dir(lookup, PATHCERTDIR(ctype), EXTCERT(ctype), data);
- else /* if(SMHOLDERTYPE(ctype) == Container) */
- *data = mem_to_certlist(CONTENTCERTLIST(ctype), ctype);
- if(data && *data)
- RENEWCERT(*data) = 0;
- if(ctype == Public)
- ps_global->smime->publiccertlist = *data;
- else
- ps_global->smime->cacertlist = *data;
+ } else{
+ free_certlist(data);
+ if(SMHOLDERTYPE(ctype) == Directory)
+ add_certs_in_dir(lookup, PATHCERTDIR(ctype), EXTCERT(ctype), data);
+ else /* if(SMHOLDERTYPE(ctype) == Container) */
+ *data = mem_to_certlist(CONTENTCERTLIST(ctype), ctype);
+ if(data && *data)
+ RENEWCERT(*data) = 0;
+ if(ctype == Public)
+ ps_global->smime->publiccertlist = *data;
+ else
+ ps_global->smime->cacertlist = *data;
+ }
}
}
}
@@ -1074,8 +1099,6 @@ setup_privatekey_storage(void)
/* private keys in a directory of files */
if(!privatekeycontainer){
- PERSONAL_CERT *result = NULL;
-
ps_global->smime->privatetype = Directory;
path[0] = '\0';
@@ -1289,7 +1312,8 @@ add_file_to_container(WhichCerts ctype, char *fpath, char *altname)
: (ctype == Private ? ps_global->smime->privatecontent
: ps_global->smime->cacontent);
char *name;
- char *s, c;
+ char *s;
+ unsigned char c;
struct stat sbuf;
STORE_S *in = NULL;
int rv = -1; /* assume error */
@@ -1323,7 +1347,7 @@ add_file_to_container(WhichCerts ctype, char *fpath, char *altname)
*content++ = '\n';
while(so_readc(&c, in))
- *content++ = c;
+ *content++ = (char) c;
*content = '\0';
switch(ctype){
@@ -1899,26 +1923,29 @@ dump_bio_to_file(BIO *in, char *filename)
/*
* Recursively stash a pointer to the decrypted data in our
* manufactured body.
+ * parameters: type: call of type 1, save the base and header for multipart messages
+ call of type 0, do not save the base and header for multipart messages
*/
static void
-create_local_cache(char *h, char *base, BODY *b)
+create_local_cache(char *h, char *base, BODY *b, int type)
{
if(b->type==TYPEMULTIPART){
PART *p;
-#if 0
- cpytxt(&b->contents.text, base + b->contents.offset, b->size.bytes);
-#else
- /*
- * We don't really want to copy the real body contents. It shouldn't be
+ if(type == 1){
+ cpytxt(&b->mime.text, h+b->mime.offset, b->mime.text.size);
+ cpytxt(&b->contents.text, base + b->contents.offset, b->size.bytes);
+ } else if(type == 0){
+ /*
+ * We don't really want to copy the real body contents. It shouldn't be
* used, and in the case of a message with attachments, we'll be
* duplicating the files multiple times.
*/
- cpytxt(&b->contents.text, "BODY UNAVAILABLE", 16);
-#endif
+ cpytxt(&b->contents.text, "BODY UNAVAILABLE", 16);
- for(p=b->nested.part; p; p=p->next)
- create_local_cache(h, base, (BODY*) p);
+ for(p=b->nested.part; p; p=p->next)
+ create_local_cache(h, base, (BODY *) p, type);
+ }
}
else{
cpytxt(&b->mime.text, h+b->mime.offset, b->mime.text.size);
@@ -2149,21 +2176,16 @@ encrypt_file(char *fp, char *text, PERSONAL_CERT *pc)
{
const EVP_CIPHER *cipher = NULL;
STACK_OF(X509) *encerts = NULL;
- X509 *cert;
- BIO *out;
+ BIO *out = NULL;
PKCS7 *p7 = NULL;
- FILE *fpp;
- int i, rv = 0;
- char *fname;
- char emailaddress[MAILTMPLEN];
+ int rv = 0;
+
+ if(pc == NULL)
+ return 0;
- smime_init();
cipher = EVP_aes_256_cbc();
encerts = sk_X509_new_null();
- if(pc == NULL)
- goto end;
-
sk_X509_push(encerts, X509_dup(pc->cert));
if(text){
@@ -2190,7 +2212,8 @@ encrypt_file(char *fp, char *text, PERSONAL_CERT *pc)
BIO_flush(out);
end:
- BIO_free(out);
+ if(out != NULL)
+ BIO_free(out);
PKCS7_free(p7);
sk_X509_pop_free(encerts, X509_free);
@@ -2393,7 +2416,6 @@ int smime_extract_and_save_cert(PKCS7 *p7)
X509 *x, *cert;
char **email;
int i, j;
- long error;
if((signers = PKCS7_get0_signers(p7, NULL, 0)) == NULL)
return -1;
@@ -2481,8 +2503,8 @@ free_smime_body_sparep(void **sparep)
When Alpine sends a message, it constructs that message, computes the
signature, but then it forgets the message it signed and reconstructs it
again. Since it signs a message containing a notice about "mime aware
- tools", but it does not send that we do not include that in the part that
- is signed, and that takes care of much of the problems.
+ tools", but it does not send that we do not include that in the part
+ that is signed, and that takes care of much of the problems.
Another problem is what is received from the servers. All servers tested
seem to transmit the message that was signed intact and Alpine can check
@@ -2493,10 +2515,10 @@ free_smime_body_sparep(void **sparep)
When a message containing and attachment is sent by Alpine, UW-IMAP,
Panda-IMAP, Gmail, and local reading of folders send exactly the message
- that was sent by Alpine, but GMX.com, Exchange, and probably other servers
- add a trailing \r\n in the message, so when validating the signature,
- these messages will not validate. There are several things that can be
- done.
+ that was sent by Alpine, but GMX.com, Exchange, and probably other
+ servers add a trailing \r\n in the message, so when validating the
+ signature, these messages will not validate. There are several things
+ that can be done.
1. Add a trailing \r\n to any message that contains attachments, sign that
and send that. In this way, all messages will validate with all
@@ -2507,21 +2529,40 @@ free_smime_body_sparep(void **sparep)
remove the trailing \r\n and try to revalidate again.
3. We do not add \r\n to validate a message that we sent, because that
- would only work in Alpine, and not in any other client. That would not
- be a good thing to do.
+ would only work in Alpine, and not in any other client. That would
+ not be a good thing to do.
PART II
- Now we have to deal with encrypted and signed messages. The problem is that
- c-client makes all its pointers point to "on disk" content, but since we
- decrypted the data earlier, we have to make sure of two things. One is that we
- saved that data (so we do not have to decrypt it again) and second that we can
- use it.
+ Now we have to deal with encrypted and signed messages. The problem is
+ that c-client makes all its pointers point to "on disk" content, but
+ since we decrypted the data earlier, we have to make sure of two things.
+ One is that we saved that data (so we do not have to decrypt it again)
+ and second that we can use it.
In order to save the data we use create_local_cache, so that we do not
have to redecrypt the message. Once this is saved, c-client functions will
find it and send it to us in mail_fetch_mime and mail_fetch_body.
+ PART III
+
+ When we are trying to verify messages with detached signatures, some
+ imap servers send incorrect information in the mail_fetch_mime call. By
+ incorrect I mean that this is not fetched directly from the message, but
+ it is read from the message, processed, and then the processed part is
+ sent to us, so this text might not agree with what is in the message,
+ and so the validation of the signature might fail. However, the good
+ news is that the message validates if saved to a local folder. This
+ means that if normal validation does not work we can make it work by
+ saving the message locally and validating that. This is implemented
+ below, and causes delay in the display of the message. I am considering
+ at this time not to do this automatically, but wait for the user to tell
+ us to do it for them by means of a command available in the
+ mail_view_screen. This might help in other situations, where a message
+ is supposed to have an attachment, but it can not be seen in the
+ processed text. Nevertheless, at this time, this is automatic, and is
+ causing a delay in the processing of the message, but it is validating
+ correctly all messages.
*/
/*
@@ -2537,9 +2578,10 @@ do_detached_signature_verify(BODY *b, long msgno, char *section)
int result, modified_the_body = 0;
unsigned long mimelen, bodylen;
char newSec[100], *mimetext, *bodytext;
- char *what_we_did, *s;
+ char *what_we_did;
dprint((9, "do_detached_signature_verify(msgno=%ld type=%d subtype=%s section=%s)", msgno, b->type, b->subtype ? b->subtype : "NULL", (section && *section) ? section : (section != NULL) ? "Top" : "NULL"));
+
smime_init();
snprintf(newSec, sizeof(newSec), "%s%s1", section ? section : "", (section && *section) ? "." : "");
@@ -2587,7 +2629,6 @@ do_detached_signature_verify(BODY *b, long msgno, char *section)
STORE_S *msg_so;
BIO_free(in);
- in = NULL;
if((in = BIO_new(BIO_s_mem())) != NULL
&& (fetch = mail_fetch_header(ps_global->mail_stream, msgno, NULL,
NULL, &hlen, FT_PEEK)) != NULL
@@ -2600,32 +2641,19 @@ do_detached_signature_verify(BODY *b, long msgno, char *section)
char *h = (char *) so_text(msg_so);
char *bstart = strstr(h, "\r\n\r\n");
ENVELOPE *env;
- BODY *body, *b2;
- char *s;
-
- dprint((1, "h = \"%s\"", h));
+ BODY *body;
bstart += 4;
INIT(&bs, mail_string, bstart, tlen);
- rfc822_parse_msg_full(&env, &body, h, (bstart-h)+2, &bs, BADHOST, 0, 0);
+ rfc822_parse_msg_full(&env, &body, h, (bstart-h), &bs, BADHOST, 0, 0);
mail_free_envelope(&env);
- if(b->nested.part->body.mime.text.data)
- fs_give((void **)&b->nested.part->body.mime.text.data);
- b->nested.part->body.mime.text.size = body->nested.part->body.mime.text.size;
- b->nested.part->body.mime.offset = body->nested.part->body.mime.offset;
-
- if(b->nested.part->body.contents.text.data)
- fs_give((void **)&b->nested.part->body.contents.text.data);
- b->nested.part->body.contents.text.size = body->nested.part->body.contents.text.size;
- b->nested.part->body.contents.offset = body->nested.part->body.contents.offset;
-
- create_local_cache(bstart, bstart, &b->nested.part->body);
-
+ mail_free_body_part(&b->nested.part);
+ b->nested.part = body->nested.part;
+ create_local_cache(bstart, bstart, &b->nested.part->body, 1);
modified_the_body = 1;
snprintf(newSec, sizeof(newSec), "%s%s1", section ? section : "", (section && *section) ? "." : "");
-
mimetext = mail_fetch_mime(ps_global->mail_stream, msgno, (char*) newSec, &mimelen, 0);
if(mimetext)
@@ -2634,20 +2662,25 @@ do_detached_signature_verify(BODY *b, long msgno, char *section)
if (mimetext == NULL || bodytext == NULL)
return modified_the_body;
+ snprintf(newSec, sizeof(newSec), "%s%s2", section ? section : "", (section && *section) ? "." : "");
+
+ if((p7 = get_pkcs7_from_part(msgno, newSec)) == NULL)
+ return modified_the_body;
+
(void) BIO_reset(in);
BIO_write(in, mimetext, mimelen);
BIO_write(in, bodytext, bodylen);
so_give(&msg_so);
if(((result = do_signature_verify(p7, in, NULL, 1)) == 0)
- && bodylen > 2
- && (strncmp(bodytext+bodylen-2,"\r\n", 2) == 0)){
- BUF_MEM *biobuf = NULL;
-
- BIO_get_mem_ptr(in, &biobuf);
- if(biobuf)
- BUF_MEM_grow(biobuf, mimelen + bodylen - 2);
- result = do_signature_verify(p7, in, NULL, 0);
+ && bodylen > 2
+ && (strncmp(bodytext+bodylen-2,"\r\n", 2) == 0)){
+ BUF_MEM *biobuf = NULL;
+
+ BIO_get_mem_ptr(in, &biobuf);
+ if(biobuf)
+ BUF_MEM_grow(biobuf, mimelen + bodylen - 2);
+ result = do_signature_verify(p7, in, NULL, 0);
}
}
}
@@ -2738,17 +2771,13 @@ char *
decrypt_file(char *fp, int *rv, PERSONAL_CERT *pc)
{
PKCS7 *p7 = NULL;
- char *text, *tmp, file_name[MAILTMPLEN];
+ char *text, *tmp;
BIO *in = NULL, *out = NULL;
- EVP_PKEY *pkey = NULL;
- X509 *recip;
int i, j;
long unsigned int len;
void *ret;
- smime_init();
-
- if(pc == NULL || (text = read_file(fp, 0)) == NULL)
+ if(pc == NULL || (text = read_file(fp, 0)) == NULL || *text == '\0')
return NULL;
tmp = fs_get(strlen(text) + (strlen(text) << 6) + 1);
@@ -2757,7 +2786,7 @@ decrypt_file(char *fp, int *rv, PERSONAL_CERT *pc)
tmp[j] = text[i];
tmp[j] = '\0';
- ret = rfc822_base64(tmp, strlen(tmp), &len);
+ ret = rfc822_base64((unsigned char *)tmp, strlen(tmp), &len);
if((in = BIO_new_mem_buf((char *)ret, len)) != NULL){
p7 = d2i_PKCS7_bio(in, NULL);
@@ -2981,7 +3010,7 @@ do_decoding(BODY *b, long msgno, const char *section)
* the decrypted data. Otherwise, it'll try to load it from the original
* data. Eek.
*/
- create_local_cache(bstart-b->nested.part->body.mime.offset, bstart, &b->nested.part->body);
+ create_local_cache(bstart-b->nested.part->body.mime.offset, bstart, &b->nested.part->body, 0);
modified_the_body = 1;
}
@@ -3329,16 +3358,6 @@ free_smime_struct(SMIME_STUFF_S **smime)
(*smime)->personal_certs = NULL;
}
-#ifdef PASSFILE
- if((*smime)->pwdcert){
- PERSONAL_CERT *pc;
-
- pc = (PERSONAL_CERT *) (*smime)->pwdcert;
- free_personal_certs(&pc);
- (*smime)->pwdcert = NULL;
- }
-#endif /* PASSFILE */
-
if((*smime)->privatecontent)
fs_give((void **) &(*smime)->privatecontent);
diff --git a/pith/smkeys.c b/pith/smkeys.c
index 7d57cdac..56103e91 100644
--- a/pith/smkeys.c
+++ b/pith/smkeys.c
@@ -399,11 +399,12 @@ save_cert_for(char *email, X509 *cert, WhichCerts ctype)
CertList *clist = DATACERT(ctype);
add_to_end_of_certlist(&clist, email, X509_dup(cert));
+
switch(ctype){
- Private: ps_global->smime->privatecertlist = clist; break;
- Public : ps_global->smime->publiccertlist = clist; break;
- CACert : ps_global->smime->cacertlist = clist; break;
- default: break;
+ case Private: ps_global->smime->privatecertlist = clist; break;
+ case Public : ps_global->smime->publiccertlist = clist; break;
+ case CACert : ps_global->smime->cacertlist = clist; break;
+ default: break;
}
if(!upath)
@@ -555,7 +556,6 @@ save_cert_for(char *email, X509 *cert, WhichCerts ctype)
X509 *
get_cert_for(char *email, WhichCerts ctype)
{
- char *path;
char certfilename[MAXPATH];
char emailaddr[MAXPATH];
X509 *cert = NULL;
@@ -666,6 +666,58 @@ get_cert_for(char *email, WhichCerts ctype)
return cert;
}
+/*
+ * load_cert_for_key finds a certificate in pathdir that matches a private key
+ * pkey. It returns its name in certfile, and the certificate in *pcert.
+ * return value: success: different from zero, failure 0. If both certfile
+ * and pcert are NULL, this function returns if there is certificate that
+ * matches the given key.
+ */
+int
+load_cert_for_key(char *pathdir, EVP_PKEY *pkey, char **certfile, X509 **pcert)
+{
+ DIR *dirp;
+ struct dirent *d;
+ int rv = 0;
+ BIO *in;
+ X509 *x;
+ char buf[MAXPATH+1], pathcert[MAXPATH+1];
+
+ if(pathdir == NULL || pkey == NULL)
+ return 0;
+
+ if(certfile) *certfile = NULL;
+ if(pcert) *pcert = NULL;
+
+ if((dirp = opendir(pathdir)) != NULL){
+ while(rv == 0 && (d=readdir(dirp)) != NULL){
+ size_t ll;
+
+ if((ll=strlen(d->d_name)) && ll > 4){
+ if(!strcmp(d->d_name+ll-4, ".crt")){
+ strncpy(buf, d->d_name, sizeof(buf));
+ buf[sizeof(buf)-1] = '\0';
+ build_path(pathcert, pathdir, buf, sizeof(pathcert));
+ if((in = BIO_new_file(pathcert, "r")) != NULL){
+ if((x = PEM_read_bio_X509(in, NULL, NULL, NULL)) != NULL){
+ if(X509_check_private_key(x, pkey) > 0){
+ rv = 1;
+ if(certfile) *certfile = cpystr(buf);
+ if(pcert) *pcert = x;
+ }
+ else
+ X509_free(x);
+ }
+ BIO_free(in);
+ }
+ }
+ }
+ }
+ closedir(dirp);
+ }
+ return rv;
+}
+
PERSONAL_CERT *
mem_to_personal_certs(char *contents)
diff --git a/pith/smkeys.h b/pith/smkeys.h
index 58705bd7..0781a018 100644
--- a/pith/smkeys.h
+++ b/pith/smkeys.h
@@ -59,6 +59,8 @@ PERSONAL_CERT *mem_to_personal_certs(char *contents);
void free_personal_certs(PERSONAL_CERT **pc);
void get_fingerprint(X509 *cert, const EVP_MD *type, char *buf, size_t maxLen);
int certlist_to_file(char *filename, CertList *certlist);
+int load_cert_for_key(char *pathdir, EVP_PKEY *pkey, char **certfile, X509 **pcert);
+
#endif /* PITH_SMKEYS_INCLUDED */
#endif /* SMIME */
diff --git a/pith/state.c b/pith/state.c
index bf5ff24e..84775792 100644
--- a/pith/state.c
+++ b/pith/state.c
@@ -179,6 +179,13 @@ free_pine_struct(struct pine **pps)
if((*pps)->passfile)
fs_give((void **)&(*pps)->passfile);
#ifdef SMIME
+ if((*pps)->pwdcert){
+ PERSONAL_CERT *pc;
+
+ pc = (PERSONAL_CERT *) (*pps)->pwdcert;
+ free_personal_certs(&pc);
+ (*pps)->pwdcert = NULL;
+ }
if((*pps)->pwdcertdir)
fs_give((void **)&(*pps)->pwdcertdir);
#endif /* SMIME inside PASSFILE */
diff --git a/pith/state.h b/pith/state.h
index 3fb4f2ee..3c0b19dc 100644
--- a/pith/state.h
+++ b/pith/state.h
@@ -356,6 +356,9 @@ struct pine {
#ifdef SMIME
SMIME_STUFF_S *smime;
+#ifdef PASSFILE
+ void *pwdcert; /* this is of type PERSONAL_CERT */
+#endif /* PASSFILE inside SMIME */
#endif /* SMIME */
struct variable *vars;
diff --git a/pith/string.c b/pith/string.c
index e23b704f..6ad1045a 100644
--- a/pith/string.c
+++ b/pith/string.c
@@ -431,7 +431,7 @@ short_str(char *src, char *buf, size_t buflen, int wid, WhereDots where)
}
q = buf;
- if(first){
+ if(first > 0){
q += utf8_to_width(q, src, buflen, first, &got_width);
if(got_width != first){
if(second)
@@ -448,7 +448,7 @@ short_str(char *src, char *buf, size_t buflen, int wid, WhereDots where)
q += strlen(q);
}
- if(second){
+ if(second > 0){
char *p;
p = utf8_count_back_width(src, src+strlen(src), second, &got_width);
@@ -2738,7 +2738,7 @@ add_escapes(char *src, char *quote_these_chars, int quoting_char,
char *
copy_quoted_string_asis(char *src)
{
- char *q, *p;
+ char *q = NULL, *p;
int done = 0, quotes = 0;
if(src){
diff --git a/pith/thread.c b/pith/thread.c
index f31dea67..a46e21a3 100644
--- a/pith/thread.c
+++ b/pith/thread.c
@@ -884,7 +884,7 @@ collapse_or_expand(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap,
void
select_thread_stmp(struct pine *state, MAILSTREAM *stream, MSGNO_S *msgmap)
{
- PINETHRD_S *thrd;
+ PINETHRD_S *thrd = NULL;
unsigned long rawno, in_thread, set_in_thread, save_branch;
/* ugly bit means the same thing as return of 1 from individual_select */
diff --git a/po/Makefile.in b/po/Makefile.in
index 49486611..0f400a12 100644
--- a/po/Makefile.in
+++ b/po/Makefile.in
@@ -11,7 +11,7 @@
# Origin: gettext-0.16
PACKAGE = alpine
-VERSION = 2.19.12
+VERSION = 2.19.99
PACKAGE_BUGREPORT = chappa@washington.edu
SHELL = /bin/sh
diff --git a/web/src/alpined.d/alpined.c b/web/src/alpined.d/alpined.c
index db9e86c0..d13783aa 100644
--- a/web/src/alpined.d/alpined.c
+++ b/web/src/alpined.d/alpined.c
@@ -14994,6 +14994,8 @@ peAddSuggestedContactInfo(Tcl_Interp *interp, Tcl_Obj *lobjp, ADDRESS *addr)
if(comment)
fs_give((void **) &comment);
+
+ return 0;
}
diff --git a/web/src/alpined.d/imap.c b/web/src/alpined.d/imap.c
index 6872d085..d9512e86 100644
--- a/web/src/alpined.d/imap.c
+++ b/web/src/alpined.d/imap.c
@@ -388,7 +388,6 @@ alpine_tcptimeout(long elapsed, long sincelast)
long
alpine_sslcertquery(char *reason, char *host, char *cert)
{
- static char buf[256];
STRLIST_S *p;
for(p = peCertHosts; p; p = p->next)