* New version 2.20.11
[alpine.git] / alpine / smime.c
blob4cfdeae84af7fa9f672b440f6d0129a08bbfb597
1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: smime.c 1074 2008-06-04 00:08:43Z hubert@u.washington.edu $";
3 #endif
5 /*
6 * ========================================================================
7 * Copyright 2013-2016 Eduardo Chappa
8 * Copyright 2008 University of Washington
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
20 * This is based on a contribution from Jonathan Paisley
22 * File: smime.c
23 * Author: paisleyj@dcs.gla.ac.uk
24 * Date: 01/2001
28 #include "headers.h"
30 #ifdef SMIME
32 #include "../pith/charconv/utf8.h"
33 #include "../pith/status.h"
34 #include "../pith/store.h"
35 #include "../pith/conf.h"
36 #include "../pith/list.h"
37 #include "../pith/mailcmd.h"
38 #include "../pith/tempfile.h"
39 #include "radio.h"
40 #include "keymenu.h"
41 #include "mailview.h"
42 #include "conftype.h"
43 #include "confscroll.h"
44 #include "setup.h"
45 #include "smime.h"
47 /* internal prototypes */
48 void format_smime_info(int pass, BODY *body, long msgno, gf_io_t pc);
49 void print_separator_line(int percent, int ch, gf_io_t pc);
50 void output_cert_info(X509 *cert, gf_io_t pc);
51 void output_X509_NAME(X509_NAME *name, gf_io_t pc);
52 void side_by_side(STORE_S *left, STORE_S *right, gf_io_t pc);
53 STORE_S *wrap_store(STORE_S *in, int width);
54 void smime_config_init_display(struct pine *, CONF_S **, CONF_S **);
55 void revert_to_saved_smime_config(struct pine *ps, SAVED_CONFIG_S *vsave);
56 SAVED_CONFIG_S *save_smime_config_vars(struct pine *ps);
57 void free_saved_smime_config(struct pine *ps, SAVED_CONFIG_S **vsavep);
58 int smime_helper_tool(struct pine *, int, CONF_S **, unsigned);
59 //int smime_public_certs_tool(struct pine *, int, CONF_S **, unsigned);
60 void manage_certificates(struct pine *, WhichCerts);
61 void smime_manage_certs_init (struct pine *, CONF_S **, CONF_S **, WhichCerts, int);
62 void display_certificate_information(struct pine *, X509 *, char *, WhichCerts, int num);
63 int manage_certs_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned flags);
64 int manage_certificate_info_tool(int, MSGNO_S *, SCROLL_S *);
65 void smime_setup_size(char **, size_t, size_t);
69 * prompt the user for their passphrase
70 * (possibly prompting with the email address in s_passphrase_emailaddr)
72 int
73 smime_get_passphrase(void)
75 int rc;
76 int flags;
77 char prompt[500];
78 HelpType help = NO_HELP;
80 assert(ps_global->smime != NULL);
81 snprintf(prompt, sizeof(prompt),
82 _("Enter passphrase for <%s>: "), (ps_global->smime && ps_global->smime->passphrase_emailaddr) ? ps_global->smime->passphrase_emailaddr[0] : "unknown");
84 do {
85 flags = OE_PASSWD | OE_DISALLOW_HELP;
86 ((char *) ps_global->smime->passphrase)[0] = '\0';
87 rc = optionally_enter((char *) ps_global->smime->passphrase,
88 -FOOTER_ROWS(ps_global), 0,
89 sizeof(ps_global->smime->passphrase),
90 prompt, NULL, help, &flags);
91 } while (rc!=0 && rc!=1 && rc>0);
93 if(rc==0){
94 if(ps_global->smime)
95 ps_global->smime->entered_passphrase = 1;
98 return rc; /* better return rc and make the caller check its return value */
102 smime_check(BODY *body)
104 int rv = 0;
105 PKCS7 *p7 = NULL;
107 if(body->type == TYPEMULTIPART){
108 PART *p;
110 for(p=body->nested.part; p && rv == 0; p=p->next)
111 rv += smime_check(&p->body);
113 if(rv > 0) return rv;
114 if(body->sparep)
115 p7 = get_smime_sparep_type(body->sparep) == P7Type
116 ? (PKCS7 *)get_smime_sparep_data(body->sparep)
117 : NULL;
118 if(p7 && (PKCS7_type_is_signed(p7) || PKCS7_type_is_enveloped(p7)))
119 rv += 1;
120 return rv;
124 void
125 display_smime_info(struct pine *ps, ENVELOPE *env, BODY *body)
127 OtherMenu what = FirstMenu;
128 HANDLE_S *handles = NULL;
129 SCROLL_S scrollargs;
130 STORE_S *store = NULL;
131 long msgno;
132 int offset = 0;
134 msgno = mn_m2raw(ps->msgmap, mn_get_cur(ps->msgmap));
135 store = so_get(CharStar, NULL, EDIT_ACCESS);
137 while(ps->next_screen == SCREEN_FUN_NULL){
139 ClearLine(1);
141 so_truncate(store, 0);
143 view_writec_init(store, &handles, HEADER_ROWS(ps),
144 HEADER_ROWS(ps) +
145 ps->ttyo->screen_rows - (HEADER_ROWS(ps)
146 + HEADER_ROWS(ps)));
148 gf_puts_uline("Overview", view_writec);
149 gf_puts(NEWLINE, view_writec);
151 format_smime_info(1, body, msgno, view_writec);
152 gf_puts(NEWLINE, view_writec);
153 format_smime_info(2, body, msgno, view_writec);
155 view_writec_destroy();
157 ps->next_screen = SCREEN_FUN_NULL;
159 memset(&scrollargs, 0, sizeof(SCROLL_S));
160 scrollargs.text.text = so_text(store);
161 scrollargs.text.src = CharStar;
162 scrollargs.text.desc = "S/MIME information";
163 scrollargs.body_valid = 1;
165 if(offset){ /* resize? preserve paging! */
166 scrollargs.start.on = Offset;
167 scrollargs.start.loc.offset = offset;
168 offset = 0L;
171 scrollargs.bar.title = "S/MIME INFORMATION";
172 /* scrollargs.end_scroll = view_end_scroll; */
173 scrollargs.resize_exit = 1;
174 scrollargs.help.text = NULL;
175 scrollargs.help.title = "HELP FOR S/MIME INFORMATION VIEW";
176 scrollargs.keys.menu = &smime_info_keymenu;
177 scrollargs.keys.what = what;
178 setbitmap(scrollargs.keys.bitmap);
180 if(scrolltool(&scrollargs) == MC_RESIZE)
181 offset = scrollargs.start.loc.offset;
184 so_give(&store);
187 void
188 smime_info_screen(struct pine *ps)
190 long msgno;
191 BODY *body;
192 ENVELOPE *env;
194 /* ps->prev_screen = smime_info_screen;
195 ps->next_screen = SCREEN_FUN_NULL; */
197 msgno = mn_m2raw(ps->msgmap, mn_get_cur(ps->msgmap));
199 env = mail_fetch_structure(ps->mail_stream, msgno, &body, 0);
201 if(!env || !body){
202 q_status_message(SM_ORDER, 0, 3,
203 _("Can't fetch body of message."));
204 return;
207 if(smime_check(body) == 0){
208 q_status_message(SM_ORDER | SM_DING, 0, 3,
209 _("Not a signed or encrypted message"));
210 return;
213 if(mn_total_cur(ps->msgmap) > 1L){
214 q_status_message(SM_ORDER | SM_DING, 0, 3,
215 _("Can only view one message's information at a time."));
216 return;
219 display_smime_info(ps, env, body);
223 void
224 format_smime_info(int pass, BODY *body, long msgno, gf_io_t pc)
226 PKCS7 *p7 = NULL;
227 int i;
229 if(body->type == TYPEMULTIPART){
230 PART *p;
232 for(p=body->nested.part; p; p=p->next)
233 format_smime_info(pass, &p->body, msgno, pc);
235 if(body->sparep)
236 p7 = get_smime_sparep_type(body->sparep) == P7Type
237 ? (PKCS7 *)get_smime_sparep_data(body->sparep)
238 : NULL;
239 if(p7){
241 if(PKCS7_type_is_signed(p7)){
242 STACK_OF(X509) *signers;
244 switch(pass){
245 case 1:
246 gf_puts(_("This message was cryptographically signed."), pc);
247 gf_puts(NEWLINE, pc);
248 break;
250 case 2:
251 signers = PKCS7_get0_signers(p7, NULL, 0);
253 if(signers){
255 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("Certificate%s used for signing"),
256 plural(sk_X509_num(signers)));
257 gf_puts_uline(tmp_20k_buf, pc);
258 gf_puts(NEWLINE, pc);
259 print_separator_line(100, '-', pc);
261 for(i=0; i<sk_X509_num(signers); i++){
262 X509 *x = sk_X509_value(signers, i);
264 if(x){
265 output_cert_info(x, pc);
266 gf_puts(NEWLINE, pc);
271 sk_X509_free(signers);
272 break;
276 else if(PKCS7_type_is_enveloped(p7)){
278 switch(pass){
279 case 1:
280 gf_puts(_("This message was encrypted."), pc);
281 gf_puts(NEWLINE, pc);
282 break;
284 case 2:
285 if(p7->d.enveloped && p7->d.enveloped->enc_data){
286 X509_ALGOR *alg = p7->d.enveloped->enc_data->algorithm;
287 STACK_OF(PKCS7_RECIP_INFO) *ris = p7->d.enveloped->recipientinfo;
288 int found = 0;
290 gf_puts(_("The algorithm used to encrypt was "), pc);
292 if(alg){
293 char *n = (char *) OBJ_nid2sn( OBJ_obj2nid(alg->algorithm));
295 gf_puts(n ? n : "<unknown>", pc);
298 else
299 gf_puts("<unknown>", pc);
301 gf_puts("." NEWLINE NEWLINE, pc);
303 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("Certificate%s for decrypting"),
304 plural(sk_PKCS7_RECIP_INFO_num(ris)));
305 gf_puts_uline(tmp_20k_buf, pc);
306 gf_puts(NEWLINE, pc);
307 print_separator_line(100, '-', pc);
309 for(i=0; i<sk_PKCS7_RECIP_INFO_num(ris); i++){
310 PKCS7_RECIP_INFO *ri;
311 PERSONAL_CERT *pcert;
313 ri = sk_PKCS7_RECIP_INFO_value(ris, i);
314 if(!ri)
315 continue;
317 pcert = find_certificate_matching_recip_info(ri);
319 if(pcert){
320 if(found){
321 print_separator_line(25, '*', pc);
322 gf_puts(NEWLINE, pc);
325 found = 1;
327 output_cert_info(pcert->cert, pc);
328 gf_puts(NEWLINE, pc);
333 if(!found){
334 gf_puts(_("No certificate capable of decrypting could be found."), pc);
335 gf_puts(NEWLINE, pc);
336 gf_puts(NEWLINE, pc);
340 break;
347 void
348 print_separator_line(int percent, int ch, gf_io_t pc)
350 int i, start, len;
352 len = ps_global->ttyo->screen_cols * percent / 100;
353 start = (ps_global->ttyo->screen_cols - len)/2;
355 for(i=0; i<start; i++)
356 pc(' ');
358 for(i=start; i<start+len; i++)
359 pc(ch);
361 gf_puts(NEWLINE, pc);
365 void
366 output_cert_info(X509 *cert, gf_io_t pc)
368 char buf[256];
369 STORE_S *left,*right;
370 gf_io_t spc;
371 int len, error;
372 STACK_OF(X509) *chain;
374 left = so_get(CharStar, NULL, EDIT_ACCESS);
375 right = so_get(CharStar, NULL, EDIT_ACCESS);
376 if(!(left && right))
377 return;
379 gf_set_so_writec(&spc, left);
381 if(!cert->cert_info){
382 gf_puts("Couldn't find certificate info.", spc);
383 gf_puts(NEWLINE, spc);
385 else{
386 gf_puts_uline("Certificate Owner", spc);
387 gf_puts(NEWLINE, spc);
389 output_X509_NAME(cert->cert_info->subject, spc);
390 gf_puts(NEWLINE, spc);
392 gf_puts_uline("Serial Number", spc);
393 gf_puts(NEWLINE, spc);
396 ASN1_INTEGER *bs;
397 long l;
398 const char *neg;
399 int i;
401 bs = X509_get_serialNumber(cert);
402 if (bs->length <= (int)sizeof(long)){
403 l = ASN1_INTEGER_get(bs);
404 if (bs->type == V_ASN1_NEG_INTEGER){
405 l = -l;
406 neg="-";
408 else
409 neg="";
410 snprintf(buf, sizeof(buf), " %s%lu (%s0x%lx)", neg, l, neg, l);
411 } else {
412 snprintf(buf, sizeof(buf), "%s", bs->type == V_ASN1_NEG_INTEGER ? "(Negative)" : "");
413 for (i = 0; i < bs->length; i++)
414 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%02x%s", bs->data[i],
415 i+1 == bs->length ? "" : ":");
418 gf_puts(buf, spc);
419 gf_puts(NEWLINE, spc);
420 gf_puts(NEWLINE, spc);
422 gf_puts_uline("Validity", spc);
423 gf_puts(NEWLINE, spc);
425 BIO *mb = BIO_new(BIO_s_mem());
426 char iobuf[4096];
428 gf_puts("Not Before: ", spc);
430 (void) BIO_reset(mb);
431 ASN1_UTCTIME_print(mb, cert->cert_info->validity->notBefore);
432 (void) BIO_flush(mb);
433 while((len = BIO_read(mb, iobuf, sizeof(iobuf))) > 0)
434 gf_nputs(iobuf, len, spc);
436 gf_puts(NEWLINE, spc);
438 gf_puts("Not After: ", spc);
440 (void) BIO_reset(mb);
441 ASN1_UTCTIME_print(mb, cert->cert_info->validity->notAfter);
442 (void) BIO_flush(mb);
443 while((len = BIO_read(mb, iobuf, sizeof(iobuf))) > 0)
444 gf_nputs(iobuf, len, spc);
446 gf_puts(NEWLINE, spc);
447 gf_puts(NEWLINE, spc);
449 BIO_free(mb);
453 gf_clear_so_writec(left);
455 gf_set_so_writec(&spc, right);
457 if(!cert->cert_info){
458 gf_puts(_("Couldn't find certificate info."), spc);
459 gf_puts(NEWLINE, spc);
461 else{
462 gf_puts_uline("Issuer", spc);
463 gf_puts(NEWLINE, spc);
465 output_X509_NAME(cert->cert_info->issuer, spc);
466 gf_puts(NEWLINE, spc);
469 gf_clear_so_writec(right);
471 side_by_side(left, right, pc);
473 gf_puts_uline("SHA1 Fingerprint", pc);
474 gf_puts(NEWLINE, pc);
475 get_fingerprint(cert, EVP_sha1(), buf, sizeof(buf), ":");
476 gf_puts(buf, pc);
477 gf_puts(NEWLINE, pc);
479 gf_puts_uline("MD5 Fingerprint", pc);
480 gf_puts(NEWLINE, pc);
481 get_fingerprint(cert, EVP_md5(), buf, sizeof(buf), ":");
482 gf_puts(buf, pc);
483 gf_puts(NEWLINE, pc);
484 gf_puts(NEWLINE, pc);
486 gf_puts_uline("Certificate Chain Information", pc);
487 gf_puts(NEWLINE, pc);
489 if((chain = get_chain_for_cert(cert, &error, &len)) != NULL){
490 X509 *x;
491 X509_NAME_ENTRY *e;
492 int i, offset = 2;
493 char space[256];
495 for(i = 0; i < offset; i++) space[i] = ' ';
497 for(i = -1; i < sk_X509_num(chain); i++){
498 char buf[256];
500 x = i == -1 ? cert : sk_X509_value(chain, i);
502 if(x && x->cert_info){
503 if(i>=0){
504 space[offset + i + 0] = ' ';
505 space[offset + i + 1] = '\\';
506 space[offset + i + 2] = '-';
507 space[offset + i + 3] = ' ';
508 space[offset + i + 4] = '\0';
509 gf_puts(space, pc);
511 else{
512 space[offset] = '\0';
513 gf_puts(space, pc);
515 if(i >= 0)
516 gf_puts_uline("Signed by: ", pc);
517 else
518 gf_puts_uline("Issued to: ", pc);
520 e = X509_NAME_get_entry(x->cert_info->subject,
521 X509_NAME_entry_count(x->cert_info->subject)-1);
523 if(e){
524 X509_NAME_get_text_by_OBJ(x->cert_info->subject, e->object, buf, sizeof(buf));
525 gf_puts(buf, pc);
526 gf_puts(NEWLINE, pc);
529 else{
530 gf_puts("No certificate info found", pc);
531 gf_puts(NEWLINE, pc);
532 break;
535 e = X509_NAME_get_entry(x->cert_info->issuer,
536 X509_NAME_entry_count(x->cert_info->issuer)-1);
537 if(e){
538 X509_NAME_get_text_by_OBJ(x->cert_info->issuer, e->object, buf, sizeof(buf));
539 space[offset + i + 0] = ' ';
540 space[offset + i + 1] = '\\';
541 space[offset + i + 2] = '-';
542 space[offset + i + 3] = ' ';
543 space[offset + i + 4] = '\0';
544 gf_puts(space, pc);
545 gf_puts_uline("Signed by: ", pc);
546 gf_puts(buf, pc);
547 gf_puts(NEWLINE, pc);
549 sk_X509_pop_free(chain, X509_free);
551 gf_puts(NEWLINE, pc);
553 so_give(&left);
554 so_give(&right);
558 void
559 output_X509_NAME(X509_NAME *name, gf_io_t pc)
561 int i, c;
562 char buf[256];
564 c = X509_NAME_entry_count(name);
566 for(i=c-1; i>=0; i--){
567 X509_NAME_ENTRY *e;
569 e = X509_NAME_get_entry(name,i);
570 if(!e)
571 continue;
573 X509_NAME_get_text_by_OBJ(name, e->object, buf, sizeof(buf));
575 gf_puts(buf, pc);
576 gf_puts(NEWLINE, pc);
582 * Output the contents of the given stores (left and right)
583 * to the given gf_io_t.
584 * The width of the terminal is inspected and two columns
585 * are created to fit the stores into. They are then wrapped
586 * and merged.
588 void
589 side_by_side(STORE_S *left, STORE_S *right, gf_io_t pc)
591 STORE_S *left_wrapped;
592 STORE_S *right_wrapped;
593 char buf_l[256];
594 char buf_r[256];
595 char *l, *r;
596 char *b;
597 int i;
598 int w = ps_global->ttyo->screen_cols/2 - 1;
600 so_seek(left, 0, 0);
601 so_seek(right, 0, 0);
603 left_wrapped = wrap_store(left, w);
604 right_wrapped = wrap_store(right, w);
606 so_seek(left_wrapped, 0, 0);
607 so_seek(right_wrapped, 0, 0);
609 for(;;){
611 l = so_fgets(left_wrapped, buf_l, sizeof(buf_l));
612 r = so_fgets(right_wrapped, buf_r, sizeof(buf_r));
613 if(l == NULL && r == NULL)
614 break;
616 for(i=0, b=buf_l; i<w && *b && *b!='\r' && *b!='\n'; i++,b++){
617 pc(*b);
618 /* reduce accumulated width if an embed tag is discovered */
619 if(*b==TAG_EMBED)
620 i-=2;
623 if(buf_r[0]){
624 while(i<w){
625 pc(' ');
626 i++;
628 pc(' ');
630 for(i=0, b=buf_r; i<w && *b && *b!='\r' && *b!='\n'; i++,b++)
631 pc(*b);
634 gf_puts(NEWLINE, pc);
637 so_give(&left_wrapped);
638 so_give(&right_wrapped);
642 * Wrap the text in the given store to the given width.
643 * A new store is created for the result.
645 STORE_S *
646 wrap_store(STORE_S *in, int width)
648 STORE_S *result;
649 void *ws;
650 gf_io_t ipc,opc;
652 if(width<10)
653 width = 10;
655 result = so_get(CharStar, NULL, EDIT_ACCESS);
656 ws = gf_wrap_filter_opt(width, width, NULL, 0, 0);
658 gf_filter_init();
659 gf_link_filter(gf_wrap, ws);
661 gf_set_so_writec(&opc, result);
662 gf_set_so_readc(&ipc, in);
664 gf_pipe(ipc, opc);
666 gf_clear_so_readc(in);
667 gf_clear_so_writec(result);
669 return result;
673 void
674 smime_config_screen(struct pine *ps, int edit_exceptions)
676 CONF_S *ctmp = NULL, *first_line = NULL;
677 SAVED_CONFIG_S *vsave;
678 OPT_SCREEN_S screen;
679 int ew, readonly_warning = 0;
681 dprint((9, "smime_config_screen()"));
682 ps->next_screen = SCREEN_FUN_NULL;
685 * this is necessary because we need to know the correct paths
686 * to configure certificates and keys, and we could get here
687 * without having done that before we reach this place.
689 smime_reinit();
691 if(ps->fix_fixed_warning)
692 offer_to_fix_pinerc(ps);
694 ew = edit_exceptions ? ps_global->ew_for_except_vars : Main;
696 if(ps->restricted)
697 readonly_warning = 1;
698 else{
699 PINERC_S *prc = NULL;
701 switch(ew){
702 case Main:
703 prc = ps->prc;
704 break;
705 case Post:
706 prc = ps->post_prc;
707 break;
708 default:
709 break;
712 readonly_warning = prc ? prc->readonly : 1;
713 if(prc && prc->quit_to_edit){
714 quit_to_edit_msg(prc);
715 return;
719 smime_config_init_display(ps, &ctmp, &first_line);
721 vsave = save_smime_config_vars(ps);
723 memset(&screen, 0, sizeof(screen));
724 screen.deferred_ro_warning = readonly_warning;
725 switch(conf_scroll_screen(ps, &screen, first_line,
726 edit_exceptions ? _("SETUP S/MIME EXCEPTIONS")
727 : _("SETUP S/MIME"),
728 /* TRANSLATORS: Print something1 using something2.
729 configuration is something1 */
730 _("configuration"), 0, NULL)){
731 case 0:
732 break;
734 case 1:
735 write_pinerc(ps, ew, WRP_NONE);
736 break;
738 case 10:
739 revert_to_saved_smime_config(ps, vsave);
740 break;
742 default:
743 q_status_message(SM_ORDER, 7, 10,
744 _("conf_scroll_screen bad ret in smime_config"));
745 break;
748 free_saved_smime_config(ps, &vsave);
749 smime_reinit();
754 smime_related_var(struct pine *ps, struct variable *var)
756 return(var == &ps->vars[V_PUBLICCERT_DIR] ||
757 var == &ps->vars[V_PUBLICCERT_CONTAINER] ||
758 var == &ps->vars[V_PRIVATEKEY_DIR] ||
759 var == &ps->vars[V_PRIVATEKEY_CONTAINER] ||
760 var == &ps->vars[V_CACERT_DIR] ||
761 var == &ps->vars[V_CACERT_CONTAINER]);
764 void
765 smime_config_init_display(struct pine *ps, CONF_S **ctmp, CONF_S **first_line)
767 char tmp[200];
768 int i, ind, ln = 0;
769 struct variable *vtmp;
770 CONF_S *ctmpb;
771 FEATURE_S *feature;
773 /* find longest variable name */
774 for(vtmp = ps->vars; vtmp->name; vtmp++){
775 if(!(smime_related_var(ps, vtmp)))
776 continue;
778 if((i = utf8_width(pretty_var_name(vtmp->name))) > ln)
779 ln = i;
782 for(vtmp = ps->vars; vtmp->name; vtmp++){
783 if(!(smime_related_var(ps, vtmp)))
784 continue;
786 new_confline(ctmp)->var = vtmp;
787 if(first_line && !*first_line)
788 *first_line = *ctmp;
790 (*ctmp)->valoffset = ln+3;
791 (*ctmp)->keymenu = &config_text_keymenu;
792 (*ctmp)->help = config_help(vtmp - ps->vars, 0);
793 (*ctmp)->tool = text_tool;
795 utf8_snprintf(tmp, sizeof(tmp), "%-*.100w =", ln, pretty_var_name(vtmp->name));
796 tmp[sizeof(tmp)-1] = '\0';
798 (*ctmp)->varname = cpystr(tmp);
799 (*ctmp)->varnamep = (*ctmp);
800 (*ctmp)->flags = CF_STARTITEM;
801 (*ctmp)->value = pretty_value(ps, *ctmp);
805 vtmp = &ps->vars[V_FEATURE_LIST];
807 new_confline(ctmp);
808 ctmpb = (*ctmp);
809 (*ctmp)->flags |= CF_NOSELECT | CF_STARTITEM;
810 (*ctmp)->keymenu = &config_checkbox_keymenu;
811 (*ctmp)->tool = NULL;
813 /* put a nice delimiter before list */
814 new_confline(ctmp)->var = NULL;
815 (*ctmp)->varnamep = ctmpb;
816 (*ctmp)->keymenu = &config_checkbox_keymenu;
817 (*ctmp)->help = NO_HELP;
818 (*ctmp)->tool = checkbox_tool;
819 (*ctmp)->valoffset = feature_indent();
820 (*ctmp)->flags |= CF_NOSELECT;
821 (*ctmp)->value = cpystr("Set Feature Name");
823 new_confline(ctmp)->var = NULL;
824 (*ctmp)->varnamep = ctmpb;
825 (*ctmp)->keymenu = &config_checkbox_keymenu;
826 (*ctmp)->help = NO_HELP;
827 (*ctmp)->tool = checkbox_tool;
828 (*ctmp)->valoffset = feature_indent();
829 (*ctmp)->flags |= CF_NOSELECT;
830 (*ctmp)->value = cpystr("--- ----------------------");
832 ind = feature_list_index(F_DONT_DO_SMIME);
833 feature = feature_list(ind);
834 new_confline(ctmp)->var = vtmp;
835 (*ctmp)->varnamep = ctmpb;
836 (*ctmp)->keymenu = &config_checkbox_keymenu;
837 (*ctmp)->help = config_help(vtmp-ps->vars, feature->id);
838 (*ctmp)->tool = checkbox_tool;
839 (*ctmp)->valoffset = feature_indent();
840 (*ctmp)->varmem = ind;
841 (*ctmp)->value = pretty_value(ps, (*ctmp));
843 ind = feature_list_index(F_ENCRYPT_DEFAULT_ON);
844 feature = feature_list(ind);
845 new_confline(ctmp)->var = vtmp;
846 (*ctmp)->varnamep = ctmpb;
847 (*ctmp)->keymenu = &config_checkbox_keymenu;
848 (*ctmp)->help = config_help(vtmp-ps->vars, feature->id);
849 (*ctmp)->tool = checkbox_tool;
850 (*ctmp)->valoffset = feature_indent();
851 (*ctmp)->varmem = ind;
852 (*ctmp)->value = pretty_value(ps, (*ctmp));
854 ind = feature_list_index(F_REMEMBER_SMIME_PASSPHRASE);
855 feature = feature_list(ind);
856 new_confline(ctmp)->var = vtmp;
857 (*ctmp)->varnamep = ctmpb;
858 (*ctmp)->keymenu = &config_checkbox_keymenu;
859 (*ctmp)->help = config_help(vtmp-ps->vars, feature->id);
860 (*ctmp)->tool = checkbox_tool;
861 (*ctmp)->valoffset = feature_indent();
862 (*ctmp)->varmem = ind;
863 (*ctmp)->value = pretty_value(ps, (*ctmp));
865 ind = feature_list_index(F_SIGN_DEFAULT_ON);
866 feature = feature_list(ind);
867 new_confline(ctmp)->var = vtmp;
868 (*ctmp)->varnamep = ctmpb;
869 (*ctmp)->keymenu = &config_checkbox_keymenu;
870 (*ctmp)->help = config_help(vtmp-ps->vars, feature->id);
871 (*ctmp)->tool = checkbox_tool;
872 (*ctmp)->valoffset = feature_indent();
873 (*ctmp)->varmem = ind;
874 (*ctmp)->value = pretty_value(ps, (*ctmp));
876 ind = feature_list_index(F_USE_CERT_STORE_ONLY);
877 feature = feature_list(ind);
878 new_confline(ctmp)->var = vtmp;
879 (*ctmp)->varnamep = ctmpb;
880 (*ctmp)->keymenu = &config_checkbox_keymenu;
881 (*ctmp)->help = config_help(vtmp-ps->vars, feature->id);
882 (*ctmp)->tool = checkbox_tool;
883 (*ctmp)->valoffset = feature_indent();
884 (*ctmp)->varmem = ind;
885 (*ctmp)->value = pretty_value(ps, (*ctmp));
887 #ifdef APPLEKEYCHAIN
888 new_confline(ctmp);
889 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
891 new_confline(ctmp);
892 (*ctmp)->flags |= CF_NOSELECT;
893 (*ctmp)->value = cpystr(_("Mac OS X specific features"));
895 ind = feature_list_index(F_PUBLICCERTS_IN_KEYCHAIN);
896 feature = feature_list(ind);
897 new_confline(ctmp)->var = vtmp;
898 (*ctmp)->varnamep = ctmpb;
899 (*ctmp)->keymenu = &config_checkbox_keymenu;
900 (*ctmp)->help = config_help(vtmp-ps->vars, feature->id);
901 (*ctmp)->tool = checkbox_tool;
902 (*ctmp)->valoffset = feature_indent();
903 (*ctmp)->varmem = ind;
904 (*ctmp)->value = pretty_value(ps, (*ctmp));
905 #endif /* APPLEKEYCHAIN */
907 new_confline(ctmp);
908 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
910 for(i = 0; i < sizeof(tmp) && i < (ps->ttyo ? ps->ttyo->screen_cols : sizeof(tmp)); i++)
911 tmp[i] = '-';
912 new_confline(ctmp);
913 (*ctmp)->flags |= CF_NOSELECT;
914 (*ctmp)->value = cpystr(tmp);
916 new_confline(ctmp);
917 (*ctmp)->flags |= CF_NOSELECT;
918 (*ctmp)->value = cpystr(_("Be careful with the following commands, they REPLACE contents in the target"));
920 new_confline(ctmp);
921 (*ctmp)->flags |= CF_NOSELECT;
922 (*ctmp)->value = cpystr(tmp);
924 new_confline(ctmp);
925 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
927 /* copy public directory to container */
928 new_confline(ctmp);
929 (*ctmp)->tool = smime_helper_tool;
930 (*ctmp)->keymenu = &config_smime_helper_keymenu;
931 (*ctmp)->help = h_config_smime_transfer_pub_to_con;
932 (*ctmp)->value = cpystr(_("Transfer public certs FROM directory TO container"));
933 (*ctmp)->varmem = 1;
935 /* copy private directory to container */
936 new_confline(ctmp);
937 (*ctmp)->tool = smime_helper_tool;
938 (*ctmp)->keymenu = &config_smime_helper_keymenu;
939 (*ctmp)->help = h_config_smime_transfer_priv_to_con;
940 (*ctmp)->value = cpystr(_("Transfer private keys FROM directory TO container"));
941 (*ctmp)->varmem = 3;
943 /* copy cacert directory to container */
944 new_confline(ctmp);
945 (*ctmp)->tool = smime_helper_tool;
946 (*ctmp)->keymenu = &config_smime_helper_keymenu;
947 (*ctmp)->help = h_config_smime_transfer_cacert_to_con;
948 (*ctmp)->value = cpystr(_("Transfer CA certs FROM directory TO container"));
949 (*ctmp)->varmem = 5;
951 new_confline(ctmp)->var = vtmp;
952 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
954 /* copy public container to directory */
955 new_confline(ctmp);
956 (*ctmp)->tool = smime_helper_tool;
957 (*ctmp)->keymenu = &config_smime_helper_keymenu;
958 (*ctmp)->help = h_config_smime_transfer_pub_to_dir;
959 (*ctmp)->value = cpystr(_("Transfer public certs FROM container TO directory"));
960 (*ctmp)->varmem = 2;
962 /* copy private container to directory */
963 new_confline(ctmp);
964 (*ctmp)->tool = smime_helper_tool;
965 (*ctmp)->keymenu = &config_smime_helper_keymenu;
966 (*ctmp)->help = h_config_smime_transfer_priv_to_dir;
967 (*ctmp)->value = cpystr(_("Transfer private keys FROM container TO directory"));
968 (*ctmp)->varmem = 4;
970 /* copy cacert container to directory */
971 new_confline(ctmp);
972 (*ctmp)->tool = smime_helper_tool;
973 (*ctmp)->keymenu = &config_smime_helper_keymenu;
974 (*ctmp)->help = h_config_smime_transfer_cacert_to_dir;
975 (*ctmp)->value = cpystr(_("Transfer CA certs FROM container TO directory"));
976 (*ctmp)->varmem = 6;
978 #ifdef APPLEKEYCHAIN
980 new_confline(ctmp)->var = vtmp;
981 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
983 /* copy public container to keychain */
984 new_confline(ctmp);
985 (*ctmp)->tool = smime_helper_tool;
986 (*ctmp)->keymenu = &config_smime_helper_keymenu;
987 (*ctmp)->help = h_config_smime_transfer_pubcon_to_key;
988 (*ctmp)->value = cpystr(_("Transfer public certs FROM container TO keychain"));
989 (*ctmp)->varmem = 7;
991 /* copy public keychain to container */
992 new_confline(ctmp);
993 (*ctmp)->tool = smime_helper_tool;
994 (*ctmp)->keymenu = &config_smime_helper_keymenu;
995 (*ctmp)->help = h_config_smime_transfer_pubkey_to_con;
996 (*ctmp)->value = cpystr(_("Transfer public certs FROM keychain TO container"));
997 (*ctmp)->varmem = 8;
999 #endif /* APPLEKEYCHAIN */
1001 if(SMHOLDERTYPE(Private) == Keychain
1002 && SMHOLDERTYPE(Public) == Keychain
1003 && SMHOLDERTYPE(CACert) == Keychain)
1004 return;
1006 new_confline(ctmp)->var = vtmp;
1007 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
1009 new_confline(ctmp);
1010 (*ctmp)->flags |= CF_NOSELECT;
1011 (*ctmp)->value = cpystr(tmp);
1013 new_confline(ctmp);
1014 (*ctmp)->flags |= CF_NOSELECT;
1015 (*ctmp)->value = cpystr(_("Manage your own certificates"));
1017 new_confline(ctmp);
1018 (*ctmp)->flags |= CF_NOSELECT;
1019 (*ctmp)->value = cpystr(tmp);
1021 new_confline(ctmp)->var = vtmp;
1022 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
1024 /* manage public certificates */
1025 new_confline(ctmp);
1026 (*ctmp)->tool = smime_helper_tool;
1027 (*ctmp)->keymenu = &config_smime_manage_certs_menu_keymenu;
1028 (*ctmp)->help = h_config_smime_public_certificates;
1029 (*ctmp)->value = cpystr(_("Manage Public Certificates"));
1030 (*ctmp)->varmem = 9;
1032 /* manage private keys */
1033 new_confline(ctmp);
1034 (*ctmp)->tool = smime_helper_tool;
1035 (*ctmp)->keymenu = &config_smime_manage_certs_menu_keymenu;
1036 (*ctmp)->help = h_config_smime_private_keys;
1037 (*ctmp)->value = cpystr(_("Manage Private Keys"));
1038 (*ctmp)->varmem = 10;
1040 /* manage Certificate Authorities */
1041 new_confline(ctmp);
1042 (*ctmp)->tool = smime_helper_tool;
1043 (*ctmp)->keymenu = &config_smime_manage_certs_menu_keymenu;
1044 (*ctmp)->help = h_config_smime_certificate_authorities;
1045 (*ctmp)->value = cpystr(_("Manage Certificate Authorities"));
1046 (*ctmp)->varmem = 11;
1048 (*ctmp)->next = NULL;
1051 void display_certificate_information(struct pine *ps, X509 *cert, char *email, WhichCerts ctype, int num)
1053 STORE_S *store;
1054 SCROLL_S scrollargs;
1055 int cmd, offset;
1056 int pub_cert, priv_cert, new_store;
1057 long error;
1058 BIO *out = NULL;
1060 cmd = offset = pub_cert = priv_cert = 0;
1061 new_store = 1;
1062 ps->next_screen = SCREEN_FUN_NULL;
1063 do {
1064 /* MC_PRIVATE and MC_PUBLIC cancel each other,
1065 * they can not be active at the same time
1067 switch(cmd){
1068 case MC_PRIVATE:
1069 pub_cert = 0;
1070 priv_cert = 1 - priv_cert;
1071 smime_certificate_info_keymenu.keys[PUBLIC_KEY].label = N_("Public Key");
1072 smime_certificate_info_keymenu.keys[PRIVATE_KEY].label = priv_cert ? N_("No Priv Key") : N_("Pivate Key");
1073 break;
1075 case MC_PUBLIC:
1076 priv_cert = 0;
1077 pub_cert = 1 - pub_cert;
1078 smime_certificate_info_keymenu.keys[PRIVATE_KEY].label = priv_cert ? N_("No Priv Key") : N_("Pivate Key");
1079 smime_certificate_info_keymenu.keys[PUBLIC_KEY].label = N_("Public Key");
1080 break;
1082 case MC_TRUST:
1083 if(SMHOLDERTYPE(CACert) == Directory)
1084 save_cert_for(email, cert, CACert);
1085 else{ /* if(SMHOLDERTYPE(CACert) == Container) */
1086 char path[MAXPATH];
1087 char *upath = PATHCERTDIR(ctype);
1088 char *tempfile = tempfile_in_same_dir(path, "az", NULL);
1089 CertList *clist;
1091 if(IS_REMOTE(upath))
1092 strncpy(path, temp_nam(NULL, "a6"), sizeof(path)-1);
1093 else
1094 strncpy(path, upath, sizeof(path)-1);
1095 path[sizeof(path)-1] = '\0';
1097 add_to_end_of_certlist(&ps_global->smime->cacertlist, email, X509_dup(cert));
1098 for(clist=ps_global->smime->cacertlist; clist && clist->next; clist = clist->next);
1099 certlist_to_file(tempfile, clist);
1100 add_file_to_container(CACert, tempfile, email);
1101 unlink(tempfile);
1103 renew_store();
1104 new_store = 1;
1105 break;
1107 case MC_DELETE:
1108 if (get_cert_deleted(ctype, num) != 0)
1109 q_status_message(SM_ORDER, 1, 3, _("Certificate already deleted"));
1110 else{
1111 mark_cert_deleted(ctype, num, 1);
1112 q_status_message(SM_ORDER, 1, 3, _("Certificate marked deleted"));
1114 break;
1116 case MC_UNDELETE:
1117 if (get_cert_deleted(ctype, num) != 0){
1118 mark_cert_deleted(ctype, num, 0);
1119 q_status_message(SM_ORDER, 1, 3, _("Certificate marked UNdeleted"));
1121 else
1122 q_status_message(SM_ORDER, 1, 3, _("Certificate not marked deleted"));
1123 break;
1125 default: break;
1128 if((pub_cert || priv_cert)
1129 && (out = print_private_key_information(email, priv_cert)) == NULL)
1130 q_status_message(SM_ORDER, 1, 3, _("Problem Reading Private Certificate Information"));
1132 if(new_store){
1133 store = so_get(CharStar, NULL, EDIT_ACCESS);
1134 view_writec_init(store, NULL, HEADER_ROWS(ps),
1135 HEADER_ROWS(ps) + ps->ttyo->screen_rows - (HEADER_ROWS(ps)+ FOOTER_ROWS(ps)));
1137 snprintf(tmp_20k_buf, SIZEOF_20KBUF,"%s", _("Certificate Information"));
1138 gf_puts_uline(tmp_20k_buf, view_writec);
1139 gf_puts(NEWLINE, view_writec);
1140 print_separator_line(100, '-', view_writec);
1142 output_cert_info(cert, view_writec);
1143 gf_puts(NEWLINE, view_writec);
1145 if(smime_validate_cert(cert, &error) < 0){
1146 const char *errorp = X509_verify_cert_error_string(error);
1147 snprintf(tmp_20k_buf, SIZEOF_20KBUF,_("Error validating certificate: %s"), errorp);
1148 } else
1149 snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s", _("Certificate validated without errors"));
1151 gf_puts_uline(tmp_20k_buf, view_writec);
1152 gf_puts(NEWLINE, view_writec);
1154 if(out != NULL){ /* print private key information */
1155 unsigned char ch[2];
1157 gf_puts(NEWLINE, view_writec);
1158 ch[1] = '\0';
1159 while(BIO_read(out, ch, 1) >= 1)
1160 gf_puts((char *)ch, view_writec);
1161 gf_puts(NEWLINE, view_writec);
1162 q_status_message1(SM_ORDER, 1, 3, _("%s information shown at bottom of certificate information"), pub_cert ? _("Public") : _("Private"));
1163 BIO_free_all(out);
1164 out = NULL;
1166 view_writec_destroy();
1167 new_store = 0;
1170 memset(&scrollargs, 0, sizeof(SCROLL_S));
1172 scrollargs.text.text = so_text(store);
1173 scrollargs.text.src = CharStar;
1174 scrollargs.text.desc = "certificate information";
1175 scrollargs.body_valid = 1;
1177 if(offset){ /* resize? preserve paging! */
1178 scrollargs.start.on = Offset;
1179 scrollargs.start.loc.offset = offset;
1180 scrollargs.body_valid = 0;
1181 offset = 0L;
1184 scrollargs.use_indexline_color = 1;
1186 scrollargs.bar.title = _("CERTIFICATE INFORMATION");
1187 scrollargs.proc.tool = manage_certificate_info_tool;
1188 scrollargs.resize_exit = 1;
1189 scrollargs.help.text = h_certificate_information;
1190 scrollargs.help.title = _("HELP FOR MESSAGE TEXT VIEW");
1191 scrollargs.keys.what = FirstMenu;
1192 scrollargs.keys.menu = &smime_certificate_info_keymenu;
1193 setbitmap(scrollargs.keys.bitmap);
1194 if(ctype != Public || error != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
1195 /*error != X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)*/
1196 clrbitn(TRUST_KEY, scrollargs.keys.bitmap);
1197 if(ctype != Private){
1198 clrbitn(PUBLIC_KEY, scrollargs.keys.bitmap);
1199 clrbitn(PRIVATE_KEY, scrollargs.keys.bitmap);
1202 cmd = scrolltool(&scrollargs);
1204 switch(cmd){
1205 case MC_RESIZE :
1206 case MC_PRIVATE:
1207 case MC_PUBLIC : if(scrollargs.start.on == Offset)
1208 offset = scrollargs.start.loc.offset;
1209 new_store = 1;
1210 default: break;
1212 if(new_store)
1213 so_give(&store);
1214 } while (cmd != MC_EXIT);
1215 ps->mangled_screen = 1;
1219 * This is silly, we just need this function so that we can tell scrolltool
1220 * that some commands are recognized. We use scrolltool because we do not
1221 * want to rewrite output_cert_info.
1224 manage_certificate_info_tool(int cmd, MSGNO_S *msgmap, SCROLL_S *sparms)
1226 int rv;
1227 switch(cmd){
1228 case MC_DELETE:
1229 case MC_UNDELETE:
1230 case MC_PRIVATE:
1231 case MC_PUBLIC:
1232 case MC_TRUST: rv = 1; break;
1233 default: rv = 0; break;
1235 return rv;
1240 manage_certs_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned flags)
1242 int rv = 0;
1243 X509 *cert = NULL;
1244 WhichCerts ctype = (*cl)->d.s.ctype;
1246 switch(cmd){
1247 case MC_CHOICE:
1248 if(PATHCERTDIR(ctype) == NULL)
1249 return 0;
1251 if((cert = get_cert_for((*cl)->d.s.address, ctype, 0)) == NULL){
1252 q_status_message(SM_ORDER, 1, 3, _("Problem Reading Certificate"));
1253 rv = 0;
1255 else{
1256 display_certificate_information(ps, cert, (*cl)->d.s.address, ctype, (*cl)->varmem);
1257 rv = 10 + (*cl)->varmem;
1259 break;
1261 case MC_DELETE:
1262 if ((*cl)->d.s.deleted != 0)
1263 q_status_message(SM_ORDER, 1, 3, _("Certificate already deleted"));
1264 else{
1265 (*cl)->d.s.deleted = 1;
1266 rv = 10 + (*cl)->varmem; /* forces redraw */
1267 mark_cert_deleted(ctype, (*cl)->varmem, 1);
1268 q_status_message(SM_ORDER, 1, 3, _("Certificate marked deleted"));
1270 break;
1272 case MC_UNDELETE:
1273 if ((*cl)->d.s.deleted == 0)
1274 q_status_message(SM_ORDER, 1, 3, _("Certificate not marked deleted"));
1275 else{
1276 (*cl)->d.s.deleted = 0;
1277 mark_cert_deleted(ctype, (*cl)->varmem, 0);
1278 rv = 10 + (*cl)->varmem; /* forces redraw */
1279 q_status_message(SM_ORDER, 1, 3, _("Certificate marked UNdeleted"));
1281 break;
1283 case MC_EXPUNGE:
1284 { CertList *cl;
1286 for(cl = DATACERT(ctype); cl != NULL && DELETEDCERT(cl) == 0; cl = cl->next);
1287 if(cl != NULL && DELETEDCERT(cl) != 0){
1288 smime_expunge_cert(ctype);
1289 rv = 10; /* forces redraw */
1291 else{
1292 q_status_message(SM_ORDER, 3, 3, _("No certificates marked deleted"));
1293 rv = 0;
1295 break;
1297 case MC_IMPORT:
1298 rv = import_certificate(ctype);
1299 if(rv < 0){
1300 switch(rv){
1301 default:
1302 case -1:
1303 cmd_cancelled("Import certificate");
1304 break;
1306 case -2:
1307 q_status_message1(SM_ORDER, 0, 2, _("Can't import certificate outside of %s"),
1308 ps_global->VAR_OPER_DIR);
1309 break;
1312 rv = 10; /* forces redraw */
1313 break;
1315 case MC_EXIT:
1316 rv = config_exit_cmd(flags);
1317 break;
1319 default:
1320 rv = -1;
1321 break;
1324 X509_free(cert);
1325 return rv;
1328 void
1329 smime_setup_size(char **s, size_t buflen, size_t n)
1331 char *t = *s;
1332 *t++ = ' ';
1333 *t++ = '%';
1334 *t++ = '-';
1335 snprintf(t, buflen-3, "%zu.%zu", n, n);
1336 t += strlen(t);
1337 *t++ = 's';
1338 *s = t;
1341 void smime_manage_certs_init(struct pine *ps, CONF_S **ctmp, CONF_S **first_line, WhichCerts ctype, int fline)
1343 char tmp[200];
1344 char *ext;
1345 CertList *data;
1346 int i;
1348 smime_init();
1350 data = DATACERT(ctype);
1351 ext = EXTCERT(ctype);
1353 if(data == NULL || RENEWCERT(data))
1354 renew_cert_data(&data, ctype);
1356 for(i = 0; i < sizeof(tmp) && i < (ps->ttyo ? ps->ttyo->screen_cols : sizeof(tmp)); i++)
1357 tmp[i] = '-';
1358 new_confline(ctmp);
1359 (*ctmp)->flags |= CF_NOSELECT;
1360 (*ctmp)->value = cpystr(tmp);
1362 (*ctmp)->keymenu = &config_text_keymenu;
1364 new_confline(ctmp);
1365 (*ctmp)->flags |= CF_NOSELECT;
1366 sprintf(tmp, _("List of %s certificates"), ctype == Public ? _("public")
1367 : (ctype == Private ? _("private")
1368 : (ctype == CACert ? _("certificate authority") : "unknown (?)")));
1369 (*ctmp)->value = cpystr(tmp);
1371 for(i = 0; i < sizeof(tmp) && i < (ps->ttyo ? ps->ttyo->screen_cols : sizeof(tmp)); i++)
1372 tmp[i] = '-';
1373 new_confline(ctmp);
1374 (*ctmp)->flags |= CF_NOSELECT;
1375 (*ctmp)->value = cpystr(tmp);
1377 new_confline(ctmp);
1378 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
1380 if(data){
1381 CertList *cl; int i;
1382 int s, e, df, dt, md5; /* sizes of certain fields */
1383 int nf; /* number of fields */
1384 char u[MAILTMPLEN], *t;
1386 for(cl = data, e = 0; cl; cl = cl->next)
1387 if(cl->name && strlen(cl->name) > e)
1388 e = strlen(cl->name);
1390 if(ctype != Private && SMHOLDERTYPE(ctype) == Directory)
1391 e -= 4; /* remove extension length */
1392 e = MIN(e, ps->ttyo->screen_cols/3); /* do not use too much screen */
1393 nf = 5; /* there are 5 fields */
1394 s = 3; /* status has fixed size */
1395 df = dt = 10; /* date from and date to have fixed size */
1396 md5 = ps->ttyo->screen_cols - s - df - dt - e - (nf - 1);
1398 t = u;
1399 smime_setup_size(&t, sizeof(u), s);
1400 smime_setup_size(&t, sizeof(u) - strlen(t), e);
1401 smime_setup_size(&t, sizeof(u) - strlen(t), df);
1402 *t++ = ' '; /* leave an extra space between dates */
1403 smime_setup_size(&t, sizeof(u) - strlen(t), dt);
1404 *t++ = ' '; /* and another space between date and md5 sum */
1405 smime_setup_size(&t, sizeof(u) - strlen(t), md5);
1406 *t = '\0'; /* tie off */
1408 for(cl = data, i = 0; cl; cl = cl->next)
1409 if(cl->name){
1410 char *s, *t;
1412 new_confline(ctmp);
1413 (*ctmp)->d.s.ctype = ctype;
1414 (*ctmp)->d.s.deleted = get_cert_deleted(ctype, i);
1415 (*ctmp)->tool = manage_certs_tool;
1416 (*ctmp)->keymenu = &config_smime_manage_certs_work_keymenu;
1417 (*ctmp)->varmem = i++;
1418 (*ctmp)->help = ctype == Public ? h_config_smime_manage_public_menu
1419 : (ctype == Private ? h_config_smime_manage_private_menu
1420 : h_config_smime_manage_cacerts_menu);
1421 if(ctype != Private && SMHOLDERTYPE(ctype) == Directory)
1422 cl->name[strlen(cl->name) - 4] = '\0'; /* FIX FIX FIX */
1423 strncpy((*ctmp)->d.s.address, cl->name, sizeof((*ctmp)->d.s.address));
1424 (*ctmp)->d.s.address[sizeof((*ctmp)->d.s.address) - 1] = '\0';
1425 snprintf(tmp, sizeof(tmp), u,
1426 (*ctmp)->d.s.deleted ? "D" : " ",
1427 ctype == CACert ? cl->cn : cl->name,
1428 DATEFROMCERT(cl), DATETOCERT(cl), MD5CERT(cl));
1429 if(ctype != Private && SMHOLDERTYPE(ctype) == Directory)
1430 cl->name[strlen(cl->name)] = '.';
1431 (*ctmp)->value = cpystr(tmp);
1432 if(i == fline+1 && first_line && !*first_line)
1433 *first_line = *ctmp;
1436 else {
1437 new_confline(ctmp);
1438 (*ctmp)->d.s.ctype = ctype;
1439 (*ctmp)->tool = manage_certs_tool;
1440 (*ctmp)->keymenu = &config_smime_add_certs_keymenu;
1441 (*ctmp)->value = cpystr(_(" \tNo certificates found, press \"RETURN\" to add one."));
1442 if(first_line && !*first_line)
1443 *first_line = *ctmp;
1447 void manage_certificates(struct pine *ps, WhichCerts ctype)
1449 OPT_SCREEN_S screen;
1450 int readonly_warning = 0, rv = 10, fline;
1452 dprint((9, "manage_certificates(ps, %s)", ctype == Public ? _("Public") : (ctype == Private ? _("Private") : (ctype == CACert ? _("certificate authority") : _("unknown")))));
1453 ps->next_screen = SCREEN_FUN_NULL;
1455 do {
1456 CONF_S *ctmp = NULL, *first_line = NULL;
1458 fline = rv >= 10 ? rv - 10 : 0;
1460 smime_init();
1462 smime_manage_certs_init(ps, &ctmp, &first_line, ctype, fline);
1464 if(ctmp == NULL){
1465 ps->mangled_screen = 1;
1466 smime_reinit();
1467 return;
1470 memset(&screen, 0, sizeof(screen));
1471 screen.deferred_ro_warning = readonly_warning;
1472 rv = conf_scroll_screen(ps, &screen, first_line,
1473 _("MANAGE CERTIFICATES"),
1474 /* TRANSLATORS: Print something1 using something2.
1475 configuration is something1 */
1476 _("configuration"), 0, NULL);
1477 } while (rv != 0);
1479 ps->mangled_screen = 1;
1480 smime_reinit();
1484 smime_helper_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned flags)
1486 int rv = 0;
1488 switch(cmd){
1489 case MC_CHOICE:
1490 switch((*cl)->varmem){
1491 case 1:
1492 rv = copy_publiccert_dir_to_container();
1493 if(rv == 0)
1494 q_status_message(SM_ORDER, 1, 3, _("Public certs transferred to container"));
1495 else{
1496 q_status_message(SM_ORDER, 3, 3, _("Problem transferring certs"));
1497 rv = 0;
1500 break;
1502 case 2:
1503 rv = copy_publiccert_container_to_dir();
1504 if(rv == 0)
1505 q_status_message(SM_ORDER, 1, 3, _("Public certs transferred to directory, delete Container config to use"));
1506 else{
1507 q_status_message(SM_ORDER, 3, 3, _("Problem transferring certs"));
1508 rv = 0;
1511 break;
1513 case 3:
1514 rv = copy_privatecert_dir_to_container();
1515 if(rv == 0)
1516 q_status_message(SM_ORDER, 1, 3, _("Private keys transferred to container"));
1517 else{
1518 q_status_message(SM_ORDER, 3, 3, _("Problem transferring certs"));
1519 rv = 0;
1522 break;
1524 case 4:
1525 rv = copy_privatecert_container_to_dir();
1526 if(rv == 0)
1527 q_status_message(SM_ORDER, 1, 3, _("Private keys transferred to directory, delete Container config to use"));
1528 else{
1529 q_status_message(SM_ORDER, 3, 3, _("Problem transferring certs"));
1530 rv = 0;
1533 break;
1535 case 5:
1536 rv = copy_cacert_dir_to_container();
1537 if(rv == 0)
1538 q_status_message(SM_ORDER, 1, 3, _("CA certs transferred to container"));
1539 else{
1540 q_status_message(SM_ORDER, 3, 3, _("Problem transferring certs"));
1541 rv = 0;
1544 break;
1546 case 6:
1547 rv = copy_cacert_container_to_dir();
1548 if(rv == 0)
1549 q_status_message(SM_ORDER, 1, 3, _("CA certs transferred to directory, delete Container config to use"));
1550 else{
1551 q_status_message(SM_ORDER, 3, 3, _("Problem transferring certs"));
1552 rv = 0;
1555 break;
1557 #ifdef APPLEKEYCHAIN
1558 case 7:
1559 rv = copy_publiccert_container_to_keychain();
1560 if(rv == 0)
1561 q_status_message(SM_ORDER, 1, 3, _("Public certs transferred to keychain"));
1562 else{
1563 q_status_message(SM_ORDER, 3, 3, _("Command not implemented yet"));
1564 rv = 0;
1567 break;
1569 case 8:
1570 rv = copy_publiccert_keychain_to_container();
1571 if(rv == 0)
1572 q_status_message(SM_ORDER, 1, 3, _("Public certs transferred to container"));
1573 else{
1574 q_status_message(SM_ORDER, 3, 3, _("Command not implemented yet"));
1575 rv = 0;
1578 break;
1579 #endif /* APPLEKEYCHAIN */
1581 case 9: manage_certificates(ps, Public) ; break;
1582 case 10: manage_certificates(ps, Private); break;
1583 case 11: manage_certificates(ps, CACert) ; break;
1585 default:
1586 rv = -1;
1587 break;
1590 break;
1592 case MC_EXIT:
1593 rv = config_exit_cmd(flags);
1594 break;
1596 case MC_IMPORT:
1597 { WhichCerts ctype;
1598 /* keep this selection consistent with the codes above */
1599 ctype = (*cl)->varmem == 9 ? Public
1600 : ((*cl)->varmem == 10 ? Private : CACert);
1601 rv = import_certificate(ctype);
1603 break;
1605 default:
1606 rv = -1;
1607 break;
1610 return rv;
1615 * Compare saved user_val with current user_val to see if it changed.
1616 * If any have changed, change it back and take the appropriate action.
1618 void
1619 revert_to_saved_smime_config(struct pine *ps, SAVED_CONFIG_S *vsave)
1621 struct variable *vreal;
1622 SAVED_CONFIG_S *v;
1623 int i, n;
1624 int changed = 0;
1625 char *pval, **apval, **lval, ***alval;
1627 v = vsave;
1628 for(vreal = ps->vars; vreal->name; vreal++,v++){
1629 if(!(smime_related_var(ps, vreal) || vreal==&ps->vars[V_FEATURE_LIST]))
1630 continue;
1632 if(vreal->is_list){
1633 lval = LVAL(vreal, ew);
1634 alval = ALVAL(vreal, ew);
1636 if((v->saved_user_val.l && !lval)
1637 || (!v->saved_user_val.l && lval))
1638 changed++;
1639 else if(!v->saved_user_val.l && !lval)
1640 ;/* no change, nothing to do */
1641 else
1642 for(i = 0; v->saved_user_val.l[i] || lval[i]; i++)
1643 if((v->saved_user_val.l[i]
1644 && (!lval[i]
1645 || strcmp(v->saved_user_val.l[i], lval[i])))
1647 (!v->saved_user_val.l[i] && lval[i])){
1648 changed++;
1649 break;
1652 if(changed){
1653 char **list;
1655 if(alval){
1656 if(*alval)
1657 free_list_array(alval);
1659 /* copy back the original one */
1660 if(v->saved_user_val.l){
1661 list = v->saved_user_val.l;
1662 n = 0;
1663 /* count how many */
1664 while(list[n])
1665 n++;
1667 *alval = (char **)fs_get((n+1) * sizeof(char *));
1669 for(i = 0; i < n; i++)
1670 (*alval)[i] = cpystr(v->saved_user_val.l[i]);
1672 (*alval)[n] = NULL;
1677 else{
1678 pval = PVAL(vreal, ew);
1679 apval = APVAL(vreal, ew);
1681 if((v->saved_user_val.p &&
1682 (!pval || strcmp(v->saved_user_val.p, pval))) ||
1683 (!v->saved_user_val.p && pval)){
1684 /* It changed, fix it */
1685 changed++;
1686 if(apval){
1687 /* free the changed value */
1688 if(*apval)
1689 fs_give((void **)apval);
1691 if(v->saved_user_val.p)
1692 *apval = cpystr(v->saved_user_val.p);
1697 if(changed){
1698 if(vreal == &ps->vars[V_FEATURE_LIST])
1699 set_feature_list_current_val(vreal);
1700 else
1701 set_current_val(vreal, TRUE, FALSE);
1703 fix_side_effects(ps, vreal, 1);
1709 SAVED_CONFIG_S *
1710 save_smime_config_vars(struct pine *ps)
1712 struct variable *vreal;
1713 SAVED_CONFIG_S *vsave, *v;
1715 vsave = (SAVED_CONFIG_S *)fs_get((V_LAST_VAR+1)*sizeof(SAVED_CONFIG_S));
1716 memset((void *)vsave, 0, (V_LAST_VAR+1)*sizeof(SAVED_CONFIG_S));
1717 v = vsave;
1718 for(vreal = ps->vars; vreal->name; vreal++,v++){
1719 if(!(smime_related_var(ps, vreal) || vreal==&ps->vars[V_FEATURE_LIST]))
1720 continue;
1722 if(vreal->is_list){
1723 int n, i;
1724 char **list;
1726 if(LVAL(vreal, ew)){
1727 /* count how many */
1728 n = 0;
1729 list = LVAL(vreal, ew);
1730 while(list[n])
1731 n++;
1733 v->saved_user_val.l = (char **)fs_get((n+1) * sizeof(char *));
1734 memset((void *)v->saved_user_val.l, 0, (n+1)*sizeof(char *));
1735 for(i = 0; i < n; i++)
1736 v->saved_user_val.l[i] = cpystr(list[i]);
1738 v->saved_user_val.l[n] = NULL;
1741 else{
1742 if(PVAL(vreal, ew))
1743 v->saved_user_val.p = cpystr(PVAL(vreal, ew));
1747 return(vsave);
1751 void
1752 free_saved_smime_config(struct pine *ps, SAVED_CONFIG_S **vsavep)
1754 struct variable *vreal;
1755 SAVED_CONFIG_S *v;
1757 if(vsavep && *vsavep){
1758 for(v = *vsavep, vreal = ps->vars; vreal->name; vreal++,v++){
1759 if(!(smime_related_var(ps, vreal)))
1760 continue;
1762 if(vreal->is_list){ /* free saved_user_val.l */
1763 if(v && v->saved_user_val.l)
1764 free_list_array(&v->saved_user_val.l);
1766 else if(v && v->saved_user_val.p)
1767 fs_give((void **)&v->saved_user_val.p);
1770 fs_give((void **)vsavep);
1774 #endif /* SMIME */