From 3540ba1bb81b478884944159730cce66f9bdb8fa Mon Sep 17 00:00:00 2001 From: Eduardo Chappa Date: Sun, 27 Mar 2016 19:57:38 -0600 Subject: [PATCH] * Unix-Alpine: Connect securely to a LDAP server on a secure port. Based on a contribution by Wang Kang. --- alpine/ldapconf.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- pith/ldap.c | 66 ++++++++++++++++++++++++++++++++++--- pith/ldap.h | 1 + pith/pine.hlp | 41 +++++++++++++++++++++++ 4 files changed, 200 insertions(+), 7 deletions(-) diff --git a/alpine/ldapconf.c b/alpine/ldapconf.c index c051f62..36993de 100644 --- a/alpine/ldapconf.c +++ b/alpine/ldapconf.c @@ -1146,6 +1146,7 @@ dir_config_edit(struct pine *ps, CONF_S **cl) #define LDAP_F_NOSUB 3 #define LDAP_F_TLS 4 #define LDAP_F_TLSMUST 5 +#define LDAP_F_LDAPS 6 bitmap_t ldap_option_list; struct variable *ldap_srch_rule_ptr; @@ -1352,6 +1353,8 @@ dir_edit_screen(struct pine *ps, LDAP_SERV_S *def, char *title, char **raw_serve setbitn(LDAP_F_TLS, ldap_option_list); if(def && def->tlsmust) setbitn(LDAP_F_TLSMUST, ldap_option_list); + if(def && def->ldaps) + setbitn(LDAP_F_LDAPS, ldap_option_list); /* save the old opt_screen before calling scroll screen again */ saved_screen = opt_screen; @@ -1475,6 +1478,38 @@ dir_edit_screen(struct pine *ps, LDAP_SERV_S *def, char *title, char **raw_serve lv = MIN(lv, 100); + /* enabling ldaps disables tls */ + if((f = ldap_feature_list(LDAP_F_LDAPS)) != NULL + && bitnset(f->value, ldap_option_list)){ + int clear = 0; + if((f = ldap_feature_list(LDAP_F_TLS)) != NULL + && bitnset(f->value, ldap_option_list)){ + clear++; + clrbitn(f->value, ldap_option_list); + } + if((f = ldap_feature_list(LDAP_F_TLSMUST)) != NULL + && bitnset(f->value, ldap_option_list)){ + clear++; + clrbitn(f->value, ldap_option_list); + } + if(clear > 0) + q_status_message(SM_ORDER, 3, 3, + _("Can not use TLS when connecting using LDAPS")); + } + + /* enabling tls disables ldaps */ + if(((f = ldap_feature_list(LDAP_F_TLS)) != NULL + && bitnset(f->value, ldap_option_list)) + || ((f = ldap_feature_list(LDAP_F_TLSMUST)) != NULL + && bitnset(f->value, ldap_option_list))){ + if((f = ldap_feature_list(LDAP_F_LDAPS)) != NULL + && bitnset(f->value, ldap_option_list)){ + clrbitn(f->value, ldap_option_list); + q_status_message(SM_ORDER, 3, 3, + _("Can not use LDAPS when connecting using TLS")); + } + } + for(i = 0; (f = ldap_feature_list(i)); i++){ new_confline(&ctmp); ctmp->var = &opt_var; @@ -1500,6 +1535,9 @@ dir_edit_screen(struct pine *ps, LDAP_SERV_S *def, char *title, char **raw_serve case LDAP_F_TLSMUST: ctmp->help = h_config_ldap_opts_tlsmust; break; + case LDAP_F_LDAPS: + ctmp->help = h_config_ldap_opts_ldaps; //TODO: SSL and TLS as radiobutton + break; } ctmp->tool = ldap_checkbox_tool; @@ -1920,7 +1958,7 @@ dir_edit_screen(struct pine *ps, LDAP_SERV_S *def, char *title, char **raw_serve } } - snprintf(dir_tmp, sizeof(dir_tmp), "%s%s%s \"/base=%s/binddn=%s/impl=%d/rhs=%d/ref=%d/nosub=%d/tls=%d/tlsm=%d/type=%s/srch=%s%s/time=%s/size=%s/cust=%s/nick=%s/matr=%s/catr=%s/satr=%s/gatr=%s\"", + snprintf(dir_tmp, sizeof(dir_tmp), "%s%s%s \"/base=%s/binddn=%s/impl=%d/rhs=%d/ref=%d/nosub=%d/tls=%d/tlsm=%d/ldaps=%d/type=%s/srch=%s%s/time=%s/size=%s/cust=%s/nick=%s/matr=%s/catr=%s/satr=%s/gatr=%s\"", server ? server : "", (portval >= 0 && port && *port) ? ":" : "", (portval >= 0 && port && *port) ? port : "", @@ -1932,6 +1970,7 @@ dir_edit_screen(struct pine *ps, LDAP_SERV_S *def, char *title, char **raw_serve bitnset(LDAP_F_NOSUB, ldap_option_list) ? 1 : 0, bitnset(LDAP_F_TLS, ldap_option_list) ? 1 : 0, bitnset(LDAP_F_TLSMUST, ldap_option_list) ? 1 : 0, + bitnset(LDAP_F_LDAPS, ldap_option_list) ? 1 : 0, srch_type ? srch_type : "", srch_rule ? srch_rule : "", custom_scope, @@ -2342,6 +2381,21 @@ void toggle_ldap_option_bit(struct pine *ps, int index, struct variable *var, char *value) { NAMEVAL_S *f; + int tls_is_on_now; + int tlsmust_is_on_now; + int ldaps_is_on_now; + int tls_is_on_after; + int tlsmust_is_on_after; + int ldaps_is_on_after; + + tls_is_on_now = (f = ldap_feature_list(LDAP_F_TLS)) != NULL + && bitnset(f->value, ldap_option_list) ? 1 : 0; + + tlsmust_is_on_now = (f = ldap_feature_list(LDAP_F_TLSMUST)) != NULL + && bitnset(f->value, ldap_option_list) ? 1 : 0; + + ldaps_is_on_now = (f = ldap_feature_list(LDAP_F_LDAPS)) != NULL + && bitnset(f->value, ldap_option_list) ? 1 : 0; f = ldap_feature_list(index); @@ -2351,6 +2405,46 @@ toggle_ldap_option_bit(struct pine *ps, int index, struct variable *var, char *v else setbitn(f->value, ldap_option_list); + tls_is_on_after = (f = ldap_feature_list(LDAP_F_TLS)) != NULL + && bitnset(f->value, ldap_option_list) ? 1 : 0; + + tlsmust_is_on_after = (f = ldap_feature_list(LDAP_F_TLSMUST)) != NULL + && bitnset(f->value, ldap_option_list) ? 1 : 0; + + ldaps_is_on_after = (f = ldap_feature_list(LDAP_F_LDAPS)) != NULL + && bitnset(f->value, ldap_option_list) ? 1 : 0; + + f = ldap_feature_list(index); + + if(!ldaps_is_on_now && ldaps_is_on_after){ + if(tlsmust_is_on_after || tls_is_on_after){ + char *name; + if(tlsmust_is_on_after) + name = ldap_feature_list(LDAP_F_TLSMUST)->name; + else + name = ldap_feature_list(LDAP_F_TLS)->name; + clrbitn(f->value, ldap_option_list); + q_status_message1(SM_ORDER, 3, 3, + _("Can not use LDAPS when using TLS. Disable \"%s\" first."), name); + } + } + else if(!tls_is_on_now && tls_is_on_after){ + if(ldaps_is_on_after){ + char *name = ldap_feature_list(LDAP_F_LDAPS)->name; + clrbitn(f->value, ldap_option_list); + q_status_message1(SM_ORDER, 3, 3, + _("Can not use TLS when using LDAPS. Disable \"%s\" first."), name); + } + } + else if(!tlsmust_is_on_now && tlsmust_is_on_after){ + if(ldaps_is_on_after){ + char *name = ldap_feature_list(LDAP_F_LDAPS)->name; + clrbitn(f->value, ldap_option_list); + q_status_message1(SM_ORDER, 3, 3, + _("Can not use TLS when using LDAPS. Disable \"%s\" first."), name); + } + } + if(value) value[1] = bitnset(f->value, ldap_option_list) ? 'X' : ' '; } @@ -2365,7 +2459,8 @@ ldap_feature_list(int index) {"save-search-criteria-not-result", NULL, LDAP_F_REF}, {"disable-ad-hoc-space-substitution", NULL, LDAP_F_NOSUB}, {"attempt-tls-on-connection", NULL, LDAP_F_TLS}, - {"require-tls-on-connection", NULL, LDAP_F_TLSMUST} + {"require-tls-on-connection", NULL, LDAP_F_TLSMUST}, // TODO rename tls to starttls + {"require-ldaps-on-connection", NULL, LDAP_F_LDAPS} }; return((index >= 0 && diff --git a/pith/ldap.c b/pith/ldap.c index 78201de..8bec9c0 100644 --- a/pith/ldap.c +++ b/pith/ldap.c @@ -26,7 +26,7 @@ static char rcsid[] = "$Id: ldap.c 1204 2009-02-02 19:54:23Z hubert@u.washington #include "../pith/busy.h" #include "../pith/signal.h" #include "../pith/ablookup.h" - +#include "../pith/readfile.h" /* * Until we can think of a better way to do this. If user exits from an @@ -475,7 +475,59 @@ ldap_lookup(LDAP_SERV_S *info, char *string, CUSTOM_FILT_S *cust, #ifdef _WINDOWS if((ld = ldap_init(serv, info->port)) == NULL) #else - snprintf(tmp_20k_buf, SIZEOF_20KBUF, "ldap://%s:%d", serv, info->port); +#ifdef SMIME_SSLCERTS + /* If we are attempting a ldaps secure connection, we need to tell + * ldap that we have certificates. There are many ways to do so. + * OpenLDAP has many ways to configure this through configuration + * files. For example the global (to the system) ldap.conf file, or the + * personal ldaprc or .ldaprc files. Setting the location of the + * certificates must happen at the time we call ldap_initialize, we + * cannot set it up before that call, nor after, so what we are going + * to do is to test for a .ldaprc file in the home directory. If such + * file exists we read it, if not we create it and if it does not have + * a line for the location of the certificates in the system, we add one. + * (so we ignore all other configuration files) + */ + if(info->ldaps && ps_global->home_dir){ + int done = 0; + char *text, *tls_conf; + char filename[MAXPATH+1]; + + build_path(filename, ps_global->home_dir, ".ldaprc", sizeof(filename)); + + if((text = read_file(filename, 0)) != NULL) + while(done == 0 + && (tls_conf = strstr(text, "TLS_CACERTDIR")) != NULL + && (tls_conf == text || *(tls_conf - 1) == '\n')){ + tls_conf += 13; /* 13 = strlen("TLS_CACERTDIR") */ + while (isspace(*tls_conf)) + tls_conf++; + if(!strncmp(tls_conf, SMIME_SSLCERTS, strlen(SMIME_SSLCERTS))) + done++; + } + + if(!done){ + STORE_S *so; + + if((so = so_get(FileStar, filename, WRITE_ACCESS)) != NULL){ + if(text != NULL){ + so_puts(so, text); + so_puts(so, NEWLINE); + } + so_puts(so, "TLS_CACERTDIR"); + so_puts(so, " "); + so_puts(so, SMIME_SSLCERTS); + so_puts(so, NEWLINE); + so_give(&so); + } + } + if(text != NULL) + fs_give((void **)&text); + } +#endif /* SMIME_SSLCERTS */ + + snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%s://%s:%d", + info->ldaps ? "ldaps" : "ldap ", serv, info->port); tmp_20k_buf[SIZEOF_20KBUF-1] = '\0'; if(ldap_initialize(&ld, tmp_20k_buf) != LDAP_SUCCESS) @@ -535,8 +587,7 @@ ldap_lookup(LDAP_SERV_S *info, char *string, CUSTOM_FILT_S *cust, our_ldap_set_option(ld, LDAP_OPT_RESTART, LDAP_OPT_ON); /* - * If we need to authenticate, get the password. We are not - * supporting SASL authentication, just LDAP simple. + * If we need to authenticate, get the password */ if(info->binddn && info->binddn[0]){ char pmt[500]; @@ -552,9 +603,10 @@ ldap_lookup(LDAP_SERV_S *info, char *string, CUSTOM_FILT_S *cust, if((space=strindex(hostbuf, ' ')) != NULL) *space = '\0'; - mail_valid_net_parse_work(hostbuf, &mb, "ldap"); + mail_valid_net_parse_work(hostbuf, &mb, info->ldaps ? "ldaps" : "ldap"); mb.port = info->port; mb.tlsflag = (info->tls || info->tlsmust) ? 1 : 0; + mb.sslflag = info->ldaps ? 1 : 0; try_password_again: @@ -1416,6 +1468,10 @@ break_up_ldap_server(char *serv_str) if((q = srchstr(tail, "/tlsm=1")) != NULL) info->tlsmust = 1; + /* get the ldaps parameter */ + if((q = srchstr(tail, "/ldaps=1")) != NULL) + info->ldaps = 1; + /* get the search type value */ if((q = srchstr(tail, "/type=")) != NULL){ NAMEVAL_S *v; diff --git a/pith/ldap.h b/pith/ldap.h index b89a651..b0cc30d 100644 --- a/pith/ldap.h +++ b/pith/ldap.h @@ -48,6 +48,7 @@ typedef struct ldap_serv { nosub, /* Disable space sub feature */ tls, /* Attempt TLS */ tlsmust, /* Require TLS */ + ldaps, /* Require LDAPS */ type, /* Search type (surname...) */ srch, /* Search rule (contains...) */ scope; /* Scope of search (base...) */ diff --git a/pith/pine.hlp b/pith/pine.hlp index 21ca255..f0b27fa 100644 --- a/pith/pine.hlp +++ b/pith/pine.hlp @@ -185,6 +185,9 @@ Additions include: variable are "en_US" or "de_DE", etc. Only the first 10 dictionaries are offered. +
  • Unix-Alpine: Connect securely to a LDAP server on a secure port. + Based on a contribution by Wang Kang. +
  • Added support for RFC 2971 - IMAP ID extension.
  • Add configuration @@ -3934,6 +3937,7 @@ There are also additional details on
  • LDAP FEATURE: Disable-Ad-Hoc-Space-Substitution
  • LDAP FEATURE: Lookup-Addrbook-Contents
  • LDAP FEATURE: Require-TLS-On-Connection +
  • LDAP FEATURE: Require-LDAPS-On-Connection
  • LDAP FEATURE: Save-Search-Criteria-Not-Result
  • LDAP FEATURE: Use-Implicitly-From-Composer
  • LDAP OPTION: Bind-DN @@ -14882,6 +14886,14 @@ on the connection. Also see the closely related feature "Require-TLS-On-Connection"

    +Note that if this option is set, then + +"Require-LDAPS-On-Connection" +can not be enabled for this server. You must disable this feature in +order to use + +"Require-LDAPS-On-Connection" +

    <End of help on this topic> @@ -14897,6 +14909,35 @@ When connecting to this server Alpine will attempt to use TLS encryption on the connection. If the StartTLS operation fails then the connection will not be used.

    +Note that if this option is set, then + +"Require-LDAPS-On-Connection" +can not be enabled for this server. You must disable this feature in +order to use + +"Require-LDAPS-On-Connection" +

    +<End of help on this topic> + + +======= h_config_ldap_opts_ldaps ======= + + +LDAP FEATURE: Require-LDAPS-On-Connection + + +

    LDAP FEATURE: Require-LDAPS-On-Connection

    + +When connecting to this server Alpine will use LDAPS (LDAP over SSL/TLS) +on the connection. +

    +This feature can not be used along with +"Require-TLS-On-Connection" + or +"Attempt-TLS-On-Connection". +If you want to connect using StartTLS to this server, you must disable +this feature first. +

    <End of help on this topic> -- 2.11.4.GIT