From b5ab8a3b42920a6b9cb80279bef99334f7aee2f7 Mon Sep 17 00:00:00 2001 From: Noriko Hosoi Date: Fri, 29 Jan 2016 14:55:51 -0800 Subject: [PATCH] Experimental - Ticket #47536 - Allow usage of OpenLDAP libraries that don't use NSS for crypto Description: This is the experiment to allow openldap client library to use non-NSS for crypto. - Replication is used for prototyping. - Adding a new config parameter to the agreement: nsDS5ReplicaCACert: /path/to/cacert.pem or cacert.pem - Extending slapi_ldap_init_ext to take the full path of the cert, where the 6th variable is either the path to LDAPI socket or the certificate. - In slapi_ldap_init_ext, if (!secure && filename), it is LDAPI; If (secure && filename), it is considered as a cacert and pass it to setup_ol_tls_conn(ld, 0, filename), in which it calls ldap_set_option(ld, LDAP_OPT_X_TLS_CACERTFILE, filename); - CLIENTAUTH On the supplier, Assume the replication uses the server cert in the NSS cert db. The pem format cert and private key are located in the certdir (e.g., /etc/dirsrv/slapd-ID). Certificate: ServerCertNickname.pem (e.g., Server-Cert.pem) Key: ServerCertNickname-Key.pem (e.g., Server-Cert-Key.pem) On the consumer, Sample certmap.conf for the replmgr cn=replication manager,cn=config: certmap Example CN=CACert Example:DNComps Example:FilterComps cn Example:verifycert on Example:CmapLdapAttr description Sample replmgr entry: dn: cn=replication manager,cn=config objectclass: inetorgperson cn: replication manager cn: Server-Cert sn: RM description: CN=test.localdomain,OU=389 Directory Server userpassword: Password userCertificate;binary:: MIICxzCCAa+gAwIBAgICA+swDQYJKoZIhvcNAQELBQAwE .... where "CN=test.localdomain,OU=389 Directory Server" is a subject of the certificate and the value of userCertificate;binary is base64 encoded binary format server cert. Build: 1) Build openldap with --with-tls=openssl make; make install (by default, it is installed in /usr/local) 2) Build ns-slapd with the following OPENLDAP_FLAG: OPENLDAP_FLAG="--with-openldap \ --with-openldap-inc=/usr/local/include \ --with-openldap-lib=/usr/local/lib \ --with-openldap-bin=/usr/local/bin" Replication tests: master -> read only replica Replication Agreement: nsDS5ReplicaPort: 389 | 636 nsDS5ReplicaTransportInfo: TLS | SSL nsDS5ReplicaCACert: cacert.pem | /path/to/cacert.pem 1) nsDS5ReplicaBindMethod: SIMPLE The master has no certs in the cert db. And the cacert pem is placed at the random location such as /tmp/nss_pem/cacert.pem. The operation to the master is successfully replicated to the consumer. 2) nsDS5ReplicaBindMethod: SSLCLIENTAUTH Configure the server with the server cert. Then place pem files: # ls *pem cacert.pem Server-Cert0-Key.pem Server-Cert0.pem Verified the replication works. Note: Instead of setting nsDS5ReplicaCACert, tried to extract the path to cacert using /etc/openldap/ldap.conf, /root/.ldaprc, as well as ~dirsrv/.ldaprc. But none of them has the impact. To Do's: - Allowing winsync, dna, and chaining to use the feature. - Cert upgrade plan -- The server checks the necessary key/cert files at the startup time, if they don't exist, extract them from the NSS database. - An idea not to store password in pin.txt using Deo: https://blog-ftweedal.rhcloud.com/2015/09/automatic-decryption-of-tls-private-keys-with-deo/ http://www.freeipa.org/page/Network_Bound_Disk_Encryption https://github.com/npmccallum/deo If the authentication with Deo fails, the server prompts for the password. - Current behavior: If pin.txt exists, the server starts with SSL enabled. If pin.txt does not exist, if the server is started by executing ns-slapd, it prompts for the password. if the server is started via systemctl, it does not prompt and the server starts with SSL disabled. To solve the issue, there is a password agent feature of systemd that is designed for this case: http://www.freedesktop.org/wiki/Software/systemd/PasswordAgents/ - After 389-ds-base, investigate 389-admin. --- ldap/schema/01core389.ldif | 3 +- ldap/schema/02common.ldif | 2 +- ldap/servers/plugins/replication/repl5.h | 3 + ldap/servers/plugins/replication/repl5_agmt.c | 56 +++++- ldap/servers/plugins/replication/repl5_agmtlist.c | 12 ++ .../servers/plugins/replication/repl5_connection.c | 2 +- ldap/servers/plugins/replication/repl_globals.c | 1 + .../plugins/replication/windows_connection.c | 2 +- ldap/servers/slapd/ldaputil.c | 72 +++++--- ldap/servers/slapd/slapi-plugin.h | 2 +- ldap/servers/slapd/ssl.c | 191 ++++++++++++--------- 11 files changed, 228 insertions(+), 118 deletions(-) diff --git a/ldap/schema/01core389.ldif b/ldap/schema/01core389.ldif index 0b14c06..134c5c4 100644 --- a/ldap/schema/01core389.ldif +++ b/ldap/schema/01core389.ldif @@ -46,6 +46,7 @@ attributeTypes: ( 1.3.6.1.4.1.250.1.2 NAME 'multiLineDescription' DESC 'Pilot at attributeTypes: ( 2.16.840.1.113730.3.1.578 NAME 'nsDS5ReplicaHost' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' ) attributeTypes: ( 2.16.840.1.113730.3.1.579 NAME 'nsDS5ReplicaPort' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' ) attributeTypes: ( 2.16.840.1.113730.3.1.580 NAME 'nsDS5ReplicaTransportInfo' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' ) +attributeTypes: ( 2.16.840.1.113730.3.1.595 NAME 'nsDS5ReplicaCACert' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' ) attributeTypes: ( 2.16.840.1.113730.3.1.581 NAME 'nsDS5ReplicaBindDN' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape Directory Server' ) attributeTypes: ( 2.16.840.1.113730.3.1.582 NAME 'nsDS5ReplicaCredentials' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' ) attributeTypes: ( 2.16.840.1.113730.3.1.583 NAME 'nsDS5ReplicaBindMethod' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' ) @@ -303,7 +304,7 @@ objectClasses: ( 2.16.840.1.113730.3.2.110 NAME 'nsMappingTree' DESC 'Netscape d objectClasses: ( 2.16.840.1.113730.3.2.104 NAME 'nsContainer' DESC 'Netscape defined objectclass' SUP top MUST ( CN ) X-ORIGIN 'Netscape Directory Server' ) objectClasses: ( 2.16.840.1.113730.3.2.108 NAME 'nsDS5Replica' DESC 'Netscape defined objectclass' SUP top MUST ( nsDS5ReplicaRoot $ nsDS5ReplicaId ) MAY (cn $ nsds5ReplicaPreciseTombstonePurging $ nsds5ReplicaCleanRUV $ nsds5ReplicaAbortCleanRUV $ nsDS5ReplicaType $ nsDS5ReplicaBindDN $ nsState $ nsDS5ReplicaName $ nsDS5Flags $ nsDS5Task $ nsDS5ReplicaReferral $ nsDS5ReplicaAutoReferral $ nsds5ReplicaPurgeDelay $ nsds5ReplicaTombstonePurgeInterval $ nsds5ReplicaChangeCount $ nsds5ReplicaLegacyConsumer $ nsds5ReplicaProtocolTimeout $ nsds5ReplicaBackoffMin $ nsds5ReplicaBackoffMax ) X-ORIGIN 'Netscape Directory Server' ) objectClasses: ( 2.16.840.1.113730.3.2.113 NAME 'nsTombstone' DESC 'Netscape defined objectclass' SUP top MAY ( nstombstonecsn $ nsParentUniqueId $ nscpEntryDN ) X-ORIGIN 'Netscape Directory Server' ) -objectClasses: ( 2.16.840.1.113730.3.2.103 NAME 'nsDS5ReplicationAgreement' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsds5ReplicaCleanRUVNotified $ nsDS5ReplicaHost $ nsDS5ReplicaPort $ nsDS5ReplicaTransportInfo $ nsDS5ReplicaBindDN $ nsDS5ReplicaCredentials $ nsDS5ReplicaBindMethod $ nsDS5ReplicaRoot $ nsDS5ReplicatedAttributeList $ nsDS5ReplicatedAttributeListTotal $ nsDS5ReplicaUpdateSchedule $ nsds5BeginReplicaRefresh $ description $ nsds50ruv $ nsruvReplicaLastModified $ nsds5ReplicaTimeout $ nsds5replicaChangesSentSinceStartup $ nsds5replicaLastUpdateEnd $ nsds5replicaLastUpdateStart $ nsds5replicaLastUpdateStatus $ nsds5replicaUpdateInProgress $ nsds5replicaLastInitEnd $ nsds5ReplicaEnabled $ nsds5replicaLastInitStart $ nsds5replicaLastInitStatus $ nsds5debugreplicatimeout $ nsds5replicaBusyWaitTime $ nsds5ReplicaStripAttrs $ nsds5replicaSessionPauseTime $ nsds5ReplicaProtocolTimeout $ nsds5ReplicaFlowControlWindow $ nsds5ReplicaFlowControlPause $ nsDS5ReplicaWaitForAsyncResults ) X-ORIGIN 'Netscape Directory Server' ) +objectClasses: ( 2.16.840.1.113730.3.2.103 NAME 'nsDS5ReplicationAgreement' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsds5ReplicaCleanRUVNotified $ nsDS5ReplicaHost $ nsDS5ReplicaPort $ nsDS5ReplicaTransportInfo $ nsDS5ReplicaCACert $ nsDS5ReplicaBindDN $ nsDS5ReplicaCredentials $ nsDS5ReplicaBindMethod $ nsDS5ReplicaRoot $ nsDS5ReplicatedAttributeList $ nsDS5ReplicatedAttributeListTotal $ nsDS5ReplicaUpdateSchedule $ nsds5BeginReplicaRefresh $ description $ nsds50ruv $ nsruvReplicaLastModified $ nsds5ReplicaTimeout $ nsds5replicaChangesSentSinceStartup $ nsds5replicaLastUpdateEnd $ nsds5replicaLastUpdateStart $ nsds5replicaLastUpdateStatus $ nsds5replicaUpdateInProgress $ nsds5replicaLastInitEnd $ nsds5ReplicaEnabled $ nsds5replicaLastInitStart $ nsds5replicaLastInitStatus $ nsds5debugreplicatimeout $ nsds5replicaBusyWaitTime $ nsds5ReplicaStripAttrs $ nsds5replicaSessionPauseTime $ nsds5ReplicaProtocolTimeout $ nsds5ReplicaFlowControlWindow $ nsds5ReplicaFlowControlPause $ nsDS5ReplicaWaitForAsyncResults ) X-ORIGIN 'Netscape Directory Server' ) objectClasses: ( 2.16.840.1.113730.3.2.39 NAME 'nsslapdConfig' DESC 'Netscape defined objectclass' SUP top MAY ( cn ) X-ORIGIN 'Netscape Directory Server' ) objectClasses: ( 2.16.840.1.113730.3.2.317 NAME 'nsSaslMapping' DESC 'Netscape defined objectclass' SUP top MUST ( cn $ nsSaslMapRegexString $ nsSaslMapBaseDNTemplate $ nsSaslMapFilterTemplate ) MAY ( nsSaslMapPriority ) X-ORIGIN 'Netscape Directory Server' ) objectClasses: ( 2.16.840.1.113730.3.2.43 NAME 'nsSNMP' DESC 'Netscape defined objectclass' SUP top MUST ( cn $ nsSNMPEnabled ) MAY ( nsSNMPOrganization $ nsSNMPLocation $ nsSNMPContact $ nsSNMPDescription $ nsSNMPName $ nsSNMPMasterHost $ nsSNMPMasterPort ) X-ORIGIN 'Netscape Directory Server' ) diff --git a/ldap/schema/02common.ldif b/ldap/schema/02common.ldif index dda75e7..f897083 100644 --- a/ldap/schema/02common.ldif +++ b/ldap/schema/02common.ldif @@ -157,7 +157,7 @@ objectClasses: ( 2.16.840.1.113730.3.2.99 NAME 'cosSuperDefinition' DESC 'Netsca objectClasses: ( 2.16.840.1.113730.3.2.100 NAME 'cosClassicDefinition' DESC 'Netscape defined objectclass' SUP cosSuperDefinition MAY ( cosTemplateDn $ cosspecifier ) X-ORIGIN 'Netscape Directory Server' ) objectClasses: ( 2.16.840.1.113730.3.2.101 NAME 'cosPointerDefinition' DESC 'Netscape defined objectclass' SUP cosSuperDefinition MAY ( cosTemplateDn ) X-ORIGIN 'Netscape Directory Server' ) objectClasses: ( 2.16.840.1.113730.3.2.102 NAME 'cosIndirectDefinition' DESC 'Netscape defined objectclass' SUP cosSuperDefinition MAY ( cosIndirectSpecifier ) X-ORIGIN 'Netscape Directory Server' ) -objectClasses: ( 2.16.840.1.113730.3.2.503 NAME 'nsDSWindowsReplicationAgreement' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsDS5ReplicaHost $ nsDS5ReplicaPort $ nsDS5ReplicaTransportInfo $ nsDS5ReplicaBindDN $ nsDS5ReplicaCredentials $ nsDS5ReplicaBindMethod $ nsDS5ReplicaRoot $ nsDS5ReplicatedAttributeList $ nsDS5ReplicaUpdateSchedule $ nsds5BeginReplicaRefresh $ description $ nsds50ruv $ nsruvReplicaLastModified $ nsds5ReplicaTimeout $ nsds5replicaChangesSentSinceStartup $ nsds5replicaLastUpdateEnd $ nsds5replicaLastUpdateStart $ nsds5replicaLastUpdateStatus $ nsds5replicaUpdateInProgress $ nsds5replicaLastInitEnd $ nsds5replicaLastInitStart $ nsds5replicaLastInitStatus $ nsds5debugreplicatimeout $ nsds5replicaBusyWaitTime $ nsds5replicaSessionPauseTime $ nsds7WindowsReplicaSubtree $ nsds7DirectoryReplicaSubtree $ nsds7NewWinUserSyncEnabled $ nsds7NewWinGroupSyncEnabled $ nsds7WindowsDomain $ nsds7DirsyncCookie $ winSyncInterval $ oneWaySync $ winSyncMoveAction $ nsds5ReplicaEnabled $ winSyncDirectoryFilter $ winSyncWindowsFilter $ winSyncSubtreePair ) X-ORIGIN 'Netscape Directory Server' ) +objectClasses: ( 2.16.840.1.113730.3.2.503 NAME 'nsDSWindowsReplicationAgreement' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsDS5ReplicaHost $ nsDS5ReplicaPort $ nsDS5ReplicaTransportInfo $ nsDS5ReplicaCACert $ nsDS5ReplicaBindDN $ nsDS5ReplicaCredentials $ nsDS5ReplicaBindMethod $ nsDS5ReplicaRoot $ nsDS5ReplicatedAttributeList $ nsDS5ReplicaUpdateSchedule $ nsds5BeginReplicaRefresh $ description $ nsds50ruv $ nsruvReplicaLastModified $ nsds5ReplicaTimeout $ nsds5replicaChangesSentSinceStartup $ nsds5replicaLastUpdateEnd $ nsds5replicaLastUpdateStart $ nsds5replicaLastUpdateStatus $ nsds5replicaUpdateInProgress $ nsds5replicaLastInitEnd $ nsds5replicaLastInitStart $ nsds5replicaLastInitStatus $ nsds5debugreplicatimeout $ nsds5replicaBusyWaitTime $ nsds5replicaSessionPauseTime $ nsds7WindowsReplicaSubtree $ nsds7DirectoryReplicaSubtree $ nsds7NewWinUserSyncEnabled $ nsds7NewWinGroupSyncEnabled $ nsds7WindowsDomain $ nsds7DirsyncCookie $ winSyncInterval $ oneWaySync $ winSyncMoveAction $ nsds5ReplicaEnabled $ winSyncDirectoryFilter $ winSyncWindowsFilter $ winSyncSubtreePair ) X-ORIGIN 'Netscape Directory Server' ) objectClasses: ( 2.16.840.1.113730.3.2.128 NAME 'costemplate' DESC 'Netscape defined objectclass' SUP top MAY ( cn $ cospriority ) X-ORIGIN 'Netscape Directory Server' ) objectClasses: ( 2.16.840.1.113730.3.2.304 NAME 'nsView' DESC 'Netscape defined objectclass' SUP top AUXILIARY MAY ( nsViewFilter $ description ) X-ORIGIN 'Netscape Directory Server' ) objectClasses: ( 2.16.840.1.113730.3.2.316 NAME 'nsAttributeEncryption' DESC 'Netscape defined objectclass' SUP top MUST ( cn $ nsEncryptionAlgorithm ) X-ORIGIN 'Netscape Directory Server' ) diff --git a/ldap/servers/plugins/replication/repl5.h b/ldap/servers/plugins/replication/repl5.h index 307da82..ea1d337 100644 --- a/ldap/servers/plugins/replication/repl5.h +++ b/ldap/servers/plugins/replication/repl5.h @@ -123,6 +123,7 @@ extern const char *type_nsds5ReplicaHost; extern const char *type_nsds5ReplicaPort; extern const char *type_nsds5TransportInfo; +extern const char *type_nsds5CACert; extern const char *type_nsds5ReplicaBindDN; extern const char *type_nsds5ReplicaBindDNGroup; extern const char *type_nsds5ReplicaBindDNGroupCheckInterval; @@ -314,6 +315,7 @@ int agmt_replicate_now(Repl_Agmt *ra); char *agmt_get_hostname(const Repl_Agmt *ra); int agmt_get_port(const Repl_Agmt *ra); PRUint32 agmt_get_transport_flags(const Repl_Agmt *ra); +char *agmt_get_cacert_path(const Repl_Agmt *ra); char *agmt_get_binddn(const Repl_Agmt *ra); struct berval *agmt_get_credentials(const Repl_Agmt *ra); int agmt_get_bindmethod(const Repl_Agmt *ra); @@ -335,6 +337,7 @@ int agmt_set_credentials_from_entry( Repl_Agmt *ra, const Slapi_Entry *e ); int agmt_set_binddn_from_entry( Repl_Agmt *ra, const Slapi_Entry *e ); int agmt_set_bind_method_from_entry( Repl_Agmt *ra, const Slapi_Entry *e ); int agmt_set_transportinfo_from_entry( Repl_Agmt *ra, const Slapi_Entry *e ); +int agmt_set_cacertpath_from_entry( Repl_Agmt *ra, const Slapi_Entry *e ); int agmt_set_port_from_entry( Repl_Agmt *ra, const Slapi_Entry *e ); int agmt_set_host_from_entry(Repl_Agmt *ra, const Slapi_Entry *e); const char *agmt_get_long_name(const Repl_Agmt *ra); diff --git a/ldap/servers/plugins/replication/repl5_agmt.c b/ldap/servers/plugins/replication/repl5_agmt.c index 76d26a1..7b9916a 100644 --- a/ldap/servers/plugins/replication/repl5_agmt.c +++ b/ldap/servers/plugins/replication/repl5_agmt.c @@ -72,6 +72,7 @@ typedef struct repl5agmt { char *hostname; /* remote hostname */ int port; /* port of remote server */ PRUint32 transport_flags; /* SSL, TLS, etc. */ + char *cacert_path; /* Path to CA Cert */ char *binddn; /* DN to bind as */ struct berval *creds; /* Password, or certificate */ int bindmethod; /* Bind method - simple, SSL */ @@ -145,6 +146,7 @@ cn nsds5ReplicaHost - hostname nsds5ReplicaPort - port number nsds5ReplicaTransportInfo - "SSL", "startTLS", or may be absent; +nsds5ReplicaCACert - "path to ca cert pem file" nsds5ReplicaBindDN nsds5ReplicaCredentials nsds5ReplicaBindMethod - "SIMPLE" or "SSLCLIENTAUTH". @@ -289,6 +291,7 @@ agmt_new_from_entry(Slapi_Entry *e) /* SSL, TLS, or other transport stuff */ ra->transport_flags = 0; (void) agmt_set_transportinfo_no_lock(ra, e); + (void) agmt_set_cacertpath_from_entry(ra, e); (void) agmt_set_WaitForAsyncResults(ra, e); /* DN to use when binding. May be empty if certain SASL auth is to be used e.g. EXTERNAL GSSAPI. */ @@ -932,6 +935,19 @@ agmt_get_transport_flags(const Repl_Agmt *ra) } /* + */ +char * +agmt_get_cacert_path(const Repl_Agmt *ra) +{ + char *return_value; + PR_ASSERT(NULL != ra); + PR_Lock(ra->lock); + return_value = ra->cacert_path == NULL ? NULL : slapi_ch_strdup(ra->cacert_path); + PR_Unlock(ra->lock); + return return_value; +} + +/* * Return a copy of the bind dn to be used with this * agreement (may return NULL if no binddn is required, * e.g. SSL client auth. @@ -1794,6 +1810,26 @@ agmt_set_transportinfo_no_lock(Repl_Agmt *ra, const Slapi_Entry *e) return (rc); } +static int +agmt_set_cacertpath_no_lock(Repl_Agmt *ra, const Slapi_Entry *e) +{ + ra->cacert_path = slapi_entry_attr_get_charptr(e, type_nsds5CACert); + if (ra->cacert_path) { /* check the validity of the ca cert path */ + char *p = PL_strrchr(ra->cacert_path, '/'); + char *endp = ra->cacert_path + strlen(ra->cacert_path); + if ((p && (p == endp - 1)) || /* ends with '/' */ + (endp - ra->cacert_path < 5) || /* given 4 chars or less */ + PL_strcasecmp(endp - 4, ".pem")) { /* not pem */ + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "agmt_set_cacertpath_no_lock: " + "%s -- Invalid value (%s); Ignoring...\n", + type_nsds5CACert, ra->cacert_path); + slapi_ch_free_string(&ra->cacert_path); + return 1; + } + } + return 0; +} + int agmt_set_WaitForAsyncResults(Repl_Agmt *ra, const Slapi_Entry *e) { @@ -1833,7 +1869,25 @@ agmt_set_transportinfo_from_entry(Repl_Agmt *ra, const Slapi_Entry *e) return return_value; } - + +int +agmt_set_cacertpath_from_entry(Repl_Agmt *ra, const Slapi_Entry *e) +{ + int return_value = 0; + + PR_ASSERT(NULL != ra); + PR_Lock(ra->lock); + if (ra->stop_in_progress) + { + PR_Unlock(ra->lock); + return return_value; + } + return_value = agmt_set_cacertpath_no_lock(ra, e); + PR_Unlock(ra->lock); + prot_notify_agmt_changed(ra->protocol, ra->long_name); + + return return_value; +} /* * Set or reset the replication schedule. Notify the protocol handler diff --git a/ldap/servers/plugins/replication/repl5_agmtlist.c b/ldap/servers/plugins/replication/repl5_agmtlist.c index f50862f..6fc31cb 100644 --- a/ldap/servers/plugins/replication/repl5_agmtlist.c +++ b/ldap/servers/plugins/replication/repl5_agmtlist.c @@ -488,6 +488,18 @@ agmtlist_modify_callback(Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry *returncode = LDAP_OPERATIONS_ERROR; rc = SLAPI_DSE_CALLBACK_ERROR; } + } + else if (slapi_attr_types_equivalent(mods[i]->mod_type, type_nsds5CACert)) + { + /* New CA cert path */ + if (agmt_set_cacertpath_from_entry(agmt, e) != 0) + { + slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: " + "failed to update CA cert path for agreement %s\n", + agmt_get_long_name(agmt)); + *returncode = LDAP_OPERATIONS_ERROR; + rc = SLAPI_DSE_CALLBACK_ERROR; + } } else if (slapi_attr_types_equivalent(mods[i]->mod_type, type_nsds5ReplicaBindMethod)) diff --git a/ldap/servers/plugins/replication/repl5_connection.c b/ldap/servers/plugins/replication/repl5_connection.c index d193938..2849b8c 100644 --- a/ldap/servers/plugins/replication/repl5_connection.c +++ b/ldap/servers/plugins/replication/repl5_connection.c @@ -1268,7 +1268,7 @@ conn_connect(Repl_Connection *conn) /* ldap_unbind internally calls ldap_ld_free */ slapi_ldap_unbind(conn->ld); } - conn->ld = slapi_ldap_init_ext(NULL, conn->hostname, conn->port, secure, 1, NULL); + conn->ld = slapi_ldap_init_ext(NULL, conn->hostname, conn->port, secure, 1, agmt_get_cacert_path(conn->agmt)); if (NULL == conn->ld) { return_value = CONN_OPERATION_FAILED; diff --git a/ldap/servers/plugins/replication/repl_globals.c b/ldap/servers/plugins/replication/repl_globals.c index 331f839..eba3c40 100644 --- a/ldap/servers/plugins/replication/repl_globals.c +++ b/ldap/servers/plugins/replication/repl_globals.c @@ -95,6 +95,7 @@ const char *type_replicaPrecisePurge = "nsds5ReplicaPreciseTombstonePurging"; const char *type_nsds5ReplicaHost = "nsds5ReplicaHost"; const char *type_nsds5ReplicaPort = "nsds5ReplicaPort"; const char *type_nsds5TransportInfo = "nsds5ReplicaTransportInfo"; +const char *type_nsds5CACert = "nsDS5ReplicaCACert"; const char *type_nsds5ReplicaBindDN = "nsds5ReplicaBindDN"; const char *type_nsds5ReplicaBindDNGroup = "nsds5ReplicaBindDNGroup"; const char *type_nsds5ReplicaBindDNGroupCheckInterval = "nsds5ReplicaBindDNGroupCheckInterval"; diff --git a/ldap/servers/plugins/replication/windows_connection.c b/ldap/servers/plugins/replication/windows_connection.c index a06a07e..cbf1124 100644 --- a/ldap/servers/plugins/replication/windows_connection.c +++ b/ldap/servers/plugins/replication/windows_connection.c @@ -1342,7 +1342,7 @@ windows_conn_connect(Repl_Connection *conn) secure ? "secure" : "non-secure", (secure == 2) ? " startTLS" : ""); - conn->ld = slapi_ldap_init_ext(NULL, conn->hostname, conn->port, secure, 0, NULL); + conn->ld = slapi_ldap_init_ext(NULL, conn->hostname, conn->port, secure, 0, NULL/* fix me for ca cert path */); if (NULL == conn->ld) { return_value = CONN_OPERATION_FAILED; diff --git a/ldap/servers/slapd/ldaputil.c b/ldap/servers/slapd/ldaputil.c index 9281e20..a8536a1 100644 --- a/ldap/servers/slapd/ldaputil.c +++ b/ldap/servers/slapd/ldaputil.c @@ -564,7 +564,7 @@ slapi_ldif_parse_line( #if defined(USE_OPENLDAP) static int -setup_ol_tls_conn(LDAP *ld, int clientauth) +setup_ol_tls_conn(LDAP *ld, int clientauth, char *cacert) { char *certdir = config_get_certdir(); int optval = 0; @@ -572,43 +572,61 @@ setup_ol_tls_conn(LDAP *ld, int clientauth) int rc = 0; if (config_get_ssl_check_hostname()) { - ssl_strength = LDAP_OPT_X_TLS_HARD; + ssl_strength = LDAP_OPT_X_TLS_HARD; } else { - /* verify certificate only */ - ssl_strength = LDAP_OPT_X_TLS_NEVER; + /* verify certificate only */ + ssl_strength = LDAP_OPT_X_TLS_NEVER; } if ((rc = ldap_set_option(ld, LDAP_OPT_X_TLS_REQUIRE_CERT, &ssl_strength))) { - slapi_log_error(SLAPI_LOG_FATAL, "setup_ol_tls_conn", - "failed: unable to set REQUIRE_CERT option to %d\n", ssl_strength); + slapi_log_error(SLAPI_LOG_FATAL, "setup_ol_tls_conn", + "failed: unable to set REQUIRE_CERT option to %d\n", ssl_strength); + } + if (cacert) { + char *path = PL_strrchr(cacert, '/'); + /* setting ca cert path */ + if (!path) { + path = slapi_ch_smprintf("%s/%s", certdir, cacert); + } else { + path = cacert; + } + rc = ldap_set_option(ld, LDAP_OPT_X_TLS_CACERTFILE, path); + if (rc) { + slapi_log_error(SLAPI_LOG_FATAL, "setup_ol_tls_conn", + "Could not set CA cert path [%s]: %d:%s\n", + cacert, rc, ldap_err2string(rc)); + } + if (path != cacert) { + slapi_ch_free_string(&path); + } } - /* tell it where our cert db is */ + /* tell it where our cert db/file is */ if ((rc = ldap_set_option(ld, LDAP_OPT_X_TLS_CACERTDIR, certdir))) { - slapi_log_error(SLAPI_LOG_FATAL, "setup_ol_tls_conn", - "failed: unable to set CACERTDIR option to %s\n", certdir); + slapi_log_error(SLAPI_LOG_FATAL, "setup_ol_tls_conn", + "failed: unable to set CACERTDIR option to %s\n", certdir); } slapi_ch_free_string(&certdir); #if defined(LDAP_OPT_X_TLS_PROTOCOL_MIN) optval = LDAP_OPT_X_TLS_PROTOCOL_SSL3; if ((rc = ldap_set_option(ld, LDAP_OPT_X_TLS_PROTOCOL_MIN, &optval))) { - slapi_log_error(SLAPI_LOG_FATAL, "setup_ol_tls_conn", - "failed: unable to set minimum TLS protocol level to SSL3\n"); + slapi_log_error(SLAPI_LOG_FATAL, "setup_ol_tls_conn", + "failed: unable to set minimum TLS protocol level to SSL3\n"); } #endif /* LDAP_OPT_X_TLS_PROTOCOL_MIN */ if (clientauth) { - rc = slapd_SSL_client_auth(ld); - if (rc) { - slapi_log_error(SLAPI_LOG_FATAL, "setup_ol_tls_conn", - "failed: unable to setup connection for TLS/SSL EXTERNAL client cert authentication - %d\n", rc); - } + rc = slapd_SSL_client_auth(ld); + if (rc) { + slapi_log_error(SLAPI_LOG_FATAL, "setup_ol_tls_conn", + "failed: unable to setup connection for TLS/SSL EXTERNAL client cert authentication - %d\n", rc); + } } /* have to do this last - this creates the new TLS handle and sets/copies all of the parameters set above into that TLS handle context - note that optval is ignored - what matters is that it is not NULL */ if ((rc = ldap_set_option(ld, LDAP_OPT_X_TLS_NEWCTX, &optval))) { - slapi_log_error(SLAPI_LOG_FATAL, "setup_ol_tls_conn", - "failed: unable to create new TLS context\n"); + slapi_log_error(SLAPI_LOG_FATAL, "setup_ol_tls_conn", + "failed: unable to create new TLS context\n"); } return rc; @@ -637,12 +655,12 @@ LDAP * slapi_ldap_init_ext( const char *ldapurl, /* full ldap url */ const char *hostname, /* can also use this to override - host in url */ + host in url */ int port, /* can also use this to override port in url */ int secure, /* 0 for ldap, 1 for ldaps, 2 for starttls - - override proto in url */ + override proto in url */ int shared, /* if true, LDAP* will be shared among multiple threads */ - const char *filename /* for ldapi */ + const char *filename /* for ldapi or ca cert pem file */ ) { LDAPURLDesc *ludp = NULL; @@ -753,7 +771,7 @@ slapi_ldap_init_ext( } else { char *makeurl = NULL; - if (filename) { + if (!secure && filename) { makeurl = slapi_ch_smprintf("ldapi://%s/", filename); } else { /* host port */ makeurl = convert_to_openldap_uri(hostname, port, (secure == 1 ? "ldaps" : "ldap")); @@ -787,13 +805,13 @@ slapi_ldap_init_ext( * hostname (such as localhost.localdomain). */ if((rc = ldap_set_option(ld, LDAP_OPT_X_SASL_NOCANON, LDAP_OPT_ON))){ - slapi_log_error(SLAPI_LOG_FATAL, "slapi_ldap_init_ext", + slapi_log_error(SLAPI_LOG_FATAL, "slapi_ldap_init_ext", "Could not set ldap option LDAP_OPT_X_SASL_NOCANON for (%s), error %d (%s)\n", ldapurl, rc, ldap_err2string(rc) ); } } #else /* !USE_OPENLDAP */ - if (filename) { + if (!secure && filename) { /* ldapi in mozldap client is not yet supported */ } else if (secure == 1) { ld = ldapssl_init(hostname, port, secure); @@ -819,7 +837,7 @@ slapi_ldap_init_ext( } } - if ((ld != NULL) && !filename) { + if (ld && (!filename || (secure && filename))) { /* * Set the outbound LDAP I/O timeout based on the server config. */ @@ -854,7 +872,7 @@ slapi_ldap_init_ext( */ if (secure > 0) { #if defined(USE_OPENLDAP) - if (setup_ol_tls_conn(ld, 0)) { + if (setup_ol_tls_conn(ld, 0, filename)) { slapi_log_error(SLAPI_LOG_FATAL, "slapi_ldap_init_ext", "failed: unable to set SSL/TLS options\n"); } @@ -1044,7 +1062,7 @@ slapi_ldap_bind( #if defined(USE_OPENLDAP) /* we already set up a tls context in slapi_ldap_init_ext() - this will free those old settings and context and create a new one */ - rc = setup_ol_tls_conn(ld, 1); + rc = setup_ol_tls_conn(ld, 1, NULL /* FIX ME */); #else /* SSL connections will use the server's security context and cert for client auth */ diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h index d2b076b..d3408c6 100644 --- a/ldap/servers/slapd/slapi-plugin.h +++ b/ldap/servers/slapd/slapi-plugin.h @@ -6200,7 +6200,7 @@ LDAP *slapi_ldap_init_ext( int secure, /* 0 for ldap, 1 for ldaps, 2 for starttls - override proto in url */ int shared, /* if true, LDAP* will be shared among multiple threads */ - const char *filename /* for ldapi */ + const char *filename /* for ldapi and ca cert path */ ); /** * The LDAP bind request - this function handles all of the different types of mechanisms diff --git a/ldap/servers/slapd/ssl.c b/ldap/servers/slapd/ssl.c index 6a23f80..098ec93 100644 --- a/ldap/servers/slapd/ssl.c +++ b/ldap/servers/slapd/ssl.c @@ -2004,111 +2004,110 @@ slapd_SSL_client_auth (LDAP* ld) char *token = NULL; SVRCOREStdPinObj *StdPinObj; SVRCOREError err = SVRCORE_Success; + char *finalpersonality = NULL; - if((family_list = getChildren(configDN))) { + if ((family_list = getChildren(configDN))) { char **family; - char *personality = NULL; char *activation = NULL; char *cipher = NULL; + char *personality = NULL; for (family = family_list; *family; family++) { getConfigEntry( *family, &entry ); if ( entry == NULL ) { - continue; + continue; } activation = slapi_entry_attr_get_charptr( entry, "nssslactivation" ); - if((!activation) || (!PL_strcasecmp(activation, "off"))) { - /* this family was turned off, goto next */ - slapi_ch_free((void **) &activation); - freeConfigEntry( &entry ); - continue; + if ((!activation) || (!PL_strcasecmp(activation, "off"))) { + /* this family was turned off, goto next */ + slapi_ch_free((void **) &activation); + freeConfigEntry( &entry ); + continue; } - - slapi_ch_free((void **) &activation); + slapi_ch_free((void **) &activation); personality = slapi_entry_attr_get_charptr( entry, "nssslpersonalityssl" ); cipher = slapi_entry_attr_get_charptr( entry, "cn" ); - if ( cipher && !PL_strcasecmp(cipher, "RSA" )) { - char *ssltoken; - - /* If there already is a token name, use it */ - if (token) { - slapi_ch_free((void **) &personality); - slapi_ch_free((void **) &cipher); - freeConfigEntry( &entry ); - continue; - } + if ( cipher && !PL_strcasecmp(cipher, "RSA" )) { + char *ssltoken; + + /* If there already is a token name, use it */ + if (token) { + slapi_ch_free_string(&personality); + slapi_ch_free_string(&cipher); + freeConfigEntry( &entry ); + continue; + } - ssltoken = slapi_entry_attr_get_charptr( entry, "nsssltoken" ); - if( ssltoken && personality ) { - if( !PL_strcasecmp(ssltoken, "internal") || - !PL_strcasecmp(ssltoken, "internal (software)") ) { + ssltoken = slapi_entry_attr_get_charptr( entry, "nsssltoken" ); + if( ssltoken && personality ) { + if (!PL_strcasecmp(ssltoken, "internal") || + !PL_strcasecmp(ssltoken, "internal (software)")) { - /* Translate config internal name to more - * readable form. Certificate name is just - * the personality for internal tokens. - */ - token = slapi_ch_strdup(internalTokenName); + /* Translate config internal name to more + * readable form. Certificate name is just + * the personality for internal tokens. + */ + token = slapi_ch_strdup(internalTokenName); #if defined(USE_OPENLDAP) - /* openldap needs tokenname:certnick */ - PR_snprintf(cert_name, sizeof(cert_name), "%s:%s", token, personality); + /* openldap needs tokenname:certnick */ + PR_snprintf(cert_name, sizeof(cert_name), "%s:%s", token, personality); #else - PL_strncpyz(cert_name, personality, sizeof(cert_name)); + PL_strncpyz(cert_name, personality, sizeof(cert_name)); #endif - slapi_ch_free((void **) &ssltoken); - } else { - /* external PKCS #11 token - attach token name */ - /*ssltoken was already dupped and we don't need it anymore*/ - token = ssltoken; - PR_snprintf(cert_name, sizeof(cert_name), "%s:%s", token, personality); - } - } else { - errorCode = PR_GetError(); - slapd_SSL_warn("Security Initialization: Failed to get cipher " - "family information. Missing nsssltoken or" - "nssslpersonalityssl in %s (" - SLAPI_COMPONENT_NAME_NSPR " error %d - %s)", - *family, errorCode, slapd_pr_strerror(errorCode)); - slapi_ch_free((void **) &ssltoken); - slapi_ch_free((void **) &personality); - slapi_ch_free((void **) &cipher); - freeConfigEntry( &entry ); - continue; - } - } else { /* external PKCS #11 cipher */ - char *ssltoken; - - ssltoken = slapi_entry_attr_get_charptr( entry, "nsssltoken" ); - if( token && personality ) { - - /* free the old token and remember the new one */ - if (token) slapi_ch_free((void **)&token); - token = ssltoken; /*ssltoken was already dupped and we don't need it anymore*/ - - /* external PKCS #11 token - attach token name */ - PR_snprintf(cert_name, sizeof(cert_name), "%s:%s", token, personality); - } else { - errorCode = PR_GetError(); - slapd_SSL_warn("Security Initialization: Failed to get cipher " - "family information. Missing nsssltoken or" - "nssslpersonalityssl in %s (" - SLAPI_COMPONENT_NAME_NSPR " error %d - %s)", - *family, errorCode, slapd_pr_strerror(errorCode)); - slapi_ch_free((void **) &ssltoken); - slapi_ch_free((void **) &personality); - slapi_ch_free((void **) &cipher); - freeConfigEntry( &entry ); - continue; - } + slapi_ch_free_string(&ssltoken); + } else { + /* external PKCS #11 token - attach token name */ + token = ssltoken; /*ssltoken was already dupped */ + PR_snprintf(cert_name, sizeof(cert_name), "%s:%s", token, personality); + } + } else { + errorCode = PR_GetError(); + slapd_SSL_warn("Security Initialization: Failed to get cipher " + "family information. Missing nsssltoken or" + "nssslpersonalityssl in %s (" + SLAPI_COMPONENT_NAME_NSPR " error %d - %s)", + *family, errorCode, slapd_pr_strerror(errorCode)); + slapi_ch_free_string(&ssltoken); + slapi_ch_free_string(&personality); + slapi_ch_free_string(&cipher); + freeConfigEntry( &entry ); + continue; + } + } else { /* external PKCS #11 cipher */ + char *ssltoken; + + ssltoken = slapi_entry_attr_get_charptr( entry, "nsssltoken" ); + if( ssltoken && personality ) { - } - slapi_ch_free((void **) &personality); - slapi_ch_free((void **) &cipher); - freeConfigEntry( &entry ); + /* free the old token and remember the new one */ + if (token) slapi_ch_free_string(&token); + token = ssltoken; /*ssltoken was already dupped */ + + /* external PKCS #11 token - attach token name */ + PR_snprintf(cert_name, sizeof(cert_name), "%s:%s", token, personality); + } else { + errorCode = PR_GetError(); + slapd_SSL_warn("Security Initialization: Failed to get cipher " + "family information. Missing nsssltoken or" + "nssslpersonalityssl in %s (" + SLAPI_COMPONENT_NAME_NSPR " error %d - %s)", + * family, errorCode, slapd_pr_strerror(errorCode)); + slapi_ch_free_string(&ssltoken); + slapi_ch_free_string(&personality); + slapi_ch_free_string(&cipher); + freeConfigEntry( &entry ); + continue; + } + } + slapi_ch_free_string(&finalpersonality); + finalpersonality = personality; + slapi_ch_free_string(&cipher); + freeConfigEntry( &entry ); } /* end of for */ - freeChildren( family_list ); + freeChildren( family_list ); } /* Free config data */ @@ -2123,16 +2122,37 @@ slapd_SSL_client_auth (LDAP* ld) errorCode, slapd_pr_strerror(errorCode)); } else { #if defined(USE_OPENLDAP) - rc = ldap_set_option(ld, LDAP_OPT_X_TLS_KEYFILE, SERVER_KEY_NAME); + char *certdir = config_get_certdir(); + char *keyfile = slapi_ch_smprintf("%s/%s-Key.pem", certdir, finalpersonality); + char *certfile = slapi_ch_smprintf("%s/%s.pem", certdir, finalpersonality); + slapi_ch_free_string(&certdir); + if (PR_SUCCESS != PR_Access(keyfile, PR_ACCESS_EXISTS)) { + slapi_ch_free_string(&keyfile); + slapd_SSL_warn("SSL key file (%s) for client authentication does not exist. " + "Using %s", keyfile, SERVER_KEY_NAME); + keyfile = slapi_ch_strdup(SERVER_KEY_NAME); + } + rc = ldap_set_option(ld, LDAP_OPT_X_TLS_KEYFILE, keyfile); if (rc) { slapd_SSL_warn("SSL client authentication cannot be used " - "unable to set the key to use to %s", SERVER_KEY_NAME); + "unable to set the key to use to %s", keyfile); + } + slapi_ch_free_string(&keyfile); + + if (PR_SUCCESS != PR_Access(certfile, PR_ACCESS_EXISTS)) { + slapi_ch_free_string(&certfile); + slapd_SSL_warn("SSL cert file (%s) for client authentication does not exist. " + "Using %s", certfile, cert_name); + certfile = cert_name; } - rc = ldap_set_option(ld, LDAP_OPT_X_TLS_CERTFILE, cert_name); + rc = ldap_set_option(ld, LDAP_OPT_X_TLS_CERTFILE, certfile); if (rc) { slapd_SSL_warn("SSL client authentication cannot be used " "unable to set the cert to use to %s", cert_name); } + if (certfile != cert_name) { + slapi_ch_free_string(&certfile); + } /* * not sure what else needs to be done for client auth - don't * currently have a way to pass in the password to use to unlock @@ -2162,6 +2182,7 @@ slapd_SSL_client_auth (LDAP* ld) slapi_ch_free_string(&token); slapi_ch_free_string(&pw); + slapi_ch_free_string(&finalpersonality); LDAPDebug (LDAP_DEBUG_TRACE, "slapd_SSL_client_auth() %i\n", rc, 0, 0); return rc; -- 2.4.3