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
4
5 /*
6 * ========================================================================
7 * Copyright 2013-2021 Eduardo Chappa
8 * Copyright 2008 University of Washington
9 *
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
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * ========================================================================
17 */
18
19 /*
20 * This is based on a contribution from Jonathan Paisley
21 *
22 * File: smime.c
23 * Author: paisleyj@dcs.gla.ac.uk
24 * Date: 01/2001
25 */
26
27
28 #include "headers.h"
29
30 #ifdef SMIME
31
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 "../pith/body.h"
40 #include "radio.h"
41 #include "keymenu.h"
42 #include "mailcmd.h"
43 #include "mailview.h"
44 #include "conftype.h"
45 #include "confscroll.h"
46 #include "setup.h"
47 #include "smime.h"
48
49 /* internal prototypes */
50 void format_smime_info(int pass, BODY *body, long msgno, gf_io_t pc);
51 void print_separator_line(int percent, int ch, gf_io_t pc);
52 void output_cert_info(X509 *cert, gf_io_t pc);
53 void output_X509_NAME(X509_NAME *name, gf_io_t pc);
54 void side_by_side(STORE_S *left, STORE_S *right, gf_io_t pc);
55 STORE_S *wrap_store(STORE_S *in, int width);
56 void smime_config_init_display(struct pine *, CONF_S **, CONF_S **);
57 void revert_to_saved_smime_config(struct pine *ps, SAVED_CONFIG_S *vsave);
58 SAVED_CONFIG_S *save_smime_config_vars(struct pine *ps);
59 void free_saved_smime_config(struct pine *ps, SAVED_CONFIG_S **vsavep);
60 int smime_helper_tool(struct pine *, int, CONF_S **, unsigned);
61 void manage_certificates(struct pine *, WhichCerts);
62 #ifdef PASSFILE
63 void manage_password_file_certificates(struct pine *);
64 #endif /* PASSFILE */
65 void smime_manage_certs_init (struct pine *, CONF_S **, CONF_S **, WhichCerts, int);
66 void smime_manage_password_file_certs_init(struct pine *, CONF_S **, CONF_S **, int, int *);
67 void display_certificate_information(struct pine *, X509 *, char *, WhichCerts, int num);
68 int manage_certs_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned flags);
69 int manage_certificate_info_tool(int, MSGNO_S *, SCROLL_S *);
70 void smime_setup_size(char **, size_t, size_t);
71
72
73 /*
74 * prompt the user for their passphrase
75 * (possibly prompting with the email address in s_passphrase_emailaddr)
76 */
77 int
smime_get_passphrase(void)78 smime_get_passphrase(void)
79 {
80 int rc;
81 int flags;
82 char prompt[500];
83 HelpType help = NO_HELP;
84
85 assert(ps_global->smime != NULL);
86 snprintf(prompt, sizeof(prompt),
87 _("Enter passphrase for <%s>: "), (ps_global->smime && ps_global->smime->passphrase_emailaddr) ? ps_global->smime->passphrase_emailaddr[0] : "unknown");
88
89 do {
90 flags = F_ON(F_QUELL_ASTERISKS, ps_global) ? OE_PASSWD_NOAST : OE_PASSWD;
91 flags |= OE_DISALLOW_HELP;
92 ((char *) ps_global->smime->passphrase)[0] = '\0';
93 rc = optionally_enter((char *) ps_global->smime->passphrase,
94 -FOOTER_ROWS(ps_global), 0,
95 sizeof(ps_global->smime->passphrase),
96 prompt, NULL, help, &flags);
97 } while (rc!=0 && rc!=1 && rc>0);
98
99 if(rc==0){
100 if(ps_global->smime)
101 ps_global->smime->entered_passphrase = 1;
102 }
103
104 return rc; /* better return rc and make the caller check its return value */
105 }
106
107 int
smime_check(BODY * body)108 smime_check(BODY *body)
109 {
110 int rv = 0;
111 PKCS7 *p7 = NULL;
112
113 if(body->type == TYPEMULTIPART){
114 PART *p;
115
116 for(p=body->nested.part; p && rv == 0; p=p->next)
117 rv += smime_check(&p->body);
118 }
119 if(rv > 0) return rv;
120 if(body->sparep)
121 p7 = get_body_sparep_type(body->sparep) == P7Type
122 ? (PKCS7 *)get_body_sparep_data(body->sparep)
123 : NULL;
124 if(p7 && (PKCS7_type_is_signed(p7) || PKCS7_type_is_enveloped(p7)))
125 rv += 1;
126 return rv;
127 }
128
129
130 void
display_smime_info(struct pine * ps,ENVELOPE * env,BODY * body)131 display_smime_info(struct pine *ps, ENVELOPE *env, BODY *body)
132 {
133 OtherMenu what = FirstMenu;
134 HANDLE_S *handles = NULL;
135 SCROLL_S scrollargs;
136 STORE_S *store = NULL;
137 long msgno;
138 int offset = 0;
139
140 msgno = mn_m2raw(ps->msgmap, mn_get_cur(ps->msgmap));
141 store = so_get(CharStar, NULL, EDIT_ACCESS);
142
143 while(ps->next_screen == SCREEN_FUN_NULL){
144
145 ClearLine(1);
146
147 so_truncate(store, 0);
148
149 view_writec_init(store, &handles, HEADER_ROWS(ps),
150 HEADER_ROWS(ps) +
151 ps->ttyo->screen_rows - (HEADER_ROWS(ps)
152 + HEADER_ROWS(ps)));
153
154 gf_puts_uline("Overview", view_writec);
155 gf_puts(NEWLINE, view_writec);
156
157 format_smime_info(1, body, msgno, view_writec);
158 gf_puts(NEWLINE, view_writec);
159 format_smime_info(2, body, msgno, view_writec);
160
161 view_writec_destroy();
162
163 ps->next_screen = SCREEN_FUN_NULL;
164
165 memset(&scrollargs, 0, sizeof(SCROLL_S));
166 scrollargs.text.text = so_text(store);
167 scrollargs.text.src = CharStar;
168 scrollargs.text.desc = "S/MIME information";
169 scrollargs.body_valid = 1;
170
171 if(offset){ /* resize? preserve paging! */
172 scrollargs.start.on = Offset;
173 scrollargs.start.loc.offset = offset;
174 offset = 0L;
175 }
176
177 scrollargs.bar.title = "S/MIME INFORMATION";
178 /* scrollargs.end_scroll = view_end_scroll; */
179 scrollargs.resize_exit = 1;
180 scrollargs.help.text = NULL;
181 scrollargs.help.title = "HELP FOR S/MIME INFORMATION VIEW";
182 scrollargs.keys.menu = &smime_info_keymenu;
183 scrollargs.keys.what = what;
184 setbitmap(scrollargs.keys.bitmap);
185
186 if(scrolltool(&scrollargs) == MC_RESIZE)
187 offset = scrollargs.start.loc.offset;
188 }
189
190 so_give(&store);
191 }
192
193 void
smime_info_screen(struct pine * ps)194 smime_info_screen(struct pine *ps)
195 {
196 long msgno;
197 BODY *body;
198 ENVELOPE *env;
199
200 /* ps->prev_screen = smime_info_screen;
201 ps->next_screen = SCREEN_FUN_NULL; */
202
203 msgno = mn_m2raw(ps->msgmap, mn_get_cur(ps->msgmap));
204
205 env = mail_fetch_structure(ps->mail_stream, msgno, &body, 0);
206
207 if(!env || !body){
208 q_status_message(SM_ORDER, 0, 3,
209 _("Can't fetch body of message."));
210 return;
211 }
212
213 if(smime_check(body) == 0){
214 q_status_message(SM_ORDER | SM_DING, 0, 3,
215 _("Not a signed or encrypted message"));
216 return;
217 }
218
219 if(mn_total_cur(ps->msgmap) > 1L){
220 q_status_message(SM_ORDER | SM_DING, 0, 3,
221 _("Can only view one message's information at a time."));
222 return;
223 }
224
225 display_smime_info(ps, env, body);
226 }
227
228
229 void
format_smime_info(int pass,BODY * body,long msgno,gf_io_t pc)230 format_smime_info(int pass, BODY *body, long msgno, gf_io_t pc)
231 {
232 PKCS7 *p7 = NULL;
233 int i;
234
235 if(body->type == TYPEMULTIPART){
236 PART *p;
237
238 for(p=body->nested.part; p; p=p->next)
239 format_smime_info(pass, &p->body, msgno, pc);
240 }
241 if(body->sparep)
242 p7 = get_body_sparep_type(body->sparep) == P7Type
243 ? (PKCS7 *)get_body_sparep_data(body->sparep)
244 : NULL;
245 if(p7){
246
247 if(PKCS7_type_is_signed(p7)){
248 STACK_OF(X509) *signers;
249
250 switch(pass){
251 case 1:
252 gf_puts(_("This message was cryptographically signed."), pc);
253 gf_puts(NEWLINE, pc);
254 break;
255
256 case 2:
257 signers = PKCS7_get0_signers(p7, NULL, 0);
258
259 if(signers){
260
261 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("Certificate%s used for signing"),
262 plural(sk_X509_num(signers)));
263 gf_puts_uline(tmp_20k_buf, pc);
264 gf_puts(NEWLINE, pc);
265 print_separator_line(100, '-', pc);
266
267 for(i=0; i<sk_X509_num(signers); i++){
268 X509 *x = sk_X509_value(signers, i);
269
270 if(x){
271 output_cert_info(x, pc);
272 gf_puts(NEWLINE, pc);
273 }
274 }
275 }
276
277 sk_X509_free(signers);
278 break;
279 }
280
281 }
282 else if(PKCS7_type_is_enveloped(p7)){
283
284 switch(pass){
285 case 1:
286 gf_puts(_("This message was encrypted."), pc);
287 gf_puts(NEWLINE, pc);
288 break;
289
290 case 2:
291 if(p7->d.enveloped && p7->d.enveloped->enc_data){
292 X509_ALGOR *alg = p7->d.enveloped->enc_data->algorithm;
293 STACK_OF(PKCS7_RECIP_INFO) *ris = p7->d.enveloped->recipientinfo;
294 int found = 0;
295
296 gf_puts(_("The algorithm used to encrypt was "), pc);
297
298 if(alg){
299 char *n = (char *) OBJ_nid2sn( OBJ_obj2nid(alg->algorithm));
300
301 gf_puts(n ? n : "<unknown>", pc);
302
303 }
304 else
305 gf_puts("<unknown>", pc);
306
307 gf_puts("." NEWLINE NEWLINE, pc);
308
309 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("Certificate%s for decrypting"),
310 plural(sk_PKCS7_RECIP_INFO_num(ris)));
311 gf_puts_uline(tmp_20k_buf, pc);
312 gf_puts(NEWLINE, pc);
313 print_separator_line(100, '-', pc);
314
315 for(i=0; i<sk_PKCS7_RECIP_INFO_num(ris); i++){
316 PKCS7_RECIP_INFO *ri;
317 PERSONAL_CERT *pcert;
318
319 ri = sk_PKCS7_RECIP_INFO_value(ris, i);
320 if(!ri)
321 continue;
322
323 pcert = find_certificate_matching_recip_info(ri);
324
325 if(pcert){
326 if(found){
327 print_separator_line(25, '*', pc);
328 gf_puts(NEWLINE, pc);
329 }
330
331 found = 1;
332
333 output_cert_info(pcert->cert, pc);
334 gf_puts(NEWLINE, pc);
335
336 }
337 }
338
339 if(!found){
340 gf_puts(_("No certificate capable of decrypting could be found."), pc);
341 gf_puts(NEWLINE, pc);
342 gf_puts(NEWLINE, pc);
343 }
344 }
345
346 break;
347 }
348 }
349 }
350 }
351
352
353 void
print_separator_line(int percent,int ch,gf_io_t pc)354 print_separator_line(int percent, int ch, gf_io_t pc)
355 {
356 int i, start, len;
357
358 len = ps_global->ttyo->screen_cols * percent / 100;
359 start = (ps_global->ttyo->screen_cols - len)/2;
360
361 for(i=0; i<start; i++)
362 pc(' ');
363
364 for(i=start; i<start+len; i++)
365 pc(ch);
366
367 gf_puts(NEWLINE, pc);
368 }
369
370
371 void
output_cert_info(X509 * cert,gf_io_t pc)372 output_cert_info(X509 *cert, gf_io_t pc)
373 {
374 char buf[256];
375 STORE_S *left,*right;
376 gf_io_t spc;
377 int len, error;
378 STACK_OF(X509) *chain;
379
380 left = so_get(CharStar, NULL, EDIT_ACCESS);
381 right = so_get(CharStar, NULL, EDIT_ACCESS);
382 if(!(left && right))
383 return;
384
385 gf_set_so_writec(&spc, left);
386
387 gf_puts_uline("Certificate Owner", spc);
388 gf_puts(NEWLINE, spc);
389
390 output_X509_NAME(X509_get_subject_name(cert), spc);
391 gf_puts(NEWLINE, spc);
392
393 gf_puts_uline("Serial Number", spc);
394 gf_puts(NEWLINE, spc);
395
396 { ASN1_INTEGER *bs;
397 long l;
398 const char *neg;
399 int i;
400
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="-";
407 }
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 ? "" : ":");
416 }
417 }
418 gf_puts(buf, spc);
419 gf_puts(NEWLINE, spc);
420 gf_puts(NEWLINE, spc);
421
422 gf_puts_uline("Validity", spc);
423 gf_puts(NEWLINE, spc);
424 { BIO *mb = BIO_new(BIO_s_mem());
425 char iobuf[4096];
426
427 gf_puts("Not Before: ", spc);
428
429 (void) BIO_reset(mb);
430 ASN1_UTCTIME_print(mb, X509_get0_notBefore(cert));
431 (void) BIO_flush(mb);
432 while((len = BIO_read(mb, iobuf, sizeof(iobuf))) > 0)
433 gf_nputs(iobuf, len, spc);
434
435 gf_puts(NEWLINE, spc);
436
437 gf_puts("Not After: ", spc);
438
439 (void) BIO_reset(mb);
440 ASN1_UTCTIME_print(mb, X509_get0_notAfter(cert));
441 (void) BIO_flush(mb);
442 while((len = BIO_read(mb, iobuf, sizeof(iobuf))) > 0)
443 gf_nputs(iobuf, len, spc);
444
445 gf_puts(NEWLINE, spc);
446 gf_puts(NEWLINE, spc);
447
448 BIO_free(mb);
449 }
450
451 gf_clear_so_writec(left);
452
453 gf_set_so_writec(&spc, right);
454
455 gf_puts_uline("Issuer", spc);
456 gf_puts(NEWLINE, spc);
457
458 output_X509_NAME(X509_get_issuer_name(cert), spc);
459 gf_puts(NEWLINE, spc);
460
461 gf_clear_so_writec(right);
462
463 side_by_side(left, right, pc);
464
465 gf_puts_uline("SHA1 Fingerprint", pc);
466 gf_puts(NEWLINE, pc);
467 get_fingerprint(cert, EVP_sha1(), buf, sizeof(buf), ":");
468 gf_puts(buf, pc);
469 gf_puts(NEWLINE, pc);
470
471 gf_puts_uline("MD5 Fingerprint", pc);
472 gf_puts(NEWLINE, pc);
473 get_fingerprint(cert, EVP_md5(), buf, sizeof(buf), ":");
474 gf_puts(buf, pc);
475 gf_puts(NEWLINE, pc);
476 gf_puts(NEWLINE, pc);
477
478 gf_puts_uline("Certificate Chain Information", pc);
479 gf_puts(NEWLINE, pc);
480
481 if((chain = get_chain_for_cert(cert, &error, &len)) != NULL){
482 X509 *x = NULL;
483 X509_NAME_ENTRY *e;
484 int i, offset = 2;
485 char space[256];
486 X509_NAME *subject;
487
488 for(i = 0; i < offset; i++) space[i] = ' ';
489
490 for(i = -1; i < sk_X509_num(chain); i++){
491 char buf[256];
492
493 x = i == -1 ? cert : sk_X509_value(chain, i);
494
495 if(x){
496 if(i>=0){
497 space[offset + i + 0] = ' ';
498 space[offset + i + 1] = '\\';
499 space[offset + i + 2] = '-';
500 space[offset + i + 3] = ' ';
501 space[offset + i + 4] = '\0';
502 gf_puts(space, pc);
503 }
504 else{
505 space[offset] = '\0';
506 gf_puts(space, pc);
507 }
508 if(i >= 0)
509 gf_puts_uline("Signed by: ", pc);
510 else
511 gf_puts_uline("Issued to: ", pc);
512
513 subject = X509_get_subject_name(x);
514
515 if((e = X509_NAME_get_entry(subject, X509_NAME_entry_count(subject)-1)) != NULL){
516 X509_NAME_get_text_by_OBJ(subject, X509_NAME_ENTRY_get_object(e), buf, sizeof(buf));
517 gf_puts(buf, pc);
518 gf_puts(NEWLINE, pc);
519 }
520 }
521 else{
522 gf_puts("No certificate info found", pc);
523 gf_puts(NEWLINE, pc);
524 break;
525 }
526 }
527 e = X509_NAME_get_entry(X509_get_issuer_name(x),
528 X509_NAME_entry_count(X509_get_issuer_name(x))-1);
529 if(e){
530 X509_NAME_get_text_by_OBJ(X509_get_issuer_name(x), X509_NAME_ENTRY_get_object(e), buf, sizeof(buf));
531 space[offset + i + 0] = ' ';
532 space[offset + i + 1] = '\\';
533 space[offset + i + 2] = '-';
534 space[offset + i + 3] = ' ';
535 space[offset + i + 4] = '\0';
536 gf_puts(space, pc);
537 gf_puts_uline("Signed by: ", pc);
538 gf_puts(buf, pc);
539 gf_puts(NEWLINE, pc);
540 }
541 sk_X509_pop_free(chain, X509_free);
542 }
543 gf_puts(NEWLINE, pc);
544
545 so_give(&left);
546 so_give(&right);
547 }
548
549
550 void
output_X509_NAME(X509_NAME * name,gf_io_t pc)551 output_X509_NAME(X509_NAME *name, gf_io_t pc)
552 {
553 int i, c;
554 char buf[256];
555
556 c = X509_NAME_entry_count(name);
557
558 for(i=c-1; i>=0; i--){
559 X509_NAME_ENTRY *e;
560
561 e = X509_NAME_get_entry(name,i);
562 if(!e)
563 continue;
564
565 X509_NAME_get_text_by_OBJ(name, X509_NAME_ENTRY_get_object(e), buf, sizeof(buf));
566
567 gf_puts(buf, pc);
568 gf_puts(NEWLINE, pc);
569 }
570 }
571
572
573 /*
574 * Output the contents of the given stores (left and right)
575 * to the given gf_io_t.
576 * The width of the terminal is inspected and two columns
577 * are created to fit the stores into. They are then wrapped
578 * and merged.
579 */
580 void
side_by_side(STORE_S * left,STORE_S * right,gf_io_t pc)581 side_by_side(STORE_S *left, STORE_S *right, gf_io_t pc)
582 {
583 STORE_S *left_wrapped;
584 STORE_S *right_wrapped;
585 char buf_l[256];
586 char buf_r[256];
587 char *l, *r;
588 char *b;
589 int i;
590 int w = ps_global->ttyo->screen_cols/2 - 1;
591
592 so_seek(left, 0, 0);
593 so_seek(right, 0, 0);
594
595 left_wrapped = wrap_store(left, w);
596 right_wrapped = wrap_store(right, w);
597
598 so_seek(left_wrapped, 0, 0);
599 so_seek(right_wrapped, 0, 0);
600
601 for(;;){
602
603 l = so_fgets(left_wrapped, buf_l, sizeof(buf_l));
604 r = so_fgets(right_wrapped, buf_r, sizeof(buf_r));
605 if(l == NULL && r == NULL)
606 break;
607
608 for(i=0, b=buf_l; i<w && *b && *b!='\r' && *b!='\n'; i++,b++){
609 pc(*b);
610 /* reduce accumulated width if an embed tag is discovered */
611 if(*b==TAG_EMBED)
612 i-=2;
613 }
614
615 if(buf_r[0]){
616 while(i<w){
617 pc(' ');
618 i++;
619 }
620 pc(' ');
621
622 for(i=0, b=buf_r; i<w && *b && *b!='\r' && *b!='\n'; i++,b++)
623 pc(*b);
624 }
625
626 gf_puts(NEWLINE, pc);
627 }
628
629 so_give(&left_wrapped);
630 so_give(&right_wrapped);
631 }
632
633 /*
634 * Wrap the text in the given store to the given width.
635 * A new store is created for the result.
636 */
637 STORE_S *
wrap_store(STORE_S * in,int width)638 wrap_store(STORE_S *in, int width)
639 {
640 STORE_S *result;
641 void *ws;
642 gf_io_t ipc,opc;
643
644 if(width<10)
645 width = 10;
646
647 result = so_get(CharStar, NULL, EDIT_ACCESS);
648 ws = gf_wrap_filter_opt(width, width, NULL, 0, 0);
649
650 gf_filter_init();
651 gf_link_filter(gf_wrap, ws);
652
653 gf_set_so_writec(&opc, result);
654 gf_set_so_readc(&ipc, in);
655
656 gf_pipe(ipc, opc);
657
658 gf_clear_so_readc(in);
659 gf_clear_so_writec(result);
660
661 return result;
662 }
663
664
665 void
smime_config_screen(struct pine * ps,int edit_exceptions)666 smime_config_screen(struct pine *ps, int edit_exceptions)
667 {
668 CONF_S *ctmp = NULL, *first_line = NULL;
669 SAVED_CONFIG_S *vsave;
670 OPT_SCREEN_S screen;
671 int ew, readonly_warning = 0;
672
673 dprint((9, "smime_config_screen()"));
674 ps->next_screen = SCREEN_FUN_NULL;
675
676 /*
677 * this is necessary because we need to know the correct paths
678 * to configure certificates and keys, and we could get here
679 * without having done that before we reach this place.
680 */
681 smime_reinit();
682
683 if(ps->fix_fixed_warning)
684 offer_to_fix_pinerc(ps);
685
686 ew = edit_exceptions ? ps_global->ew_for_except_vars : Main;
687
688 if(ps->restricted)
689 readonly_warning = 1;
690 else{
691 PINERC_S *prc = NULL;
692
693 switch(ew){
694 case Main:
695 prc = ps->prc;
696 break;
697 case Post:
698 prc = ps->post_prc;
699 break;
700 default:
701 break;
702 }
703
704 readonly_warning = prc ? prc->readonly : 1;
705 if(prc && prc->quit_to_edit){
706 quit_to_edit_msg(prc);
707 return;
708 }
709 }
710
711 smime_config_init_display(ps, &ctmp, &first_line);
712
713 vsave = save_smime_config_vars(ps);
714
715 memset(&screen, 0, sizeof(screen));
716 screen.deferred_ro_warning = readonly_warning;
717 switch(conf_scroll_screen(ps, &screen, first_line,
718 edit_exceptions ? _("SETUP S/MIME EXCEPTIONS")
719 : _("SETUP S/MIME"),
720 /* TRANSLATORS: Print something1 using something2.
721 configuration is something1 */
722 _("configuration"), 0, NULL)){
723 case 0:
724 break;
725
726 case 1:
727 write_pinerc(ps, ew, WRP_NONE);
728 break;
729
730 case 10:
731 revert_to_saved_smime_config(ps, vsave);
732 break;
733
734 default:
735 q_status_message(SM_ORDER, 7, 10,
736 _("conf_scroll_screen bad ret in smime_config"));
737 break;
738 }
739
740 free_saved_smime_config(ps, &vsave);
741 smime_reinit();
742 }
743
744
745 int
smime_related_var(struct pine * ps,struct variable * var)746 smime_related_var(struct pine *ps, struct variable *var)
747 {
748 return(var == &ps->vars[V_PUBLICCERT_DIR] ||
749 var == &ps->vars[V_PUBLICCERT_CONTAINER] ||
750 var == &ps->vars[V_PRIVATEKEY_DIR] ||
751 var == &ps->vars[V_PRIVATEKEY_CONTAINER] ||
752 var == &ps->vars[V_CACERT_DIR] ||
753 var == &ps->vars[V_CACERT_CONTAINER]);
754 }
755
756 void
smime_config_init_display(struct pine * ps,CONF_S ** ctmp,CONF_S ** first_line)757 smime_config_init_display(struct pine *ps, CONF_S **ctmp, CONF_S **first_line)
758 {
759 char tmp[200];
760 int i, ind, ln = 0;
761 struct variable *vtmp;
762 CONF_S *ctmpb;
763 FEATURE_S *feature;
764
765 /* find longest variable name */
766 for(vtmp = ps->vars; vtmp->name; vtmp++){
767 if(!(smime_related_var(ps, vtmp)))
768 continue;
769
770 if((i = utf8_width(pretty_var_name(vtmp->name))) > ln)
771 ln = i;
772 }
773
774 for(vtmp = ps->vars; vtmp->name; vtmp++){
775 if(!(smime_related_var(ps, vtmp)))
776 continue;
777
778 new_confline(ctmp)->var = vtmp;
779 if(first_line && !*first_line)
780 *first_line = *ctmp;
781
782 (*ctmp)->valoffset = ln+3;
783 (*ctmp)->keymenu = &config_text_keymenu;
784 (*ctmp)->help = config_help(vtmp - ps->vars, 0);
785 (*ctmp)->tool = text_tool;
786
787 utf8_snprintf(tmp, sizeof(tmp), "%-*.100w =", ln, pretty_var_name(vtmp->name));
788 tmp[sizeof(tmp)-1] = '\0';
789
790 (*ctmp)->varname = cpystr(tmp);
791 (*ctmp)->varnamep = (*ctmp);
792 (*ctmp)->flags = CF_STARTITEM;
793 (*ctmp)->value = pretty_value(ps, *ctmp);
794 }
795
796
797 vtmp = &ps->vars[V_FEATURE_LIST];
798
799 new_confline(ctmp);
800 ctmpb = (*ctmp);
801 (*ctmp)->flags |= CF_NOSELECT | CF_STARTITEM;
802 (*ctmp)->keymenu = &config_checkbox_keymenu;
803 (*ctmp)->tool = NULL;
804
805 /* put a nice delimiter before list */
806 new_confline(ctmp)->var = NULL;
807 (*ctmp)->varnamep = ctmpb;
808 (*ctmp)->keymenu = &config_checkbox_keymenu;
809 (*ctmp)->help = NO_HELP;
810 (*ctmp)->tool = checkbox_tool;
811 (*ctmp)->valoffset = feature_indent();
812 (*ctmp)->flags |= CF_NOSELECT;
813 (*ctmp)->value = cpystr("Set Feature Name");
814
815 new_confline(ctmp)->var = NULL;
816 (*ctmp)->varnamep = ctmpb;
817 (*ctmp)->keymenu = &config_checkbox_keymenu;
818 (*ctmp)->help = NO_HELP;
819 (*ctmp)->tool = checkbox_tool;
820 (*ctmp)->valoffset = feature_indent();
821 (*ctmp)->flags |= CF_NOSELECT;
822 (*ctmp)->value = cpystr("--- ----------------------");
823
824 ind = feature_list_index(F_DONT_DO_SMIME);
825 feature = feature_list(ind);
826 new_confline(ctmp)->var = vtmp;
827 (*ctmp)->varnamep = ctmpb;
828 (*ctmp)->keymenu = &config_checkbox_keymenu;
829 (*ctmp)->help = config_help(vtmp-ps->vars, feature->id);
830 (*ctmp)->tool = checkbox_tool;
831 (*ctmp)->valoffset = feature_indent();
832 (*ctmp)->varmem = ind;
833 (*ctmp)->value = pretty_value(ps, (*ctmp));
834
835 ind = feature_list_index(F_ENCRYPT_DEFAULT_ON);
836 feature = feature_list(ind);
837 new_confline(ctmp)->var = vtmp;
838 (*ctmp)->varnamep = ctmpb;
839 (*ctmp)->keymenu = &config_checkbox_keymenu;
840 (*ctmp)->help = config_help(vtmp-ps->vars, feature->id);
841 (*ctmp)->tool = checkbox_tool;
842 (*ctmp)->valoffset = feature_indent();
843 (*ctmp)->varmem = ind;
844 (*ctmp)->value = pretty_value(ps, (*ctmp));
845
846 ind = feature_list_index(F_REMEMBER_SMIME_PASSPHRASE);
847 feature = feature_list(ind);
848 new_confline(ctmp)->var = vtmp;
849 (*ctmp)->varnamep = ctmpb;
850 (*ctmp)->keymenu = &config_checkbox_keymenu;
851 (*ctmp)->help = config_help(vtmp-ps->vars, feature->id);
852 (*ctmp)->tool = checkbox_tool;
853 (*ctmp)->valoffset = feature_indent();
854 (*ctmp)->varmem = ind;
855 (*ctmp)->value = pretty_value(ps, (*ctmp));
856
857 ind = feature_list_index(F_SIGN_DEFAULT_ON);
858 feature = feature_list(ind);
859 new_confline(ctmp)->var = vtmp;
860 (*ctmp)->varnamep = ctmpb;
861 (*ctmp)->keymenu = &config_checkbox_keymenu;
862 (*ctmp)->help = config_help(vtmp-ps->vars, feature->id);
863 (*ctmp)->tool = checkbox_tool;
864 (*ctmp)->valoffset = feature_indent();
865 (*ctmp)->varmem = ind;
866 (*ctmp)->value = pretty_value(ps, (*ctmp));
867
868 ind = feature_list_index(F_USE_CERT_STORE_ONLY);
869 feature = feature_list(ind);
870 new_confline(ctmp)->var = vtmp;
871 (*ctmp)->varnamep = ctmpb;
872 (*ctmp)->keymenu = &config_checkbox_keymenu;
873 (*ctmp)->help = config_help(vtmp-ps->vars, feature->id);
874 (*ctmp)->tool = checkbox_tool;
875 (*ctmp)->valoffset = feature_indent();
876 (*ctmp)->varmem = ind;
877 (*ctmp)->value = pretty_value(ps, (*ctmp));
878
879 #ifdef APPLEKEYCHAIN
880 new_confline(ctmp);
881 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
882
883 new_confline(ctmp);
884 (*ctmp)->flags |= CF_NOSELECT;
885 (*ctmp)->value = cpystr(_("Mac OS X specific features"));
886
887 ind = feature_list_index(F_PUBLICCERTS_IN_KEYCHAIN);
888 feature = feature_list(ind);
889 new_confline(ctmp)->var = vtmp;
890 (*ctmp)->varnamep = ctmpb;
891 (*ctmp)->keymenu = &config_checkbox_keymenu;
892 (*ctmp)->help = config_help(vtmp-ps->vars, feature->id);
893 (*ctmp)->tool = checkbox_tool;
894 (*ctmp)->valoffset = feature_indent();
895 (*ctmp)->varmem = ind;
896 (*ctmp)->value = pretty_value(ps, (*ctmp));
897 #endif /* APPLEKEYCHAIN */
898
899 new_confline(ctmp);
900 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
901
902 for(i = 0; i < sizeof(tmp) && i < (ps->ttyo ? ps->ttyo->screen_cols : sizeof(tmp)); i++)
903 tmp[i] = '-';
904 tmp[i] = '\0';
905 new_confline(ctmp);
906 (*ctmp)->flags |= CF_NOSELECT;
907 (*ctmp)->value = cpystr(tmp);
908
909 new_confline(ctmp);
910 (*ctmp)->flags |= CF_NOSELECT;
911 (*ctmp)->value = cpystr(_("Be careful with the following commands, they REPLACE contents in the target"));
912
913 new_confline(ctmp);
914 (*ctmp)->flags |= CF_NOSELECT;
915 (*ctmp)->value = cpystr(tmp);
916
917 new_confline(ctmp);
918 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
919
920 /* copy public directory to container */
921 new_confline(ctmp);
922 (*ctmp)->tool = smime_helper_tool;
923 (*ctmp)->keymenu = &config_smime_helper_keymenu;
924 (*ctmp)->help = h_config_smime_transfer_pub_to_con;
925 (*ctmp)->value = cpystr(_("Transfer public certs FROM directory TO container"));
926 (*ctmp)->varmem = 1;
927
928 /* copy private directory to container */
929 new_confline(ctmp);
930 (*ctmp)->tool = smime_helper_tool;
931 (*ctmp)->keymenu = &config_smime_helper_keymenu;
932 (*ctmp)->help = h_config_smime_transfer_priv_to_con;
933 (*ctmp)->value = cpystr(_("Transfer private keys FROM directory TO container"));
934 (*ctmp)->varmem = 3;
935
936 /* copy cacert directory to container */
937 new_confline(ctmp);
938 (*ctmp)->tool = smime_helper_tool;
939 (*ctmp)->keymenu = &config_smime_helper_keymenu;
940 (*ctmp)->help = h_config_smime_transfer_cacert_to_con;
941 (*ctmp)->value = cpystr(_("Transfer CA certs FROM directory TO container"));
942 (*ctmp)->varmem = 5;
943
944 new_confline(ctmp)->var = vtmp;
945 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
946
947 /* copy public container to directory */
948 new_confline(ctmp);
949 (*ctmp)->tool = smime_helper_tool;
950 (*ctmp)->keymenu = &config_smime_helper_keymenu;
951 (*ctmp)->help = h_config_smime_transfer_pub_to_dir;
952 (*ctmp)->value = cpystr(_("Transfer public certs FROM container TO directory"));
953 (*ctmp)->varmem = 2;
954
955 /* copy private container to directory */
956 new_confline(ctmp);
957 (*ctmp)->tool = smime_helper_tool;
958 (*ctmp)->keymenu = &config_smime_helper_keymenu;
959 (*ctmp)->help = h_config_smime_transfer_priv_to_dir;
960 (*ctmp)->value = cpystr(_("Transfer private keys FROM container TO directory"));
961 (*ctmp)->varmem = 4;
962
963 /* copy cacert container to directory */
964 new_confline(ctmp);
965 (*ctmp)->tool = smime_helper_tool;
966 (*ctmp)->keymenu = &config_smime_helper_keymenu;
967 (*ctmp)->help = h_config_smime_transfer_cacert_to_dir;
968 (*ctmp)->value = cpystr(_("Transfer CA certs FROM container TO directory"));
969 (*ctmp)->varmem = 6;
970
971 #ifdef APPLEKEYCHAIN
972
973 new_confline(ctmp)->var = vtmp;
974 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
975
976 /* copy public container to keychain */
977 new_confline(ctmp);
978 (*ctmp)->tool = smime_helper_tool;
979 (*ctmp)->keymenu = &config_smime_helper_keymenu;
980 (*ctmp)->help = h_config_smime_transfer_pubcon_to_key;
981 (*ctmp)->value = cpystr(_("Transfer public certs FROM container TO keychain"));
982 (*ctmp)->varmem = 7;
983
984 /* copy public keychain to container */
985 new_confline(ctmp);
986 (*ctmp)->tool = smime_helper_tool;
987 (*ctmp)->keymenu = &config_smime_helper_keymenu;
988 (*ctmp)->help = h_config_smime_transfer_pubkey_to_con;
989 (*ctmp)->value = cpystr(_("Transfer public certs FROM keychain TO container"));
990 (*ctmp)->varmem = 8;
991
992 #endif /* APPLEKEYCHAIN */
993
994 if(ps_global->smime
995 && SMHOLDERTYPE(Private) == Keychain
996 && SMHOLDERTYPE(Public) == Keychain
997 && SMHOLDERTYPE(CACert) == Keychain)
998 return;
999
1000 new_confline(ctmp)->var = vtmp;
1001 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
1002
1003 new_confline(ctmp);
1004 (*ctmp)->flags |= CF_NOSELECT;
1005 (*ctmp)->value = cpystr(tmp);
1006
1007 new_confline(ctmp);
1008 (*ctmp)->flags |= CF_NOSELECT;
1009 (*ctmp)->value = cpystr(_("Manage your own certificates"));
1010
1011 new_confline(ctmp);
1012 (*ctmp)->flags |= CF_NOSELECT;
1013 (*ctmp)->value = cpystr(tmp);
1014
1015 new_confline(ctmp)->var = vtmp;
1016 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
1017
1018 /* manage public certificates */
1019 new_confline(ctmp);
1020 (*ctmp)->tool = smime_helper_tool;
1021 (*ctmp)->keymenu = &config_smime_manage_certs_menu_keymenu;
1022 (*ctmp)->help = h_config_smime_public_certificates;
1023 (*ctmp)->value = cpystr(_("Manage Public Certificates"));
1024 (*ctmp)->varmem = 9;
1025 (*ctmp)->d.s.ctype = Public;
1026
1027 /* manage private keys */
1028 new_confline(ctmp);
1029 (*ctmp)->tool = smime_helper_tool;
1030 (*ctmp)->keymenu = &config_smime_manage_certs_menu_keymenu;
1031 (*ctmp)->help = h_config_smime_private_keys;
1032 (*ctmp)->value = cpystr(_("Manage Private Keys"));
1033 (*ctmp)->varmem = 10;
1034 (*ctmp)->d.s.ctype = Private;
1035
1036 /* manage Certificate Authorities */
1037 new_confline(ctmp);
1038 (*ctmp)->tool = smime_helper_tool;
1039 (*ctmp)->keymenu = &config_smime_manage_certs_menu_keymenu;
1040 (*ctmp)->help = h_config_smime_certificate_authorities;
1041 (*ctmp)->value = cpystr(_("Manage Certificate Authorities"));
1042 (*ctmp)->varmem = 11;
1043 (*ctmp)->d.s.ctype = CACert;
1044
1045 #ifdef PASSFILE
1046 new_confline(ctmp)->var = vtmp;
1047 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
1048
1049 new_confline(ctmp);
1050 (*ctmp)->flags |= CF_NOSELECT;
1051 (*ctmp)->value = cpystr(tmp);
1052
1053 new_confline(ctmp);
1054 (*ctmp)->flags |= CF_NOSELECT;
1055 (*ctmp)->value = cpystr(_("Manage Key and Certificate for Password File"));
1056
1057 new_confline(ctmp);
1058 (*ctmp)->flags |= CF_NOSELECT;
1059 (*ctmp)->value = cpystr(tmp);
1060
1061 new_confline(ctmp)->var = vtmp;
1062 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
1063
1064 /* manage password file certificates */
1065 new_confline(ctmp);
1066 (*ctmp)->tool = smime_helper_tool;
1067 (*ctmp)->keymenu = &config_smime_manage_password_file_menu_keymenu;
1068 (*ctmp)->help = h_config_smime_password_file_certificates;
1069 (*ctmp)->value = cpystr(_("Manage Password File Key and Certificate"));
1070 (*ctmp)->varmem = 12;
1071 (*ctmp)->d.s.ctype = Password;
1072 #endif /* PASSFILE */
1073
1074 (*ctmp)->next = NULL;
1075 }
1076
1077 void
display_certificate_information(struct pine * ps,X509 * cert,char * email,WhichCerts ctype,int num)1078 display_certificate_information(struct pine *ps, X509 *cert, char *email, WhichCerts ctype, int num)
1079 {
1080 STORE_S *store;
1081 SCROLL_S scrollargs;
1082 int cmd, offset;
1083 int pub_cert, priv_cert, new_store;
1084 long error;
1085 BIO *out = NULL;
1086
1087 cmd = offset = pub_cert = priv_cert = 0;
1088 new_store = 1;
1089 ps->next_screen = SCREEN_FUN_NULL;
1090 do {
1091 /* MC_PRIVATE and MC_PUBLIC cancel each other,
1092 * they can not be active at the same time
1093 */
1094 switch(cmd){
1095 case MC_PRIVATE:
1096 pub_cert = 0;
1097 priv_cert = 1 - priv_cert;
1098 smime_certificate_info_keymenu.keys[PUBLIC_KEY].label = N_("Public Key");
1099 smime_certificate_info_keymenu.keys[PRIVATE_KEY].label = priv_cert ? N_("No Priv Key") : N_("Pivate Key");
1100 break;
1101
1102 case MC_PUBLIC:
1103 priv_cert = 0;
1104 pub_cert = 1 - pub_cert;
1105 smime_certificate_info_keymenu.keys[PRIVATE_KEY].label = priv_cert ? N_("No Priv Key") : N_("Pivate Key");
1106 smime_certificate_info_keymenu.keys[PUBLIC_KEY].label = N_("Public Key");
1107 break;
1108
1109 case MC_TRUST:
1110 if(SMHOLDERTYPE(CACert) == Directory)
1111 save_cert_for(email, cert, CACert);
1112 else{ /* if(SMHOLDERTYPE(CACert) == Container) */
1113 char path[MAXPATH];
1114 char *upath = PATHCERTDIR(ctype);
1115 char *tempfile = tempfile_in_same_dir(path, "az", NULL);
1116 CertList *clist;
1117
1118 if(IS_REMOTE(upath))
1119 strncpy(path, temp_nam(NULL, "a6"), sizeof(path)-1);
1120 else
1121 strncpy(path, upath, sizeof(path)-1);
1122 path[sizeof(path)-1] = '\0';
1123
1124 add_to_end_of_certlist(&ps_global->smime->cacertlist, email, X509_dup(cert));
1125 for(clist=ps_global->smime->cacertlist; clist && clist->next; clist = clist->next);
1126 certlist_to_file(tempfile, clist);
1127 add_file_to_container(CACert, tempfile, email);
1128 unlink(tempfile);
1129 }
1130 renew_store();
1131 new_store = 1;
1132 break;
1133
1134 case MC_DELETE:
1135 if (get_cert_deleted(ctype, num) != 0)
1136 q_status_message(SM_ORDER, 1, 3, _("Certificate already deleted"));
1137 else{
1138 mark_cert_deleted(ctype, num, 1);
1139 q_status_message(SM_ORDER, 1, 3, _("Certificate marked deleted"));
1140 }
1141 break;
1142
1143 case MC_UNDELETE:
1144 if (get_cert_deleted(ctype, num) != 0){
1145 mark_cert_deleted(ctype, num, 0);
1146 q_status_message(SM_ORDER, 1, 3, _("Certificate marked UNdeleted"));
1147 }
1148 else
1149 q_status_message(SM_ORDER, 1, 3, _("Certificate not marked deleted"));
1150 break;
1151
1152 default: break;
1153 }
1154
1155 if((pub_cert || priv_cert)
1156 && (out = print_private_key_information(email, priv_cert)) == NULL)
1157 q_status_message(SM_ORDER, 1, 3, _("Problem Reading Private Certificate Information"));
1158
1159 if(new_store){
1160 store = so_get(CharStar, NULL, EDIT_ACCESS);
1161 view_writec_init(store, NULL, HEADER_ROWS(ps),
1162 HEADER_ROWS(ps) + ps->ttyo->screen_rows - (HEADER_ROWS(ps)+ FOOTER_ROWS(ps)));
1163
1164 snprintf(tmp_20k_buf, SIZEOF_20KBUF,"%s", _("Certificate Information"));
1165 gf_puts_uline(tmp_20k_buf, view_writec);
1166 gf_puts(NEWLINE, view_writec);
1167 print_separator_line(100, '-', view_writec);
1168
1169 output_cert_info(cert, view_writec);
1170 gf_puts(NEWLINE, view_writec);
1171
1172 if(smime_validate_cert(cert, &error) < 0){
1173 const char *errorp = X509_verify_cert_error_string(error);
1174 snprintf(tmp_20k_buf, SIZEOF_20KBUF,_("Error validating certificate: %s"), errorp);
1175 } else
1176 snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s", _("Certificate validated without errors"));
1177
1178 gf_puts_uline(tmp_20k_buf, view_writec);
1179 gf_puts(NEWLINE, view_writec);
1180
1181 if(out != NULL){ /* print private key information */
1182 unsigned char ch[2];
1183
1184 gf_puts(NEWLINE, view_writec);
1185 ch[1] = '\0';
1186 while(BIO_read(out, ch, 1) >= 1)
1187 gf_puts((char *)ch, view_writec);
1188 gf_puts(NEWLINE, view_writec);
1189 q_status_message1(SM_ORDER, 1, 3, _("%s information shown at bottom of certificate information"), pub_cert ? _("Public") : _("Private"));
1190 BIO_free_all(out);
1191 out = NULL;
1192 }
1193 view_writec_destroy();
1194 new_store = 0;
1195 }
1196
1197 memset(&scrollargs, 0, sizeof(SCROLL_S));
1198
1199 scrollargs.text.text = so_text(store);
1200 scrollargs.text.src = CharStar;
1201 scrollargs.text.desc = "certificate information";
1202 scrollargs.body_valid = 1;
1203
1204 if(offset){ /* resize? preserve paging! */
1205 scrollargs.start.on = Offset;
1206 scrollargs.start.loc.offset = offset;
1207 scrollargs.body_valid = 0;
1208 offset = 0L;
1209 }
1210
1211 scrollargs.use_indexline_color = 1;
1212
1213 scrollargs.bar.title = _("CERTIFICATE INFORMATION");
1214 scrollargs.proc.tool = manage_certificate_info_tool;
1215 scrollargs.resize_exit = 1;
1216 scrollargs.help.text = h_certificate_information;
1217 scrollargs.help.title = _("HELP FOR MESSAGE TEXT VIEW");
1218 scrollargs.keys.what = FirstMenu;
1219 scrollargs.keys.menu = &smime_certificate_info_keymenu;
1220 setbitmap(scrollargs.keys.bitmap);
1221 if(ctype != Public || error != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
1222 /*error != X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)*/
1223 clrbitn(TRUST_KEY, scrollargs.keys.bitmap);
1224 if(ctype != Private){
1225 clrbitn(PUBLIC_KEY, scrollargs.keys.bitmap);
1226 clrbitn(PRIVATE_KEY, scrollargs.keys.bitmap);
1227 }
1228 if(ctype == Password){
1229 clrbitn(DELETE_CERT_KEY, scrollargs.keys.bitmap);
1230 clrbitn(UNDELETE_CERT_KEY, scrollargs.keys.bitmap);
1231 }
1232
1233 cmd = scrolltool(&scrollargs);
1234
1235 switch(cmd){
1236 case MC_RESIZE :
1237 case MC_PRIVATE:
1238 case MC_PUBLIC : if(scrollargs.start.on == Offset)
1239 offset = scrollargs.start.loc.offset;
1240 new_store = 1;
1241 default: break;
1242 }
1243 if(new_store)
1244 so_give(&store);
1245 } while (cmd != MC_EXIT);
1246 ps->mangled_screen = 1;
1247 }
1248
1249 /*
1250 * This is silly, we just need this function so that we can tell scrolltool
1251 * that some commands are recognized. We use scrolltool because we do not
1252 * want to rewrite output_cert_info.
1253 */
1254 int
manage_certificate_info_tool(int cmd,MSGNO_S * msgmap,SCROLL_S * sparms)1255 manage_certificate_info_tool(int cmd, MSGNO_S *msgmap, SCROLL_S *sparms)
1256 {
1257 int rv;
1258 switch(cmd){
1259 case MC_DELETE:
1260 case MC_UNDELETE:
1261 case MC_PRIVATE:
1262 case MC_PUBLIC:
1263 case MC_TRUST: rv = 1; break;
1264 default: rv = 0; break;
1265 }
1266 return rv;
1267 }
1268
1269
1270 int
manage_certs_tool(struct pine * ps,int cmd,CONF_S ** cl,unsigned flags)1271 manage_certs_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned flags)
1272 {
1273 int rv = 0;
1274 X509 *cert = NULL;
1275 WhichCerts ctype = (*cl)->d.s.ctype;
1276
1277 switch(cmd){
1278 case MC_ADD: /* create a self signed certificate and import it */
1279 if(ctype == Password){
1280 PERSONAL_CERT *pc;
1281 char pathdir[MAXPATH+1], filename[MAXPATH+1];
1282 struct stat sbuf;
1283 int st;
1284 smime_path(DF_SMIMETMPDIR, pathdir, sizeof(pathdir));
1285 if(((st = our_stat(pathdir, &sbuf)) == 0
1286 && (sbuf.st_mode & S_IFMT) == S_IFDIR)
1287 || (st != 0
1288 && can_access(pathdir, ACCESS_EXISTS) != 0
1289 && our_mkpath(pathdir, 0700) == 0)){
1290 pc = ALPINE_self_signed_certificate(NULL, 0, pathdir, MASTERNAME);
1291 if(strlen(pathdir) + strlen(MASTERNAME) + 5 + 1 > sizeof(filename)){
1292 q_status_message(SM_ORDER, 0, 2,
1293 _("pathdir for key too long"));
1294 }
1295 else{
1296 snprintf(filename, sizeof(filename), "%.*s/%.*s.key",
1297 (int) strlen(pathdir), pathdir,
1298 (int) (sizeof(filename) - strlen(MASTERNAME) - 5 - 1), MASTERNAME);
1299 filename[sizeof(filename)-1] = '\0';
1300 rv = import_certificate(ctype, pc, filename);
1301 if(rv == 1){
1302 ps->keyemptypwd = 0;
1303 if(our_stat(pathdir, &sbuf) == 0){
1304 if(unlink(filename) < 0)
1305 q_status_message1(SM_ORDER, 0, 2,
1306 _("Could not remove private key %s.key"), MASTERNAME);
1307 filename[strlen(filename)-4] = '\0';
1308 strcat(filename, ".crt");
1309 if(unlink(filename) < 0)
1310 q_status_message1(SM_ORDER, 0, 2,
1311 _("Could not remove public certificate %s.crt"), MASTERNAME);
1312 if(rmdir(pathdir) < 0)
1313 q_status_message1(SM_ORDER, 0, 2,
1314 _("Could not remove temporary directory %s"), pathdir);
1315 }
1316 }
1317 }
1318 }
1319 rv = 10; /* forces redraw */
1320 }
1321 break;
1322
1323 case MC_CHOICE:
1324 if(PATHCERTDIR(ctype) == NULL)
1325 return 0;
1326
1327 if((cert = get_cert_for((*cl)->d.s.address, ctype, 0)) == NULL){
1328 q_status_message(SM_ORDER, 1, 3, _("Problem Reading Certificate"));
1329 rv = 0;
1330 }
1331 else{
1332 display_certificate_information(ps, cert, (*cl)->d.s.address, ctype, (*cl)->varmem);
1333 rv = 10 + (*cl)->varmem;
1334 }
1335 break;
1336
1337 case MC_DELETE:
1338 if(ctype == Password){
1339 EVP_PKEY *key = NULL;
1340 PERSONAL_CERT *pc = (PERSONAL_CERT *) ps->pwdcert;
1341 RSA *rsa = NULL;
1342 const EVP_CIPHER *enc = NULL;
1343 BIO *out = NULL;
1344 BIO *in = NULL;
1345 char filename[MAXPATH+1];
1346 char passwd[MAILTMPLEN];
1347 char prompt[MAILTMPLEN];
1348
1349 if (pc != NULL && pc->key != NULL){
1350 strncpy(prompt, _("Enter password to unlock key: "), sizeof(prompt));
1351 prompt[sizeof(prompt)-1] = '\0';
1352 passwd[0] = '\0';
1353
1354 rv = alpine_get_password(prompt, passwd, sizeof(passwd));
1355
1356 if(rv == 1)
1357 q_status_message(SM_ORDER, 1, 3, _("Password deletion cancelled"));
1358 else if(rv == 0){
1359 snprintf(filename, sizeof(filename), "%s/%s.key", ps->pwdcertdir, pc->name);
1360 filename[sizeof(filename)-1] = '\0';
1361 if((in = BIO_new_file(filename, "r")) != NULL){
1362 key = PEM_read_bio_PrivateKey(in, NULL, NULL, passwd);
1363 if(key != NULL){
1364 if((rsa = EVP_PKEY_get1_RSA(key)) != NULL
1365 && (out = BIO_new(BIO_s_file())) != NULL
1366 && BIO_write_filename(out, filename) > 0
1367 && PEM_write_bio_RSAPrivateKey(out, rsa, enc, NULL, 0, NULL, passwd) > 0){
1368 q_status_message(SM_ORDER, 1, 3, _("Password Removed from private key"));
1369 ps->keyemptypwd = 1;
1370 }
1371 else
1372 rv = 1;
1373 }
1374 else{
1375 rv = 1;
1376 q_status_message(SM_ORDER, 1, 3, _("Failed to unlock private key"));
1377 }
1378 BIO_free(in);
1379 }
1380 else
1381 rv = 1;
1382 }
1383 if(rv == 1)
1384 q_status_message(SM_ORDER, 1, 3, _("Failed to remove password from private key"));
1385 rv += 10; /* forces redraw */
1386 if(out != NULL)
1387 BIO_free_all(out);
1388 if(rsa != NULL)
1389 RSA_free(rsa);
1390 if(key != NULL)
1391 EVP_PKEY_free(key);
1392 }
1393 }
1394 else {
1395 if ((*cl)->d.s.deleted != 0)
1396 q_status_message(SM_ORDER, 1, 3, _("Certificate already deleted"));
1397 else{
1398 (*cl)->d.s.deleted = 1;
1399 rv = 10 + (*cl)->varmem; /* forces redraw */
1400 mark_cert_deleted(ctype, (*cl)->varmem, 1);
1401 q_status_message(SM_ORDER, 1, 3, _("Certificate marked deleted"));
1402 }
1403 }
1404 break;
1405
1406 case MC_UNDELETE:
1407 if ((*cl)->d.s.deleted == 0)
1408 q_status_message(SM_ORDER, 1, 3, _("Certificate not marked deleted"));
1409 else{
1410 (*cl)->d.s.deleted = 0;
1411 mark_cert_deleted(ctype, (*cl)->varmem, 0);
1412 rv = 10 + (*cl)->varmem; /* forces redraw */
1413 q_status_message(SM_ORDER, 1, 3, _("Certificate marked UNdeleted"));
1414 }
1415 break;
1416
1417 case MC_EXPUNGE:
1418 { CertList *cl;
1419
1420 for(cl = DATACERT(ctype); cl != NULL && DELETEDCERT(cl) == 0; cl = cl->next);
1421 if(cl != NULL && DELETEDCERT(cl) != 0){
1422 smime_expunge_cert(ctype);
1423 rv = 10; /* forces redraw */
1424 }
1425 else{
1426 q_status_message(SM_ORDER, 3, 3, _("No certificates marked deleted"));
1427 rv = 0;
1428 }
1429 break;
1430 }
1431 case MC_IMPORT:
1432 rv = import_certificate(ctype, NULL, NULL);
1433 if(rv < 0){
1434 switch(rv){
1435 default:
1436 case -1:
1437 cmd_cancelled("Import certificate");
1438 break;
1439
1440 case -2:
1441 q_status_message1(SM_ORDER, 0, 2, _("Can't import certificate outside of %s"),
1442 ps_global->VAR_OPER_DIR);
1443 break;
1444 }
1445 }
1446 rv = 10; /* forces redraw */
1447 break;
1448
1449 case MC_EXIT:
1450 rv = config_exit_cmd(flags);
1451 break;
1452
1453 default:
1454 rv = -1;
1455 break;
1456 }
1457
1458 X509_free(cert);
1459 return rv;
1460 }
1461
1462 void
smime_setup_size(char ** s,size_t buflen,size_t n)1463 smime_setup_size(char **s, size_t buflen, size_t n)
1464 {
1465 char *t = *s;
1466 *t++ = ' ';
1467 *t++ = '%';
1468 *t++ = '-';
1469 snprintf(t, buflen-3, "%zu.%zu", n, n);
1470 t += strlen(t);
1471 *t++ = 's';
1472 *t = '\0';
1473 *s = t;
1474 }
1475
1476 #ifdef PASSFILE
1477 void
manage_password_file_certificates(struct pine * ps)1478 manage_password_file_certificates(struct pine *ps)
1479 {
1480 OPT_SCREEN_S screen;
1481 int readonly_warning = 0, rv = 10, fline, state = 0;
1482
1483 dprint((9, "manage_password_file_certificates"));
1484 ps->next_screen = SCREEN_FUN_NULL;
1485 ps->keyemptypwd = 0; /* just in case */
1486
1487 do {
1488 CONF_S *ctmp = NULL, *first_line = NULL;
1489
1490 fline = rv >= 10 ? rv - 10 : 0;
1491
1492 smime_manage_password_file_certs_init(ps, &ctmp, &first_line, fline, &state);
1493
1494 if(ctmp == NULL){
1495 ps->mangled_screen = 1;
1496 q_status_message(SM_ORDER, 1, 3, _("Failed to initialize password management screen (no key)"));
1497 return;
1498 }
1499
1500 memset(&screen, 0, sizeof(screen));
1501 screen.deferred_ro_warning = readonly_warning;
1502
1503 rv = conf_scroll_screen(ps, &screen, first_line,
1504 _("MANAGE PASSWORD FILE CERTS"),
1505 /* TRANSLATORS: Print something1 using something2.
1506 configuration is something1 */
1507 _("configuration"), 0, NULL);
1508 } while (rv != 0);
1509
1510 ps->mangled_screen = 1;
1511 ps->keyemptypwd = 0; /* reset this so it will not confuse other routines */
1512 smime_reinit();
1513 }
1514
1515 /* state: 0 = first time,
1516 * 1 = second or another time
1517 */
1518 void
smime_manage_password_file_certs_init(struct pine * ps,CONF_S ** ctmp,CONF_S ** first_line,int fline,int * state)1519 smime_manage_password_file_certs_init(struct pine *ps, CONF_S **ctmp, CONF_S **first_line, int fline, int *state)
1520 {
1521 char tmp[200];
1522 char *ext;
1523 CertList *cl;
1524 int i;
1525 void *pwdcert = NULL; /* this is our current password file */
1526 X509_LOOKUP *lookup = NULL;
1527 X509_STORE *store = NULL;
1528 char filename[MAXPATH+1];
1529 BIO *in = NULL;
1530 EVP_PKEY *key = NULL;
1531 PERSONAL_CERT *pc;
1532
1533 if(*state == 0){ /* first time around? */
1534 setup_pwdcert(&pwdcert);
1535 if(pwdcert == NULL) return;
1536 if(ps->pwdcert == NULL)
1537 ps->pwdcert = pwdcert;
1538 else
1539 free_personal_certs((PERSONAL_CERT **) &pwdcert);
1540 (*state)++;
1541 }
1542
1543 pc = (PERSONAL_CERT *) ps_global->pwdcert;
1544 snprintf(filename, sizeof(filename), "%s/%s.key", ps->pwdcertdir, pc->name);
1545 filename[sizeof(filename)-1] = '\0';
1546 if((in = BIO_new_file(filename, "r")) != NULL
1547 && (key = PEM_read_bio_PrivateKey(in, NULL, NULL, "")) != NULL)
1548 ps->keyemptypwd = 1;
1549 if(in != NULL)
1550 BIO_free(in);
1551 if(key != NULL)
1552 EVP_PKEY_free(key);
1553
1554 ps->pwdcertlist = cl = smime_X509_to_cert_info(X509_dup(pc->cert), pc->name);
1555
1556 for(i = 0; i < sizeof(tmp) && i < (ps->ttyo ? ps->ttyo->screen_cols : sizeof(tmp)); i++)
1557 tmp[i] = '-';
1558 tmp[i] = '\0';
1559
1560 new_confline(ctmp);
1561 (*ctmp)->flags |= CF_NOSELECT;
1562 (*ctmp)->value = cpystr(tmp);
1563
1564 new_confline(ctmp);
1565 (*ctmp)->flags |= CF_NOSELECT;
1566 (*ctmp)->value = cpystr(_("Manage Certificates and Keys Used to Encrypt your Password File"));
1567
1568 new_confline(ctmp);
1569 (*ctmp)->flags |= CF_NOSELECT;
1570 (*ctmp)->value = cpystr(tmp);
1571
1572 new_confline(ctmp);
1573 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
1574
1575 if(cl){
1576 int s, e, df, dt, md5; /* sizes of certain fields */
1577 int nf; /* number of fields */
1578 char u[MAILTMPLEN], *t;
1579
1580 e = MIN(strlen(cl->name), ps->ttyo->screen_cols/3); /* do not use too much screen */
1581 nf = 5; /* there are 5 fields */
1582 s = 3; /* status has fixed size */
1583 df = dt = 10; /* date from and date to have fixed size */
1584 md5 = ps->ttyo->screen_cols - s - df - dt - e - (nf - 1);
1585
1586 t = u;
1587 smime_setup_size(&t, sizeof(u), s);
1588 smime_setup_size(&t, sizeof(u) - strlen(t), e);
1589 smime_setup_size(&t, sizeof(u) - strlen(t), df);
1590 *t++ = ' '; /* leave an extra space between dates */
1591 *t = '\0'; /* make valgrind happy */
1592 smime_setup_size(&t, sizeof(u) - strlen(t), dt);
1593 *t++ = ' '; /* and another space between date and md5 sum */
1594 *t = '\0'; /* make valgrind happy again */
1595 smime_setup_size(&t, sizeof(u) - strlen(t), md5);
1596 *t = '\0'; /* tie off */
1597
1598 new_confline(ctmp);
1599 (*ctmp)->flags |= CF_NOSELECT;
1600 (*ctmp)->value = cpystr(_("New Public Certificate and Key:"));
1601
1602 new_confline(ctmp);
1603 (*ctmp)->d.s.ctype = Password;
1604 (*ctmp)->help = h_config_smime_password_file_certificates;
1605 (*ctmp)->tool = manage_certs_tool;
1606 (*ctmp)->keymenu = &config_smime_add_new_key_keymenu;
1607 s += 2;
1608 for(i = 0; i < s; i++) tmp[i] = ' ';
1609 tmp[i] = '\0';
1610 strncpy(tmp+s, _("Press \"RETURN\" to add new personal key"), sizeof(tmp)-s-1);
1611 for(i = strlen(tmp); i < (ps->ttyo ? ps->ttyo->screen_cols : sizeof(tmp) - 1); i++)
1612 tmp[i] = ' ';
1613 tmp[i] = '\0';
1614 (*ctmp)->value = cpystr(tmp);
1615 *first_line = *ctmp;
1616
1617 new_confline(ctmp);
1618 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
1619
1620 new_confline(ctmp);
1621 (*ctmp)->flags |= CF_NOSELECT;
1622 (*ctmp)->value = cpystr(_("Current Public Certificate and Key:"));
1623
1624 new_confline(ctmp);
1625 (*ctmp)->d.s.ctype = Password;
1626 (*ctmp)->d.s.deleted = 0;
1627 (*ctmp)->help = h_config_smime_password_file_certificates;
1628 (*ctmp)->tool = manage_certs_tool;
1629 (*ctmp)->keymenu = ps->keyemptypwd == 0
1630 ? &config_smime_manage_view_cert_keymenu
1631 : &config_smime_manage_view_cert_keymenu_no_delete;
1632 (*ctmp)->varmem = 0;
1633 strncpy((*ctmp)->d.s.address, cl->name, sizeof((*ctmp)->d.s.address));
1634 (*ctmp)->d.s.address[sizeof((*ctmp)->d.s.address) - 1] = '\0';
1635 snprintf(tmp, sizeof(tmp), u,
1636 (*ctmp)->d.s.deleted ? "D" : " ",
1637 cl->name,
1638 DATEFROMCERT(cl), DATETOCERT(cl), MD5CERT(cl));
1639 (*ctmp)->value = cpystr(tmp);
1640 }
1641 }
1642 #endif /* PASSFILE */
1643
1644
1645 void
smime_manage_certs_init(struct pine * ps,CONF_S ** ctmp,CONF_S ** first_line,WhichCerts ctype,int fline)1646 smime_manage_certs_init(struct pine *ps, CONF_S **ctmp, CONF_S **first_line, WhichCerts ctype, int fline)
1647 {
1648 char tmp[200];
1649 CertList *data;
1650 int i;
1651
1652 smime_init();
1653
1654 data = DATACERT(ctype);
1655 // ext = EXTCERT(ctype);
1656
1657 if(data == NULL || RENEWCERT(data))
1658 renew_cert_data(&data, ctype);
1659
1660 for(i = 0; i < sizeof(tmp) && i < (ps->ttyo ? ps->ttyo->screen_cols : sizeof(tmp)); i++)
1661 tmp[i] = '-';
1662 tmp[i] = '\0';
1663
1664 new_confline(ctmp);
1665 (*ctmp)->flags |= CF_NOSELECT;
1666 (*ctmp)->value = cpystr(tmp);
1667
1668 (*ctmp)->keymenu = &config_text_keymenu;
1669
1670 new_confline(ctmp);
1671 (*ctmp)->flags |= CF_NOSELECT;
1672 sprintf(tmp, _("List of %s certificates"), ctype == Public ? _("public")
1673 : (ctype == Private ? _("private")
1674 : (ctype == CACert ? _("certificate authority") : "unknown (?)")));
1675 (*ctmp)->value = cpystr(tmp);
1676
1677 for(i = 0; i < sizeof(tmp) && i < (ps->ttyo ? ps->ttyo->screen_cols : sizeof(tmp)); i++)
1678 tmp[i] = '-';
1679 tmp[i] = '\0';
1680
1681 new_confline(ctmp);
1682 (*ctmp)->flags |= CF_NOSELECT;
1683 (*ctmp)->value = cpystr(tmp);
1684
1685 new_confline(ctmp);
1686 (*ctmp)->flags |= CF_NOSELECT | CF_B_LINE;
1687
1688 if(data){
1689 CertList *cl; int i;
1690 int s, e, df, dt, md5; /* sizes of certain fields */
1691 int nf; /* number of fields */
1692 char u[MAILTMPLEN], *t;
1693
1694 for(cl = data, e = 0; cl; cl = cl->next)
1695 if(cl->name && strlen(cl->name) > e)
1696 e = strlen(cl->name);
1697
1698 if(ctype != Private && SMHOLDERTYPE(ctype) == Directory)
1699 e -= 4; /* remove extension length */
1700 e = MIN(e, ps->ttyo->screen_cols/3); /* do not use too much screen */
1701 nf = 5; /* there are 5 fields */
1702 s = 3; /* status has fixed size */
1703 df = dt = 10; /* date from and date to have fixed size */
1704 md5 = ps->ttyo->screen_cols - s - df - dt - e - (nf - 1);
1705
1706 t = u;
1707 smime_setup_size(&t, sizeof(u), s);
1708 smime_setup_size(&t, sizeof(u) - strlen(t), e);
1709 smime_setup_size(&t, sizeof(u) - strlen(t), df);
1710 *t++ = ' '; /* leave an extra space between dates */
1711 *t = '\0'; /* make valgrind happy */
1712 smime_setup_size(&t, sizeof(u) - strlen(t), dt);
1713 *t++ = ' '; /* and another space between date and md5 sum */
1714 *t = '\0'; /* make valgrind happy again */
1715 smime_setup_size(&t, sizeof(u) - strlen(t), md5);
1716 *t = '\0'; /* tie off */
1717
1718 for(cl = data, i = 0; cl; cl = cl->next)
1719 if(cl->name){
1720 new_confline(ctmp);
1721 (*ctmp)->d.s.ctype = ctype;
1722 (*ctmp)->d.s.deleted = get_cert_deleted(ctype, i);
1723 (*ctmp)->tool = manage_certs_tool;
1724 (*ctmp)->keymenu = &config_smime_manage_certs_work_keymenu;
1725 (*ctmp)->varmem = i++;
1726 (*ctmp)->help = ctype == Public ? h_config_smime_manage_public_menu
1727 : (ctype == Private ? h_config_smime_manage_private_menu
1728 : h_config_smime_manage_cacerts_menu);
1729 if(ctype != Private && SMHOLDERTYPE(ctype) == Directory)
1730 cl->name[strlen(cl->name) - 4] = '\0'; /* FIX FIX FIX */
1731 strncpy((*ctmp)->d.s.address, cl->name, sizeof((*ctmp)->d.s.address));
1732 (*ctmp)->d.s.address[sizeof((*ctmp)->d.s.address) - 1] = '\0';
1733 snprintf(tmp, sizeof(tmp), u,
1734 (*ctmp)->d.s.deleted ? "D" : " ",
1735 ctype == CACert ? cl->cn : cl->name,
1736 DATEFROMCERT(cl), DATETOCERT(cl), MD5CERT(cl));
1737 if(ctype != Private && SMHOLDERTYPE(ctype) == Directory)
1738 cl->name[strlen(cl->name)] = '.';
1739 (*ctmp)->value = cpystr(tmp);
1740 if(i == fline+1 && first_line && !*first_line)
1741 *first_line = *ctmp;
1742 }
1743 }
1744 else {
1745 new_confline(ctmp);
1746 (*ctmp)->d.s.ctype = ctype;
1747 (*ctmp)->tool = manage_certs_tool;
1748 (*ctmp)->keymenu = &config_smime_add_certs_keymenu;
1749 (*ctmp)->value = cpystr(_(" \tNo certificates found, press \"RETURN\" to add one."));
1750 if(first_line && !*first_line)
1751 *first_line = *ctmp;
1752 }
1753 }
1754
1755 void
manage_certificates(struct pine * ps,WhichCerts ctype)1756 manage_certificates(struct pine *ps, WhichCerts ctype)
1757 {
1758 OPT_SCREEN_S screen;
1759 int readonly_warning = 0, rv = 10, fline;
1760
1761 dprint((9, "manage_certificates(ps, %s)", ctype == Public ? _("Public") : (ctype == Private ? _("Private") : (ctype == CACert ? _("certificate authority") : _("unknown")))));
1762 ps->next_screen = SCREEN_FUN_NULL;
1763
1764 do {
1765 CONF_S *ctmp = NULL, *first_line = NULL;
1766
1767 fline = rv >= 10 ? rv - 10 : 0;
1768
1769 smime_init();
1770
1771 smime_manage_certs_init(ps, &ctmp, &first_line, ctype, fline);
1772
1773 if(ctmp == NULL){
1774 ps->mangled_screen = 1;
1775 smime_reinit();
1776 return;
1777 }
1778
1779 memset(&screen, 0, sizeof(screen));
1780 screen.deferred_ro_warning = readonly_warning;
1781 rv = conf_scroll_screen(ps, &screen, first_line,
1782 _("MANAGE CERTIFICATES"),
1783 /* TRANSLATORS: Print something1 using something2.
1784 configuration is something1 */
1785 _("configuration"), 0, NULL);
1786 } while (rv != 0);
1787
1788 ps->mangled_screen = 1;
1789 smime_reinit();
1790 }
1791
1792 int
smime_helper_tool(struct pine * ps,int cmd,CONF_S ** cl,unsigned flags)1793 smime_helper_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned flags)
1794 {
1795 int rv = 0;
1796
1797 switch(cmd){
1798 case MC_CHOICE:
1799 switch((*cl)->varmem){
1800 case 1:
1801 rv = copy_publiccert_dir_to_container();
1802 if(rv == 0)
1803 q_status_message(SM_ORDER, 1, 3, _("Public certs transferred to container"));
1804 else{
1805 q_status_message(SM_ORDER, 3, 3, _("Problem transferring certs"));
1806 rv = 0;
1807 }
1808
1809 break;
1810
1811 case 2:
1812 rv = copy_publiccert_container_to_dir();
1813 if(rv == 0)
1814 q_status_message(SM_ORDER, 1, 3, _("Public certs transferred to directory, delete Container config to use"));
1815 else{
1816 q_status_message(SM_ORDER, 3, 3, _("Problem transferring certs"));
1817 rv = 0;
1818 }
1819
1820 break;
1821
1822 case 3:
1823 rv = copy_privatecert_dir_to_container();
1824 if(rv == 0)
1825 q_status_message(SM_ORDER, 1, 3, _("Private keys transferred to container"));
1826 else{
1827 q_status_message(SM_ORDER, 3, 3, _("Problem transferring certs"));
1828 rv = 0;
1829 }
1830
1831 break;
1832
1833 case 4:
1834 rv = copy_privatecert_container_to_dir();
1835 if(rv == 0)
1836 q_status_message(SM_ORDER, 1, 3, _("Private keys transferred to directory, delete Container config to use"));
1837 else{
1838 q_status_message(SM_ORDER, 3, 3, _("Problem transferring certs"));
1839 rv = 0;
1840 }
1841
1842 break;
1843
1844 case 5:
1845 rv = copy_cacert_dir_to_container();
1846 if(rv == 0)
1847 q_status_message(SM_ORDER, 1, 3, _("CA certs transferred to container"));
1848 else{
1849 q_status_message(SM_ORDER, 3, 3, _("Problem transferring certs"));
1850 rv = 0;
1851 }
1852
1853 break;
1854
1855 case 6:
1856 rv = copy_cacert_container_to_dir();
1857 if(rv == 0)
1858 q_status_message(SM_ORDER, 1, 3, _("CA certs transferred to directory, delete Container config to use"));
1859 else{
1860 q_status_message(SM_ORDER, 3, 3, _("Problem transferring certs"));
1861 rv = 0;
1862 }
1863
1864 break;
1865
1866 #ifdef APPLEKEYCHAIN
1867 case 7:
1868 rv = copy_publiccert_container_to_keychain();
1869 if(rv == 0)
1870 q_status_message(SM_ORDER, 1, 3, _("Public certs transferred to keychain"));
1871 else{
1872 q_status_message(SM_ORDER, 3, 3, _("Command not implemented yet"));
1873 rv = 0;
1874 }
1875
1876 break;
1877
1878 case 8:
1879 rv = copy_publiccert_keychain_to_container();
1880 if(rv == 0)
1881 q_status_message(SM_ORDER, 1, 3, _("Public certs transferred to container"));
1882 else{
1883 q_status_message(SM_ORDER, 3, 3, _("Command not implemented yet"));
1884 rv = 0;
1885 }
1886
1887 break;
1888 #endif /* APPLEKEYCHAIN */
1889
1890 case 9: manage_certificates(ps, Public) ; break;
1891 case 10: manage_certificates(ps, Private); break;
1892 case 11: manage_certificates(ps, CACert) ; break;
1893
1894 #ifdef PASSFILE
1895 case 12: manage_password_file_certificates(ps); break;
1896 #endif /* PASSFILE */
1897
1898 default:
1899 rv = -1;
1900 break;
1901 }
1902
1903 break;
1904
1905 case MC_EXIT:
1906 rv = config_exit_cmd(flags);
1907 break;
1908
1909 case MC_IMPORT:
1910 rv = import_certificate((*cl)->d.s.ctype, NULL, NULL);
1911 break;
1912
1913 default:
1914 rv = -1;
1915 break;
1916 }
1917
1918 return rv;
1919 }
1920
1921
1922 /*
1923 * Compare saved user_val with current user_val to see if it changed.
1924 * If any have changed, change it back and take the appropriate action.
1925 */
1926 void
revert_to_saved_smime_config(struct pine * ps,SAVED_CONFIG_S * vsave)1927 revert_to_saved_smime_config(struct pine *ps, SAVED_CONFIG_S *vsave)
1928 {
1929 struct variable *vreal;
1930 SAVED_CONFIG_S *v;
1931 int i, n;
1932 int changed = 0;
1933 char *pval, **apval, **lval, ***alval;
1934
1935 v = vsave;
1936 for(vreal = ps->vars; vreal->name; vreal++,v++){
1937 if(!(smime_related_var(ps, vreal) || vreal==&ps->vars[V_FEATURE_LIST]))
1938 continue;
1939
1940 if(vreal->is_list){
1941 lval = LVAL(vreal, ew);
1942 alval = ALVAL(vreal, ew);
1943
1944 if((v->saved_user_val.l && !lval)
1945 || (!v->saved_user_val.l && lval))
1946 changed++;
1947 else if(!v->saved_user_val.l && !lval)
1948 ;/* no change, nothing to do */
1949 else
1950 for(i = 0; v->saved_user_val.l[i] || lval[i]; i++)
1951 if((v->saved_user_val.l[i]
1952 && (!lval[i]
1953 || strcmp(v->saved_user_val.l[i], lval[i])))
1954 ||
1955 (!v->saved_user_val.l[i] && lval[i])){
1956 changed++;
1957 break;
1958 }
1959
1960 if(changed){
1961 char **list;
1962
1963 if(alval){
1964 if(*alval)
1965 free_list_array(alval);
1966
1967 /* copy back the original one */
1968 if(v->saved_user_val.l){
1969 list = v->saved_user_val.l;
1970 n = 0;
1971 /* count how many */
1972 while(list[n])
1973 n++;
1974
1975 *alval = (char **)fs_get((n+1) * sizeof(char *));
1976
1977 for(i = 0; i < n; i++)
1978 (*alval)[i] = cpystr(v->saved_user_val.l[i]);
1979
1980 (*alval)[n] = NULL;
1981 }
1982 }
1983 }
1984 }
1985 else{
1986 pval = PVAL(vreal, ew);
1987 apval = APVAL(vreal, ew);
1988
1989 if((v->saved_user_val.p &&
1990 (!pval || strcmp(v->saved_user_val.p, pval))) ||
1991 (!v->saved_user_val.p && pval)){
1992 /* It changed, fix it */
1993 changed++;
1994 if(apval){
1995 /* free the changed value */
1996 if(*apval)
1997 fs_give((void **)apval);
1998
1999 if(v->saved_user_val.p)
2000 *apval = cpystr(v->saved_user_val.p);
2001 }
2002 }
2003 }
2004
2005 if(changed){
2006 if(vreal == &ps->vars[V_FEATURE_LIST])
2007 set_feature_list_current_val(vreal);
2008 else
2009 set_current_val(vreal, TRUE, FALSE);
2010
2011 fix_side_effects(ps, vreal, 1);
2012 }
2013 }
2014 }
2015
2016
2017 SAVED_CONFIG_S *
save_smime_config_vars(struct pine * ps)2018 save_smime_config_vars(struct pine *ps)
2019 {
2020 struct variable *vreal;
2021 SAVED_CONFIG_S *vsave, *v;
2022
2023 vsave = (SAVED_CONFIG_S *)fs_get((V_LAST_VAR+1)*sizeof(SAVED_CONFIG_S));
2024 memset((void *)vsave, 0, (V_LAST_VAR+1)*sizeof(SAVED_CONFIG_S));
2025 for(v = vsave, vreal = ps->vars; vreal->name; vreal++,v++){
2026 if(!(smime_related_var(ps, vreal) || vreal==&ps->vars[V_FEATURE_LIST]))
2027 continue;
2028
2029 if(vreal->is_list){
2030 int n, i;
2031 char **list;
2032
2033 if(LVAL(vreal, ew)){
2034 /* count how many */
2035 n = 0;
2036 list = LVAL(vreal, ew);
2037 while(list[n])
2038 n++;
2039
2040 v->saved_user_val.l = (char **)fs_get((n+1)*sizeof(char *));
2041 memset((void *)v->saved_user_val.l, 0, (n+1)*sizeof(char *));
2042 for(i = 0; i < n; i++)
2043 v->saved_user_val.l[i] = cpystr(list[i]);
2044
2045 v->saved_user_val.l[n] = NULL;
2046 }
2047 }
2048 else{
2049 if(PVAL(vreal, ew))
2050 v->saved_user_val.p = cpystr(PVAL(vreal, ew));
2051 }
2052 }
2053
2054 return(vsave);
2055 }
2056
2057
2058 void
free_saved_smime_config(struct pine * ps,SAVED_CONFIG_S ** vsavep)2059 free_saved_smime_config(struct pine *ps, SAVED_CONFIG_S **vsavep)
2060 {
2061 struct variable *vreal;
2062 SAVED_CONFIG_S *v;
2063
2064 if(vsavep && *vsavep){
2065 for(v = *vsavep, vreal = ps->vars; vreal->name; vreal++,v++){
2066 if(!(smime_related_var(ps, vreal) || vreal==&ps->vars[V_FEATURE_LIST]))
2067 continue;
2068
2069 if(vreal->is_list){ /* free saved_user_val.l */
2070 if(v && v->saved_user_val.l)
2071 free_list_array(&v->saved_user_val.l);
2072 }
2073 else if(v && v->saved_user_val.p)
2074 fs_give((void **)&v->saved_user_val.p);
2075 }
2076
2077 fs_give((void **)vsavep);
2078 }
2079 }
2080
2081 #endif /* SMIME */
2082