From ef159279c142ec4f3b3a1938cfeadc74d5891070 Mon Sep 17 00:00:00 2001 From: Eduardo Chappa Date: Sat, 18 Jul 2020 00:53:34 -0600 Subject: * Addition of the variables User Certs Dir and User Certs File, which allow a user to specify the location of server certificates that the user trusts. --- alpine/alpine.c | 2 + alpine/confscroll.c | 2 + configure | 10 +++++ configure.ac | 2 + imap/src/c-client/mail.h | 8 +++- imap/src/osdep/nt/env_nt.c | 16 +++++++ imap/src/osdep/nt/ssl_libressl.c | 6 ++- imap/src/osdep/unix/env_unix.c | 16 +++++++ imap/src/osdep/unix/ssl_unix.c | 5 +++ include/config.h.in | 6 +++ pith/conf.c | 97 +++++++++++++++++++++++++++++++++++++++- pith/conf.h | 6 +++ pith/conftype.h | 2 + pith/pine.hlp | 80 ++++++++++++++++++++++++++++++--- 14 files changed, 249 insertions(+), 9 deletions(-) diff --git a/alpine/alpine.c b/alpine/alpine.c index a2585af8..5182e869 100644 --- a/alpine/alpine.c +++ b/alpine/alpine.c @@ -475,6 +475,8 @@ main(int argc, char **argv) #if !defined(_WINDOWS) || defined(WINDOWS_UNIXSSL_CERTS) set_system_certs_path(pine_state); set_system_certs_container(pine_state); + set_user_certs_path(pine_state); + set_user_certs_container(pine_state); #endif #ifdef SMIME diff --git a/alpine/confscroll.c b/alpine/confscroll.c index 67b15704..4f366424 100644 --- a/alpine/confscroll.c +++ b/alpine/confscroll.c @@ -5782,6 +5782,8 @@ fix_side_effects(struct pine *ps, struct variable *var, int revert) #if !defined(_WINDOWS) || defined(ENABLE_WINDOWS_UNIXSSL_CERTS) var == &ps->vars[V_SSLCAPATH] || var == &ps->vars[V_SSLCAFILE] || + var == &ps->vars[V_USERSSLCAPATH] || + var == &ps->vars[V_USERSSLCAFILE] || #endif var == &ps->vars[V_RSHPATH] || var == &ps->vars[V_RSHCMD] || diff --git a/configure b/configure index 9d11f5ea..d1b076df 100755 --- a/configure +++ b/configure @@ -16997,6 +16997,16 @@ cat >>confdefs.h <<_ACEOF _ACEOF +cat >>confdefs.h <<_ACEOF +#define DEFAULT_SSLUSERCAPATH ".alpine-certs" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define DEFAULT_SSLUSERCAFILE ".alpine-certs/certs.pem" +_ACEOF + + # Check whether --with-passfile was given. if test "${with_passfile+set}" = set; then : diff --git a/configure.ac b/configure.ac index 118f0ae5..aee1a29e 100644 --- a/configure.ac +++ b/configure.ac @@ -626,6 +626,8 @@ PINEVAR_UNQUOTED(default-printer, DF_DEFAULT_PRINTER, [ANSI_PRINTER], [Default p AC_DEFINE_UNQUOTED([DF_PUBLIC_CONTAINER], "PublicContainer", [Name of default public container]) AC_DEFINE_UNQUOTED([DF_PRIVATE_CONTAINER], "PrivateContainer", [Name of default private container]) AC_DEFINE_UNQUOTED([DF_CA_CONTAINER], "CAContainer", [Name of default certificate authority container]) +AC_DEFINE_UNQUOTED([DEFAULT_SSLUSERCAPATH], ".alpine-certs", [Default directory for user trusted certificates]) +AC_DEFINE_UNQUOTED([DEFAULT_SSLUSERCAFILE], ".alpine-certs/certs.pem", [Name of default container for user trusted certificates]) dnl set PASSFILE? AC_ARG_WITH(passfile, diff --git a/imap/src/c-client/mail.h b/imap/src/c-client/mail.h index 32df37ba..adcad4d9 100644 --- a/imap/src/c-client/mail.h +++ b/imap/src/c-client/mail.h @@ -196,8 +196,12 @@ #define SET_SSLCAPATH (long) 232 #define GET_SSLCAFILE (long) 233 #define SET_SSLCAFILE (long) 234 -#define GET_RESTRICTIONS (long) 235 -#define SET_RESTRICTIONS (long) 236 +#define GET_SSLAPPCAPATH (long) 235 +#define SET_SSLAPPCAPATH (long) 236 +#define GET_SSLAPPCAFILE (long) 237 +#define SET_SSLAPPCAFILE (long) 238 +#define GET_RESTRICTIONS (long) 239 +#define SET_RESTRICTIONS (long) 240 /* 3xx: TCP/IP */ #define GET_OPENTIMEOUT (long) 300 diff --git a/imap/src/osdep/nt/env_nt.c b/imap/src/osdep/nt/env_nt.c index 8fc72f0c..52211ea2 100644 --- a/imap/src/osdep/nt/env_nt.c +++ b/imap/src/osdep/nt/env_nt.c @@ -45,6 +45,8 @@ static int server_nli = 0; /* server and not logged in */ static int logtry = 3; /* number of login tries */ static char *sslCApath = NIL; /* non-standard CA path */ static char *sslCAfile = NIL; /* non-standard CA container */ +static char *sslAppCApath = NIL; /* App SSL Certs CA path */ +static char *sslAppCAfile = NIL; /* App SSL CA container */ /* block notification */ static blocknotify_t mailblocknotify = mm_blocknotify; /* callback to get username */ @@ -143,6 +145,20 @@ void *env_parameters (long function,void *value) case GET_SSLCAFILE: ret = (void *) sslCAfile; break; + case SET_SSLAPPCAPATH: /* this can be set null */ + if (sslAppCApath) fs_give ((void **) &sslAppCApath); + sslAppCApath = value ? cpystr ((char *) value) : value; + break; + case GET_SSLAPPCAPATH: + ret = (void *) sslAppCApath; + break; + case SET_SSLCAFILE: /* this can be set null */ + if (sslAppCAfile) fs_give ((void **) &sslAppCAfile); + sslAppCAfile = value ? cpystr ((char *) value) : value; + break; + case GET_SSLAPPCAFILE: + ret = (void *) sslAppCAfile; + break; } return ret; } diff --git a/imap/src/osdep/nt/ssl_libressl.c b/imap/src/osdep/nt/ssl_libressl.c index 5270a9f8..04dfb36e 100644 --- a/imap/src/osdep/nt/ssl_libressl.c +++ b/imap/src/osdep/nt/ssl_libressl.c @@ -8,7 +8,7 @@ * * Author: Eduardo Chappa, based on ssl_unix.c * - * Last Edited: January 25, 2020 + * Last Edited: July 17, 2020 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -413,6 +413,10 @@ static char *ssl_start_work(SSLSTREAM *stream, char *host, unsigned long flags) SSL_CTX_load_verify_locations (stream->context, CAfile, CApath); else /* otherwise we set default paths to CAs... */ SSL_CTX_set_default_verify_paths(stream->context); + CAfile = (char *) mail_parameters (NIL,GET_SSLAPPCAFILE,NIL); + CApath = (char *) mail_parameters (NIL,GET_SSLAPPCAPATH,NIL); + if (CAfile != NIL || CApath != NIL) + SSL_CTX_load_verify_locations (stream->context, CAfile, CApath); /* want to send client certificate? */ if (scc && (s = (*scc) ()) && (sl = strlen(s))) { if ((cert = PEM_read_bio_X509(bio = BIO_new_mem_buf(s, sl), NIL, NIL, NIL)) != NIL) { diff --git a/imap/src/osdep/unix/env_unix.c b/imap/src/osdep/unix/env_unix.c index fe1b91d4..afec59b1 100644 --- a/imap/src/osdep/unix/env_unix.c +++ b/imap/src/osdep/unix/env_unix.c @@ -74,6 +74,8 @@ static char *blackBoxDir = NIL; /* black box directory name */ static char *blackBoxDefaultHome = NIL; static char *sslCApath = NIL; /* non-standard CA path */ static char *sslCAfile = NIL; /* non-standard CA container */ +static char *sslAppCApath = NIL; /* App SSL CA path */ +static char *sslAppCAfile = NIL; /* App SSL CA container */ static short anonymous = NIL; /* is anonymous */ static short blackBox = NIL; /* is a black box */ static short closedBox = NIL; /* is a closed box (uses chroot() jail) */ @@ -354,6 +356,20 @@ void *env_parameters (long function,void *value) case GET_SSLCAFILE: ret = (void *) sslCAfile; break; + case SET_SSLAPPCAPATH: /* this can be set null */ + if (sslAppCApath) fs_give ((void **) &sslAppCApath); + sslAppCApath = value ? cpystr ((char *) value) : value; + break; + case GET_SSLAPPCAPATH: + ret = (void *) sslAppCApath; + break; + case SET_SSLAPPCAFILE: /* this can be set null */ + if (sslAppCAfile) fs_give ((void **) &sslAppCAfile); + sslAppCAfile = value ? cpystr ((char *) value) : value; + break; + case GET_SSLAPPCAFILE: + ret = (void *) sslAppCAfile; + break; case SET_LISTMAXLEVEL: list_max_level = (long) value; case GET_LISTMAXLEVEL: diff --git a/imap/src/osdep/unix/ssl_unix.c b/imap/src/osdep/unix/ssl_unix.c index 4ebe1ae7..1f64b57e 100644 --- a/imap/src/osdep/unix/ssl_unix.c +++ b/imap/src/osdep/unix/ssl_unix.c @@ -421,6 +421,11 @@ static char *ssl_start_work (SSLSTREAM *stream,char *host,unsigned long flags) SSL_CTX_load_verify_locations (stream->context, CAfile, CApath); else /* set default paths to CAs... */ SSL_CTX_set_default_verify_paths (stream->context); + /* Load app certificates */ + CAfile = (char *) mail_parameters (NIL,GET_SSLAPPCAFILE,NIL); + CApath = (char *) mail_parameters (NIL,GET_SSLAPPCAPATH,NIL); + if (CAfile != NIL || CApath != NIL) + SSL_CTX_load_verify_locations (stream->context, CAfile, CApath); /* want to send client certificate? */ if (scc && (s = (*scc) ()) && (sl = strlen (s))) { if ((cert = PEM_read_bio_X509 (bio = BIO_new_mem_buf (s,sl),NIL,NIL,NIL)) != NULL) { diff --git a/include/config.h.in b/include/config.h.in index 134b813a..834950c3 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -42,6 +42,12 @@ /* Default configuration value */ #undef DEFAULT_SAVE +/* Name of default container for user trusted certificates */ +#undef DEFAULT_SSLUSERCAFILE + +/* Default directory for user trusted certificates */ +#undef DEFAULT_SSLUSERCAPATH + /* Default configuration value */ #undef DF_AB_SORT_RULE diff --git a/pith/conf.c b/pith/conf.c index f856c961..e4f64c71 100644 --- a/pith/conf.c +++ b/pith/conf.c @@ -381,6 +381,10 @@ CONF_TXT_T cf_text_mimetype_path[] = "Sets the search path for the mimetypes con CONF_TXT_T cf_text_system_certs_path[] = "Sets the path for the system ssl certificates issued by a trusted\n# certificate authority. Note that this could be a list of paths, if the same\n# pinerc is used in different systems. Alpine always chooses the first one that\n# it finds. Value must be an absolute path."; CONF_TXT_T cf_text_system_certs_file[] = "Sets the path for the system ssl file container of certificates issued by a\n# certificate authority. Note that this could be a list of container files,\n# if the same pinerc is used in different systems. Alpine always chooses the,\n# first one that it finds. Value must be an absolute path."; + +CONF_TXT_T cf_text_user_certs_path[] = "Sets the path for additional ssl certificates that the user trusts. Note\n#that this could be a list of paths, if the same\n# pinerc is used in different systems. Alpine always chooses the first one that\n# it finds. Value must be an absolute path."; + +CONF_TXT_T cf_text_user_certs_file[] = "Sets the path for a file that contains certificates that a user trusts.\nNote that this could be a list of container files,\n# if the same pinerc is used in different systems. Alpine always chooses the,\n# first one that it finds. Value must be an absolute path."; #endif CONF_TXT_T cf_text_newmail_fifo_path[] = "Sets the filename for the newmail fifo (named pipe). Unix only."; @@ -670,6 +674,10 @@ static struct variable variables[] = { "System CACerts Dir", cf_text_system_certs_path}, {"system-certs-file", 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, "System CACerts File", cf_text_system_certs_file}, +{"user-certs-path", 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, + "User Certs Dir", cf_text_user_certs_file}, +{"user-certs-file", 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, + "User Certs File", cf_text_user_certs_file}, #endif {"url-viewers", 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, "URL-Viewers", cf_text_browser}, @@ -1740,6 +1748,56 @@ init_vars(struct pine *ps, void (*cmds_f) (struct pine *, char **)) GLO_SSLCAFILE = parse_list(DEFAULT_SSLCAFILE, 1, PL_REMSURRQUOT, NULL); #endif /* DEFAULT_SSLCAFILE */ +#ifdef DEFAULT_SSLUSERCAPATH + { char **l, path[MAXPATH+1]; + int i; + l = parse_list(DEFAULT_SSLUSERCAPATH, 1, + PL_REMSURRQUOT, NULL); + if(l && *l && **l){ + for(i = 0; l[i] && *l[i]; i++){ + path[0] = '\0'; + if(ps_global->VAR_OPER_DIR){ + if(strlen(ps_global->VAR_OPER_DIR) + strlen(l[i]) < MAXPATH) + build_path(path, ps_global->VAR_OPER_DIR, l[i], MAXPATH); + } + else if(ps_global->home_dir){ + if(strlen(ps_global->home_dir) + strlen(l[i]) < MAXPATH) + build_path(path, ps_global->home_dir, l[i], MAXPATH); + } + if(path[0]){ + fs_give((void **) &l[i]); + l[i] = cpystr(path); + } + } + } + GLO_SSLUSERCAPATH = l; + } +#endif /* DEFAULT_SSLUSERCAPATH */ +#ifdef DEFAULT_SSLUSERCAFILE + { char **l, path[MAXPATH+1]; + int i; + l = parse_list(DEFAULT_SSLUSERCAFILE, 1, + PL_REMSURRQUOT, NULL); + if(l && *l && **l){ + for(i = 0; l[i] && *l[i]; i++){ + path[0] = '\0'; + if(ps_global->VAR_OPER_DIR){ + if(strlen(ps_global->VAR_OPER_DIR) + strlen(l[i]) < MAXPATH) + build_path(path, ps_global->VAR_OPER_DIR, l[i], MAXPATH); + } + else if(ps_global->home_dir){ + if(strlen(ps_global->home_dir) + strlen(l[i]) < MAXPATH) + build_path(path, ps_global->home_dir, l[i], MAXPATH); + } + if(path[0]){ + fs_give((void **) &l[i]); + l[i] = cpystr(path); + } + } + } + GLO_SSLUSERCAFILE = l; + } +#endif /* DEFAULT_SSLUSERCAFILE */ #ifdef DF_VAR_SPELLER GLO_SPELLER = cpystr(DF_VAR_SPELLER); #endif @@ -2379,6 +2437,8 @@ init_vars(struct pine *ps, void (*cmds_f) (struct pine *, char **)) #if !defined(_WINDOWS) || defined(WINDOWS_UNIXSSL_CERTS) set_current_val(&vars[V_SSLCAPATH], TRUE, TRUE); set_current_val(&vars[V_SSLCAFILE], TRUE, TRUE); + set_current_val(&vars[V_USERSSLCAPATH], TRUE, TRUE); + set_current_val(&vars[V_USERSSLCAFILE], TRUE, TRUE); #endif #if !defined(DOS) && !defined(OS2) && !defined(LEAVEOUTFIFO) set_current_val(&vars[V_FIFOPATH], TRUE, TRUE); @@ -7088,7 +7148,7 @@ set_system_certs_container(struct pine *ps) { char **l; - for (l = ps->vars[V_SSLCAPATH].current_val.l; l && *l; l++){ + for (l = ps->vars[V_SSLCAFILE].current_val.l; l && *l; l++){ if(is_absolute_path(*l) && can_access(*l, ACCESS_EXISTS) == 0 && can_access(*l, READ_ACCESS) == 0){ @@ -7097,6 +7157,37 @@ set_system_certs_container(struct pine *ps) } } } + +void +set_user_certs_path(struct pine *ps) +{ + char **l; + + for (l = ps->vars[V_USERSSLCAPATH].current_val.l; l && *l; l++){ + if(is_absolute_path(*l) + && can_access(*l, ACCESS_EXISTS) == 0 + && can_access(*l, READ_ACCESS) == 0){ + mail_parameters(NULL, SET_SSLAPPCAPATH, (void *) *l); + break; + } + } +} + + +void +set_user_certs_container(struct pine *ps) +{ + char **l; + + for (l = ps->vars[V_USERSSLCAFILE].current_val.l; l && *l; l++){ + if(is_absolute_path(*l) + && can_access(*l, ACCESS_EXISTS) == 0 + && can_access(*l, READ_ACCESS) == 0){ + mail_parameters(NULL, SET_SSLAPPCAFILE, (void *) *l); + break; + } + } +} #endif int @@ -7958,6 +8049,10 @@ config_help(int var, int feature) return(h_config_system_certs_path); case V_SSLCAFILE : return(h_config_system_certs_file); + case V_USERSSLCAPATH : + return(h_config_user_certs_path); + case V_USERSSLCAFILE : + return(h_config_user_certs_file); #endif #if !defined(DOS) && !defined(OS2) && !defined(LEAVEOUTFIFO) case V_FIFOPATH : diff --git a/pith/conf.h b/pith/conf.h index 100224bc..90c2325c 100644 --- a/pith/conf.h +++ b/pith/conf.h @@ -138,6 +138,10 @@ #define GLO_SSLCAPATH vars[V_SSLCAPATH].global_val.l #define VAR_SSLCAFILE vars[V_SSLCAFILE].current_val.l #define GLO_SSLCAFILE vars[V_SSLCAFILE].global_val.l +#define VAR_SSLUSERCAPATH vars[V_USERSSLCAPATH].current_val.l +#define GLO_SSLUSERCAPATH vars[V_USERSSLCAPATH].global_val.l +#define VAR_SSLUSERCAFILE vars[V_USERSSLCAFILE].current_val.l +#define GLO_SSLUSERCAFILE vars[V_USERSSLCAFILE].global_val.l #endif #define VAR_INDEX_COLOR_STYLE vars[V_INDEX_COLOR_STYLE].current_val.p #define GLO_INDEX_COLOR_STYLE vars[V_INDEX_COLOR_STYLE].global_val.p @@ -919,6 +923,8 @@ void panic1(char *, char *); #if !defined(_WINDOWS) || defined(WINDOWS_UNIXSSL_CERTS) void set_system_certs_path(struct pine *); void set_system_certs_container(struct pine *); +void set_user_certs_path(struct pine *); +void set_user_certs_container(struct pine *); #endif /* mandatory to implement prototypes */ diff --git a/pith/conftype.h b/pith/conftype.h index 4ea7993e..3ed5040f 100644 --- a/pith/conftype.h +++ b/pith/conftype.h @@ -127,6 +127,8 @@ typedef enum { V_PERSONAL_NAME = 0 #if !defined(_WINDOWS) || defined(WINDOWS_UNIXSSL_CERTS) , V_SSLCAPATH , V_SSLCAFILE + , V_USERSSLCAPATH + , V_USERSSLCAFILE #endif , V_BROWSER , V_HISTORY diff --git a/pith/pine.hlp b/pith/pine.hlp index c6c1a2e4..b9729c77 100644 --- a/pith/pine.hlp +++ b/pith/pine.hlp @@ -140,7 +140,7 @@ with help text for the config screen and the composer that didn't have any reasonable place to be called from. Dummy change to get revision in pine.hlp ============= h_revision ================= -Alpine Commit 494 2020-07-17 01:43:03 +Alpine Commit 495 2020-07-18 00:53:30 ============= h_news ================= @@ -192,7 +192,7 @@ problems you find with this release.

