summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEduardo Chappa <chappa@washington.edu>2016-02-28 14:12:49 -0700
committerEduardo Chappa <chappa@washington.edu>2016-02-28 14:12:49 -0700
commit4bf825141cd564a2c5a23c55f79e04665c428641 (patch)
tree4fd033202e91d414985f4896fe63b0039adc2cf2
parentdc1062254da60a0f2bf8d52e861dbf4fb7b8cab9 (diff)
downloadalpine-4bf825141cd564a2c5a23c55f79e04665c428641.tar.xz
* Add the ability to change the private key and certificates used
to encrypt a password file in the SMIME setup configuration screen.
-rw-r--r--alpine/imap.c52
-rw-r--r--alpine/keymenu.c47
-rw-r--r--alpine/keymenu.h7
-rw-r--r--alpine/smime.c214
-rw-r--r--pith/conftype.h51
-rw-r--r--pith/imap.c52
-rw-r--r--pith/imap.h4
-rw-r--r--pith/pine.hlp54
-rw-r--r--pith/smime.c261
-rw-r--r--pith/smime.h2
-rw-r--r--pith/smkeys.c90
-rw-r--r--pith/smkeys.h4
-rw-r--r--pith/state.h9
13 files changed, 681 insertions, 166 deletions
diff --git a/alpine/imap.c b/alpine/imap.c
index 20b98068..99c03e4e 100644
--- a/alpine/imap.c
+++ b/alpine/imap.c
@@ -115,7 +115,6 @@ int save_password = 1;
#ifdef PASSFILE
char xlate_in(int);
char xlate_out(char);
-char *passfile_name(char *, char *, size_t);
int line_get(char *, size_t, char **);
#endif /* PASSFILE */
@@ -1990,57 +1989,6 @@ xlate_out(char c)
else
return(c);
}
-
-
-char *
-passfile_name(char *pinerc, char *path, size_t len)
-{
- struct stat sbuf;
- char *p = NULL;
- int i, j;
-
- if(!path || !((pinerc && pinerc[0]) || ps_global->passfile))
- return(NULL);
-
- if(ps_global->passfile)
- strncpy(path, ps_global->passfile, len-1);
- else{
- if((p = last_cmpnt(pinerc)) && *(p-1) && *(p-1) != PASSFILE[0])
- for(i = 0; pinerc < p && i < len; pinerc++, i++)
- path[i] = *pinerc;
- else
- i = 0;
-
- for(j = 0; (i < len) && (path[i] = PASSFILE[j]); i++, j++)
- ;
-
- }
-
- path[len-1] = '\0';
-
- dprint((9, "Looking for passfile \"%s\"\n",
- path ? path : "?"));
-
-#if defined(DOS) || defined(OS2)
- return((our_stat(path, &sbuf) == 0
- && ((sbuf.st_mode & S_IFMT) == S_IFREG))
- ? path : NULL);
-#else
- /* First, make sure it's ours and not sym-linked */
- if(our_lstat(path, &sbuf) == 0
- && ((sbuf.st_mode & S_IFMT) == S_IFREG)
- && sbuf.st_uid == getuid()){
- /* if too liberal permissions, fix them */
- if((sbuf.st_mode & 077) != 0)
- if(our_chmod(path, sbuf.st_mode & ~077) != 0)
- return(NULL);
-
- return(path);
- }
- else
- return(NULL);
-#endif
-}
#endif /* PASSFILE */
diff --git a/alpine/keymenu.c b/alpine/keymenu.c
index beb6e7ea..7c8d167e 100644
--- a/alpine/keymenu.c
+++ b/alpine/keymenu.c
@@ -2665,6 +2665,21 @@ struct key config_smime_add_certs_keys[] =
NULL_MENU};
INST_KEY_MENU(config_smime_add_certs_keymenu, config_smime_add_certs_keys);
+struct key config_smime_add_new_key[] =
+ {HELP_MENU,
+ NULL_MENU,
+ EXIT_SETUP_MENU,
+ {"I", N_("Import Key"), {MC_IMPORT,3,{'i', ctrl('M'), ctrl('J')}}, KS_NONE},
+ NULL_MENU,
+ NULL_MENU,
+ NULL_MENU,
+ NULL_MENU,
+ NULL_MENU,
+ NULL_MENU,
+ NULL_MENU,
+ NULL_MENU};
+INST_KEY_MENU(config_smime_add_new_key_keymenu, config_smime_add_new_key);
+
struct key config_smime_manage_certs_work_keys[] =
{HELP_MENU,
OTHER_MENU,
@@ -2693,6 +2708,21 @@ struct key config_smime_manage_certs_work_keys[] =
ENDKEY_MENU};
INST_KEY_MENU(config_smime_manage_certs_work_keymenu, config_smime_manage_certs_work_keys);
+struct key config_smime_view_cert[] =
+ {HELP_MENU,
+ OTHER_MENU,
+ EXIT_SETUP_MENU,
+ {"V", "[" N_("View Info") "]", {MC_CHOICE,3,{'v',ctrl('M'),ctrl('J')}}, KS_NONE},
+ NULL_MENU,
+ NULL_MENU,
+ NULL_MENU,
+ NULL_MENU,
+ NULL_MENU,
+ NULL_MENU,
+ NULL_MENU,
+ NULL_MENU};
+INST_KEY_MENU(config_smime_manage_view_cert_keymenu, config_smime_view_cert);
+
struct key smime_certificate_info_keys[] =
{HELP_MENU,
OTHER_MENU,
@@ -2722,6 +2752,23 @@ struct key smime_certificate_info_keys[] =
INST_KEY_MENU(smime_certificate_info_keymenu, smime_certificate_info_keys);
+struct key config_smime_manage_password_file_menu_keys[] =
+ {HELP_MENU,
+ WHEREIS_MENU,
+ EXIT_SETUP_MENU,
+ {"S", "[" N_("Select") "]", {MC_CHOICE,3,{'s',ctrl('M'),ctrl('J')}}, KS_NONE},
+ {"I", N_("Import Cert"), {MC_IMPORT,1,{'i'}}, KS_NONE},
+ NULL_MENU,
+ PREV_MENU,
+ NEXT_MENU,
+ PREVPAGE_MENU,
+ NEXTPAGE_MENU,
+ HOMEKEY_MENU,
+ ENDKEY_MENU};
+INST_KEY_MENU(config_smime_manage_password_file_menu_keymenu, config_smime_manage_password_file_menu_keys);
+
+
+
/*
* Internal prototypes
*/
diff --git a/alpine/keymenu.h b/alpine/keymenu.h
index b79b1fe2..b2d82412 100644
--- a/alpine/keymenu.h
+++ b/alpine/keymenu.h
@@ -560,6 +560,8 @@ struct key_menu {
#define TRUST_KEY 3
#define PUBLIC_KEY 6
#define PRIVATE_KEY 7
+#define DELETE_CERT_KEY 4
+#define UNDELETE_CERT_KEY 5
extern struct key_menu cancel_keymenu,
ab_keymenu,
@@ -661,7 +663,10 @@ extern struct key_menu cancel_keymenu,
smime_info_keymenu,
config_smime_manage_certs_menu_keymenu,
config_smime_manage_certs_work_keymenu,
- smime_certificate_info_keymenu;
+ config_smime_manage_password_file_menu_keymenu,
+ smime_certificate_info_keymenu,
+ config_smime_add_new_key_keymenu,
+ config_smime_manage_view_cert_keymenu;
extern struct key rev_msg_keys[];
diff --git a/alpine/smime.c b/alpine/smime.c
index 4cfdeae8..3ba7d397 100644
--- a/alpine/smime.c
+++ b/alpine/smime.c
@@ -56,13 +56,16 @@ void revert_to_saved_smime_config(struct pine *ps, SAVED_CONFIG_S *vsave);
SAVED_CONFIG_S *save_smime_config_vars(struct pine *ps);
void free_saved_smime_config(struct pine *ps, SAVED_CONFIG_S **vsavep);
int smime_helper_tool(struct pine *, int, CONF_S **, unsigned);
-//int smime_public_certs_tool(struct pine *, int, CONF_S **, unsigned);
void manage_certificates(struct pine *, WhichCerts);
-void smime_manage_certs_init (struct pine *, CONF_S **, CONF_S **, WhichCerts, int);
-void display_certificate_information(struct pine *, X509 *, char *, WhichCerts, int num);
-int manage_certs_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned flags);
-int manage_certificate_info_tool(int, MSGNO_S *, SCROLL_S *);
-void smime_setup_size(char **, size_t, size_t);
+#ifdef PASSFILE
+void manage_password_file_certificates(struct pine *);
+#endif /* PASSFILE */
+void smime_manage_certs_init (struct pine *, CONF_S **, CONF_S **, WhichCerts, int);
+void smime_manage_password_file_certs_init(struct pine *, CONF_S **, CONF_S **, int, int *);
+void display_certificate_information(struct pine *, X509 *, char *, WhichCerts, int num);
+int manage_certs_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned flags);
+int manage_certificate_info_tool(int, MSGNO_S *, SCROLL_S *);
+void smime_setup_size(char **, size_t, size_t);
/*
@@ -1028,6 +1031,7 @@ smime_config_init_display(struct pine *ps, CONF_S **ctmp, CONF_S **first_line)
(*ctmp)->help = h_config_smime_public_certificates;
(*ctmp)->value = cpystr(_("Manage Public Certificates"));
(*ctmp)->varmem = 9;
+ (*ctmp)->d.s.ctype = Public;
/* manage private keys */
new_confline(ctmp);
@@ -1036,6 +1040,7 @@ smime_config_init_display(struct pine *ps, CONF_S **ctmp, CONF_S **first_line)
(*ctmp)->help = h_config_smime_private_keys;
(*ctmp)->value = cpystr(_("Manage Private Keys"));
(*ctmp)->varmem = 10;
+ (*ctmp)->d.s.ctype = Private;
/* manage Certificate Authorities */
new_confline(ctmp);
@@ -1044,6 +1049,36 @@ smime_config_init_display(struct pine *ps, CONF_S **ctmp, CONF_S **first_line)
(*ctmp)->help = h_config_smime_certificate_authorities;
(*ctmp)->value = cpystr(_("Manage Certificate Authorities"));
(*ctmp)->varmem = 11;
+ (*ctmp)->d.s.ctype = CACert;
+
+#ifdef PASSFILE
+ new_confline(ctmp)->var = vtmp;
+ (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
+
+ new_confline(ctmp);
+ (*ctmp)->flags |= CF_NOSELECT;
+ (*ctmp)->value = cpystr(tmp);
+
+ new_confline(ctmp);
+ (*ctmp)->flags |= CF_NOSELECT;
+ (*ctmp)->value = cpystr(_("Manage Key and Certificate for Password File"));
+
+ new_confline(ctmp);
+ (*ctmp)->flags |= CF_NOSELECT;
+ (*ctmp)->value = cpystr(tmp);
+
+ new_confline(ctmp)->var = vtmp;
+ (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
+
+ /* manage password file certificates */
+ new_confline(ctmp);
+ (*ctmp)->tool = smime_helper_tool;
+ (*ctmp)->keymenu = &config_smime_manage_password_file_menu_keymenu;
+ (*ctmp)->help = h_config_smime_password_file_certificates;
+ (*ctmp)->value = cpystr(_("Manage Password File Key and Certificate"));
+ (*ctmp)->varmem = 12;
+ (*ctmp)->d.s.ctype = Password;
+#endif /* PASSFILE */
(*ctmp)->next = NULL;
}
@@ -1198,6 +1233,10 @@ void display_certificate_information(struct pine *ps, X509 *cert, char *email, W
clrbitn(PUBLIC_KEY, scrollargs.keys.bitmap);
clrbitn(PRIVATE_KEY, scrollargs.keys.bitmap);
}
+ if(ctype == Password){
+ clrbitn(DELETE_CERT_KEY, scrollargs.keys.bitmap);
+ clrbitn(UNDELETE_CERT_KEY, scrollargs.keys.bitmap);
+ }
cmd = scrolltool(&scrollargs);
@@ -1338,6 +1377,121 @@ smime_setup_size(char **s, size_t buflen, size_t n)
*s = t;
}
+#ifdef PASSFILE
+ /* state: 0 = first time,
+ * 1 = second or another time
+ */
+void
+smime_manage_password_file_certs_init(struct pine *ps, CONF_S **ctmp, CONF_S **first_line, int fline, int *state)
+{
+ char tmp[200];
+ char *ext;
+ CertList *cl;
+ int i;
+ void *pwdcert = NULL; /* this is our current password file */
+ PERSONAL_CERT *pc;
+ X509_LOOKUP *lookup = NULL;
+ X509_STORE *store = NULL;
+
+ if(*state == 0){ /* first time around? */
+ setup_pwdcert(&pwdcert);
+ if(pwdcert == NULL) return;
+ if(ps->pwdcert == NULL)
+ ps->pwdcert = pwdcert;
+ else
+ free_personal_certs((PERSONAL_CERT **) &pwdcert);
+ (*state)++;
+ }
+
+ pc = (PERSONAL_CERT *) ps_global->pwdcert;
+ ps->pwdcertlist = cl = smime_X509_to_cert_info(pc->cert, pc->name);
+
+ for(i = 0; i < sizeof(tmp) && i < (ps->ttyo ? ps->ttyo->screen_cols : sizeof(tmp)); i++)
+ tmp[i] = '-';
+
+ new_confline(ctmp);
+ (*ctmp)->flags |= CF_NOSELECT;
+ (*ctmp)->value = cpystr(tmp);
+
+ new_confline(ctmp);
+ (*ctmp)->flags |= CF_NOSELECT;
+ (*ctmp)->value = cpystr(_("Manage Certificates and Keys Used to Encrypt your Password File"));
+
+ new_confline(ctmp);
+ (*ctmp)->flags |= CF_NOSELECT;
+ (*ctmp)->value = cpystr(tmp);
+
+ new_confline(ctmp);
+ (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
+
+ if(cl){
+ int s, e, df, dt, md5; /* sizes of certain fields */
+ int nf; /* number of fields */
+ char u[MAILTMPLEN], *t;
+
+ e = MIN(strlen(cl->name), ps->ttyo->screen_cols/3); /* do not use too much screen */
+ nf = 5; /* there are 5 fields */
+ s = 3; /* status has fixed size */
+ df = dt = 10; /* date from and date to have fixed size */
+ md5 = ps->ttyo->screen_cols - s - df - dt - e - (nf - 1);
+
+ t = u;
+ smime_setup_size(&t, sizeof(u), s);
+ smime_setup_size(&t, sizeof(u) - strlen(t), e);
+ smime_setup_size(&t, sizeof(u) - strlen(t), df);
+ *t++ = ' '; /* leave an extra space between dates */
+ smime_setup_size(&t, sizeof(u) - strlen(t), dt);
+ *t++ = ' '; /* and another space between date and md5 sum */
+ smime_setup_size(&t, sizeof(u) - strlen(t), md5);
+ *t = '\0'; /* tie off */
+
+ new_confline(ctmp);
+ (*ctmp)->flags |= CF_NOSELECT;
+ (*ctmp)->value = cpystr(_("New Public Certificate and Key:"));
+
+ new_confline(ctmp);
+ (*ctmp)->d.s.ctype = Password;
+ (*ctmp)->help = h_config_smime_password_file_certificates;
+ (*ctmp)->tool = manage_certs_tool;
+ (*ctmp)->keymenu = &config_smime_add_new_key_keymenu;
+ s += 2;
+ for(i = 0; i < s; i++) tmp[i] = ' ';
+ tmp[i] = '\0';
+ strncpy(tmp+s, _("Press \"RETURN\" to add new personal key"), sizeof(tmp)-s-1);
+ for(i = strlen(tmp); i < (ps->ttyo ? ps->ttyo->screen_cols : sizeof(tmp) - 1); i++)
+ tmp[i] = ' ';
+ tmp[i] = '\0';
+ (*ctmp)->value = cpystr(tmp);
+ *first_line = *ctmp;
+
+ new_confline(ctmp);
+ (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
+
+ new_confline(ctmp);
+ (*ctmp)->flags |= CF_NOSELECT;
+ (*ctmp)->value = cpystr(_("Current Public Certificate and Key:"));
+
+ new_confline(ctmp);
+ (*ctmp)->d.s.ctype = Password;
+ (*ctmp)->d.s.deleted = 0;
+ (*ctmp)->help = h_config_smime_password_file_certificates;
+ (*ctmp)->tool = manage_certs_tool;
+ (*ctmp)->keymenu = &config_smime_manage_view_cert_keymenu;
+ (*ctmp)->varmem = 0;
+ (*ctmp)->help = h_config_smime_manage_public_menu;
+ strncpy((*ctmp)->d.s.address, cl->name, sizeof((*ctmp)->d.s.address));
+ (*ctmp)->d.s.address[sizeof((*ctmp)->d.s.address) - 1] = '\0';
+ snprintf(tmp, sizeof(tmp), u,
+ (*ctmp)->d.s.deleted ? "D" : " ",
+ cl->name,
+ DATEFROMCERT(cl), DATETOCERT(cl), MD5CERT(cl));
+ (*ctmp)->value = cpystr(tmp);
+
+ }
+}
+#endif /* PASSFILE */
+
+
void smime_manage_certs_init(struct pine *ps, CONF_S **ctmp, CONF_S **first_line, WhichCerts ctype, int fline)
{
char tmp[200];
@@ -1480,6 +1634,43 @@ void manage_certificates(struct pine *ps, WhichCerts ctype)
smime_reinit();
}
+void manage_password_file_certificates(struct pine *ps)
+{
+ OPT_SCREEN_S screen;
+ int readonly_warning = 0, rv = 10, fline, state = 0;
+
+ dprint((9, "manage_password_file_certificates"));
+ ps->next_screen = SCREEN_FUN_NULL;
+
+ do {
+ CONF_S *ctmp = NULL, *first_line = NULL;
+
+ fline = rv >= 10 ? rv - 10 : 0;
+
+ smime_init();
+
+ smime_manage_password_file_certs_init(ps, &ctmp, &first_line, fline, &state);
+
+ if(ctmp == NULL){
+ ps->mangled_screen = 1;
+ smime_reinit();
+ return;
+ }
+
+ memset(&screen, 0, sizeof(screen));
+ screen.deferred_ro_warning = readonly_warning;
+ rv = conf_scroll_screen(ps, &screen, first_line,
+ _("MANAGE PASSWORD FILE CERTS"),
+ /* TRANSLATORS: Print something1 using something2.
+ configuration is something1 */
+ _("configuration"), 0, NULL);
+ } while (rv != 0);
+
+ ps->mangled_screen = 1;
+ smime_reinit();
+}
+
+
int
smime_helper_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned flags)
{
@@ -1582,6 +1773,10 @@ smime_helper_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned flags)
case 10: manage_certificates(ps, Private); break;
case 11: manage_certificates(ps, CACert) ; break;
+#ifdef PASSFILE
+ case 12: manage_password_file_certificates(ps); break;
+#endif /* PASSFILE */
+
default:
rv = -1;
break;
@@ -1594,12 +1789,7 @@ smime_helper_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned flags)
break;
case MC_IMPORT:
- { WhichCerts ctype;
- /* keep this selection consistent with the codes above */
- ctype = (*cl)->varmem == 9 ? Public
- : ((*cl)->varmem == 10 ? Private : CACert);
- rv = import_certificate(ctype);
- }
+ rv = import_certificate((*cl)->d.s.ctype);
break;
default:
diff --git a/pith/conftype.h b/pith/conftype.h
index abae2b0d..3c9316fa 100644
--- a/pith/conftype.h
+++ b/pith/conftype.h
@@ -675,7 +675,7 @@ typedef enum {Main, Post, None} EditWhich;
typedef enum {Directory, Container, Keychain, Nada} SmimeHolderType;
-typedef enum {Public, Private, CACert} WhichCerts;
+typedef enum {Public, Private, CACert, Password} WhichCerts;
typedef struct certdata {
unsigned deleted:1; /* certificate is marked deleted */
@@ -721,7 +721,6 @@ typedef struct smime_stuff {
char *privatecontent;
CertList *privatecertlist;
CertList *backupprivatecertlist;
- void *backuppersonal_certs; /* this is type (PERSONAL_CERT *) */
void *personal_certs; /* this is type (PERSONAL_CERT *) */
SmimeHolderType catype;
@@ -732,25 +731,35 @@ typedef struct smime_stuff {
} SMIME_STUFF_S;
-#define BACKUPDATACERT(X) (((X) == Public ? ps_global->smime->backuppubliccertlist \
- : ((X) == Private ? ps_global->smime->backupprivatecertlist \
- : ps_global->smime->backupcacertlist)))
-
-#define DATACERT(X) (((X) == Public ? ps_global->smime->publiccertlist \
- : ((X) == Private ? ps_global->smime->privatecertlist \
- : ps_global->smime->cacertlist)))
-
-#define PATHCERTDIR(X) (((X) == Public ? ps_global->smime->publicpath \
- : ((X) == Private ? ps_global->smime->privatepath \
- : ((X) == CACert ? ps_global->smime->capath : NULL))))
-
-#define CONTENTCERTLIST(X) (((X) == Public ? ps_global->smime->publiccontent \
- : ((X) == Private ? ps_global->smime->privatecontent \
- : ((X) == CACert ? ps_global->smime->cacontent : NULL))))
-
-#define SMHOLDERTYPE(X) (((X) == Public ? ps_global->smime->publictype \
- : ((X) == Private ? ps_global->smime->privatetype \
- : ((X) == CACert ? ps_global->smime->catype : Nada))))
+#define BACKUPDATACERT(X) ((X) == Public ? ps_global->smime->backuppubliccertlist : \
+ (X) == Private ? ps_global->smime->backupprivatecertlist : \
+ (X) == CACert ? ps_global->smime->backupcacertlist : \
+ (X) == Password ? (CertList *) ps_global->backuppassword : \
+ NULL)
+
+#define DATACERT(X) ((X) == Public ? ps_global->smime->publiccertlist : \
+ (X) == Private ? ps_global->smime->privatecertlist : \
+ (X) == CACert ? ps_global->smime->cacertlist : \
+ (X) == Password ? (CertList *) ps_global->pwdcertlist : \
+ NULL)
+
+#define PATHCERTDIR(X) ((X) == Public ? ps_global->smime->publicpath : \
+ (X) == Private ? ps_global->smime->privatepath : \
+ (X) == CACert ? ps_global->smime->capath : \
+ (X) == Password ? ps_global->pwdcertdir : \
+ NULL)
+
+#define CONTENTCERTLIST(X) ((X) == Public ? ps_global->smime->publiccontent : \
+ (X) == Private ? ps_global->smime->privatecontent : \
+ (X) == CACert ? ps_global->smime->cacontent : \
+ (X) == Password ? ps_global->pwdcertcontent : \
+ NULL)
+
+#define SMHOLDERTYPE(X) ((X) == Public ? ps_global->smime->publictype : \
+ (X) == Private ? ps_global->smime->privatetype : \
+ (X) == CACert ? ps_global->smime->catype : \
+ (X) == Password ? Directory : \
+ Nada)
#define EXTCERT(X) (((X) == Public ? ".crt" \
: ((X) == Private ? ".key" \
diff --git a/pith/imap.c b/pith/imap.c
index da338712..e02f46ba 100644
--- a/pith/imap.c
+++ b/pith/imap.c
@@ -1109,3 +1109,55 @@ ps_get(size_t size)
return(block);
}
+
+#ifdef PASSFILE
+char *
+passfile_name(char *pinerc, char *path, size_t len)
+{
+ struct stat sbuf;
+ char *p = NULL;
+ int i, j;
+
+ if(!path || !((pinerc && pinerc[0]) || ps_global->passfile))
+ return(NULL);
+
+ if(ps_global->passfile)
+ strncpy(path, ps_global->passfile, len-1);
+ else{
+ if((p = last_cmpnt(pinerc)) && *(p-1) && *(p-1) != PASSFILE[0])
+ for(i = 0; pinerc < p && i < len; pinerc++, i++)
+ path[i] = *pinerc;
+ else
+ i = 0;
+
+ for(j = 0; (i < len) && (path[i] = PASSFILE[j]); i++, j++)
+ ;
+
+ }
+
+ path[len-1] = '\0';
+
+ dprint((9, "Looking for passfile \"%s\"\n",
+ path ? path : "?"));
+
+#if defined(DOS) || defined(OS2)
+ return((our_stat(path, &sbuf) == 0
+ && ((sbuf.st_mode & S_IFMT) == S_IFREG))
+ ? path : NULL);
+#else
+ /* First, make sure it's ours and not sym-linked */
+ if(our_lstat(path, &sbuf) == 0
+ && ((sbuf.st_mode & S_IFMT) == S_IFREG)
+ && sbuf.st_uid == getuid()){
+ /* if too liberal permissions, fix them */
+ if((sbuf.st_mode & 077) != 0)
+ if(our_chmod(path, sbuf.st_mode & ~077) != 0)
+ return(NULL);
+
+ return(path);
+ }
+ else
+ return(NULL);
+#endif
+}
+#endif /* PASSFILE */
diff --git a/pith/imap.h b/pith/imap.h
index 86a0b533..1b30e456 100644
--- a/pith/imap.h
+++ b/pith/imap.h
@@ -131,5 +131,9 @@ void imap_flush_passwd_cache(int);
void set_read_predicted(int);
void mm_login_work (NETMBX *mb,char *user,char *pwd,long trial,char *usethisprompt, char *altuserforcache);
+/* this is necessary to figure out the name of the password file of the application */
+#ifdef PASSFILE
+char *passfile_name(char *, char *, size_t);
+#endif /* PASSFILE */
#endif /* PITH_IMAP_INCLUDED */
diff --git a/pith/pine.hlp b/pith/pine.hlp
index de174d2b..2e0fd0c4 100644
--- a/pith/pine.hlp
+++ b/pith/pine.hlp
@@ -197,6 +197,10 @@ Additions include:
in lower case, as some SMTP servers, such as those of libero.it
reject messages if the boundary attribute is in uppercase.
+ <LI> Add the ability to change the private key and certificates used
+ to encrypt a password file in the SMIME setup configuration screen.
+ <A HREF="h_config_smime_password_file_certificates">Learn more</A>
+
<LI> SMIME: The ctrl-E command that gives information on the certificate
is only available for messages that have a signed or encrypted
part.
@@ -35422,6 +35426,56 @@ import a command to this collection.
&lt;End of help on this topic&gt;
</BODY>
</HTML>
+====== h_config_smime_password_file_certificates =====
+<HTML>
+<HEAD>
+<TITLE>S/MIME: Manage Password File Certificates</TITLE>
+</HEAD>
+<BODY>
+<H1>S/MIME: Manage Password File Certificates</H1>
+
+UNIX Alpine only.
+<P>
+This option allows you to manage the certificates that are used to
+encrypt and decrypt your password file. This is useful in case you
+want to change the certificates used to encrypt your password file.
+<P>
+In order to avoid unauthorized use of this option, you are asked to
+enter the password of the current private key used to encrypt your
+password file.
+<P>
+Once you have entered your password for the current key, you enter a
+screen where you can import your new key, and see the information on your
+current key.
+<P>
+To import a new key press &quot;RETURN&quot; and enter the location of
+the new key. You will be asked to enter the password of the new key. If
+this part of the process is successful, Alpine will search for the
+certificate that matches that key. If your key is named
+&quot;your_email@address.com.key&quot;, then Alpine will look for your
+certificate in the same directory in the file named
+&quot;your_email@address.com.crt&quot;, otherwise it will look for it
+as part of your key (that is, it will look to see if your certificate
+is in the file &quot;your_email@address.com.key&quot;), if all of this
+fails, Alpine will ask you to enter the location of the certificate
+that matches the key you unlocked. If a certificate is found, it will be
+used, and in this case, the password file will be read, decrypted with the
+old key and encrypted with the new key. Once this is done, the new key and
+certificates are saved, and the old keys are permanently deleted.
+<P>
+Alpine does not create a backup of your password file, or your old keys
+that will be replaced. If you need to keep old copies, you will have to do
+this operation outside Alpine.
+<UL>
+<LI><A HREF="h_mainhelp_smime">General S/MIME help</A>
+</UL><P>
+<P>
+<UL>
+<LI><A HREF="h_finding_help">Finding more information and requesting help</A>
+</UL><P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
====== h_certificate_information =====
<HTML>
<HEAD>
diff --git a/pith/smime.c b/pith/smime.c
index 6f9efc7f..d32a97c9 100644
--- a/pith/smime.c
+++ b/pith/smime.c
@@ -42,6 +42,9 @@ static char rcsid[] = "$Id: smime.c 1176 2008-09-29 21:16:42Z hubert@u.washingto
#include "../pith/tempfile.h"
#include "../pith/readfile.h"
#include "../pith/remote.h"
+#ifdef PASSFILE
+#include "../pith/imap.h"
+#endif /* PASSFILE */
#include <openssl/buffer.h>
#include <openssl/x509v3.h>
@@ -70,10 +73,8 @@ static void setup_storage_locations(void);
static int copy_container_to_dir(WhichCerts which);
static int do_fiddle_smime_message(BODY *b, long msgno, char *section);
void setup_privatekey_storage(void);
-int smime_path(char *rpath, char *fpath, size_t len);
int smime_extract_and_save_cert(PKCS7 *p7, int check_cert);
int same_cert(X509 *, X509 *);
-CertList * certlist_from_personal_certs(PERSONAL_CERT *pc);
#ifdef PASSFILE
int load_key_and_cert(char *pathkeydir, char *pathcertdir, char **keyfile, char **certfile, EVP_PKEY **pkey, X509 **pcert);
#endif /* PASSFILE */
@@ -245,14 +246,18 @@ setup_pwdcert(void **pwdcert)
return;
}
+
+ if(ps_global->pwdcertdir == NULL) /* save the result of pwdcertdir */
+ ps_global->pwdcertdir = cpystr(pathdir);
+
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;
+ pc->cname = certfile;
*pwdcert = (void *) pc;
- fs_give((void **)&certfile);
was_here = 0;
return;
}
@@ -596,8 +601,10 @@ load_pkey_with_prompt(char *fpath, char *text, char *prompt, int *ret)
return pkey;
}
-
-
+/* This is a tool for conf_screen, The return value must be zero when
+ * nothing changed, so if there is a failure in the import return 0
+ * and return 1 when we succeeded
+ */
int
import_certificate(WhichCerts ctype)
{
@@ -607,18 +614,221 @@ import_certificate(WhichCerts ctype)
if(pith_smime_import_certificate == NULL){
q_status_message(SM_ORDER, 0, 2,
_("import of certificates not implemented yet!"));
- return -1;
+ return 0;
}
- smime_init();
-
r = (*pith_smime_import_certificate)(filename, full_filename, sizeof(filename) - 20);
+ if(r < 0)
+ return 0;
+
+ /* we are trying to import a new key for the password file. First we ask for the
+ * private key. Once this is loaded, we make a reasonable attempt to find the
+ * public key in the same directory as the key was loaded from. We do this by
+ * looking for a file with the correct public certificate name, then we look
+ * in the same private key, and if not, we ask the user for its location. If all
+ * of this works, we import the key and public to the password directory.
+ */
+ if(ctype == Password){
+ char PrivateKeyPath[MAXPATH+1], PublicCertPath[MAXPATH+1], s[MAXPATH+1];
+ char full_name_key[MAXPATH+1], full_name_cert[MAXPATH+1];
+ char *use_this_file;
+ char prompt[500];
+ EVP_PKEY *key = NULL;
+
+ rc = 1; /* assume success :) */
+ if(strlen(filename) > 4){
+ strncpy(s, filename, sizeof(s));
+ s[sizeof(s)-1] = '\0';
+ if(!strcmp(s + strlen(s) - strlen(EXTCERT(Private)), EXTCERT(Private)))
+ s[strlen(s) - strlen(EXTCERT(Private))] = '\0';
+ else
+ rc = 0;
+ } else rc = 0;
+
+ if(rc == 0){
+ q_status_message(SM_ORDER, 1, 3, _("Error in key name. Check file extension"));
+ return 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)) != NULL){
+ BIO *ins = NULL;
+ X509 *cert = NULL;
+
+ strncpy(full_name_key, full_filename, sizeof(full_filename));
+ full_name_key[sizeof(full_name_key)-1] = '\0';
+
+ build_path(buf, PATHCERTDIR(ctype), s, sizeof(buf));
+
+ strncpy(PrivateKeyPath, buf, sizeof(PrivateKeyPath));
+ PrivateKeyPath[sizeof(PrivateKeyPath)-1] = '\0';
+ if(strlen(PrivateKeyPath) + 4 < sizeof(PrivateKeyPath)){
+ strncat(PrivateKeyPath, EXTCERT(Private), 4);
+ PrivateKeyPath[sizeof(PrivateKeyPath)-1] = '\0';
+ }
+
+ /* remove .key extension and replace it with .crt extension */
+ strncpy(full_name_cert, full_name_key, sizeof(full_name_key));
+ full_name_cert[sizeof(full_name_cert)-1] = '\0';
+ full_name_cert[strlen(full_name_cert) - strlen(EXTCERT(Private))] = '\0';
+ strncat(full_name_cert, EXTCERT(Public), 4);
+ full_name_cert[sizeof(full_name_cert)-1] = '\0';
+
+
+ /* set up path to location where we will save public cert */
+ strncpy(PublicCertPath, buf, sizeof(PublicCertPath));
+ PublicCertPath[sizeof(PublicCertPath)-1] = '\0';
+ if(strlen(PublicCertPath) + 4 < sizeof(PublicCertPath)){
+ strncat(PublicCertPath, EXTCERT(Public), 4);
+ PublicCertPath[sizeof(PublicCertPath)-1] = '\0';
+ }
+
+ /* attempt #1 to guess public cert name, use .crt extension */
+ if((ins = BIO_new_file(full_name_cert, "r")) != NULL){
+ if((cert = PEM_read_bio_X509(ins, NULL, NULL, NULL)) != NULL){
+ use_this_file = &full_name_cert[0];
+ }
+ }
+ else{
+ /* attempt #2 to guess public cert name: user the original key */
+ if((ins = BIO_new_file(full_name_key, "r")) != NULL){
+ if((cert = PEM_read_bio_X509(ins, NULL, NULL, NULL)) != NULL){
+ use_this_file = &full_name_key[0];
+ }
+ }
+ else {
+ int done = 0;
+ /* attempt #3, ask the user */
+ do {
+ r = (*pith_smime_import_certificate)(filename, use_this_file, sizeof(filename) - 20);
+ if(r < 0){
+ if(ins != NULL) BIO_free(ins);
+ if(cert != NULL) X509_free(cert);
+ return 0;
+ }
+ if((ins = BIO_new_file(use_this_file, "r")) != NULL){
+ if((cert = PEM_read_bio_X509(ins, NULL, NULL, NULL)) != NULL)
+ done++;
+ else
+ q_status_message(SM_ORDER, 1, 3, _("Error parsing certificate"));
+ }
+ else
+ q_status_message(SM_ORDER, 1, 3, _("Error reading certificate"));
+ } while (done == 0);
+ }
+ }
+ if(ins != NULL){
+ if(cert != NULL){ /* check that certificate matches key */
+ if(!X509_check_private_key(cert, key)){
+ rc = 0;
+ q_status_message(SM_ORDER, 1, 3, _("Certificate does not match key"));
+ }
+ else
+ rc = 1; /* Success! */
+ }
+ else
+ q_status_message(SM_ORDER, 1, 3, _("Error in certificate file (not a certificate?)"));
+ }
+ if(rc == 1){ /* if everything has been successful,
+ * copy the files to their final destination */
+ if(our_copy(PrivateKeyPath, full_filename) == 0){ /* <-- save the private key */
+ q_status_message(SM_ORDER, 1, 3, _("Private key saved"));
+ if(our_copy(PublicCertPath, use_this_file) == 0){
+ char tmp[MAILTMPLEN];
+ FILE *fp;
+
+ if(!passfile_name(ps_global->pinerc, tmp, sizeof(tmp))
+ || !(fp = our_fopen(tmp, "rb"))){
+ q_status_message(SM_ORDER, 1, 3, _("Error reading password file!"));
+ rc = 0;
+ }
+ else {
+ char tmp2[MAILTMPLEN];
+ int encrypted = 0;
+ char *text;
+ PERSONAL_CERT *pwdcert, *pc;
+
+ pwdcert = (PERSONAL_CERT *) ps_global->pwdcert;
+ if(pwdcert == NULL)
+ setup_pwdcert((void **)&pwdcert);
+
+ tmp2[0] = '\0';
+ fgets(tmp2, sizeof(tmp2), fp);
+ fclose(fp);
+ if(strcmp(tmp2, "-----BEGIN PKCS7-----\n")){
+ if(encrypt_file((char *)tmp, NULL, pwdcert))
+ encrypted++;
+ }
+ else
+ encrypted++;
+
+ if(encrypted){
+ text = decrypt_file((char *)tmp, NULL, pwdcert);
+ if(text != NULL){
+ pc = fs_get(sizeof(PERSONAL_CERT));
+ memset((void *)pc, 0, sizeof(PERSONAL_CERT));
+ filename[strlen(filename)-strlen(EXTCERT(Private))] = '\0';
+ pc->name = cpystr(filename);
+ snprintf(buf, sizeof(buf), "%s%s", filename, EXTCERT(Public));
+ buf[sizeof(buf)-1] = '\0';
+ pc->cname = cpystr(buf);
+ pc->key = key;
+ pc->cert = cert;
+
+ if(encrypt_file((char *)tmp, text, pc)){ /* we did it! */
+ build_path(buf, PATHCERTDIR(ctype), pwdcert->name, sizeof(buf));
+ strncat(buf, EXTCERT(Private), 4);
+ buf[sizeof(buf)-1] = '\0';
+ if(unlink(buf) < 0)
+ q_status_message(SM_ORDER, 1, 3, _("Failed to remove old key"));
+ build_path(buf, PATHCERTDIR(ctype), pwdcert->cname, sizeof(buf));
+ if(unlink(buf) < 0)
+ q_status_message(SM_ORDER, 1, 3, _("Failed to remove old certificate"));
+ free_personal_certs((PERSONAL_CERT **)&ps_global->pwdcert);
+ ps_global->pwdcert = pc;
+ rc = 1;
+ q_status_message(SM_ORDER, 1, 3, _("Password file reencrypted"));
+ } else {
+ q_status_message(SM_ORDER, 1, 3, _("Failed to reencrypt password file"));
+ rc = 0;
+ }
+ } else {
+ q_status_message(SM_ORDER, 1, 3, _("Error decrypting Password file"));
+ }
+ } else {
+ q_status_message(SM_ORDER, 1, 3, _("Password file not encrypted and coulr not encrypt"));
+ rc = 0;
+ }
+ }
+ }
+ else{
+ q_status_message(SM_ORDER, 1, 3, _("Error saving public certificate"));
+ if(our_unlink(PrivateKeyPath) < 0)
+ q_status_message(SM_ORDER, 1, 3, _("Error while cleaning private key"));
+ rc = 0;
+ }
+ }
+ else{
+ rc = 0;
+ q_status_message(SM_ORDER, 1, 3, _("Error saving private key"));
+ }
+ if(ins != NULL) BIO_free(ins);
+ if(rc == 0 && cert != NULL) X509_free(cert);
+ }
+ } else {
+ rc = 0;
+ q_status_message(SM_ORDER, 1, 3, _("Error unlocking private key"));
+ }
+
+ return rc;
+ }
+
+ smime_init();
ps_global->mangled_screen = 1;
- if(r < 0)
- return r;
- else if (ctype == Private){
+ if (ctype == Private){
char prompt[500], *s, *t;
EVP_PKEY *key = NULL;
@@ -651,7 +861,7 @@ import_certificate(WhichCerts ctype)
ps_global->smime->publiccertlist->data.renew = 1;
}
else
- q_status_message(SM_ORDER, 1, 3, _("Problem unlocking key (not a certificate and/or wrong password)"));
+ q_status_message(SM_ORDER, 1, 3, _("Problem unlocking key (not a certificate or wrong password)"));
} else if (ctype == CACert){
BIO *ins;
X509 *cert;
@@ -713,7 +923,7 @@ import_certificate(WhichCerts ctype)
}
}
if(DATACERT(ctype)) RENEWCERT(DATACERT(ctype)) = 1;
- return 0;
+ return 1;
}
/* itype: information type to add: 0 - public, 1 - private.
@@ -920,23 +1130,12 @@ certlist_from_personal_certs(PERSONAL_CERT *pc)
{
CertList *cl;
X509 *x;
- char buf[MAXPATH];
if(pc == NULL)
return NULL;
-
- cl = fs_get(sizeof(CertList));
- memset((void *)cl, 0, sizeof(CertList));
- cl->name = cpystr(pc->name);
- x = get_cert_for(pc->name, Public, 1);
- if(x){
- if(x->cert_info){
- cl->data.date_from = smime_get_date(x->cert_info->validity->notBefore);
- cl->data.date_to = smime_get_date(x->cert_info->validity->notAfter);
- get_fingerprint(x, EVP_md5(), buf, sizeof(buf), NULL);
- cl->data.md5 = cpystr(buf);
- cl->cn = smime_get_cn(x->cert_info->subject);
- }
+
+ if((x = get_cert_for(pc->name, Public, 1)) != NULL){
+ cl = smime_X509_to_cert_info(x, pc->name);
X509_free(x);
}
cl->next = certlist_from_personal_certs(pc->next);
@@ -3641,14 +3840,6 @@ free_smime_struct(SMIME_STUFF_S **smime)
(*smime)->personal_certs = NULL;
}
- if((*smime)->backuppersonal_certs){
- PERSONAL_CERT *pc;
-
- pc = (PERSONAL_CERT *) (*smime)->backuppersonal_certs;
- free_personal_certs(&pc);
- (*smime)->backuppersonal_certs = NULL;
- }
-
if((*smime)->privatecontent)
fs_give((void **) &(*smime)->privatecontent);
diff --git a/pith/smime.h b/pith/smime.h
index 636d8805..01e4cdc0 100644
--- a/pith/smime.h
+++ b/pith/smime.h
@@ -85,6 +85,8 @@ void *create_smime_sparep(SpareType stype, void *s);
SpareType get_smime_sparep_type(void *s);
void *get_smime_sparep_data(void *s);
STACK_OF(X509) *get_chain_for_cert(X509 *cert, int *error, int *level);
+CertList *certlist_from_personal_certs(PERSONAL_CERT *pc);
+int smime_path(char *rpath, char *fpath, size_t len);
#endif /* PITH_SMIME_INCLUDED */
#endif /* SMIME */
diff --git a/pith/smkeys.c b/pith/smkeys.c
index 18509622..415bc190 100644
--- a/pith/smkeys.c
+++ b/pith/smkeys.c
@@ -49,6 +49,30 @@ static char *emailstrclean(char *string);
static int mem_add_extra_cacerts(char *contents, X509_LOOKUP *lookup);
int compare_certs_by_name(const void *data1, const void *data2);
+
+CertList *
+smime_X509_to_cert_info(X509 *x, char *name)
+{
+ CertList *cert;
+ char buf[MAXPATH+1];
+
+ if(x == NULL) return NULL;
+
+ cert = fs_get(sizeof(CertList));
+ memset((void *)cert, 0, sizeof(CertList));
+ cert->x509_cert = x;
+ cert->name = name ? cpystr(name) : NULL;
+ if(x && x->cert_info){
+ cert->data.date_from = smime_get_date(x->cert_info->validity->notBefore);
+ cert->data.date_to = smime_get_date(x->cert_info->validity->notAfter);
+ cert->cn = smime_get_cn(x->cert_info->subject);
+ }
+ get_fingerprint(x, EVP_md5(), buf, sizeof(buf), NULL);
+ cert->data.md5 = cpystr(buf);
+
+ return cert;
+}
+
#define SMIME_BACKUP_DIR ".backup"
#define MAX_TRY_BACKUP 100
@@ -199,25 +223,11 @@ setup_certs_backup_by_type(WhichCerts ctype)
if((in = BIO_new_file(buf2, "r"))!=0){
x = PEM_read_bio_X509(in, NULL, NULL, NULL);
if(x && x->cert_info){ /* for now copy this information */
- X509_NAME_ENTRY *e;
-
- cert = fs_get(sizeof(CertList));
- memset((void *)cert, 0, sizeof(CertList));
- cert->x509_cert = x;
- cert->data.date_from = smime_get_date(x->cert_info->validity->notBefore);
- cert->data.date_to = smime_get_date(x->cert_info->validity->notAfter);
- get_fingerprint(x, EVP_md5(), buf, sizeof(buf), NULL);
- cert->data.md5 = cpystr(buf);
- cert->name = cpystr(df->d_name);
- cert->cn = smime_get_cn(x->cert_info->subject);
+ cert = smime_X509_to_cert_info(x, df->d_name);
/* we will use the cert->data.md5 variable to find a backup
certificate, not the name */
- if(data == NULL)
- data = cert;
- else{
- for (cl2 = data; cl2 && cl2->next; cl2 = cl2->next);
- cl2->next = cert;
- }
+ cert->next = data;
+ data = cert;
}
BIO_free(in);
}
@@ -872,6 +882,25 @@ get_cert_for(char *email, WhichCerts ctype, int tolower)
X509 *cert = NULL;
BIO *in;
+ if(ctype == Password){
+ build_path(certfilename, PATHCERTDIR(ctype), email, sizeof(certfilename));
+ strncat(certfilename, EXTCERT(Public), sizeof(certfilename)-1-strlen(certfilename));
+ certfilename[sizeof(certfilename)-1] = 0;
+
+ if((in = BIO_new_file(certfilename, "r"))!=0){
+
+ cert = PEM_read_bio_X509(in, NULL, NULL, NULL);
+
+ if(cert){
+ /* could check email addr in cert matches */
+ }
+
+ BIO_free(in);
+ }
+
+ return cert;
+ }
+
if(!ps_global->smime)
return cert;
@@ -1274,33 +1303,14 @@ certlist_to_file(char *filename, CertList *certlist)
void
add_to_end_of_certlist(CertList **cl, char *name, X509 *cert)
{
- CertList *new, *clp;
- char buf[MAILTMPLEN];
+ CertList *new;
if(!cl)
return;
- new = (CertList *) fs_get(sizeof(*new));
- memset((void *) new, 0, sizeof(*new));
- new->x509_cert = cert;
- new->name = name ? cpystr(name) : NULL;
- if(cert && cert->cert_info){
- new->data.date_from = smime_get_date(cert->cert_info->validity->notBefore);
- new->data.date_to = smime_get_date(cert->cert_info->validity->notAfter);
- get_fingerprint(cert, EVP_md5(), buf, sizeof(buf), NULL);
- new->data.md5 = cpystr(buf);
- new->cn = smime_get_cn(cert->cert_info->subject);
- }
-
- if(!*cl){
- *cl = new;
- }
- else{
- for(clp = (*cl); clp->next; clp = clp->next)
- ;
-
- clp->next = new;
- }
+ new = smime_X509_to_cert_info(cert, name);
+ new->next = *cl;
+ *cl = new;
}
diff --git a/pith/smkeys.h b/pith/smkeys.h
index 0a2b0065..8c23d905 100644
--- a/pith/smkeys.h
+++ b/pith/smkeys.h
@@ -38,7 +38,8 @@
typedef struct personal_cert {
X509 *cert;
EVP_PKEY *key;
- char *name;
+ char *name; /* name of key */
+ char *cname; /* name of cert */
char *keytext;
struct personal_cert *next;
} PERSONAL_CERT;
@@ -67,6 +68,7 @@ char *smime_get_date(ASN1_GENERALIZEDTIME *tm);
void resort_certificates(CertList **data, WhichCerts ctype);
int setup_certs_backup_by_type(WhichCerts ctype);
char *smime_get_cn(X509_NAME *);
+CertList *smime_X509_to_cert_info(X509 *, char *);
#endif /* PITH_SMKEYS_INCLUDED */
diff --git a/pith/state.h b/pith/state.h
index 481d8b41..52628cf0 100644
--- a/pith/state.h
+++ b/pith/state.h
@@ -272,9 +272,6 @@ struct pine {
#endif
#ifdef PASSFILE
*passfile,
-#ifdef SMIME
- *pwdcertdir,
-#endif /* SMIME inside PASSFILE */
#endif /* PASSFILE */
*pinerc, /* Location of user's pinerc */
*exceptions, /* Location of user's exceptions */
@@ -359,7 +356,11 @@ struct pine {
char *smimedir;
SMIME_STUFF_S *smime;
#ifdef PASSFILE
- void *pwdcert; /* this is of type PERSONAL_CERT */
+ char *pwdcertdir; /* path to location of certificates for password file */
+ char *pwdcertcontent; /* No comment yet */
+ void *pwdcert; /* this is of type PERSONAL_CERT */
+ void *backuppassword; /* this is of type CertList */
+ void *pwdcertlist; /* this is of type CertList */
#endif /* PASSFILE inside SMIME */
#endif /* SMIME */