Here's a long-awaiting patch that I found years ago and adapted for 1.3.3-1.3.5 (afaik).
Might require some additional work/close review, but it works for me as expected with 1.3.5 on Linux x86_64.
--- contrib/mod_ldap.c.orig 2013-11-24 04:45:28.000000000 +0400
+++ contrib/mod_ldap.c 2014-05-16 13:13:12.326617345 +0400
@@ -142,7 +142,14 @@
*ldap_attr_memberuid = "memberUid",
*ldap_attr_ftpquota = "ftpQuota",
*ldap_attr_ftpquota_profiledn = "ftpQuotaProfileDN",
- *ldap_attr_ssh_pubkey = "sshPublicKey";
+ *ldap_attr_ssh_pubkey = "sshPublicKey",
+ *ldap_tls_ca_cert_dir,
+ *ldap_tls_ca_cert_file,
+ *ldap_tls_cert_file,
+ *ldap_tls_cipher_suite,
+ *ldap_tls_crl_file,
+ *ldap_tls_dh_file,
+ *ldap_tls_key_file;
#ifdef HAS_LDAP_INITIALIZE
static char *ldap_server_url;
#endif /* HAS_LDAP_INITIALIZE */
@@ -152,7 +159,9 @@
ldap_forcedefaultuid = FALSE, ldap_forcedefaultgid = FALSE,
ldap_forcegenhdir = FALSE, ldap_protocol_version = 3,
ldap_dereference = LDAP_DEREF_NEVER,
- ldap_search_scope = LDAP_SCOPE_SUBTREE;
+ ldap_search_scope = LDAP_SCOPE_SUBTREE,
+ ldap_tls_crl_check = -1,
+ ldap_tls_require_cert = -1;
static struct timeval ldap_querytimeout_tv;
#define PR_LDAP_QUERY_TIMEOUT_DEFAULT 5
@@ -196,6 +205,86 @@
struct berval bindcred;
#endif
+ if (ldap_tls_ca_cert_dir) {
+ res = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTDIR, ldap_tls_ca_cert_dir);
+ if (res != LDAP_OPT_SUCCESS) {
+ pr_log_pri(PR_LOG_ERR, MOD_LDAP_VERSION ": pr_ldap_connect(): Setting LDAP_OPT_X_TLS_CACERTDIR option failed: %s", ldap_err2string(res));
+ pr_ldap_unbind();
+ return -1;
+ }
+ pr_log_debug(DEBUG3, MOD_LDAP_VERSION ": set LDAP_OPT_X_TLS_CACERTDIR to %s", ldap_tls_ca_cert_dir);
+ }
+
+ if (ldap_tls_ca_cert_file) {
+ res = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, ldap_tls_ca_cert_file);
+ if (res != LDAP_OPT_SUCCESS) {
+ pr_log_pri(PR_LOG_ERR, MOD_LDAP_VERSION ": pr_ldap_connect(): Setting LDAP_OPT_X_TLS_CACERTFILE option failed: %s", ldap_err2string(res));
+ pr_ldap_unbind();
+ return -1;
+ }
+ pr_log_debug(DEBUG3, MOD_LDAP_VERSION ": set LDAP_OPT_X_TLS_CACERTFILE to %s", ldap_tls_ca_cert_file);
+ }
+
+ if (ldap_tls_cert_file) {
+ res = ldap_set_option(NULL, LDAP_OPT_X_TLS_CERTFILE, ldap_tls_cert_file);
+ if (res != LDAP_OPT_SUCCESS) {
+ pr_log_pri(PR_LOG_ERR, MOD_LDAP_VERSION ": pr_ldap_connect(): Setting LDAP_OPT_X_TLS_CERTFILE option failed: %s", ldap_err2string(res));
+ pr_ldap_unbind();
+ return -1;
+ }
+ pr_log_debug(DEBUG3, MOD_LDAP_VERSION ": set LDAP_OPT_X_TLS_CERTFILE to %s", ldap_tls_cert_file);
+ }
+
+ if (ldap_tls_cipher_suite) {
+ res = ldap_set_option(NULL, LDAP_OPT_X_TLS_CIPHER_SUITE, ldap_tls_cipher_suite);
+ if (res != LDAP_OPT_SUCCESS) {
+ pr_log_pri(PR_LOG_ERR, MOD_LDAP_VERSION ": pr_ldap_connect(): Setting LDAP_OPT_X_TLS_CIPHER_SUITE option failed: %s", ldap_err2string(res));
+ pr_ldap_unbind();
+ return -1;
+ }
+ pr_log_debug(DEBUG3, MOD_LDAP_VERSION ": set LDAP_OPT_X_TLS_CIPHER_SUITE to %s", ldap_tls_cipher_suite);
+ }
+
+ if (ldap_tls_dh_file) {
+ res = ldap_set_option(NULL, LDAP_OPT_X_TLS_DHFILE, ldap_tls_dh_file);
+ if (res != LDAP_OPT_SUCCESS) {
+ pr_log_pri(PR_LOG_ERR, MOD_LDAP_VERSION ": pr_ldap_connect(): Setting LDAP_OPT_X_TLS_DHFILE option failed: %s", ldap_err2string(res));
+ pr_ldap_unbind();
+ return -1;
+ }
+ pr_log_debug(DEBUG3, MOD_LDAP_VERSION ": set LDAP_OPT_X_TLS_DHFILE version to %s", ldap_tls_dh_file);
+ }
+
+ if (ldap_tls_key_file) {
+ res = ldap_set_option(NULL, LDAP_OPT_X_TLS_KEYFILE, ldap_tls_key_file);
+ if (res != LDAP_OPT_SUCCESS) {
+ pr_log_pri(PR_LOG_ERR, MOD_LDAP_VERSION ": pr_ldap_connect(): Setting LDAP_OPT_X_TLS_KEYFILE option failed: %s", ldap_err2string(res));
+ pr_ldap_unbind();
+ return -1;
+ }
+ pr_log_debug(DEBUG3, MOD_LDAP_VERSION ": pr_ldap_connect(): set LDAP_OPT_X_TLS_KEYFILE to %s", ldap_tls_key_file);
+ }
+
+ if (ldap_tls_crl_check != -1) {
+ res = ldap_set_option(NULL, LDAP_OPT_X_TLS_CRLCHECK, (void *)&ldap_tls_crl_check);
+ if (res != LDAP_OPT_SUCCESS) {
+ pr_log_pri(PR_LOG_ERR, MOD_LDAP_VERSION ": pr_ldap_connect(): Setting LDAP_OPT_X_TLS_CRLCHECK option failed: %s", ldap_err2string(res));
+ pr_ldap_unbind();
+ return -1;
+ }
+ pr_log_debug(DEBUG3, MOD_LDAP_VERSION ": set LDAP_OPT_X_TLS_CRLCHECK to %d", ldap_tls_crl_check);
+ }
+
+ if (ldap_tls_require_cert != -1) {
+ res = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, (void *)&ldap_tls_require_cert);
+ if (res != LDAP_OPT_SUCCESS) {
+ pr_log_pri(PR_LOG_ERR, MOD_LDAP_VERSION ": pr_ldap_connect(): Setting LDAP_OPT_X_TLS_REQUIRE_CERT option failed: %s", ldap_err2string(res));
+ pr_ldap_unbind();
+ return -1;
+ }
+ pr_log_debug(DEBUG3, MOD_LDAP_VERSION ": set LDAP_OPT_X_TLS_REQUIRE_CERT to %d", ldap_tls_require_cert);
+ }
+
#ifdef HAS_LDAP_INITIALIZE
(void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
"attempting connection to URL %s",
@@ -2029,6 +2118,130 @@
return PR_HANDLED(cmd);
}
+MODRET
+set_ldap_tls_ca_cert_dir(cmd_rec *cmd)
+{
+ CHECK_ARGS(cmd, 1);
+ CHECK_CONF(cmd, CONF_ROOT | CONF_VIRTUAL | CONF_GLOBAL);
+
+ add_config_param_str(cmd->argv[0], 1, cmd->argv[1]);
+ return PR_HANDLED(cmd);
+}
+
+MODRET
+set_ldap_tls_ca_cert_file(cmd_rec *cmd)
+{
+ CHECK_ARGS(cmd, 1);
+ CHECK_CONF(cmd, CONF_ROOT | CONF_VIRTUAL | CONF_GLOBAL);
+
+ add_config_param_str(cmd->argv[0], 1, cmd->argv[1]);
+ return PR_HANDLED(cmd);
+}
+
+MODRET
+set_ldap_tls_cert_file(cmd_rec *cmd)
+{
+ CHECK_ARGS(cmd, 1);
+ CHECK_CONF(cmd, CONF_ROOT | CONF_VIRTUAL | CONF_GLOBAL);
+
+ add_config_param_str(cmd->argv[0], 1, cmd->argv[1]);
+ return PR_HANDLED(cmd);
+}
+
+MODRET
+set_ldap_tls_cipher_suite(cmd_rec *cmd)
+{
+ CHECK_ARGS(cmd, 1);
+ CHECK_CONF(cmd, CONF_ROOT | CONF_VIRTUAL | CONF_GLOBAL);
+
+ add_config_param_str(cmd->argv[0], 1, cmd->argv[1]);
+ return PR_HANDLED(cmd);
+}
+
+MODRET
+set_ldap_tls_crl_check(cmd_rec *cmd)
+{
+ int value;
+ config_rec *c;
+
+ CHECK_ARGS(cmd, 1);
+ CHECK_CONF(cmd, CONF_ROOT | CONF_VIRTUAL | CONF_GLOBAL);
+
+ if (strcasecmp(cmd->argv[1], "none") == 0) {
+ value = LDAP_OPT_X_TLS_CRL_NONE;
+ } else if (strcasecmp(cmd->argv[1], "peer") == 0) {
+ value = LDAP_OPT_X_TLS_CRL_PEER;
+ } else if (strcasecmp(cmd->argv[1], "all") == 0) {
+ value = LDAP_OPT_X_TLS_CRL_ALL;
+ } else {
+ CONF_ERROR(cmd, "LDAPTLSCrlCheck: expected a valid LDAP_OPT_X_TLS_CRLCHECK option (none, peer, all).");
+ }
+
+ c = add_config_param("LDAPTLSCrlCheck", 1, NULL);
+ c->argv[0] = pcalloc(c->pool, sizeof(int));
+ *((int *) c->argv[0]) = value;
+ return PR_HANDLED(cmd);
+}
+
+MODRET
+set_ldap_tls_dh_file(cmd_rec *cmd)
+{
+ CHECK_ARGS(cmd, 1);
+ CHECK_CONF(cmd, CONF_ROOT | CONF_VIRTUAL | CONF_GLOBAL);
+
+ add_config_param_str(cmd->argv[0], 1, cmd->argv[1]);
+ return PR_HANDLED(cmd);
+}
+
+MODRET
+set_ldap_tls_crl_file(cmd_rec *cmd)
+{
+ CHECK_ARGS(cmd, 1);
+ CHECK_CONF(cmd, CONF_ROOT | CONF_VIRTUAL | CONF_GLOBAL);
+
+ add_config_param_str(cmd->argv[0], 1, cmd->argv[1]);
+ return PR_HANDLED(cmd);
+}
+
+MODRET
+set_ldap_tls_key_file(cmd_rec *cmd)
+{
+ CHECK_ARGS(cmd, 1);
+ CHECK_CONF(cmd, CONF_ROOT | CONF_VIRTUAL | CONF_GLOBAL);
+
+ add_config_param_str(cmd->argv[0], 1, cmd->argv[1]);
+ return PR_HANDLED(cmd);
+}
+
+MODRET
+set_ldap_tls_require_cert(cmd_rec *cmd)
+{
+ int value;
+ config_rec *c;
+
+ CHECK_ARGS(cmd, 1);
+ CHECK_CONF(cmd, CONF_ROOT | CONF_VIRTUAL | CONF_GLOBAL);
+
+ if (strcasecmp(cmd->argv[1], "never") == 0) {
+ value = LDAP_OPT_X_TLS_NEVER;
+ } else if (strcasecmp(cmd->argv[1], "hard") == 0) {
+ value = LDAP_OPT_X_TLS_HARD;
+ } else if (strcasecmp(cmd->argv[1], "demand") == 0) {
+ value = LDAP_OPT_X_TLS_DEMAND;
+ } else if (strcasecmp(cmd->argv[1], "allow") == 0) {
+ value = LDAP_OPT_X_TLS_ALLOW;
+ } else if (strcasecmp(cmd->argv[1], "try") == 0) {
+ value = LDAP_OPT_X_TLS_TRY;
+ } else {
+ CONF_ERROR(cmd, "LDAPTLSRequireCert: expected a valid LDAP_OPT_X_TLS_REQUIRE_CERT option (never, hard, demand, allow, try).");
+ }
+
+ c = add_config_param("LDAPTLSRequireCert", 1, NULL);
+ c->argv[0] = pcalloc(c->pool, sizeof(int));
+ *((int *) c->argv[0]) = value;
+ return PR_HANDLED(cmd);
+}
+
/* Initialization routines
*/
@@ -2279,6 +2492,22 @@
}
}
+ ldap_tls_ca_cert_dir = (char *)get_param_ptr(main_server->conf, "LDAPTLSCACertDir", FALSE);
+ ldap_tls_ca_cert_file = (char *)get_param_ptr(main_server->conf, "LDAPTLSCACertFile", FALSE);
+ ldap_tls_cert_file = (char *)get_param_ptr(main_server->conf, "LDAPTLSCertFile", FALSE);
+ ldap_tls_cipher_suite = (char *)get_param_ptr(main_server->conf, "LDAPTLSCipherSuite", FALSE);
+ ldap_tls_crl_file = (char *)get_param_ptr(main_server->conf, "LDAPTLSCrlFile", FALSE);
+ ldap_tls_dh_file = (char *)get_param_ptr(main_server->conf, "LDAPTLSDHFile", FALSE);
+ ldap_tls_key_file = (char *)get_param_ptr(main_server->conf, "LDAPTLSKeyFile", FALSE);
+ ptr = get_param_ptr(main_server->conf, "LDAPTLSCrlCheck", FALSE);
+ if (ptr) {
+ ldap_tls_crl_check = *((int *) ptr);
+ }
+ ptr = get_param_ptr(main_server->conf, "LDAPTLSRequireCert", FALSE);
+ if (ptr) {
+ ldap_tls_require_cert = *((int *) ptr);
+ }
+
return 0;
}
@@ -2309,7 +2538,15 @@
{ "LDAPServer", set_ldapserver, NULL },
{ "LDAPUsers", set_ldapuserlookups, NULL },
{ "LDAPUseTLS", set_ldapusetls, NULL },
-
+ { "LDAPTLSCACertDir", set_ldap_tls_ca_cert_dir, NULL },
+ { "LDAPTLSCACertFile", set_ldap_tls_ca_cert_file, NULL },
+ { "LDAPTLSCertFile", set_ldap_tls_cert_file, NULL },
+ { "LDAPTLSCipherSuite", set_ldap_tls_cipher_suite, NULL },
+ { "LDAPTLSCrlCheck", set_ldap_tls_crl_check, NULL },
+ { "LDAPTLSCrlFile", set_ldap_tls_crl_file, NULL },
+ { "LDAPTLSDHFile", set_ldap_tls_dh_file, NULL },
+ { "LDAPTLSKeyFile", set_ldap_tls_key_file, NULL },
+ { "LDAPTLSRequireCert", set_ldap_tls_require_cert, NULL },
{ NULL, NULL, NULL },
};