@@ -22518,9 +22523,9 @@ allows for users to be able to use the same pinerc file in different systems. Example of values for this option might be:

-System Certs Path = /etc/ssl/certs/cert.pem
-                    /usr/local/ssl/ca-root-nss.crt
-                    C:\\libressl\\ssl\\certs\\cert.pem
+System CACerts File = /etc/ssl/certs/cert.pem
+                      /usr/local/ssl/ca-root-nss.crt
+                      C:\\libressl\\ssl\\certs\\cert.pem
 
 
 

@@ -22533,6 +22538,71 @@ and adding "/certs" to that value. In Windows the default location for the certificates is C:\\libressl\\ssl\\certs\\cert.pem. This value was set by LibreSSL developers, and this option can be used to override this default. +

+<End of help on this topic> + +====== h_config_user_certs_path ====== + + +OPTION: <!--#echo var="VAR_user-certs-path"--> + + +

OPTION:

+ +(UNIX ALPINE ONLY) +This directory is used by Alpine to store certificates that a user +trusts. Alpine will use the first directory in this list that exists in your +system and can be accessed. This allows for users to be able to +use the same pinerc file in different systems. The default location +is ~/.alpine-certs. + +

+In addition to the certificates stored in this directory, Alpine also +trusts certificates saved in the container file referenced in the +configuration variable +. + +

+Example of values for this option might be: + +

+User Certs Dir = /home/fred/.alpine-certs
+                 C:\\Users\\Admin\\alpine-certs
+
+
+

+<End of help on this topic> + +====== h_config_user_certs_file ====== + + +OPTION: <!--#echo var="VAR_user-certs-file"--> + + +

OPTION:

+ +(UNIX ALPINE ONLY) +This option sets the location of a container file that holds certificate +authority (CA) certificates that the user trusts. Its value is the +full path referencing the location of this file. Alpine will use the first +container in this list that exists and can be accessed in your system. This +allows for users to be able to use the same pinerc file in different +systems. The default location is ~/.alpine-certs/certs.pem. + +

+In addition to the certificates stored in this directory, Alpine also +trusts certificates saved in the directory referenced in the +configuration variable +. + +

+Example of values for this option might be: + +

+User Certs File = /home/fred/.alpine-certs/certs.pem
+                  C:\\libressl\\ssl\\certs\\cert.pem
+
+
 

<End of help on this topic> -- cgit v1.2.3-54-g00ecf