From 400e8becf03e8b40fd06f027fc9f5ec248e5afdf Mon Sep 17 00:00:00 2001 From: Graham Leggett Date: Sat, 30 Dec 2023 16:51:07 +0000 Subject: [PATCH 1/2] Add per replication agreement certificate settings Allow TLS certificates to be configured individually on replication agreements. Add nsDS5ReplicaTransportUri, nsDS5ReplicaTransportCAUri, nsDS5ReplicaBootstrapTransportUri and nsDS5ReplicaBootstrapTransportCAUri to allow the URIs of certificates, keys and ca certificates to be specified for each agreement. Based on OpenSSL provider support added to openldap here: https://bugs.openldap.org/show_bug.cgi?id=10149 https://github.com/openldap/openldap/pull/11 --- ldap/schema/01core389.ldif | 6 +- ldap/servers/plugins/replication/repl5.h | 12 +- ldap/servers/plugins/replication/repl5_agmt.c | 183 +++++++++++++++++- .../plugins/replication/repl5_agmtlist.c | 44 ++++- .../plugins/replication/repl5_connection.c | 49 ++++- .../plugins/replication/repl_globals.c | 6 +- ldap/servers/slapd/ldaputil.c | 71 ++++--- ldap/servers/slapd/ssl.c | 9 + src/lib389/lib389/agreement.py | 14 +- src/lib389/lib389/cli_conf/replication.py | 52 ++++- src/lib389/lib389/properties.py | 4 + src/lib389/lib389/replica.py | 2 + 12 files changed, 409 insertions(+), 43 deletions(-) diff --git a/ldap/schema/01core389.ldif b/ldap/schema/01core389.ldif index fad8bc2f96..aaaf28cd21 100644 --- a/ldap/schema/01core389.ldif +++ b/ldap/schema/01core389.ldif @@ -46,6 +46,8 @@ 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 'nsDS5ReplicaTransportUri' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Directory Server' ) +attributeTypes: ( 2.16.840.1.113730.3.1.596 NAME 'nsDS5ReplicaTransportCAUri' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 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' ) @@ -325,6 +327,8 @@ attributeTypes: ( 2.16.840.1.113730.3.1.2371 NAME 'nsDS5ReplicaBootstrapBindDN' attributeTypes: ( 2.16.840.1.113730.3.1.2372 NAME 'nsDS5ReplicaBootstrapCredentials' 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.2373 NAME 'nsDS5ReplicaBootstrapBindMethod' 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.2374 NAME 'nsDS5ReplicaBootstrapTransportInfo' 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.2398 NAME 'nsDS5ReplicaBootstrapTransportUri' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Directory Server' ) +attributeTypes: ( 2.16.840.1.113730.3.1.2399 NAME 'nsDS5ReplicaBootstrapTransportCAUri' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Directory Server' ) attributeTypes: ( 2.16.840.1.113730.3.1.2387 NAME 'nsslapd-tcp-fin-timeout' 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.2388 NAME 'nsslapd-tcp-keepalive-time' 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.2390 NAME 'nsds5ReplicaKeepAliveUpdateInterval' DESC '389 defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN '389 Directory Server' ) @@ -342,7 +346,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 'Replication configuration objectclass' SUP top MUST ( nsDS5ReplicaRoot $ nsDS5ReplicaId ) MAY (cn $ nsds5ReplicaPreciseTombstonePurging $ nsds5ReplicaCleanRUV $ nsds5ReplicaAbortCleanRUV $ nsDS5ReplicaType $ nsDS5ReplicaBindDN $ nsDS5ReplicaBindDNGroup $ nsState $ nsDS5ReplicaName $ nsDS5Flags $ nsDS5Task $ nsDS5ReplicaReferral $ nsDS5ReplicaAutoReferral $ nsds5ReplicaPurgeDelay $ nsds5ReplicaTombstonePurgeInterval $ nsds5ReplicaChangeCount $ nsds5ReplicaLegacyConsumer $ nsds5ReplicaProtocolTimeout $ nsds5ReplicaBackoffMin $ nsds5ReplicaBackoffMax $ nsds5ReplicaReleaseTimeout $ nsDS5ReplicaBindDnGroupCheckInterval $ nsds5ReplicaKeepAliveUpdateInterval ) 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 $ nsds5ReplicaIgnoreMissingChange $ nsDS5ReplicaBootstrapBindDN $ nsDS5ReplicaBootstrapCredentials $ nsDS5ReplicaBootstrapBindMethod $ nsDS5ReplicaBootstrapTransportInfo ) 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 $ nsDS5ReplicaTransportUri $ nsDS5ReplicaTransportCAUri $ 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 $ nsds5ReplicaIgnoreMissingChange $ nsDS5ReplicaBootstrapBindDN $ nsDS5ReplicaBootstrapCredentials $ nsDS5ReplicaBootstrapBindMethod $ nsDS5ReplicaBootstrapTransportInfo $ nsDS5ReplicaBootstrapTransportUri $ nsDS5ReplicaBootstrapTransportCAUri ) 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/servers/plugins/replication/repl5.h b/ldap/servers/plugins/replication/repl5.h index f7fc74e829..89fd16ab34 100644 --- a/ldap/servers/plugins/replication/repl5.h +++ b/ldap/servers/plugins/replication/repl5.h @@ -140,7 +140,9 @@ /* Attribute names for replication agreement attributes */ extern const char *type_nsds5ReplicaHost; extern const char *type_nsds5ReplicaPort; -extern const char *type_nsds5TransportInfo; +extern const char *type_nsds5ReplicaTransportInfo; +extern const char *type_nsds5ReplicaTransportUri; +extern const char *type_nsds5ReplicaTransportCAUri; extern const char *type_nsds5ReplicaBindDN; extern const char *type_nsds5ReplicaBindDNGroup; extern const char *type_nsds5ReplicaBindDNGroupCheckInterval; @@ -168,6 +170,8 @@ extern const char *type_nsds5ReplicaBootstrapBindDN; extern const char *type_nsds5ReplicaBootstrapCredentials; extern const char *type_nsds5ReplicaBootstrapBindMethod; extern const char *type_nsds5ReplicaBootstrapTransportInfo; +extern const char *type_nsds5ReplicaBootstrapTransportUri; +extern const char *type_nsds5ReplicaBootstrapTransportCAUri; extern const char *type_replicaKeepAliveUpdateInterval; /* Attribute names for windows replication agreements */ @@ -399,6 +403,10 @@ char *agmt_get_hostname(const Repl_Agmt *ra); int agmt_get_port(const Repl_Agmt *ra); uint32_t agmt_get_transport_flags(const Repl_Agmt *ra); uint32_t agmt_get_bootstrap_transport_flags(const Repl_Agmt *ra); +char **agmt_get_transport_uri(const Repl_Agmt *ra); +char **agmt_get_bootstrap_transport_uri(const Repl_Agmt *ra); +char **agmt_get_transport_ca_uri(const Repl_Agmt *ra); +char **agmt_get_bootstrap_transport_ca_uri(const Repl_Agmt *ra); char *agmt_get_binddn(const Repl_Agmt *ra); char *agmt_get_bootstrap_binddn(const Repl_Agmt *ra); struct berval *agmt_get_credentials(const Repl_Agmt *ra); @@ -426,6 +434,8 @@ int agmt_set_binddn_from_entry(Repl_Agmt *ra, const Slapi_Entry *e); int32_t agmt_set_bootstrap_binddn_from_entry(Repl_Agmt *ra, const Slapi_Entry *e); int agmt_set_bind_method_from_entry(Repl_Agmt *ra, const Slapi_Entry *e, PRBool bootstrap); int agmt_set_transportinfo_from_entry(Repl_Agmt *ra, const Slapi_Entry *e, PRBool bootstrap); +int agmt_set_transporturi_from_entry(Repl_Agmt *ra, const Slapi_Entry *e, PRBool bootstrap); +int agmt_set_transportcauri_from_entry(Repl_Agmt *ra, const Slapi_Entry *e, PRBool bootstrap); 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 e93a1b111a..5c9ca19343 100644 --- a/ldap/servers/plugins/replication/repl5_agmt.c +++ b/ldap/servers/plugins/replication/repl5_agmt.c @@ -141,7 +141,10 @@ typedef struct repl5agmt struct berval *bootstrapCreds; /* Bootstrap credentials */ int64_t bootstrapBindmethod; /* Bootstrap Bind Method: simple, TLS, client auth, etc */ uint32_t bootstrapTransportFlags; /* Bootstrap Transport Info: LDAPS, StartTLS, etc. */ - + char **transportUris; /* Transport URIs: client certificates and keys */ + char **bootstrapTransportUris; /* Bootstap Transport URIs: client certificates and keys */ + char **transportCAUris; /* Transport CA URIs: client CA certificates */ + char **bootstrapTransportCAUris; /* Bootstap Transport CA URIs: client CA certificates */ } repl5agmt; /* Forward declarations */ @@ -165,6 +168,8 @@ nsds5ReplicaTransportInfo - "LDAPS", "StartTLS", or may be absent ("SSL" and "TL nsds5ReplicaBindDN nsds5ReplicaCredentials nsds5ReplicaBindMethod - "SIMPLE" or "SSLCLIENTAUTH". +nsds5ReplicaTransportUri - URIs of certificates and keys for TLS client authentication +nsds5ReplicaTransportCAUri - URIs of CA certificates for TLS client authentication nsds5ReplicaRoot - Replicated suffix nsds5ReplicatedAttributeList - Fractional attrs for incremental update protocol (and total if not separately defined) nsds5ReplicatedAttributeListTotal - Fractional attrs for total update protocol @@ -221,7 +226,19 @@ agmt_is_valid(Repl_Agmt *ra) slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "agmt_is_valid - Replication agreement \"%s\" " " is malformed: cannot use SSLCLIENTAUTH if using plain LDAP - please " "change %s to LDAPS or StartTLS before changing %s to use SSLCLIENTAUTH\n", - slapi_sdn_get_dn(ra->dn), type_nsds5TransportInfo, type_nsds5ReplicaBindMethod); + slapi_sdn_get_dn(ra->dn), type_nsds5ReplicaTransportInfo, type_nsds5ReplicaBindMethod); + return_value = 0; + } + if ((BINDMETHOD_SSL_CLIENTAUTH != ra->bindmethod) && (NULL != ra->transportUris)) { + slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "agmt_is_valid - Replication agreement \"%s\" " + " is malformed: cannot use %s if %s is not set to SSLCLIENTAUTH\n", + slapi_sdn_get_dn(ra->dn), type_nsds5ReplicaTransportUri, type_nsds5ReplicaTransportInfo); + return_value = 0; + } + if ((BINDMETHOD_SSL_CLIENTAUTH != ra->bindmethod) && (NULL != ra->transportCAUris)) { + slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "agmt_is_valid - Replication agreement \"%s\" " + " is malformed: cannot use %s if %s is not set to SSLCLIENTAUTH\n", + slapi_sdn_get_dn(ra->dn), type_nsds5ReplicaTransportCAUri, type_nsds5ReplicaTransportInfo); return_value = 0; } /* @@ -310,6 +327,8 @@ agmt_new_from_entry(Slapi_Entry *e) /* LDAPS, StartTLS, or other transport stuff */ ra->transport_flags = 0; (void)agmt_set_transportinfo_no_lock(ra, e); + (void)agmt_set_transporturi_from_entry(ra, e, 0); + (void)agmt_set_transportcauri_from_entry(ra, e, 0); (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. */ @@ -346,6 +365,8 @@ agmt_new_from_entry(Slapi_Entry *e) } ra->bootstrapTransportFlags = 0; (void)agmt_set_bootstrap_transportinfo_no_lock(ra, e); + (void)agmt_set_transporturi_from_entry(ra, e, 1); + (void)agmt_set_transportcauri_from_entry(ra, e, 1); (void)agmt_set_bootstrap_bind_method_no_lock(ra, e); /* timeout. */ @@ -618,7 +639,6 @@ agmt_new_from_pblock(Slapi_PBlock *pb) return agmt_new_from_entry(e); } - /* This should never be called directly - only should be called as a destructor. XXXggood this is not finished @@ -665,6 +685,11 @@ agmt_delete(void **rap) slapi_ch_array_free(ra->frac_attrs_total); ra->frac_attr_total_defined = PR_FALSE; + slapi_ch_array_free(ra->transportUris); + slapi_ch_array_free(ra->transportCAUris); + slapi_ch_array_free(ra->bootstrapTransportUris); + slapi_ch_array_free(ra->bootstrapTransportCAUris); + if (NULL != ra->creds) { ber_bvfree(ra->creds); } @@ -1078,6 +1103,56 @@ agmt_get_bootstrap_bindmethod(const Repl_Agmt *ra) return return_value; } +/* Returns a COPY of the uri list, remember to free it */ +char ** +agmt_get_transport_uri(const Repl_Agmt *ra) +{ + char **return_value; + PR_ASSERT(NULL != ra); + PR_Lock(ra->lock); + return_value = charray_dup(ra->transportUris); + PR_Unlock(ra->lock); + return return_value; +} + +/* Returns a COPY of the uri list, remember to free it */ +char ** +agmt_get_bootstrap_transport_uri(const Repl_Agmt *ra) +{ + char **return_value; + + PR_Lock(ra->lock); + return_value = charray_dup(ra->bootstrapTransportUris); + PR_Unlock(ra->lock); + + return return_value; +} + +/* Returns a COPY of the uri list, remember to free it */ +char ** +agmt_get_transport_ca_uri(const Repl_Agmt *ra) +{ + char **return_value; + PR_ASSERT(NULL != ra); + PR_Lock(ra->lock); + return_value = charray_dup(ra->transportCAUris); + PR_Unlock(ra->lock); + return return_value; +} + +/* Returns a COPY of the uri list, remember to free it */ +char ** +agmt_get_bootstrap_transport_ca_uri(const Repl_Agmt *ra) +{ + char **return_value; + + PR_Lock(ra->lock); + return_value = charray_dup(ra->bootstrapTransportCAUris); + PR_Unlock(ra->lock); + + return return_value; +} + /* * Return a copy of the dn at the top of the replicated area. */ @@ -1913,7 +1988,7 @@ agmt_set_transportinfo_no_lock(Repl_Agmt *ra, const Slapi_Entry *e) const char *tmpstr; int rc = 0; - tmpstr = slapi_entry_attr_get_ref((Slapi_Entry *)e, type_nsds5TransportInfo); + tmpstr = slapi_entry_attr_get_ref((Slapi_Entry *)e, type_nsds5ReplicaTransportInfo); if (!tmpstr || !strcasecmp(tmpstr, "LDAP")) { ra->transport_flags = 0; } else if (strcasecmp(tmpstr, "SSL") == 0 || strcasecmp(tmpstr, "LDAPS") == 0) { @@ -1990,6 +2065,106 @@ agmt_set_transportinfo_from_entry(Repl_Agmt *ra, const Slapi_Entry *e, PRBool bo } +int +agmt_set_transporturi_from_entry(Repl_Agmt *ra, const Slapi_Entry *e, PRBool bootstrap) +{ + int return_value = 0; + + Slapi_Attr *attr; + Slapi_Value *sval = NULL; + + char **uris = NULL; + + PR_ASSERT(NULL != ra); + PR_Lock(ra->lock); + if (ra->stop_in_progress) { + PR_Unlock(ra->lock); + return return_value; + } + + if (0 == slapi_entry_attr_find(e, + bootstrap ? type_nsds5ReplicaBootstrapTransportUri : type_nsds5ReplicaTransportUri, &attr)) { + + int i; + int uri_count = 0; + + /* Get a count and allocate an array for the official matching rules */ + slapi_attr_get_numvalues(attr, &uri_count); + uris = (char **)slapi_ch_malloc((uri_count + 1) * sizeof(char *)); + + for (i = slapi_attr_first_value(attr, &sval); + i >= 0; i = slapi_attr_next_value(attr, i, &sval)) { + uris[i] = slapi_ch_strdup(slapi_value_get_string(sval)); + } + + uris[uri_count] = NULL; + } + + if (bootstrap) { + slapi_ch_array_free(ra->bootstrapTransportUris); + ra->bootstrapTransportUris = uris; + } else { + slapi_ch_array_free(ra->transportUris); + ra->transportUris = uris; + } + + PR_Unlock(ra->lock); + prot_notify_agmt_changed(ra->protocol, ra->long_name); + + return return_value; +} + + +int +agmt_set_transportcauri_from_entry(Repl_Agmt *ra, const Slapi_Entry *e, PRBool bootstrap) +{ + int return_value = 0; + + Slapi_Attr *attr; + Slapi_Value *sval = NULL; + + char **uris = NULL; + + PR_ASSERT(NULL != ra); + PR_Lock(ra->lock); + if (ra->stop_in_progress) { + PR_Unlock(ra->lock); + return return_value; + } + + if (0 == slapi_entry_attr_find(e, + bootstrap ? type_nsds5ReplicaBootstrapTransportCAUri : type_nsds5ReplicaTransportCAUri, &attr)) { + + int i; + int uri_count = 0; + + /* Get a count and allocate an array for the official matching rules */ + slapi_attr_get_numvalues(attr, &uri_count); + uris = (char **)slapi_ch_malloc((uri_count + 1) * sizeof(char *)); + + for (i = slapi_attr_first_value(attr, &sval); + i >= 0; i = slapi_attr_next_value(attr, i, &sval)) { + uris[i] = slapi_ch_strdup(slapi_value_get_string(sval)); + } + + uris[uri_count] = NULL; + } + + if (bootstrap) { + slapi_ch_array_free(ra->bootstrapTransportCAUris); + ra->bootstrapTransportCAUris = uris; + } else { + slapi_ch_array_free(ra->transportCAUris); + ra->transportCAUris = uris; + } + + 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 * that a change has been made. diff --git a/ldap/servers/plugins/replication/repl5_agmtlist.c b/ldap/servers/plugins/replication/repl5_agmtlist.c index 0ebbc376ae..713f15cc8c 100644 --- a/ldap/servers/plugins/replication/repl5_agmtlist.c +++ b/ldap/servers/plugins/replication/repl5_agmtlist.c @@ -466,7 +466,7 @@ agmtlist_modify_callback(Slapi_PBlock *pb, agmt_remove_maxcsn(agmt); } } else if (slapi_attr_types_equivalent(mods[i]->mod_type, - type_nsds5TransportInfo)) { + type_nsds5ReplicaTransportInfo)) { /* New Transport info */ if (agmt_set_transportinfo_from_entry(agmt, e, PR_FALSE /* get default value */) != 0) { slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "agmtlist_modify_callback - " @@ -486,6 +486,48 @@ agmtlist_modify_callback(Slapi_PBlock *pb, *returncode = LDAP_OPERATIONS_ERROR; rc = SLAPI_DSE_CALLBACK_ERROR; } + } else if (slapi_attr_types_equivalent(mods[i]->mod_type, + type_nsds5ReplicaTransportUri)) { + /* New Transport URI */ + if (agmt_set_transporturi_from_entry(agmt, e, PR_FALSE /* get default value */) != 0) { + slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "agmtlist_modify_callback - " + "Transport uri not supported 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_nsds5ReplicaBootstrapTransportUri)) + { + /* Bootstrap Transport URI */ + if (agmt_set_transporturi_from_entry(agmt, e, PR_TRUE /* get bootstrap value */) != 0) { + slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "agmtlist_modify_callback - " + "Bootstrap transport uri not supported 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_nsds5ReplicaTransportCAUri)) { + /* New Transport CA URI */ + if (agmt_set_transportcauri_from_entry(agmt, e, PR_FALSE /* get default value */) != 0) { + slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "agmtlist_modify_callback - " + "Transport CA uri not supported 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_nsds5ReplicaBootstrapTransportCAUri)) + { + /* Bootstrap Transport CA URI */ + if (agmt_set_transportcauri_from_entry(agmt, e, PR_TRUE /* get bootstrap value */) != 0) { + slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "agmtlist_modify_callback - " + "Bootstrap transport CA uri not supported 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)) { if (agmt_set_bind_method_from_entry(agmt, e, PR_FALSE /* get default value */) != 0) { diff --git a/ldap/servers/plugins/replication/repl5_connection.c b/ldap/servers/plugins/replication/repl5_connection.c index 809ffeeac9..e776dfc9a2 100644 --- a/ldap/servers/plugins/replication/repl5_connection.c +++ b/ldap/servers/plugins/replication/repl5_connection.c @@ -42,6 +42,8 @@ typedef struct repl_connection const char *status; char *last_ldap_errmsg; PRUint32 transport_flags; + char **transport_uris; + char **transport_ca_uris; LDAP *ld; int supports_ldapv3; /* 1 if does, 0 if doesn't, -1 if not determined */ int supports_ds50_repl; /* 1 if does, 0 if doesn't, -1 if not determined */ @@ -1107,12 +1109,16 @@ conn_connect_with_bootstrap(Repl_Connection *conn, PRBool bootstrap) creds = agmt_get_bootstrap_credentials(conn->agmt); conn->bindmethod = agmt_get_bootstrap_bindmethod(conn->agmt); conn->transport_flags = agmt_get_bootstrap_transport_flags(conn->agmt); + conn->transport_uris = agmt_get_bootstrap_transport_uri(conn->agmt); + conn->transport_ca_uris = agmt_get_bootstrap_transport_ca_uri(conn->agmt); } else { slapi_ch_free_string(&conn->binddn); conn->binddn = agmt_get_binddn(conn->agmt); creds = agmt_get_credentials(conn->agmt); conn->bindmethod = agmt_get_bindmethod(conn->agmt); conn->transport_flags = agmt_get_transport_flags(conn->agmt); + conn->transport_uris = agmt_get_transport_uri(conn->agmt); + conn->transport_ca_uris = agmt_get_transport_ca_uri(conn->agmt); } if (conn->flag_agmt_changed) { @@ -1222,7 +1228,48 @@ conn_connect_with_bootstrap(Repl_Connection *conn, PRBool bootstrap) /* override the default timeout with the specified timeout */ ldap_set_option(conn->ld, LDAP_OPT_NETWORK_TIMEOUT, &conn->timeout); - /* We've got an ld. Now bind to the server. */ + + /* if we have TLS uris, set them now */ +#ifdef LDAP_OPT_X_TLS_URIS + ldap_set_option(conn->ld, LDAP_OPT_X_TLS_URIS, conn->transport_uris); +#else + if (conn->transport_uris) { + return_value = CONN_OPERATION_FAILED; + conn->state = STATE_DISCONNECTED; + conn->last_operation = CONN_INIT; + conn->last_ldap_error = LDAP_LOCAL_ERROR; + slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, + "conn_connect - %s - %s set but not supported, Replication over SSL FAILED\n", + agmt_get_long_name(conn->agmt), type_nsds5ReplicaTransportUri); + return_value = CONN_SSL_NOT_ENABLED; + goto done; + } +#endif + + /* if we have TLS CA uris, set them now */ +#ifdef LDAP_OPT_X_TLS_CACERTURIS + if (conn->transport_ca_uris) { + ldap_set_option(conn->ld, LDAP_OPT_X_TLS_CACERTURIS, conn->transport_ca_uris); + + /* unset any prior ca certificates */ + ldap_set_option(conn->ld, LDAP_OPT_X_TLS_CACERTFILE, NULL); + ldap_set_option(conn->ld, LDAP_OPT_X_TLS_CACERTDIR, NULL); + } +#else + if (conn->transport_ca_uris) { + return_value = CONN_OPERATION_FAILED; + conn->state = STATE_DISCONNECTED; + conn->last_operation = CONN_INIT; + conn->last_ldap_error = LDAP_LOCAL_ERROR; + slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, + "conn_connect - %s - %s set but not supported, Replication over SSL FAILED\n", + agmt_get_long_name(conn->agmt), type_nsds5ReplicaTransportCAUri); + return_value = CONN_SSL_NOT_ENABLED; + goto done; + } +#endif + + /* We've got an ld. Now bind to the server. */ conn->last_operation = CONN_BIND; } diff --git a/ldap/servers/plugins/replication/repl_globals.c b/ldap/servers/plugins/replication/repl_globals.c index 24204a639b..39346a4cde 100644 --- a/ldap/servers/plugins/replication/repl_globals.c +++ b/ldap/servers/plugins/replication/repl_globals.c @@ -94,7 +94,9 @@ const char *type_replicaKeepAliveUpdateInterval = "nsds5ReplicaKeepAliveUpdateIn /* Attribute names for replication agreement attributes */ const char *type_nsds5ReplicaHost = "nsds5ReplicaHost"; const char *type_nsds5ReplicaPort = "nsds5ReplicaPort"; -const char *type_nsds5TransportInfo = "nsds5ReplicaTransportInfo"; +const char *type_nsds5ReplicaTransportInfo = "nsds5ReplicaTransportInfo"; +const char *type_nsds5ReplicaTransportUri = "nsds5ReplicaTransportUri"; +const char *type_nsds5ReplicaTransportCAUri = "nsds5ReplicaTransportCAUri"; const char *type_nsds5ReplicaBindDN = "nsds5ReplicaBindDN"; const char *type_nsds5ReplicaBindDNGroup = "nsds5ReplicaBindDNGroup"; const char *type_nsds5ReplicaBindDNGroupCheckInterval = "nsds5ReplicaBindDNGroupCheckInterval"; @@ -118,6 +120,8 @@ const char *type_nsds5ReplicaBootstrapBindDN = "nsds5ReplicaBootstrapBindDN"; const char *type_nsds5ReplicaBootstrapCredentials = "nsds5ReplicaBootstrapCredentials"; const char *type_nsds5ReplicaBootstrapBindMethod = "nsds5ReplicaBootstrapBindMethod"; const char *type_nsds5ReplicaBootstrapTransportInfo = "nsds5ReplicaBootstrapTransportInfo"; +const char *type_nsds5ReplicaBootstrapTransportUri = "nsds5ReplicaBootstrapTransportUri"; +const char *type_nsds5ReplicaBootstrapTransportCAUri = "nsds5ReplicaBootstrapTransportCAUri"; /* windows sync specific attributes */ const char *type_nsds7WindowsReplicaArea = "nsds7WindowsReplicaSubtree"; diff --git a/ldap/servers/slapd/ldaputil.c b/ldap/servers/slapd/ldaputil.c index 5c161cf6d9..01427716e5 100644 --- a/ldap/servers/slapd/ldaputil.c +++ b/ldap/servers/slapd/ldaputil.c @@ -508,16 +508,12 @@ setup_ol_tls_conn(LDAP *ld, int clientauth) int ssl_strength = 0; int rc = 0; const char *cacert = NULL; + char **cauris = NULL; - /* certdir is used to setup outgoing secure connection (openldap) - * It refers to the place where PEM files have been extracted - * - * If a private tmp namespace exists - * it is the place where PEM files have been extracted - */ - if ((certdir = check_private_certdir()) == NULL) { - certdir = config_get_certdir(); - } + /* if set, cacerturis takes precedence */ +#ifdef LDAP_OPT_X_TLS_CACERTURIS + ldap_get_option(ld, LDAP_OPT_X_TLS_CACERTURIS, &cauris); +#endif if (config_get_ssl_check_hostname()) { ssl_strength = LDAP_OPT_X_TLS_HARD; @@ -530,18 +526,7 @@ setup_ol_tls_conn(LDAP *ld, int clientauth) slapi_log_err(SLAPI_LOG_ERR, "setup_ol_tls_conn", "failed: unable to set REQUIRE_CERT option to %d\n", ssl_strength); } - if (slapi_client_uses_non_nss(ld) && config_get_extract_pem()) { - cacert = slapi_get_cacertfile(); - if (cacert) { - /* CA Cert PEM file exists. Set the path to openldap option. */ - rc = ldap_set_option(ld, LDAP_OPT_X_TLS_CACERTFILE, cacert); - if (rc) { - slapi_log_err(SLAPI_LOG_ERR, "setup_ol_tls_conn", - "Could not set CA cert path [%s]: %d:%s\n", - cacert, rc, ldap_err2string(rc)); - } - } - } + if (slapi_client_uses_openssl(ld)) { int32_t crlcheck = LDAP_OPT_X_TLS_CRL_NONE; tls_check_crl_t tls_check_state = config_get_tls_check_crl(); @@ -558,12 +543,47 @@ setup_ol_tls_conn(LDAP *ld, int clientauth) crlcheck, rc, ldap_err2string(rc)); } } + /* tell it where our cert db/file is */ - if (ldap_set_option(ld, LDAP_OPT_X_TLS_CACERTDIR, certdir)) { - slapi_log_err(SLAPI_LOG_ERR, "setup_ol_tls_conn", - "failed: unable to set CACERTDIR option to %s\n", certdir); + if (!cauris) { + + if (slapi_client_uses_non_nss(ld) && config_get_extract_pem()) { + cacert = slapi_get_cacertfile(); + if (cacert) { + /* CA Cert PEM file exists. Set the path to openldap option. */ + rc = ldap_set_option(ld, LDAP_OPT_X_TLS_CACERTFILE, cacert); + if (rc) { + slapi_log_err(SLAPI_LOG_ERR, "setup_ol_tls_conn", + "Could not set CA cert path [%s]: %d:%s\n", + cacert, rc, ldap_err2string(rc)); + } + } + } + + /* certdir is used to setup outgoing secure connection (openldap) + * It refers to the place where PEM files have been extracted + * + * If a private tmp namespace exists + * it is the place where PEM files have been extracted + */ + if ((certdir = check_private_certdir()) == NULL) { + certdir = config_get_certdir(); + } + + if (ldap_set_option(ld, LDAP_OPT_X_TLS_CACERTDIR, certdir)) { + slapi_log_err(SLAPI_LOG_ERR, "setup_ol_tls_conn", + "failed: unable to set CACERTDIR option to %s\n", certdir); + } + + slapi_ch_free_string(&certdir); + } + +#ifdef LDAP_OPT_X_TLS_CACERTURIS + else { + slapi_ch_array_free(cauris); } - slapi_ch_free_string(&certdir); +#endif + #if defined(LDAP_OPT_X_TLS_PROTOCOL_MIN) getSSLVersionRangeOL(&optval, NULL); if (ldap_set_option(ld, LDAP_OPT_X_TLS_PROTOCOL_MIN, &optval)) { @@ -574,6 +594,7 @@ setup_ol_tls_conn(LDAP *ld, int clientauth) slapi_ch_free_string(&minstr); } #endif /* LDAP_OPT_X_TLS_PROTOCOL_MIN */ + if (clientauth) { rc = slapd_SSL_client_auth(ld); if (rc) { diff --git a/ldap/servers/slapd/ssl.c b/ldap/servers/slapd/ssl.c index ef9e97fb9f..d1bac302a0 100644 --- a/ldap/servers/slapd/ssl.c +++ b/ldap/servers/slapd/ssl.c @@ -2066,6 +2066,15 @@ slapd_SSL_client_auth(LDAP *ld) char *CertExtractFile = NULL; char *KeyExtractFile = NULL; +#ifdef LDAP_OPT_X_TLS_URIS + char **uris = NULL; + ldap_get_option(ld, LDAP_OPT_X_TLS_URIS, &uris); + if (uris) { + slapi_ch_array_free(uris); + return rc; + } +#endif + if ((family_list = getChildren(configDN))) { char **family; char *activation = NULL; diff --git a/src/lib389/lib389/agreement.py b/src/lib389/lib389/agreement.py index 170ab9050d..3a4e99cd96 100644 --- a/src/lib389/lib389/agreement.py +++ b/src/lib389/lib389/agreement.py @@ -729,9 +729,10 @@ def getProperties(self, agmnt_dn=None, properties=None): :supported properties are: RA_NAME, RA_SUFFIX, RA_BINDDN, RA_BINDPW, RA_METHOD, - RA_DESCRIPTION, RA_SCHEDULE, RA_TRANSPORT_PROT, RA_FRAC_EXCLUDE, - RA_FRAC_EXCLUDE_TOTAL_UPDATE, RA_FRAC_STRIP, RA_CONSUMER_PORT, - RA_CONSUMER_HOST, RA_CONSUMER_TOTAL_INIT, RA_TIMEOUT, RA_CHANGES + RA_DESCRIPTION, RA_SCHEDULE, RA_TRANSPORT_PROT, RA_TRANSPORT_URI, + RA_TRANSPORT_CA_URI, RA_FRAC_EXCLUDE, RA_FRAC_EXCLUDE_TOTAL_UPDATE, + RA_FRAC_STRIP, RA_CONSUMER_PORT, RA_CONSUMER_HOST, + RA_CONSUMER_TOTAL_INIT, RA_TIMEOUT, RA_CHANGES """ if not agmnt_dn: @@ -794,9 +795,10 @@ def setProperties(self, suffix=None, agmnt_dn=None, agmnt_entry=None, :supported properties are: RA_NAME, RA_SUFFIX, RA_BINDDN, RA_BINDPW, RA_METHOD, - RA_DESCRIPTION, RA_SCHEDULE, RA_TRANSPORT_PROT, RA_FRAC_EXCLUDE, - RA_FRAC_EXCLUDE_TOTAL_UPDATE, RA_FRAC_STRIP, RA_CONSUMER_PORT, - RA_CONSUMER_HOST, RA_CONSUMER_TOTAL_INIT, RA_TIMEOUT, RA_CHANGES + RA_DESCRIPTION, RA_SCHEDULE, RA_TRANSPORT_PROT, RA_TRANSPORT_URI, + RA_TRANSPORT_CA_URI, RA_FRAC_EXCLUDE, RA_FRAC_EXCLUDE_TOTAL_UPDATE, + RA_FRAC_STRIP, RA_CONSUMER_PORT, RA_CONSUMER_HOST, + RA_CONSUMER_TOTAL_INIT, RA_TIMEOUT, RA_CHANGES """ # No properties provided diff --git a/src/lib389/lib389/cli_conf/replication.py b/src/lib389/lib389/cli_conf/replication.py index 35233c5f50..53576b910d 100644 --- a/src/lib389/lib389/cli_conf/replication.py +++ b/src/lib389/lib389/cli_conf/replication.py @@ -45,10 +45,18 @@ 'host': 'nsds5replicahost', 'port': 'nsds5replicaport', 'conn_protocol': 'nsds5replicatransportinfo', + 'conn_tls_uri': 'nsds5replicatransporturi', + 'no_conn_tls_uri': 'nsds5replicatransporturi', + 'conn_tls_ca_uri': 'nsds5replicatransportcauri', + 'no_conn_tls_ca_uri': 'nsds5replicatransportcauri', 'bind_dn': 'nsds5replicabinddn', 'bind_passwd': 'nsds5replicacredentials', 'bind_method': 'nsds5replicabindmethod', 'bootstrap_conn_protocol': 'nsds5replicabootstraptransportinfo', + 'bootstrap_conn_tls_uri': 'nsds5replicabootstraptransporturi', + 'no_bootstrap_conn_tls_uri': 'nsds5replicabootstraptransporturi', + 'bootstrap_conn_tls_ca_uri': 'nsds5replicabootstraptransportcauri', + 'no_bootstrap_conn_tls_ca_uri': 'nsds5replicabootstraptransportcauri', 'bootstrap_bind_dn': 'nsds5replicabootstrapbinddn', 'bootstrap_bind_passwd': 'nsds5replicabootstrapcredentials', 'bootstrap_bind_method': 'nsds5replicabootstrapbindmethod', @@ -775,6 +783,10 @@ def add_agmt(inst, basedn, log, args): properties['nsDS5ReplicaCredentials'] = passwd elif args.bind_passwd is not None: properties['nsDS5ReplicaCredentials'] = args.bind_passwd + if args.conn_tls_uri is not None: + properties['nsDS5ReplicaTransportUri'] = args.conn_tls_uri + if args.conn_tls_ca_uri is not None: + properties['nsDS5ReplicaTransportCAUri'] = args.conn_tls_ca_uri if args.schedule is not None: properties['nsds5replicaupdateschedule'] = args.schedule if frac_list is not None: @@ -808,6 +820,10 @@ def add_agmt(inst, basedn, log, args): if bootstrap_conn_protocol != "ldap" and bootstrap_conn_protocol != "ldaps" and bootstrap_conn_protocol != "starttls": raise ValueError('Bootstrap connection protocol can only be "LDAP", "LDAPS", or "STARTTLS"') properties['nsDS5ReplicaBootstrapTransportInfo'] = args.bootstrap_conn_protocol + if args.bootstrap_conn_tls_uri is not None: + properties['nsDS5ReplicaBootstrapTransportUri'] = args.bootstrap_conn_tls_uri + if args.bootstrap_conn_tls_ca_uri is not None: + properties['nsDS5ReplicaBootstrapTransportCAUri'] = args.bootstrap_conn_tls_ca_uri # We do need the bind dn and credentials for 'simple' bind method if (bind_method == 'simple') and (args.bind_dn is None or @@ -878,7 +894,7 @@ def set_agmt(inst, basedn, log, args): modlist = [] did_something = False for attr, value in attrs.items(): - if value == "": + if value == "" or not value: # Delete value agmt.remove_all(attr) did_something = True @@ -1006,6 +1022,10 @@ def add_winsync_agmt(inst, basedn, log, args): properties['winsyncdirectoryfilter'] = args.ds_filter if args.win_filter is not None: properties['winsyncwindowsfilter'] = args.win_filter + if args.conn_tls_uri is not None: + properties['nsDS5ReplicaTransportUri'] = args.conn_tls_uri + if args.conn_tls_ca_uri is not None: + properties['nsDS5ReplicaTransportCAUri'] = args.conn_tls_ca_uri if args.schedule is not None: properties['nsds5replicaupdateschedule'] = args.schedule if frac_list is not None: @@ -1045,7 +1065,7 @@ def set_winsync_agmt(inst, basedn, log, args): if attr == "onewaysync" and value == "both": value == "" - if value == "": + if value == "" or not value: # Delete value agmt.remove_all(attr) did_something = True @@ -1431,7 +1451,7 @@ def create_parser(subparsers): repl_set_parser.add_argument('--repl-add-bind-dn', help="Adds a bind (supplier) DN") repl_set_parser.add_argument('--repl-del-bind-dn', help="Removes a bind (supplier) DN") repl_set_parser.add_argument('--repl-add-ref', help="Adds a replication referral (for consumers only)") - repl_set_parser.add_argument('--repl-del-ref', help="Removes a replication referral (for conusmers only)") + repl_set_parser.add_argument('--repl-del-ref', help="Removes a replication referral (for consumers only)") repl_set_parser.add_argument('--repl-purge-delay', help="Sets the replication purge delay") repl_set_parser.add_argument('--repl-tombstone-purge-interval', help="Sets the interval in seconds to check for tombstones that can be purged") repl_set_parser.add_argument('--repl-fast-tombstone-purging', help="Enables or disables improving the tombstone purging performance") @@ -1527,6 +1547,8 @@ def create_parser(subparsers): agmt_add_parser.add_argument('--host', required=True, help="Sets the hostname of the remote replica") agmt_add_parser.add_argument('--port', required=True, help="Sets the port number of the remote replica") agmt_add_parser.add_argument('--conn-protocol', required=True, help="Sets the replication connection protocol: LDAP, LDAPS, or StartTLS") + agmt_add_parser.add_argument('--conn-tls-uri', action='append', help="Sets the replication connection TLS uris") + agmt_add_parser.add_argument('--conn-tls-ca-uri', action='append', help="Sets the replication connection TLS CA uris") agmt_add_parser.add_argument('--bind-dn', help="Sets the bind DN the agreement uses to authenticate to the replica") agmt_add_parser.add_argument('--bind-passwd', help="Sets the credentials for the bind DN") agmt_add_parser.add_argument('--bind-passwd-file', help="File containing the password") @@ -1561,6 +1583,10 @@ def create_parser(subparsers): agmt_add_parser.add_argument('--bootstrap-bind-passwd-prompt', action='store_true', help="File containing the password") agmt_add_parser.add_argument('--bootstrap-conn-protocol', help="Sets the replication bootstrap connection protocol: LDAP, LDAPS, or StartTLS") + agmt_add_parser.add_argument('--bootstrap-conn-tls-uri', action='append', + help="Sets the replication bootstrap connection TLS uris") + agmt_add_parser.add_argument('--bootstrap-conn-tls-ca-uri', action='append', + help="Sets the replication bootstrap connection TLS CA uris") agmt_add_parser.add_argument('--bootstrap-bind-method', help="Sets the bind method: \"SIMPLE\", or \"SSLCLIENTAUTH\"") agmt_add_parser.add_argument('--init', action='store_true', default=False, help="Initializes the agreement after creating it") @@ -1572,6 +1598,10 @@ def create_parser(subparsers): agmt_set_parser.add_argument('--host', help="Sets the hostname of the remote replica") agmt_set_parser.add_argument('--port', help="Sets the port number of the remote replica") agmt_set_parser.add_argument('--conn-protocol', help="Sets the replication connection protocol: LDAP, LDAPS, or StartTLS") + agmt_set_parser.add_argument('--conn-tls-uri', action='append', help="Sets the replication connection TLS uris") + agmt_set_parser.add_argument('--no-conn-tls-uri', action='store_const', const='', help="Unsets all replication connection TLS uris") + agmt_set_parser.add_argument('--conn-tls-ca-uri', action='append', help="Sets the replication connection TLS CA uris") + agmt_set_parser.add_argument('--no-conn-tls-ca-uri', action='store_const', const='', help="Unsets all replication connection TLS CA uris") agmt_set_parser.add_argument('--bind-dn', help="Sets the Bind DN the agreement uses to authenticate to the replica") agmt_set_parser.add_argument('--bind-passwd', help="Sets the credentials for the bind DN") agmt_set_parser.add_argument('--bind-passwd-file', help="File containing the password") @@ -1605,6 +1635,14 @@ def create_parser(subparsers): agmt_set_parser.add_argument('--bootstrap-bind-passwd-prompt', action='store_true', help="Prompt for password") agmt_set_parser.add_argument('--bootstrap-conn-protocol', help="Sets the replication bootstrap connection protocol: LDAP, LDAPS, or StartTLS") + agmt_set_parser.add_argument('--bootstrap-conn-tls-uri', action='append', + help="Sets the replication bootstrap connection TLS uris") + agmt_set_parser.add_argument('--no-bootstrap-conn-tls-uri', action='store_const', const='', + help="Unsets the replication bootstrap connection TLS uris") + agmt_set_parser.add_argument('--bootstrap-conn-tls-ca-uri', action='append', + help="Sets the replication bootstrap connection TLS CA uris") + agmt_set_parser.add_argument('--no-bootstrap-conn-tls-ca-uri', action='store_const', const='', + help="Unsets the replication bootstrap connection TLS CA uris") agmt_set_parser.add_argument('--bootstrap-bind-method', help="Sets the bind method: \"SIMPLE\", or \"SSLCLIENTAUTH\"") # Get @@ -1676,6 +1714,10 @@ def create_parser(subparsers): winsync_agmt_add_parser.add_argument('--port', required=True, help="Sets the port number of the AD server") winsync_agmt_add_parser.add_argument('--conn-protocol', required=True, help="Sets the replication winsync connection protocol: LDAP, LDAPS, or StartTLS") + winsync_agmt_add_parser.add_argument('--conn-tls-uri', action='append', + help="Sets the replication winsync connection TLS uri") + winsync_agmt_add_parser.add_argument('--conn-tls-ca-uri', action='append', + help="Sets the replication winsync connection TLS CA uri") winsync_agmt_add_parser.add_argument('--bind-dn', required=True, help="Sets the bind DN the agreement uses to authenticate to the AD Server") winsync_agmt_add_parser.add_argument('--bind-passwd', help="Sets the credentials for the Bind DN") @@ -1721,6 +1763,10 @@ def create_parser(subparsers): winsync_agmt_set_parser.add_argument('--host', help="Sets the hostname of the AD server") winsync_agmt_set_parser.add_argument('--port', help="Sets the port number of the AD server") winsync_agmt_set_parser.add_argument('--conn-protocol', help="Sets the replication winsync connection protocol: LDAP, LDAPS, or StartTLS") + winsync_agmt_set_parser.add_argument('--conn-tls-uri', action='append', help="Sets the replication winsync connection TLS uris") + winsync_agmt_set_parser.add_argument('--no-conn-tls-uri', action='store_const', const='', help="Unsets the replication winsync connection TLS uris") + winsync_agmt_set_parser.add_argument('--conn-tls-ca-uri', action='append', help="Sets the replication winsync connection TLS CA uris") + winsync_agmt_set_parser.add_argument('--no-conn-tls-ca-uri', action='store_const', const='', help="Unsets the replication winsync connection TLS CA uris") winsync_agmt_set_parser.add_argument('--bind-dn', help="Sets the bind DN the agreement uses to authenticate to the AD Server") winsync_agmt_set_parser.add_argument('--bind-passwd', help="Sets the credentials for the Bind DN") winsync_agmt_set_parser.add_argument('--bind-passwd-file', help="File containing the password") diff --git a/src/lib389/lib389/properties.py b/src/lib389/lib389/properties.py index 83ac717fc7..acf8016b01 100644 --- a/src/lib389/lib389/properties.py +++ b/src/lib389/lib389/properties.py @@ -309,6 +309,8 @@ AGMT_HOST = 'nsDS5ReplicaHost' AGMT_PORT = 'nsDS5ReplicaPort' AGMT_TRANSPORT_INFO = 'nsDS5ReplicaTransportInfo' +AGMT_TRANSPORT_URI = 'nsDS5ReplicaTransportUri' +AGMT_TRANSPORT_CA_URI = 'nsDS5ReplicaTransportCAUri' AGMT_ATTR_LIST = 'nsDS5ReplicatedAttributeList' AGMT_ATTR_LIST_TOTAL = 'nsDS5ReplicatedAttributeListTotal' AGMT_TIMEOUT = 'nsds5replicaTimeout' @@ -356,6 +358,8 @@ RA_DESCRIPTION = 'description' RA_SCHEDULE = 'ReplicaSchedule' RA_TRANSPORT_PROT = 'ReplicaTransportInfo' +RA_TRANSPORT_URI = 'ReplicaTransportUri' +RA_TRANSPORT_CA_URI = 'ReplicaTransportCAUri' RA_FRAC_EXCLUDE = 'ReplicatedAttributeList' RA_FRAC_EXCLUDE_TOTAL_UPDATE = 'ReplicatedAttributeListTotal' RA_FRAC_STRIP = 'ReplicaStripAttrs' diff --git a/src/lib389/lib389/replica.py b/src/lib389/lib389/replica.py index 177128202a..e705d70d20 100644 --- a/src/lib389/lib389/replica.py +++ b/src/lib389/lib389/replica.py @@ -1606,6 +1606,8 @@ def get_consumer_replicas(self, get_credentials): host = agmt.get_attr_val_utf8("nsDS5ReplicaHost") port = agmt.get_attr_val_utf8("nsDS5ReplicaPort") protocol = agmt.get_attr_val_utf8_l("nsDS5ReplicaTransportInfo") + tls_uri = agmt.get_attr_val_utf8_l("nsDS5ReplicaTransportUri") + tls_ca_uri = agmt.get_attr_val_utf8_l("nsDS5ReplicaTransportCAUri") # The function should be defined outside and # it should have all the logic for figuring out the credentials From 90df72f333261b46681b1a5a31f20098f57b1d44 Mon Sep 17 00:00:00 2001 From: Graham Leggett Date: Tue, 23 Jan 2024 11:27:59 +0000 Subject: [PATCH 2/2] Use size_t in the for loop. --- ldap/servers/plugins/replication/repl5_agmt.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ldap/servers/plugins/replication/repl5_agmt.c b/ldap/servers/plugins/replication/repl5_agmt.c index 5c9ca19343..bf4308c1cc 100644 --- a/ldap/servers/plugins/replication/repl5_agmt.c +++ b/ldap/servers/plugins/replication/repl5_agmt.c @@ -2135,14 +2135,13 @@ agmt_set_transportcauri_from_entry(Repl_Agmt *ra, const Slapi_Entry *e, PRBool b if (0 == slapi_entry_attr_find(e, bootstrap ? type_nsds5ReplicaBootstrapTransportCAUri : type_nsds5ReplicaTransportCAUri, &attr)) { - int i; int uri_count = 0; /* Get a count and allocate an array for the official matching rules */ slapi_attr_get_numvalues(attr, &uri_count); uris = (char **)slapi_ch_malloc((uri_count + 1) * sizeof(char *)); - for (i = slapi_attr_first_value(attr, &sval); + for (size_t i = slapi_attr_first_value(attr, &sval); i >= 0; i = slapi_attr_next_value(attr, i, &sval)) { uris[i] = slapi_ch_strdup(slapi_value_get_string(sval)); }