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