2 * ========================================================================
3 * Copyright 2013-2021 Eduardo Chappa
4 * Copyright 2008 University of Washington
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * ========================================================================
16 * This is based on a contribution from Jonathan Paisley
19 * Author: paisleyj@dcs.gla.ac.uk
28 #include "../pith/charconv/utf8.h"
29 #include "../pith/status.h"
30 #include "../pith/store.h"
31 #include "../pith/conf.h"
32 #include "../pith/list.h"
33 #include "../pith/mailcmd.h"
34 #include "../pith/tempfile.h"
35 #include "../pith/body.h"
41 #include "confscroll.h"
45 /* internal prototypes */
46 void format_smime_info(int pass
, BODY
*body
, long msgno
, gf_io_t pc
);
47 void print_separator_line(int percent
, int ch
, gf_io_t pc
);
48 void output_cert_info(X509
*cert
, gf_io_t pc
);
49 void output_X509_NAME(X509_NAME
*name
, gf_io_t pc
);
50 void side_by_side(STORE_S
*left
, STORE_S
*right
, gf_io_t pc
);
51 STORE_S
*wrap_store(STORE_S
*in
, int width
);
52 void smime_config_init_display(struct pine
*, CONF_S
**, CONF_S
**);
53 void revert_to_saved_smime_config(struct pine
*ps
, SAVED_CONFIG_S
*vsave
);
54 SAVED_CONFIG_S
*save_smime_config_vars(struct pine
*ps
);
55 void free_saved_smime_config(struct pine
*ps
, SAVED_CONFIG_S
**vsavep
);
56 int smime_helper_tool(struct pine
*, int, CONF_S
**, unsigned);
57 void manage_certificates(struct pine
*, WhichCerts
);
59 void manage_password_file_certificates(struct pine
*);
61 void smime_manage_certs_init (struct pine
*, CONF_S
**, CONF_S
**, WhichCerts
, int);
62 void smime_manage_password_file_certs_init(struct pine
*, CONF_S
**, CONF_S
**, int, int *);
63 void display_certificate_information(struct pine
*, X509
*, char *, WhichCerts
, int num
);
64 int manage_certs_tool(struct pine
*ps
, int cmd
, CONF_S
**cl
, unsigned flags
);
65 int manage_certificate_info_tool(int, MSGNO_S
*, SCROLL_S
*);
66 void smime_setup_size(char **, size_t, size_t);
70 * prompt the user for their passphrase
71 * (possibly prompting with the email address in s_passphrase_emailaddr)
74 smime_get_passphrase(void)
79 HelpType help
= NO_HELP
;
81 assert(ps_global
->smime
!= NULL
);
82 snprintf(prompt
, sizeof(prompt
),
83 _("Enter passphrase for <%s>: "), (ps_global
->smime
&& ps_global
->smime
->passphrase_emailaddr
) ? ps_global
->smime
->passphrase_emailaddr
[0] : "unknown");
86 flags
= F_ON(F_QUELL_ASTERISKS
, ps_global
) ? OE_PASSWD_NOAST
: OE_PASSWD
;
87 flags
|= OE_DISALLOW_HELP
;
88 ((char *) ps_global
->smime
->passphrase
)[0] = '\0';
89 rc
= optionally_enter((char *) ps_global
->smime
->passphrase
,
90 -FOOTER_ROWS(ps_global
), 0,
91 sizeof(ps_global
->smime
->passphrase
),
92 prompt
, NULL
, help
, &flags
);
93 } while (rc
!=0 && rc
!=1 && rc
>0);
97 ps_global
->smime
->entered_passphrase
= 1;
100 return rc
; /* better return rc and make the caller check its return value */
104 smime_check(BODY
*body
)
109 if(body
->type
== TYPEMULTIPART
){
112 for(p
=body
->nested
.part
; p
&& rv
== 0; p
=p
->next
)
113 rv
+= smime_check(&p
->body
);
115 if(rv
> 0) return rv
;
117 p7
= get_body_sparep_type(body
->sparep
) == P7Type
118 ? (PKCS7
*)get_body_sparep_data(body
->sparep
)
120 if(p7
&& (PKCS7_type_is_signed(p7
) || PKCS7_type_is_enveloped(p7
)))
127 display_smime_info(struct pine
*ps
, ENVELOPE
*env
, BODY
*body
)
129 OtherMenu what
= FirstMenu
;
130 HANDLE_S
*handles
= NULL
;
132 STORE_S
*store
= NULL
;
136 msgno
= mn_m2raw(ps
->msgmap
, mn_get_cur(ps
->msgmap
));
137 store
= so_get(CharStar
, NULL
, EDIT_ACCESS
);
139 while(ps
->next_screen
== SCREEN_FUN_NULL
){
143 so_truncate(store
, 0);
145 view_writec_init(store
, &handles
, HEADER_ROWS(ps
),
147 ps
->ttyo
->screen_rows
- (HEADER_ROWS(ps
)
150 gf_puts_uline("Overview", view_writec
);
151 gf_puts(NEWLINE
, view_writec
);
153 format_smime_info(1, body
, msgno
, view_writec
);
154 gf_puts(NEWLINE
, view_writec
);
155 format_smime_info(2, body
, msgno
, view_writec
);
157 view_writec_destroy();
159 ps
->next_screen
= SCREEN_FUN_NULL
;
161 memset(&scrollargs
, 0, sizeof(SCROLL_S
));
162 scrollargs
.text
.text
= so_text(store
);
163 scrollargs
.text
.src
= CharStar
;
164 scrollargs
.text
.desc
= "S/MIME information";
165 scrollargs
.body_valid
= 1;
167 if(offset
){ /* resize? preserve paging! */
168 scrollargs
.start
.on
= Offset
;
169 scrollargs
.start
.loc
.offset
= offset
;
173 scrollargs
.bar
.title
= "S/MIME INFORMATION";
174 /* scrollargs.end_scroll = view_end_scroll; */
175 scrollargs
.resize_exit
= 1;
176 scrollargs
.help
.text
= NULL
;
177 scrollargs
.help
.title
= "HELP FOR S/MIME INFORMATION VIEW";
178 scrollargs
.keys
.menu
= &smime_info_keymenu
;
179 scrollargs
.keys
.what
= what
;
180 setbitmap(scrollargs
.keys
.bitmap
);
182 if(scrolltool(&scrollargs
) == MC_RESIZE
)
183 offset
= scrollargs
.start
.loc
.offset
;
190 smime_info_screen(struct pine
*ps
)
196 /* ps->prev_screen = smime_info_screen;
197 ps->next_screen = SCREEN_FUN_NULL; */
199 msgno
= mn_m2raw(ps
->msgmap
, mn_get_cur(ps
->msgmap
));
201 env
= mail_fetch_structure(ps
->mail_stream
, msgno
, &body
, 0);
204 q_status_message(SM_ORDER
, 0, 3,
205 _("Can't fetch body of message."));
209 if(smime_check(body
) == 0){
210 q_status_message(SM_ORDER
| SM_DING
, 0, 3,
211 _("Not a signed or encrypted message"));
215 if(mn_total_cur(ps
->msgmap
) > 1L){
216 q_status_message(SM_ORDER
| SM_DING
, 0, 3,
217 _("Can only view one message's information at a time."));
221 display_smime_info(ps
, env
, body
);
226 format_smime_info(int pass
, BODY
*body
, long msgno
, gf_io_t pc
)
231 if(body
->type
== TYPEMULTIPART
){
234 for(p
=body
->nested
.part
; p
; p
=p
->next
)
235 format_smime_info(pass
, &p
->body
, msgno
, pc
);
238 p7
= get_body_sparep_type(body
->sparep
) == P7Type
239 ? (PKCS7
*)get_body_sparep_data(body
->sparep
)
243 if(PKCS7_type_is_signed(p7
)){
244 STACK_OF(X509
) *signers
;
248 gf_puts(_("This message was cryptographically signed."), pc
);
249 gf_puts(NEWLINE
, pc
);
253 signers
= PKCS7_get0_signers(p7
, NULL
, 0);
257 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _("Certificate%s used for signing"),
258 plural(sk_X509_num(signers
)));
259 gf_puts_uline(tmp_20k_buf
, pc
);
260 gf_puts(NEWLINE
, pc
);
261 print_separator_line(100, '-', pc
);
263 for(i
=0; i
<sk_X509_num(signers
); i
++){
264 X509
*x
= sk_X509_value(signers
, i
);
267 output_cert_info(x
, pc
);
268 gf_puts(NEWLINE
, pc
);
273 sk_X509_free(signers
);
278 else if(PKCS7_type_is_enveloped(p7
)){
282 gf_puts(_("This message was encrypted."), pc
);
283 gf_puts(NEWLINE
, pc
);
287 if(p7
->d
.enveloped
&& p7
->d
.enveloped
->enc_data
){
288 X509_ALGOR
*alg
= p7
->d
.enveloped
->enc_data
->algorithm
;
289 STACK_OF(PKCS7_RECIP_INFO
) *ris
= p7
->d
.enveloped
->recipientinfo
;
292 gf_puts(_("The algorithm used to encrypt was "), pc
);
295 char *n
= (char *) OBJ_nid2sn( OBJ_obj2nid(alg
->algorithm
));
297 gf_puts(n
? n
: "<unknown>", pc
);
301 gf_puts("<unknown>", pc
);
303 gf_puts("." NEWLINE NEWLINE
, pc
);
305 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _("Certificate%s for decrypting"),
306 plural(sk_PKCS7_RECIP_INFO_num(ris
)));
307 gf_puts_uline(tmp_20k_buf
, pc
);
308 gf_puts(NEWLINE
, pc
);
309 print_separator_line(100, '-', pc
);
311 for(i
=0; i
<sk_PKCS7_RECIP_INFO_num(ris
); i
++){
312 PKCS7_RECIP_INFO
*ri
;
313 PERSONAL_CERT
*pcert
;
315 ri
= sk_PKCS7_RECIP_INFO_value(ris
, i
);
319 pcert
= find_certificate_matching_recip_info(ri
);
323 print_separator_line(25, '*', pc
);
324 gf_puts(NEWLINE
, pc
);
329 output_cert_info(pcert
->cert
, pc
);
330 gf_puts(NEWLINE
, pc
);
336 gf_puts(_("No certificate capable of decrypting could be found."), pc
);
337 gf_puts(NEWLINE
, pc
);
338 gf_puts(NEWLINE
, pc
);
350 print_separator_line(int percent
, int ch
, gf_io_t pc
)
354 len
= ps_global
->ttyo
->screen_cols
* percent
/ 100;
355 start
= (ps_global
->ttyo
->screen_cols
- len
)/2;
357 for(i
=0; i
<start
; i
++)
360 for(i
=start
; i
<start
+len
; i
++)
363 gf_puts(NEWLINE
, pc
);
368 output_cert_info(X509
*cert
, gf_io_t pc
)
371 STORE_S
*left
,*right
;
374 STACK_OF(X509
) *chain
;
376 left
= so_get(CharStar
, NULL
, EDIT_ACCESS
);
377 right
= so_get(CharStar
, NULL
, EDIT_ACCESS
);
381 gf_set_so_writec(&spc
, left
);
383 gf_puts_uline("Certificate Owner", spc
);
384 gf_puts(NEWLINE
, spc
);
386 output_X509_NAME(X509_get_subject_name(cert
), spc
);
387 gf_puts(NEWLINE
, spc
);
389 gf_puts_uline("Serial Number", spc
);
390 gf_puts(NEWLINE
, spc
);
397 bs
= X509_get_serialNumber(cert
);
398 if (bs
->length
<= (int)sizeof(long)){
399 l
= ASN1_INTEGER_get(bs
);
400 if (bs
->type
== V_ASN1_NEG_INTEGER
){
406 snprintf(buf
, sizeof(buf
), " %s%lu (%s0x%lx)", neg
, l
, neg
, l
);
408 snprintf(buf
, sizeof(buf
), "%s", bs
->type
== V_ASN1_NEG_INTEGER
? "(Negative)" : "");
409 for (i
= 0; i
< bs
->length
; i
++)
410 snprintf(buf
+ strlen(buf
), sizeof(buf
) - strlen(buf
), "%02x%s", bs
->data
[i
],
411 i
+1 == bs
->length
? "" : ":");
415 gf_puts(NEWLINE
, spc
);
416 gf_puts(NEWLINE
, spc
);
418 gf_puts_uline("Validity", spc
);
419 gf_puts(NEWLINE
, spc
);
420 { BIO
*mb
= BIO_new(BIO_s_mem());
423 gf_puts("Not Before: ", spc
);
425 (void) BIO_reset(mb
);
426 ASN1_UTCTIME_print(mb
, X509_get0_notBefore(cert
));
427 (void) BIO_flush(mb
);
428 while((len
= BIO_read(mb
, iobuf
, sizeof(iobuf
))) > 0)
429 gf_nputs(iobuf
, len
, spc
);
431 gf_puts(NEWLINE
, spc
);
433 gf_puts("Not After: ", spc
);
435 (void) BIO_reset(mb
);
436 ASN1_UTCTIME_print(mb
, X509_get0_notAfter(cert
));
437 (void) BIO_flush(mb
);
438 while((len
= BIO_read(mb
, iobuf
, sizeof(iobuf
))) > 0)
439 gf_nputs(iobuf
, len
, spc
);
441 gf_puts(NEWLINE
, spc
);
442 gf_puts(NEWLINE
, spc
);
447 gf_clear_so_writec(left
);
449 gf_set_so_writec(&spc
, right
);
451 gf_puts_uline("Issuer", spc
);
452 gf_puts(NEWLINE
, spc
);
454 output_X509_NAME(X509_get_issuer_name(cert
), spc
);
455 gf_puts(NEWLINE
, spc
);
457 gf_clear_so_writec(right
);
459 side_by_side(left
, right
, pc
);
461 gf_puts_uline("SHA1 Fingerprint", pc
);
462 gf_puts(NEWLINE
, pc
);
463 get_fingerprint(cert
, EVP_sha1(), buf
, sizeof(buf
), ":");
465 gf_puts(NEWLINE
, pc
);
467 gf_puts_uline("MD5 Fingerprint", pc
);
468 gf_puts(NEWLINE
, pc
);
469 get_fingerprint(cert
, EVP_md5(), buf
, sizeof(buf
), ":");
471 gf_puts(NEWLINE
, pc
);
472 gf_puts(NEWLINE
, pc
);
474 gf_puts_uline("Certificate Chain Information", pc
);
475 gf_puts(NEWLINE
, pc
);
477 if((chain
= get_chain_for_cert(cert
, &error
, &len
)) != NULL
){
484 for(i
= 0; i
< offset
; i
++) space
[i
] = ' ';
486 for(i
= -1; i
< sk_X509_num(chain
); i
++){
489 x
= i
== -1 ? cert
: sk_X509_value(chain
, i
);
493 space
[offset
+ i
+ 0] = ' ';
494 space
[offset
+ i
+ 1] = '\\';
495 space
[offset
+ i
+ 2] = '-';
496 space
[offset
+ i
+ 3] = ' ';
497 space
[offset
+ i
+ 4] = '\0';
501 space
[offset
] = '\0';
505 gf_puts_uline("Signed by: ", pc
);
507 gf_puts_uline("Issued to: ", pc
);
509 subject
= X509_get_subject_name(x
);
511 if((e
= X509_NAME_get_entry(subject
, X509_NAME_entry_count(subject
)-1)) != NULL
){
512 X509_NAME_get_text_by_OBJ(subject
, X509_NAME_ENTRY_get_object(e
), buf
, sizeof(buf
));
514 gf_puts(NEWLINE
, pc
);
518 gf_puts("No certificate info found", pc
);
519 gf_puts(NEWLINE
, pc
);
523 e
= X509_NAME_get_entry(X509_get_issuer_name(x
),
524 X509_NAME_entry_count(X509_get_issuer_name(x
))-1);
526 X509_NAME_get_text_by_OBJ(X509_get_issuer_name(x
), X509_NAME_ENTRY_get_object(e
), buf
, sizeof(buf
));
527 space
[offset
+ i
+ 0] = ' ';
528 space
[offset
+ i
+ 1] = '\\';
529 space
[offset
+ i
+ 2] = '-';
530 space
[offset
+ i
+ 3] = ' ';
531 space
[offset
+ i
+ 4] = '\0';
533 gf_puts_uline("Signed by: ", pc
);
535 gf_puts(NEWLINE
, pc
);
537 sk_X509_pop_free(chain
, X509_free
);
539 gf_puts(NEWLINE
, pc
);
547 output_X509_NAME(X509_NAME
*name
, gf_io_t pc
)
552 c
= X509_NAME_entry_count(name
);
554 for(i
=c
-1; i
>=0; i
--){
557 e
= X509_NAME_get_entry(name
,i
);
561 X509_NAME_get_text_by_OBJ(name
, X509_NAME_ENTRY_get_object(e
), buf
, sizeof(buf
));
564 gf_puts(NEWLINE
, pc
);
570 * Output the contents of the given stores (left and right)
571 * to the given gf_io_t.
572 * The width of the terminal is inspected and two columns
573 * are created to fit the stores into. They are then wrapped
577 side_by_side(STORE_S
*left
, STORE_S
*right
, gf_io_t pc
)
579 STORE_S
*left_wrapped
;
580 STORE_S
*right_wrapped
;
586 int w
= ps_global
->ttyo
->screen_cols
/2 - 1;
589 so_seek(right
, 0, 0);
591 left_wrapped
= wrap_store(left
, w
);
592 right_wrapped
= wrap_store(right
, w
);
594 so_seek(left_wrapped
, 0, 0);
595 so_seek(right_wrapped
, 0, 0);
599 l
= so_fgets(left_wrapped
, buf_l
, sizeof(buf_l
));
600 r
= so_fgets(right_wrapped
, buf_r
, sizeof(buf_r
));
601 if(l
== NULL
&& r
== NULL
)
604 for(i
=0, b
=buf_l
; i
<w
&& *b
&& *b
!='\r' && *b
!='\n'; i
++,b
++){
606 /* reduce accumulated width if an embed tag is discovered */
618 for(i
=0, b
=buf_r
; i
<w
&& *b
&& *b
!='\r' && *b
!='\n'; i
++,b
++)
622 gf_puts(NEWLINE
, pc
);
625 so_give(&left_wrapped
);
626 so_give(&right_wrapped
);
630 * Wrap the text in the given store to the given width.
631 * A new store is created for the result.
634 wrap_store(STORE_S
*in
, int width
)
643 result
= so_get(CharStar
, NULL
, EDIT_ACCESS
);
644 ws
= gf_wrap_filter_opt(width
, width
, NULL
, 0, 0);
647 gf_link_filter(gf_wrap
, ws
);
649 gf_set_so_writec(&opc
, result
);
650 gf_set_so_readc(&ipc
, in
);
654 gf_clear_so_readc(in
);
655 gf_clear_so_writec(result
);
662 smime_config_screen(struct pine
*ps
, int edit_exceptions
)
664 CONF_S
*ctmp
= NULL
, *first_line
= NULL
;
665 SAVED_CONFIG_S
*vsave
;
667 int ew
, readonly_warning
= 0;
669 dprint((9, "smime_config_screen()"));
670 ps
->next_screen
= SCREEN_FUN_NULL
;
673 * this is necessary because we need to know the correct paths
674 * to configure certificates and keys, and we could get here
675 * without having done that before we reach this place.
679 if(ps
->fix_fixed_warning
)
680 offer_to_fix_pinerc(ps
);
682 ew
= edit_exceptions
? ps_global
->ew_for_except_vars
: Main
;
685 readonly_warning
= 1;
687 PINERC_S
*prc
= NULL
;
700 readonly_warning
= prc
? prc
->readonly
: 1;
701 if(prc
&& prc
->quit_to_edit
){
702 quit_to_edit_msg(prc
);
707 smime_config_init_display(ps
, &ctmp
, &first_line
);
709 vsave
= save_smime_config_vars(ps
);
711 memset(&screen
, 0, sizeof(screen
));
712 screen
.deferred_ro_warning
= readonly_warning
;
713 switch(conf_scroll_screen(ps
, &screen
, first_line
,
714 edit_exceptions
? _("SETUP S/MIME EXCEPTIONS")
716 /* TRANSLATORS: Print something1 using something2.
717 configuration is something1 */
718 _("configuration"), 0, NULL
)){
723 write_pinerc(ps
, ew
, WRP_NONE
);
727 revert_to_saved_smime_config(ps
, vsave
);
731 q_status_message(SM_ORDER
, 7, 10,
732 _("conf_scroll_screen bad ret in smime_config"));
736 free_saved_smime_config(ps
, &vsave
);
742 smime_related_var(struct pine
*ps
, struct variable
*var
)
744 return(var
== &ps
->vars
[V_PUBLICCERT_DIR
] ||
745 var
== &ps
->vars
[V_PUBLICCERT_CONTAINER
] ||
746 var
== &ps
->vars
[V_PRIVATEKEY_DIR
] ||
747 var
== &ps
->vars
[V_PRIVATEKEY_CONTAINER
] ||
748 var
== &ps
->vars
[V_CACERT_DIR
] ||
749 var
== &ps
->vars
[V_CACERT_CONTAINER
]);
753 smime_config_init_display(struct pine
*ps
, CONF_S
**ctmp
, CONF_S
**first_line
)
757 struct variable
*vtmp
;
761 /* find longest variable name */
762 for(vtmp
= ps
->vars
; vtmp
->name
; vtmp
++){
763 if(!(smime_related_var(ps
, vtmp
)))
766 if((i
= utf8_width(pretty_var_name(vtmp
->name
))) > ln
)
770 for(vtmp
= ps
->vars
; vtmp
->name
; vtmp
++){
771 if(!(smime_related_var(ps
, vtmp
)))
774 new_confline(ctmp
)->var
= vtmp
;
775 if(first_line
&& !*first_line
)
778 (*ctmp
)->valoffset
= ln
+3;
779 (*ctmp
)->keymenu
= &config_text_keymenu
;
780 (*ctmp
)->help
= config_help(vtmp
- ps
->vars
, 0);
781 (*ctmp
)->tool
= text_tool
;
783 utf8_snprintf(tmp
, sizeof(tmp
), "%-*.100w =", ln
, pretty_var_name(vtmp
->name
));
784 tmp
[sizeof(tmp
)-1] = '\0';
786 (*ctmp
)->varname
= cpystr(tmp
);
787 (*ctmp
)->varnamep
= (*ctmp
);
788 (*ctmp
)->flags
= CF_STARTITEM
;
789 (*ctmp
)->value
= pretty_value(ps
, *ctmp
);
793 vtmp
= &ps
->vars
[V_FEATURE_LIST
];
797 (*ctmp
)->flags
|= CF_NOSELECT
| CF_STARTITEM
;
798 (*ctmp
)->keymenu
= &config_checkbox_keymenu
;
799 (*ctmp
)->tool
= NULL
;
801 /* put a nice delimiter before list */
802 new_confline(ctmp
)->var
= NULL
;
803 (*ctmp
)->varnamep
= ctmpb
;
804 (*ctmp
)->keymenu
= &config_checkbox_keymenu
;
805 (*ctmp
)->help
= NO_HELP
;
806 (*ctmp
)->tool
= checkbox_tool
;
807 (*ctmp
)->valoffset
= feature_indent();
808 (*ctmp
)->flags
|= CF_NOSELECT
;
809 (*ctmp
)->value
= cpystr("Set Feature Name");
811 new_confline(ctmp
)->var
= NULL
;
812 (*ctmp
)->varnamep
= ctmpb
;
813 (*ctmp
)->keymenu
= &config_checkbox_keymenu
;
814 (*ctmp
)->help
= NO_HELP
;
815 (*ctmp
)->tool
= checkbox_tool
;
816 (*ctmp
)->valoffset
= feature_indent();
817 (*ctmp
)->flags
|= CF_NOSELECT
;
818 (*ctmp
)->value
= cpystr("--- ----------------------");
820 ind
= feature_list_index(F_DONT_DO_SMIME
);
821 feature
= feature_list(ind
);
822 new_confline(ctmp
)->var
= vtmp
;
823 (*ctmp
)->varnamep
= ctmpb
;
824 (*ctmp
)->keymenu
= &config_checkbox_keymenu
;
825 (*ctmp
)->help
= config_help(vtmp
-ps
->vars
, feature
->id
);
826 (*ctmp
)->tool
= checkbox_tool
;
827 (*ctmp
)->valoffset
= feature_indent();
828 (*ctmp
)->varmem
= ind
;
829 (*ctmp
)->value
= pretty_value(ps
, (*ctmp
));
831 ind
= feature_list_index(F_ENCRYPT_DEFAULT_ON
);
832 feature
= feature_list(ind
);
833 new_confline(ctmp
)->var
= vtmp
;
834 (*ctmp
)->varnamep
= ctmpb
;
835 (*ctmp
)->keymenu
= &config_checkbox_keymenu
;
836 (*ctmp
)->help
= config_help(vtmp
-ps
->vars
, feature
->id
);
837 (*ctmp
)->tool
= checkbox_tool
;
838 (*ctmp
)->valoffset
= feature_indent();
839 (*ctmp
)->varmem
= ind
;
840 (*ctmp
)->value
= pretty_value(ps
, (*ctmp
));
842 ind
= feature_list_index(F_REMEMBER_SMIME_PASSPHRASE
);
843 feature
= feature_list(ind
);
844 new_confline(ctmp
)->var
= vtmp
;
845 (*ctmp
)->varnamep
= ctmpb
;
846 (*ctmp
)->keymenu
= &config_checkbox_keymenu
;
847 (*ctmp
)->help
= config_help(vtmp
-ps
->vars
, feature
->id
);
848 (*ctmp
)->tool
= checkbox_tool
;
849 (*ctmp
)->valoffset
= feature_indent();
850 (*ctmp
)->varmem
= ind
;
851 (*ctmp
)->value
= pretty_value(ps
, (*ctmp
));
853 ind
= feature_list_index(F_SIGN_DEFAULT_ON
);
854 feature
= feature_list(ind
);
855 new_confline(ctmp
)->var
= vtmp
;
856 (*ctmp
)->varnamep
= ctmpb
;
857 (*ctmp
)->keymenu
= &config_checkbox_keymenu
;
858 (*ctmp
)->help
= config_help(vtmp
-ps
->vars
, feature
->id
);
859 (*ctmp
)->tool
= checkbox_tool
;
860 (*ctmp
)->valoffset
= feature_indent();
861 (*ctmp
)->varmem
= ind
;
862 (*ctmp
)->value
= pretty_value(ps
, (*ctmp
));
864 ind
= feature_list_index(F_USE_CERT_STORE_ONLY
);
865 feature
= feature_list(ind
);
866 new_confline(ctmp
)->var
= vtmp
;
867 (*ctmp
)->varnamep
= ctmpb
;
868 (*ctmp
)->keymenu
= &config_checkbox_keymenu
;
869 (*ctmp
)->help
= config_help(vtmp
-ps
->vars
, feature
->id
);
870 (*ctmp
)->tool
= checkbox_tool
;
871 (*ctmp
)->valoffset
= feature_indent();
872 (*ctmp
)->varmem
= ind
;
873 (*ctmp
)->value
= pretty_value(ps
, (*ctmp
));
877 (*ctmp
)->flags
|= CF_NOSELECT
| CF_B_LINE
;
880 (*ctmp
)->flags
|= CF_NOSELECT
;
881 (*ctmp
)->value
= cpystr(_("Mac OS X specific features"));
883 ind
= feature_list_index(F_PUBLICCERTS_IN_KEYCHAIN
);
884 feature
= feature_list(ind
);
885 new_confline(ctmp
)->var
= vtmp
;
886 (*ctmp
)->varnamep
= ctmpb
;
887 (*ctmp
)->keymenu
= &config_checkbox_keymenu
;
888 (*ctmp
)->help
= config_help(vtmp
-ps
->vars
, feature
->id
);
889 (*ctmp
)->tool
= checkbox_tool
;
890 (*ctmp
)->valoffset
= feature_indent();
891 (*ctmp
)->varmem
= ind
;
892 (*ctmp
)->value
= pretty_value(ps
, (*ctmp
));
893 #endif /* APPLEKEYCHAIN */
896 (*ctmp
)->flags
|= CF_NOSELECT
| CF_B_LINE
;
898 for(i
= 0; i
< sizeof(tmp
) && i
< (ps
->ttyo
? ps
->ttyo
->screen_cols
: sizeof(tmp
)); i
++)
902 (*ctmp
)->flags
|= CF_NOSELECT
;
903 (*ctmp
)->value
= cpystr(tmp
);
906 (*ctmp
)->flags
|= CF_NOSELECT
;
907 (*ctmp
)->value
= cpystr(_("Be careful with the following commands, they REPLACE contents in the target"));
910 (*ctmp
)->flags
|= CF_NOSELECT
;
911 (*ctmp
)->value
= cpystr(tmp
);
914 (*ctmp
)->flags
|= CF_NOSELECT
| CF_B_LINE
;
916 /* copy public directory to container */
918 (*ctmp
)->tool
= smime_helper_tool
;
919 (*ctmp
)->keymenu
= &config_smime_helper_keymenu
;
920 (*ctmp
)->help
= h_config_smime_transfer_pub_to_con
;
921 (*ctmp
)->value
= cpystr(_("Transfer public certs FROM directory TO container"));
924 /* copy private directory to container */
926 (*ctmp
)->tool
= smime_helper_tool
;
927 (*ctmp
)->keymenu
= &config_smime_helper_keymenu
;
928 (*ctmp
)->help
= h_config_smime_transfer_priv_to_con
;
929 (*ctmp
)->value
= cpystr(_("Transfer private keys FROM directory TO container"));
932 /* copy cacert directory to container */
934 (*ctmp
)->tool
= smime_helper_tool
;
935 (*ctmp
)->keymenu
= &config_smime_helper_keymenu
;
936 (*ctmp
)->help
= h_config_smime_transfer_cacert_to_con
;
937 (*ctmp
)->value
= cpystr(_("Transfer CA certs FROM directory TO container"));
940 new_confline(ctmp
)->var
= vtmp
;
941 (*ctmp
)->flags
|= CF_NOSELECT
| CF_B_LINE
;
943 /* copy public container to directory */
945 (*ctmp
)->tool
= smime_helper_tool
;
946 (*ctmp
)->keymenu
= &config_smime_helper_keymenu
;
947 (*ctmp
)->help
= h_config_smime_transfer_pub_to_dir
;
948 (*ctmp
)->value
= cpystr(_("Transfer public certs FROM container TO directory"));
951 /* copy private container to directory */
953 (*ctmp
)->tool
= smime_helper_tool
;
954 (*ctmp
)->keymenu
= &config_smime_helper_keymenu
;
955 (*ctmp
)->help
= h_config_smime_transfer_priv_to_dir
;
956 (*ctmp
)->value
= cpystr(_("Transfer private keys FROM container TO directory"));
959 /* copy cacert container to directory */
961 (*ctmp
)->tool
= smime_helper_tool
;
962 (*ctmp
)->keymenu
= &config_smime_helper_keymenu
;
963 (*ctmp
)->help
= h_config_smime_transfer_cacert_to_dir
;
964 (*ctmp
)->value
= cpystr(_("Transfer CA certs FROM container TO directory"));
969 new_confline(ctmp
)->var
= vtmp
;
970 (*ctmp
)->flags
|= CF_NOSELECT
| CF_B_LINE
;
972 /* copy public container to keychain */
974 (*ctmp
)->tool
= smime_helper_tool
;
975 (*ctmp
)->keymenu
= &config_smime_helper_keymenu
;
976 (*ctmp
)->help
= h_config_smime_transfer_pubcon_to_key
;
977 (*ctmp
)->value
= cpystr(_("Transfer public certs FROM container TO keychain"));
980 /* copy public keychain to container */
982 (*ctmp
)->tool
= smime_helper_tool
;
983 (*ctmp
)->keymenu
= &config_smime_helper_keymenu
;
984 (*ctmp
)->help
= h_config_smime_transfer_pubkey_to_con
;
985 (*ctmp
)->value
= cpystr(_("Transfer public certs FROM keychain TO container"));
988 #endif /* APPLEKEYCHAIN */
991 && SMHOLDERTYPE(Private
) == Keychain
992 && SMHOLDERTYPE(Public
) == Keychain
993 && SMHOLDERTYPE(CACert
) == Keychain
)
996 new_confline(ctmp
)->var
= vtmp
;
997 (*ctmp
)->flags
|= CF_NOSELECT
| CF_B_LINE
;
1000 (*ctmp
)->flags
|= CF_NOSELECT
;
1001 (*ctmp
)->value
= cpystr(tmp
);
1004 (*ctmp
)->flags
|= CF_NOSELECT
;
1005 (*ctmp
)->value
= cpystr(_("Manage your own certificates"));
1008 (*ctmp
)->flags
|= CF_NOSELECT
;
1009 (*ctmp
)->value
= cpystr(tmp
);
1011 new_confline(ctmp
)->var
= vtmp
;
1012 (*ctmp
)->flags
|= CF_NOSELECT
| CF_B_LINE
;
1014 /* manage public certificates */
1016 (*ctmp
)->tool
= smime_helper_tool
;
1017 (*ctmp
)->keymenu
= &config_smime_manage_certs_menu_keymenu
;
1018 (*ctmp
)->help
= h_config_smime_public_certificates
;
1019 (*ctmp
)->value
= cpystr(_("Manage Public Certificates"));
1020 (*ctmp
)->varmem
= 9;
1021 (*ctmp
)->d
.s
.ctype
= Public
;
1023 /* manage private keys */
1025 (*ctmp
)->tool
= smime_helper_tool
;
1026 (*ctmp
)->keymenu
= &config_smime_manage_certs_menu_keymenu
;
1027 (*ctmp
)->help
= h_config_smime_private_keys
;
1028 (*ctmp
)->value
= cpystr(_("Manage Private Keys"));
1029 (*ctmp
)->varmem
= 10;
1030 (*ctmp
)->d
.s
.ctype
= Private
;
1032 /* manage Certificate Authorities */
1034 (*ctmp
)->tool
= smime_helper_tool
;
1035 (*ctmp
)->keymenu
= &config_smime_manage_certs_menu_keymenu
;
1036 (*ctmp
)->help
= h_config_smime_certificate_authorities
;
1037 (*ctmp
)->value
= cpystr(_("Manage Certificate Authorities"));
1038 (*ctmp
)->varmem
= 11;
1039 (*ctmp
)->d
.s
.ctype
= CACert
;
1042 new_confline(ctmp
)->var
= vtmp
;
1043 (*ctmp
)->flags
|= CF_NOSELECT
| CF_B_LINE
;
1046 (*ctmp
)->flags
|= CF_NOSELECT
;
1047 (*ctmp
)->value
= cpystr(tmp
);
1050 (*ctmp
)->flags
|= CF_NOSELECT
;
1051 (*ctmp
)->value
= cpystr(_("Manage Key and Certificate for Password File"));
1054 (*ctmp
)->flags
|= CF_NOSELECT
;
1055 (*ctmp
)->value
= cpystr(tmp
);
1057 new_confline(ctmp
)->var
= vtmp
;
1058 (*ctmp
)->flags
|= CF_NOSELECT
| CF_B_LINE
;
1060 /* manage password file certificates */
1062 (*ctmp
)->tool
= smime_helper_tool
;
1063 (*ctmp
)->keymenu
= &config_smime_manage_password_file_menu_keymenu
;
1064 (*ctmp
)->help
= h_config_smime_password_file_certificates
;
1065 (*ctmp
)->value
= cpystr(_("Manage Password File Key and Certificate"));
1066 (*ctmp
)->varmem
= 12;
1067 (*ctmp
)->d
.s
.ctype
= Password
;
1068 #endif /* PASSFILE */
1070 (*ctmp
)->next
= NULL
;
1074 display_certificate_information(struct pine
*ps
, X509
*cert
, char *email
, WhichCerts ctype
, int num
)
1077 SCROLL_S scrollargs
;
1079 int pub_cert
, priv_cert
, new_store
;
1083 cmd
= offset
= pub_cert
= priv_cert
= 0;
1085 ps
->next_screen
= SCREEN_FUN_NULL
;
1087 /* MC_PRIVATE and MC_PUBLIC cancel each other,
1088 * they can not be active at the same time
1093 priv_cert
= 1 - priv_cert
;
1094 smime_certificate_info_keymenu
.keys
[PUBLIC_KEY
].label
= N_("Public Key");
1095 smime_certificate_info_keymenu
.keys
[PRIVATE_KEY
].label
= priv_cert
? N_("No Priv Key") : N_("Pivate Key");
1100 pub_cert
= 1 - pub_cert
;
1101 smime_certificate_info_keymenu
.keys
[PRIVATE_KEY
].label
= priv_cert
? N_("No Priv Key") : N_("Pivate Key");
1102 smime_certificate_info_keymenu
.keys
[PUBLIC_KEY
].label
= N_("Public Key");
1106 if(SMHOLDERTYPE(CACert
) == Directory
)
1107 save_cert_for(email
, cert
, CACert
);
1108 else{ /* if(SMHOLDERTYPE(CACert) == Container) */
1110 char *upath
= PATHCERTDIR(ctype
);
1111 char *tempfile
= tempfile_in_same_dir(path
, "az", NULL
);
1114 if(IS_REMOTE(upath
))
1115 strncpy(path
, temp_nam(NULL
, "a6"), sizeof(path
)-1);
1117 strncpy(path
, upath
, sizeof(path
)-1);
1118 path
[sizeof(path
)-1] = '\0';
1120 add_to_end_of_certlist(&ps_global
->smime
->cacertlist
, email
, X509_dup(cert
));
1121 for(clist
=ps_global
->smime
->cacertlist
; clist
&& clist
->next
; clist
= clist
->next
);
1122 certlist_to_file(tempfile
, clist
);
1123 add_file_to_container(CACert
, tempfile
, email
);
1131 if (get_cert_deleted(ctype
, num
) != 0)
1132 q_status_message(SM_ORDER
, 1, 3, _("Certificate already deleted"));
1134 mark_cert_deleted(ctype
, num
, 1);
1135 q_status_message(SM_ORDER
, 1, 3, _("Certificate marked deleted"));
1140 if (get_cert_deleted(ctype
, num
) != 0){
1141 mark_cert_deleted(ctype
, num
, 0);
1142 q_status_message(SM_ORDER
, 1, 3, _("Certificate marked UNdeleted"));
1145 q_status_message(SM_ORDER
, 1, 3, _("Certificate not marked deleted"));
1151 if((pub_cert
|| priv_cert
)
1152 && (out
= print_private_key_information(email
, priv_cert
)) == NULL
)
1153 q_status_message(SM_ORDER
, 1, 3, _("Problem Reading Private Certificate Information"));
1156 store
= so_get(CharStar
, NULL
, EDIT_ACCESS
);
1157 view_writec_init(store
, NULL
, HEADER_ROWS(ps
),
1158 HEADER_ROWS(ps
) + ps
->ttyo
->screen_rows
- (HEADER_ROWS(ps
)+ FOOTER_ROWS(ps
)));
1160 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,"%s", _("Certificate Information"));
1161 gf_puts_uline(tmp_20k_buf
, view_writec
);
1162 gf_puts(NEWLINE
, view_writec
);
1163 print_separator_line(100, '-', view_writec
);
1165 output_cert_info(cert
, view_writec
);
1166 gf_puts(NEWLINE
, view_writec
);
1168 if(smime_validate_cert(cert
, &error
) < 0){
1169 const char *errorp
= X509_verify_cert_error_string(error
);
1170 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,_("Error validating certificate: %s"), errorp
);
1172 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "%s", _("Certificate validated without errors"));
1174 gf_puts_uline(tmp_20k_buf
, view_writec
);
1175 gf_puts(NEWLINE
, view_writec
);
1177 if(out
!= NULL
){ /* print private key information */
1178 unsigned char ch
[2];
1180 gf_puts(NEWLINE
, view_writec
);
1182 while(BIO_read(out
, ch
, 1) >= 1)
1183 gf_puts((char *)ch
, view_writec
);
1184 gf_puts(NEWLINE
, view_writec
);
1185 q_status_message1(SM_ORDER
, 1, 3, _("%s information shown at bottom of certificate information"), pub_cert
? _("Public") : _("Private"));
1189 view_writec_destroy();
1193 memset(&scrollargs
, 0, sizeof(SCROLL_S
));
1195 scrollargs
.text
.text
= so_text(store
);
1196 scrollargs
.text
.src
= CharStar
;
1197 scrollargs
.text
.desc
= "certificate information";
1198 scrollargs
.body_valid
= 1;
1200 if(offset
){ /* resize? preserve paging! */
1201 scrollargs
.start
.on
= Offset
;
1202 scrollargs
.start
.loc
.offset
= offset
;
1203 scrollargs
.body_valid
= 0;
1207 scrollargs
.use_indexline_color
= 1;
1209 scrollargs
.bar
.title
= _("CERTIFICATE INFORMATION");
1210 scrollargs
.proc
.tool
= manage_certificate_info_tool
;
1211 scrollargs
.resize_exit
= 1;
1212 scrollargs
.help
.text
= h_certificate_information
;
1213 scrollargs
.help
.title
= _("HELP FOR MESSAGE TEXT VIEW");
1214 scrollargs
.keys
.what
= FirstMenu
;
1215 scrollargs
.keys
.menu
= &smime_certificate_info_keymenu
;
1216 setbitmap(scrollargs
.keys
.bitmap
);
1217 if(ctype
!= Public
|| error
!= X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT
)
1218 /*error != X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)*/
1219 clrbitn(TRUST_KEY
, scrollargs
.keys
.bitmap
);
1220 if(ctype
!= Private
){
1221 clrbitn(PUBLIC_KEY
, scrollargs
.keys
.bitmap
);
1222 clrbitn(PRIVATE_KEY
, scrollargs
.keys
.bitmap
);
1224 if(ctype
== Password
){
1225 clrbitn(DELETE_CERT_KEY
, scrollargs
.keys
.bitmap
);
1226 clrbitn(UNDELETE_CERT_KEY
, scrollargs
.keys
.bitmap
);
1229 cmd
= scrolltool(&scrollargs
);
1234 case MC_PUBLIC
: if(scrollargs
.start
.on
== Offset
)
1235 offset
= scrollargs
.start
.loc
.offset
;
1241 } while (cmd
!= MC_EXIT
);
1242 ps
->mangled_screen
= 1;
1246 * This is silly, we just need this function so that we can tell scrolltool
1247 * that some commands are recognized. We use scrolltool because we do not
1248 * want to rewrite output_cert_info.
1251 manage_certificate_info_tool(int cmd
, MSGNO_S
*msgmap
, SCROLL_S
*sparms
)
1259 case MC_TRUST
: rv
= 1; break;
1260 default: rv
= 0; break;
1267 manage_certs_tool(struct pine
*ps
, int cmd
, CONF_S
**cl
, unsigned flags
)
1271 WhichCerts ctype
= (*cl
)->d
.s
.ctype
;
1274 case MC_ADD
: /* create a self signed certificate and import it */
1275 if(ctype
== Password
){
1277 char pathdir
[MAXPATH
+1], filename
[MAXPATH
+1];
1280 smime_path(DF_SMIMETMPDIR
, pathdir
, sizeof(pathdir
));
1281 if(((st
= our_stat(pathdir
, &sbuf
)) == 0
1282 && (sbuf
.st_mode
& S_IFMT
) == S_IFDIR
)
1284 && can_access(pathdir
, ACCESS_EXISTS
) != 0
1285 && our_mkpath(pathdir
, 0700) == 0)){
1286 pc
= ALPINE_self_signed_certificate(NULL
, 0, pathdir
, MASTERNAME
);
1287 if(strlen(pathdir
) + strlen(MASTERNAME
) + 5 + 1 > sizeof(filename
)){
1288 q_status_message(SM_ORDER
, 0, 2,
1289 _("pathdir for key too long"));
1292 snprintf(filename
, sizeof(filename
), "%.*s/%.*s.key",
1293 (int) strlen(pathdir
), pathdir
,
1294 (int) (sizeof(filename
) - strlen(MASTERNAME
) - 5 - 1), MASTERNAME
);
1295 filename
[sizeof(filename
)-1] = '\0';
1296 rv
= import_certificate(ctype
, pc
, filename
);
1298 ps
->keyemptypwd
= 0;
1299 if(our_stat(pathdir
, &sbuf
) == 0){
1300 if(unlink(filename
) < 0)
1301 q_status_message1(SM_ORDER
, 0, 2,
1302 _("Could not remove private key %s.key"), MASTERNAME
);
1303 filename
[strlen(filename
)-4] = '\0';
1304 strcat(filename
, ".crt");
1305 if(unlink(filename
) < 0)
1306 q_status_message1(SM_ORDER
, 0, 2,
1307 _("Could not remove public certificate %s.crt"), MASTERNAME
);
1308 if(rmdir(pathdir
) < 0)
1309 q_status_message1(SM_ORDER
, 0, 2,
1310 _("Could not remove temporary directory %s"), pathdir
);
1315 rv
= 10; /* forces redraw */
1320 if(PATHCERTDIR(ctype
) == NULL
)
1323 if((cert
= get_cert_for((*cl
)->d
.s
.address
, ctype
, 0)) == NULL
){
1324 q_status_message(SM_ORDER
, 1, 3, _("Problem Reading Certificate"));
1328 display_certificate_information(ps
, cert
, (*cl
)->d
.s
.address
, ctype
, (*cl
)->varmem
);
1329 rv
= 10 + (*cl
)->varmem
;
1334 if(ctype
== Password
){
1335 EVP_PKEY
*key
= NULL
;
1336 PERSONAL_CERT
*pc
= (PERSONAL_CERT
*) ps
->pwdcert
;
1338 const EVP_CIPHER
*enc
= NULL
;
1341 char filename
[MAXPATH
+1];
1342 char passwd
[MAILTMPLEN
];
1343 char prompt
[MAILTMPLEN
];
1345 if (pc
!= NULL
&& pc
->key
!= NULL
){
1346 strncpy(prompt
, _("Enter password to unlock key: "), sizeof(prompt
));
1347 prompt
[sizeof(prompt
)-1] = '\0';
1350 rv
= alpine_get_password(prompt
, passwd
, sizeof(passwd
));
1353 q_status_message(SM_ORDER
, 1, 3, _("Password deletion cancelled"));
1355 snprintf(filename
, sizeof(filename
), "%s/%s.key", ps
->pwdcertdir
, pc
->name
);
1356 filename
[sizeof(filename
)-1] = '\0';
1357 if((in
= BIO_new_file(filename
, "r")) != NULL
){
1358 key
= PEM_read_bio_PrivateKey(in
, NULL
, NULL
, passwd
);
1360 if((rsa
= EVP_PKEY_get1_RSA(key
)) != NULL
1361 && (out
= BIO_new(BIO_s_file())) != NULL
1362 && BIO_write_filename(out
, filename
) > 0
1363 && PEM_write_bio_RSAPrivateKey(out
, rsa
, enc
, NULL
, 0, NULL
, passwd
) > 0){
1364 q_status_message(SM_ORDER
, 1, 3, _("Password Removed from private key"));
1365 ps
->keyemptypwd
= 1;
1372 q_status_message(SM_ORDER
, 1, 3, _("Failed to unlock private key"));
1380 q_status_message(SM_ORDER
, 1, 3, _("Failed to remove password from private key"));
1381 rv
+= 10; /* forces redraw */
1391 if ((*cl
)->d
.s
.deleted
!= 0)
1392 q_status_message(SM_ORDER
, 1, 3, _("Certificate already deleted"));
1394 (*cl
)->d
.s
.deleted
= 1;
1395 rv
= 10 + (*cl
)->varmem
; /* forces redraw */
1396 mark_cert_deleted(ctype
, (*cl
)->varmem
, 1);
1397 q_status_message(SM_ORDER
, 1, 3, _("Certificate marked deleted"));
1403 if ((*cl
)->d
.s
.deleted
== 0)
1404 q_status_message(SM_ORDER
, 1, 3, _("Certificate not marked deleted"));
1406 (*cl
)->d
.s
.deleted
= 0;
1407 mark_cert_deleted(ctype
, (*cl
)->varmem
, 0);
1408 rv
= 10 + (*cl
)->varmem
; /* forces redraw */
1409 q_status_message(SM_ORDER
, 1, 3, _("Certificate marked UNdeleted"));
1416 for(cl
= DATACERT(ctype
); cl
!= NULL
&& DELETEDCERT(cl
) == 0; cl
= cl
->next
);
1417 if(cl
!= NULL
&& DELETEDCERT(cl
) != 0){
1418 smime_expunge_cert(ctype
);
1419 rv
= 10; /* forces redraw */
1422 q_status_message(SM_ORDER
, 3, 3, _("No certificates marked deleted"));
1428 rv
= import_certificate(ctype
, NULL
, NULL
);
1433 cmd_cancelled("Import certificate");
1437 q_status_message1(SM_ORDER
, 0, 2, _("Can't import certificate outside of %s"),
1438 ps_global
->VAR_OPER_DIR
);
1442 rv
= 10; /* forces redraw */
1446 rv
= config_exit_cmd(flags
);
1459 smime_setup_size(char **s
, size_t buflen
, size_t n
)
1465 snprintf(t
, buflen
-3, "%zu.%zu", n
, n
);
1474 manage_password_file_certificates(struct pine
*ps
)
1476 OPT_SCREEN_S screen
;
1477 int readonly_warning
= 0, rv
= 10, fline
, state
= 0;
1479 dprint((9, "manage_password_file_certificates"));
1480 ps
->next_screen
= SCREEN_FUN_NULL
;
1481 ps
->keyemptypwd
= 0; /* just in case */
1484 CONF_S
*ctmp
= NULL
, *first_line
= NULL
;
1486 fline
= rv
>= 10 ? rv
- 10 : 0;
1488 smime_manage_password_file_certs_init(ps
, &ctmp
, &first_line
, fline
, &state
);
1491 ps
->mangled_screen
= 1;
1492 q_status_message(SM_ORDER
, 1, 3, _("Failed to initialize password management screen (no key)"));
1496 memset(&screen
, 0, sizeof(screen
));
1497 screen
.deferred_ro_warning
= readonly_warning
;
1499 rv
= conf_scroll_screen(ps
, &screen
, first_line
,
1500 _("MANAGE PASSWORD FILE CERTS"),
1501 /* TRANSLATORS: Print something1 using something2.
1502 configuration is something1 */
1503 _("configuration"), 0, NULL
);
1506 ps
->mangled_screen
= 1;
1507 ps
->keyemptypwd
= 0; /* reset this so it will not confuse other routines */
1511 /* state: 0 = first time,
1512 * 1 = second or another time
1515 smime_manage_password_file_certs_init(struct pine
*ps
, CONF_S
**ctmp
, CONF_S
**first_line
, int fline
, int *state
)
1520 void *pwdcert
= NULL
; /* this is our current password file */
1521 char filename
[MAXPATH
+1];
1523 EVP_PKEY
*key
= NULL
;
1526 if(*state
== 0){ /* first time around? */
1527 setup_pwdcert(&pwdcert
);
1528 if(pwdcert
== NULL
) return;
1529 if(ps
->pwdcert
== NULL
)
1530 ps
->pwdcert
= pwdcert
;
1532 free_personal_certs((PERSONAL_CERT
**) &pwdcert
);
1536 pc
= (PERSONAL_CERT
*) ps_global
->pwdcert
;
1537 snprintf(filename
, sizeof(filename
), "%s/%s.key", ps
->pwdcertdir
, pc
->name
);
1538 filename
[sizeof(filename
)-1] = '\0';
1539 if((in
= BIO_new_file(filename
, "r")) != NULL
1540 && (key
= PEM_read_bio_PrivateKey(in
, NULL
, NULL
, "")) != NULL
)
1541 ps
->keyemptypwd
= 1;
1547 ps
->pwdcertlist
= cl
= smime_X509_to_cert_info(X509_dup(pc
->cert
), pc
->name
);
1549 for(i
= 0; i
< sizeof(tmp
) && i
< (ps
->ttyo
? ps
->ttyo
->screen_cols
: sizeof(tmp
)); i
++)
1554 (*ctmp
)->flags
|= CF_NOSELECT
;
1555 (*ctmp
)->value
= cpystr(tmp
);
1558 (*ctmp
)->flags
|= CF_NOSELECT
;
1559 (*ctmp
)->value
= cpystr(_("Manage Certificates and Keys Used to Encrypt your Password File"));
1562 (*ctmp
)->flags
|= CF_NOSELECT
;
1563 (*ctmp
)->value
= cpystr(tmp
);
1566 (*ctmp
)->flags
|= CF_NOSELECT
| CF_B_LINE
;
1569 int s
, e
, df
, dt
, md5
; /* sizes of certain fields */
1570 int nf
; /* number of fields */
1571 char u
[MAILTMPLEN
], *t
;
1573 e
= MIN(strlen(cl
->name
), ps
->ttyo
->screen_cols
/3); /* do not use too much screen */
1574 nf
= 5; /* there are 5 fields */
1575 s
= 3; /* status has fixed size */
1576 df
= dt
= 10; /* date from and date to have fixed size */
1577 md5
= ps
->ttyo
->screen_cols
- s
- df
- dt
- e
- (nf
- 1);
1580 smime_setup_size(&t
, sizeof(u
), s
);
1581 smime_setup_size(&t
, sizeof(u
) - strlen(t
), e
);
1582 smime_setup_size(&t
, sizeof(u
) - strlen(t
), df
);
1583 *t
++ = ' '; /* leave an extra space between dates */
1584 *t
= '\0'; /* make valgrind happy */
1585 smime_setup_size(&t
, sizeof(u
) - strlen(t
), dt
);
1586 *t
++ = ' '; /* and another space between date and md5 sum */
1587 *t
= '\0'; /* make valgrind happy again */
1588 smime_setup_size(&t
, sizeof(u
) - strlen(t
), md5
);
1589 *t
= '\0'; /* tie off */
1592 (*ctmp
)->flags
|= CF_NOSELECT
;
1593 (*ctmp
)->value
= cpystr(_("New Public Certificate and Key:"));
1596 (*ctmp
)->d
.s
.ctype
= Password
;
1597 (*ctmp
)->help
= h_config_smime_password_file_certificates
;
1598 (*ctmp
)->tool
= manage_certs_tool
;
1599 (*ctmp
)->keymenu
= &config_smime_add_new_key_keymenu
;
1601 for(i
= 0; i
< s
; i
++) tmp
[i
] = ' ';
1603 strncpy(tmp
+s
, _("Press \"RETURN\" to add new personal key"), sizeof(tmp
)-s
-1);
1604 for(i
= strlen(tmp
); i
< (ps
->ttyo
? ps
->ttyo
->screen_cols
: sizeof(tmp
) - 1); i
++)
1607 (*ctmp
)->value
= cpystr(tmp
);
1608 *first_line
= *ctmp
;
1611 (*ctmp
)->flags
|= CF_NOSELECT
| CF_B_LINE
;
1614 (*ctmp
)->flags
|= CF_NOSELECT
;
1615 (*ctmp
)->value
= cpystr(_("Current Public Certificate and Key:"));
1618 (*ctmp
)->d
.s
.ctype
= Password
;
1619 (*ctmp
)->d
.s
.deleted
= 0;
1620 (*ctmp
)->help
= h_config_smime_password_file_certificates
;
1621 (*ctmp
)->tool
= manage_certs_tool
;
1622 (*ctmp
)->keymenu
= ps
->keyemptypwd
== 0
1623 ? &config_smime_manage_view_cert_keymenu
1624 : &config_smime_manage_view_cert_keymenu_no_delete
;
1625 (*ctmp
)->varmem
= 0;
1626 strncpy((*ctmp
)->d
.s
.address
, cl
->name
, sizeof((*ctmp
)->d
.s
.address
));
1627 (*ctmp
)->d
.s
.address
[sizeof((*ctmp
)->d
.s
.address
) - 1] = '\0';
1628 snprintf(tmp
, sizeof(tmp
), u
,
1629 (*ctmp
)->d
.s
.deleted
? "D" : " ",
1631 DATEFROMCERT(cl
), DATETOCERT(cl
), MD5CERT(cl
));
1632 (*ctmp
)->value
= cpystr(tmp
);
1635 #endif /* PASSFILE */
1639 smime_manage_certs_init(struct pine
*ps
, CONF_S
**ctmp
, CONF_S
**first_line
, WhichCerts ctype
, int fline
)
1647 data
= DATACERT(ctype
);
1648 // ext = EXTCERT(ctype);
1650 if(data
== NULL
|| RENEWCERT(data
))
1651 renew_cert_data(&data
, ctype
);
1653 for(i
= 0; i
< sizeof(tmp
) && i
< (ps
->ttyo
? ps
->ttyo
->screen_cols
: sizeof(tmp
)); i
++)
1658 (*ctmp
)->flags
|= CF_NOSELECT
;
1659 (*ctmp
)->value
= cpystr(tmp
);
1661 (*ctmp
)->keymenu
= &config_text_keymenu
;
1664 (*ctmp
)->flags
|= CF_NOSELECT
;
1665 sprintf(tmp
, _("List of %s certificates"), ctype
== Public
? _("public")
1666 : (ctype
== Private
? _("private")
1667 : (ctype
== CACert
? _("certificate authority") : "unknown (?)")));
1668 (*ctmp
)->value
= cpystr(tmp
);
1670 for(i
= 0; i
< sizeof(tmp
) && i
< (ps
->ttyo
? ps
->ttyo
->screen_cols
: sizeof(tmp
)); i
++)
1675 (*ctmp
)->flags
|= CF_NOSELECT
;
1676 (*ctmp
)->value
= cpystr(tmp
);
1679 (*ctmp
)->flags
|= CF_NOSELECT
| CF_B_LINE
;
1682 CertList
*cl
; int i
;
1683 int s
, e
, df
, dt
, md5
; /* sizes of certain fields */
1684 int nf
; /* number of fields */
1685 char u
[MAILTMPLEN
], *t
;
1687 for(cl
= data
, e
= 0; cl
; cl
= cl
->next
)
1688 if(cl
->name
&& strlen(cl
->name
) > e
)
1689 e
= strlen(cl
->name
);
1691 if(ctype
!= Private
&& SMHOLDERTYPE(ctype
) == Directory
)
1692 e
-= 4; /* remove extension length */
1693 e
= MIN(e
, ps
->ttyo
->screen_cols
/3); /* do not use too much screen */
1694 nf
= 5; /* there are 5 fields */
1695 s
= 3; /* status has fixed size */
1696 df
= dt
= 10; /* date from and date to have fixed size */
1697 md5
= ps
->ttyo
->screen_cols
- s
- df
- dt
- e
- (nf
- 1);
1700 smime_setup_size(&t
, sizeof(u
), s
);
1701 smime_setup_size(&t
, sizeof(u
) - strlen(t
), e
);
1702 smime_setup_size(&t
, sizeof(u
) - strlen(t
), df
);
1703 *t
++ = ' '; /* leave an extra space between dates */
1704 *t
= '\0'; /* make valgrind happy */
1705 smime_setup_size(&t
, sizeof(u
) - strlen(t
), dt
);
1706 *t
++ = ' '; /* and another space between date and md5 sum */
1707 *t
= '\0'; /* make valgrind happy again */
1708 smime_setup_size(&t
, sizeof(u
) - strlen(t
), md5
);
1709 *t
= '\0'; /* tie off */
1711 for(cl
= data
, i
= 0; cl
; cl
= cl
->next
)
1714 (*ctmp
)->d
.s
.ctype
= ctype
;
1715 (*ctmp
)->d
.s
.deleted
= get_cert_deleted(ctype
, i
);
1716 (*ctmp
)->tool
= manage_certs_tool
;
1717 (*ctmp
)->keymenu
= &config_smime_manage_certs_work_keymenu
;
1718 (*ctmp
)->varmem
= i
++;
1719 (*ctmp
)->help
= ctype
== Public
? h_config_smime_manage_public_menu
1720 : (ctype
== Private
? h_config_smime_manage_private_menu
1721 : h_config_smime_manage_cacerts_menu
);
1722 if(ctype
!= Private
&& SMHOLDERTYPE(ctype
) == Directory
)
1723 cl
->name
[strlen(cl
->name
) - 4] = '\0'; /* FIX FIX FIX */
1724 strncpy((*ctmp
)->d
.s
.address
, cl
->name
, sizeof((*ctmp
)->d
.s
.address
));
1725 (*ctmp
)->d
.s
.address
[sizeof((*ctmp
)->d
.s
.address
) - 1] = '\0';
1726 snprintf(tmp
, sizeof(tmp
), u
,
1727 (*ctmp
)->d
.s
.deleted
? "D" : " ",
1728 ctype
== CACert
? cl
->cn
: cl
->name
,
1729 DATEFROMCERT(cl
), DATETOCERT(cl
), MD5CERT(cl
));
1730 if(ctype
!= Private
&& SMHOLDERTYPE(ctype
) == Directory
)
1731 cl
->name
[strlen(cl
->name
)] = '.';
1732 (*ctmp
)->value
= cpystr(tmp
);
1733 if(i
== fline
+1 && first_line
&& !*first_line
)
1734 *first_line
= *ctmp
;
1739 (*ctmp
)->d
.s
.ctype
= ctype
;
1740 (*ctmp
)->tool
= manage_certs_tool
;
1741 (*ctmp
)->keymenu
= &config_smime_add_certs_keymenu
;
1742 (*ctmp
)->value
= cpystr(_(" \tNo certificates found, press \"RETURN\" to add one."));
1743 if(first_line
&& !*first_line
)
1744 *first_line
= *ctmp
;
1749 manage_certificates(struct pine
*ps
, WhichCerts ctype
)
1751 OPT_SCREEN_S screen
;
1752 int readonly_warning
= 0, rv
= 10, fline
;
1754 dprint((9, "manage_certificates(ps, %s)", ctype
== Public
? _("Public") : (ctype
== Private
? _("Private") : (ctype
== CACert
? _("certificate authority") : _("unknown")))));
1755 ps
->next_screen
= SCREEN_FUN_NULL
;
1758 CONF_S
*ctmp
= NULL
, *first_line
= NULL
;
1760 fline
= rv
>= 10 ? rv
- 10 : 0;
1764 smime_manage_certs_init(ps
, &ctmp
, &first_line
, ctype
, fline
);
1767 ps
->mangled_screen
= 1;
1772 memset(&screen
, 0, sizeof(screen
));
1773 screen
.deferred_ro_warning
= readonly_warning
;
1774 rv
= conf_scroll_screen(ps
, &screen
, first_line
,
1775 _("MANAGE CERTIFICATES"),
1776 /* TRANSLATORS: Print something1 using something2.
1777 configuration is something1 */
1778 _("configuration"), 0, NULL
);
1781 ps
->mangled_screen
= 1;
1786 smime_helper_tool(struct pine
*ps
, int cmd
, CONF_S
**cl
, unsigned flags
)
1792 switch((*cl
)->varmem
){
1794 rv
= copy_publiccert_dir_to_container();
1796 q_status_message(SM_ORDER
, 1, 3, _("Public certs transferred to container"));
1798 q_status_message(SM_ORDER
, 3, 3, _("Problem transferring certs"));
1805 rv
= copy_publiccert_container_to_dir();
1807 q_status_message(SM_ORDER
, 1, 3, _("Public certs transferred to directory, delete Container config to use"));
1809 q_status_message(SM_ORDER
, 3, 3, _("Problem transferring certs"));
1816 rv
= copy_privatecert_dir_to_container();
1818 q_status_message(SM_ORDER
, 1, 3, _("Private keys transferred to container"));
1820 q_status_message(SM_ORDER
, 3, 3, _("Problem transferring certs"));
1827 rv
= copy_privatecert_container_to_dir();
1829 q_status_message(SM_ORDER
, 1, 3, _("Private keys transferred to directory, delete Container config to use"));
1831 q_status_message(SM_ORDER
, 3, 3, _("Problem transferring certs"));
1838 rv
= copy_cacert_dir_to_container();
1840 q_status_message(SM_ORDER
, 1, 3, _("CA certs transferred to container"));
1842 q_status_message(SM_ORDER
, 3, 3, _("Problem transferring certs"));
1849 rv
= copy_cacert_container_to_dir();
1851 q_status_message(SM_ORDER
, 1, 3, _("CA certs transferred to directory, delete Container config to use"));
1853 q_status_message(SM_ORDER
, 3, 3, _("Problem transferring certs"));
1859 #ifdef APPLEKEYCHAIN
1861 rv
= copy_publiccert_container_to_keychain();
1863 q_status_message(SM_ORDER
, 1, 3, _("Public certs transferred to keychain"));
1865 q_status_message(SM_ORDER
, 3, 3, _("Command not implemented yet"));
1872 rv
= copy_publiccert_keychain_to_container();
1874 q_status_message(SM_ORDER
, 1, 3, _("Public certs transferred to container"));
1876 q_status_message(SM_ORDER
, 3, 3, _("Command not implemented yet"));
1881 #endif /* APPLEKEYCHAIN */
1883 case 9: manage_certificates(ps
, Public
) ; break;
1884 case 10: manage_certificates(ps
, Private
); break;
1885 case 11: manage_certificates(ps
, CACert
) ; break;
1888 case 12: manage_password_file_certificates(ps
); break;
1889 #endif /* PASSFILE */
1899 rv
= config_exit_cmd(flags
);
1903 rv
= import_certificate((*cl
)->d
.s
.ctype
, NULL
, NULL
);
1916 * Compare saved user_val with current user_val to see if it changed.
1917 * If any have changed, change it back and take the appropriate action.
1920 revert_to_saved_smime_config(struct pine
*ps
, SAVED_CONFIG_S
*vsave
)
1922 struct variable
*vreal
;
1926 char *pval
, **apval
, **lval
, ***alval
;
1929 for(vreal
= ps
->vars
; vreal
->name
; vreal
++,v
++){
1930 if(!(smime_related_var(ps
, vreal
) || vreal
==&ps
->vars
[V_FEATURE_LIST
]))
1934 lval
= LVAL(vreal
, ew
);
1935 alval
= ALVAL(vreal
, ew
);
1937 if((v
->saved_user_val
.l
&& !lval
)
1938 || (!v
->saved_user_val
.l
&& lval
))
1940 else if(!v
->saved_user_val
.l
&& !lval
)
1941 ;/* no change, nothing to do */
1943 for(i
= 0; v
->saved_user_val
.l
[i
] || lval
[i
]; i
++)
1944 if((v
->saved_user_val
.l
[i
]
1946 || strcmp(v
->saved_user_val
.l
[i
], lval
[i
])))
1948 (!v
->saved_user_val
.l
[i
] && lval
[i
])){
1958 free_list_array(alval
);
1960 /* copy back the original one */
1961 if(v
->saved_user_val
.l
){
1962 list
= v
->saved_user_val
.l
;
1964 /* count how many */
1968 *alval
= (char **)fs_get((n
+1) * sizeof(char *));
1970 for(i
= 0; i
< n
; i
++)
1971 (*alval
)[i
] = cpystr(v
->saved_user_val
.l
[i
]);
1979 pval
= PVAL(vreal
, ew
);
1980 apval
= APVAL(vreal
, ew
);
1982 if((v
->saved_user_val
.p
&&
1983 (!pval
|| strcmp(v
->saved_user_val
.p
, pval
))) ||
1984 (!v
->saved_user_val
.p
&& pval
)){
1985 /* It changed, fix it */
1988 /* free the changed value */
1990 fs_give((void **)apval
);
1992 if(v
->saved_user_val
.p
)
1993 *apval
= cpystr(v
->saved_user_val
.p
);
1999 if(vreal
== &ps
->vars
[V_FEATURE_LIST
])
2000 set_feature_list_current_val(vreal
);
2002 set_current_val(vreal
, TRUE
, FALSE
);
2004 fix_side_effects(ps
, vreal
, 1);
2011 save_smime_config_vars(struct pine
*ps
)
2013 struct variable
*vreal
;
2014 SAVED_CONFIG_S
*vsave
, *v
;
2016 vsave
= (SAVED_CONFIG_S
*)fs_get((V_LAST_VAR
+1)*sizeof(SAVED_CONFIG_S
));
2017 memset((void *)vsave
, 0, (V_LAST_VAR
+1)*sizeof(SAVED_CONFIG_S
));
2018 for(v
= vsave
, vreal
= ps
->vars
; vreal
->name
; vreal
++,v
++){
2019 if(!(smime_related_var(ps
, vreal
) || vreal
==&ps
->vars
[V_FEATURE_LIST
]))
2026 if(LVAL(vreal
, ew
)){
2027 /* count how many */
2029 list
= LVAL(vreal
, ew
);
2033 v
->saved_user_val
.l
= (char **)fs_get((n
+1)*sizeof(char *));
2034 memset((void *)v
->saved_user_val
.l
, 0, (n
+1)*sizeof(char *));
2035 for(i
= 0; i
< n
; i
++)
2036 v
->saved_user_val
.l
[i
] = cpystr(list
[i
]);
2038 v
->saved_user_val
.l
[n
] = NULL
;
2043 v
->saved_user_val
.p
= cpystr(PVAL(vreal
, ew
));
2052 free_saved_smime_config(struct pine
*ps
, SAVED_CONFIG_S
**vsavep
)
2054 struct variable
*vreal
;
2057 if(vsavep
&& *vsavep
){
2058 for(v
= *vsavep
, vreal
= ps
->vars
; vreal
->name
; vreal
++,v
++){
2059 if(!(smime_related_var(ps
, vreal
) || vreal
==&ps
->vars
[V_FEATURE_LIST
]))
2062 if(vreal
->is_list
){ /* free saved_user_val.l */
2063 if(v
&& v
->saved_user_val
.l
)
2064 free_list_array(&v
->saved_user_val
.l
);
2066 else if(v
&& v
->saved_user_val
.p
)
2067 fs_give((void **)&v
->saved_user_val
.p
);
2070 fs_give((void **)vsavep
);