From 0157534faae43bc95adda09edd7cd3f19dd32e50 Mon Sep 17 00:00:00 2001 From: Nathan Kinder Date: Sep 16 2011 17:01:08 +0000 Subject: Bug 739172 - Allow separate fractional attrs for incremental and total protocols This patch adds the ability to have a separate fractional attribute list for the incremental and total update replication protocols. A new nsDS5ReplicatedAttributeListTotal attribute can be added to a replication agreement to list the attributes to exclude from the total update protocol. This has the same format as the existing nsDS5ReplicatedAttributeList attribute. If a separate total update attribute list is not specified, the nsDS5ReplicatedAttributeList value will be used for both incremental and total update. To use a total update attribute list, an incremental list must be specified as well. --- diff --git a/ldap/schema/01core389.ldif b/ldap/schema/01core389.ldif index 90ca5cb..91bdb44 100644 --- a/ldap/schema/01core389.ldif +++ b/ldap/schema/01core389.ldif @@ -79,6 +79,7 @@ attributeTypes: ( 2.16.840.1.113730.3.1.582 NAME 'nsDS5ReplicaCredentials' DESC 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' ) attributeTypes: ( 2.16.840.1.113730.3.1.584 NAME 'nsDS5ReplicaRoot' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' ) attributeTypes: ( 2.16.840.1.113730.3.1.585 NAME 'nsDS5ReplicatedAttributeList' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' ) +attributeTypes: ( 2.16.840.1.113730.3.1.594 NAME 'nsDS5ReplicatedAttributeListTotal' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' ) attributeTypes: ( 2.16.840.1.113730.3.1.586 NAME 'nsDS5ReplicaUpdateSchedule' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' ) attributeTypes: ( 2.16.840.1.113730.3.1.587 NAME 'nsds50ruv' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' ) attributeTypes: ( 2.16.840.1.113730.3.1.2027 NAME 'nsruvReplicaLastModified' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' ) @@ -138,7 +139,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 $ nsDS5ReplicaType $ nsDS5ReplicaBindDN $ nsState $ nsDS5ReplicaName $ nsDS5Flags $ nsDS5Task $ nsDS5ReplicaReferral $ nsDS5ReplicaAutoReferral $ nsds5ReplicaPurgeDelay $ nsds5ReplicaTombstonePurgeInterval $ nsds5ReplicaChangeCount $ nsds5ReplicaLegacyConsumer) X-ORIGIN 'Netscape Directory Server' ) objectClasses: ( 2.16.840.1.113730.3.2.113 NAME 'nsTombstone' DESC 'Netscape defined objectclass' SUP top MAY ( 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 ( 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 ) 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 ( nsDS5ReplicaHost $ nsDS5ReplicaPort $ nsDS5ReplicaTransportInfo $ nsDS5ReplicaBindDN $ nsDS5ReplicaCredentials $ nsDS5ReplicaBindMethod $ nsDS5ReplicaRoot $ nsDS5ReplicatedAttributeList $ nsDS5ReplicatedAttributeListTotal $ nsDS5ReplicaUpdateSchedule $ nsds5BeginReplicaRefresh $ description $ nsds50ruv $ nsruvReplicaLastModified $ nsds5ReplicaTimeout $ nsds5replicaChangesSentSinceStartup $ nsds5replicaLastUpdateEnd $ nsds5replicaLastUpdateStart $ nsds5replicaLastUpdateStatus $ nsds5replicaUpdateInProgress $ nsds5replicaLastInitEnd $ nsds5replicaLastInitStart $ nsds5replicaLastInitStatus $ nsds5debugreplicatimeout $ nsds5replicaBusyWaitTime $ nsds5replicaSessionPauseTime ) 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 ) 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 79abb7a..79465e4 100644 --- a/ldap/servers/plugins/replication/repl5.h +++ b/ldap/servers/plugins/replication/repl5.h @@ -143,6 +143,7 @@ extern const char *type_nsds5ReplicaCredentials; extern const char *type_nsds5ReplicaBindMethod; extern const char *type_nsds5ReplicaRoot; extern const char *type_nsds5ReplicatedAttributeList; +extern const char *type_nsds5ReplicatedAttributeListTotal; extern const char *type_nsds5ReplicaUpdateSchedule; extern const char *type_nsds5ReplicaInitialize; extern const char *type_nsds5ReplicaTimeout; @@ -298,6 +299,7 @@ int agmt_get_bindmethod(const Repl_Agmt *ra); Slapi_DN *agmt_get_replarea(const Repl_Agmt *ra); int agmt_is_fractional(const Repl_Agmt *ra); int agmt_is_fractional_attr(const Repl_Agmt *ra, const char *attrname); +int agmt_is_fractional_attr_total(const Repl_Agmt *ra, const char *attrname); int agmt_is_50_mm_protocol(const Repl_Agmt *ra); int agmt_matches_name(const Repl_Agmt *ra, const Slapi_DN *name); int agmt_replarea_matches(const Repl_Agmt *ra, const Slapi_DN *name); @@ -332,9 +334,12 @@ void agmt_set_last_init_status (Repl_Agmt *ra, int ldaprc, int replrc, const cha void agmt_inc_last_update_changecount (Repl_Agmt *ra, ReplicaId rid, int skipped); void agmt_get_changecount_string (Repl_Agmt *ra, char *buf, int bufsize); int agmt_set_replicated_attributes_from_entry(Repl_Agmt *ra, const Slapi_Entry *e); +int agmt_set_replicated_attributes_total_from_entry(Repl_Agmt *ra, const Slapi_Entry *e); int agmt_set_replicated_attributes_from_attr(Repl_Agmt *ra, Slapi_Attr *sattr); +int agmt_set_replicated_attributes_total_from_attr(Repl_Agmt *ra, Slapi_Attr *sattr); char **agmt_get_fractional_attrs(const Repl_Agmt *ra); -char **agmt_validate_replicated_attributes(Repl_Agmt *ra); +char **agmt_get_fractional_attrs_total(const Repl_Agmt *ra); +char **agmt_validate_replicated_attributes(Repl_Agmt *ra, int total); void* agmt_get_priv (const Repl_Agmt *agmt); void agmt_set_priv (Repl_Agmt *agmt, void* priv); diff --git a/ldap/servers/plugins/replication/repl5_agmt.c b/ldap/servers/plugins/replication/repl5_agmt.c index b5e66ee..61aa9ba 100644 --- a/ldap/servers/plugins/replication/repl5_agmt.c +++ b/ldap/servers/plugins/replication/repl5_agmt.c @@ -104,6 +104,7 @@ typedef struct repl5agmt { int bindmethod; /* Bind method - simple, SSL */ Slapi_DN *replarea; /* DN of replicated area */ char **frac_attrs; /* list of fractional attributes to be replicated */ + char **frac_attrs_total; /* list of fractional attributes to be replicated for total update protocol */ Schedule *schedule; /* Scheduling information */ int auto_initialize; /* 1 = automatically re-initialize replica */ const Slapi_DN *dn; /* DN of replication agreement entry */ @@ -159,7 +160,8 @@ nsds5ReplicaBindDN nsds5ReplicaCredentials nsds5ReplicaBindMethod - "SIMPLE" or "SSLCLIENTAUTH". nsds5ReplicaRoot - Replicated suffix -nsds5ReplicatedAttributeList - Unused so far (meant for fractional repl). +nsds5ReplicatedAttributeList - Fractional attrs for incremental update protocol (and total if not separately defined) +nsds5ReplicatedAttributeListTotal - Fractional attrs for total update protocol nsds5ReplicaUpdateSchedule nsds5ReplicaTimeout - Outbound repl operations timeout nsds50ruv - consumer's RUV @@ -402,7 +404,7 @@ agmt_new_from_entry(Slapi_Entry *e) agmt_get_long_name(ra)); } /* Check that there are no verboten attributes in the exclude list */ - denied_attrs = agmt_validate_replicated_attributes(ra); + denied_attrs = agmt_validate_replicated_attributes(ra, 0 /* incremental */); if (denied_attrs) { /* Report the error to the client */ @@ -414,6 +416,28 @@ agmt_new_from_entry(Slapi_Entry *e) goto loser; } + /* Total update fractional attributes */ + slapi_entry_attr_find(e, type_nsds5ReplicatedAttributeListTotal, &sattr); + if (sattr && agmt_set_replicated_attributes_total_from_attr(ra, sattr) != 0) + { + slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, + "agmtlist_add_callback: failed to parse total " + "update replicated attributes for agreement %s\n", + agmt_get_long_name(ra)); + } + /* Check that there are no verboten attributes in the exclude list */ + denied_attrs = agmt_validate_replicated_attributes(ra, 1 /* total */); + if (denied_attrs) + { + /* Report the error to the client */ + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, + "WARNING: Attempt to exclude illegal attributes " + "from a fractional agreement for total update protocol\n"); + /* Free the list */ + slapi_ch_array_free(denied_attrs); + goto loser; + } + if (!agmt_is_valid(ra)) { goto loser; @@ -440,7 +464,6 @@ loser: } - Repl_Agmt * agmt_new_from_pblock(Slapi_PBlock *pb) { @@ -492,6 +515,7 @@ agmt_delete(void **rap) slapi_ch_free((void **)&(ra->binddn)); slapi_ch_array_free(ra->frac_attrs); + slapi_ch_array_free(ra->frac_attrs_total); if (NULL != ra->creds) { @@ -790,6 +814,23 @@ agmt_get_fractional_attrs(const Repl_Agmt *ra) PR_Unlock(ra->lock); return return_value; } + +/* Returns a COPY of the attr list, remember to free it */ +char ** +agmt_get_fractional_attrs_total(const Repl_Agmt *ra) +{ + char ** return_value = NULL; + PR_ASSERT(NULL != ra); + if (NULL == ra->frac_attrs_total) + { + return agmt_get_fractional_attrs(ra); + } + PR_Lock(ra->lock); + return_value = charray_dup(ra->frac_attrs_total); + PR_Unlock(ra->lock); + return return_value; +} + int agmt_is_fractional_attr(const Repl_Agmt *ra, const char *attrname) { @@ -806,6 +847,21 @@ agmt_is_fractional_attr(const Repl_Agmt *ra, const char *attrname) return return_value; } +int agmt_is_fractional_attr_total(const Repl_Agmt *ra, const char *attrname) +{ + int return_value; + PR_ASSERT(NULL != ra); + if (NULL == ra->frac_attrs_total) + { + return agmt_is_fractional_attr(ra, attrname); + } + PR_Lock(ra->lock); + /* Scan the list looking for a match */ + return_value = charray_inlist(ra->frac_attrs_total,(char*)attrname); + PR_Unlock(ra->lock); + return return_value; +} + int agmt_get_auto_initialize(const Repl_Agmt *ra) { @@ -1258,6 +1314,40 @@ agmt_set_replicated_attributes_from_entry(Repl_Agmt *ra, const Slapi_Entry *e) } /* + * Set or reset the set of total update replicated attributes. + * + * Returns 0 if DN set, or -1 if an error occurred. + */ +int +agmt_set_replicated_attributes_total_from_entry(Repl_Agmt *ra, const Slapi_Entry *e) +{ + Slapi_Attr *sattr = NULL; + int return_value = 0; + + PR_ASSERT(NULL != ra); + slapi_entry_attr_find(e, type_nsds5ReplicatedAttributeListTotal, &sattr); + PR_Lock(ra->lock); + if (ra->frac_attrs_total) + { + slapi_ch_array_free(ra->frac_attrs_total); + ra->frac_attrs_total = NULL; + } + if (NULL != sattr) + { + Slapi_Value *sval = NULL; + slapi_attr_first_value(sattr, &sval); + if (NULL != sval) + { + const char *val = slapi_value_get_string(sval); + return_value = agmt_parse_excluded_attrs_config_attr(val,&(ra->frac_attrs_total)); + } + } + PR_Unlock(ra->lock); + prot_notify_agmt_changed(ra->protocol, ra->long_name); + return return_value; +} + +/* * Set or reset the set of replicated attributes. * * Returns 0 if DN set, or -1 if an error occurred. @@ -1289,8 +1379,39 @@ agmt_set_replicated_attributes_from_attr(Repl_Agmt *ra, Slapi_Attr *sattr) return return_value; } +/* + * Set or reset the set of total update replicated attributes. + * + * Returns 0 if DN set, or -1 if an error occurred. + */ +int +agmt_set_replicated_attributes_total_from_attr(Repl_Agmt *ra, Slapi_Attr *sattr) +{ + int return_value = 0; + + PR_ASSERT(NULL != ra); + PR_Lock(ra->lock); + if (ra->frac_attrs_total) + { + slapi_ch_array_free(ra->frac_attrs_total); + ra->frac_attrs_total = NULL; + } + if (NULL != sattr) + { + Slapi_Value *sval = NULL; + slapi_attr_first_value(sattr, &sval); + if (NULL != sval) + { + const char *val = slapi_value_get_string(sval); + return_value = agmt_parse_excluded_attrs_config_attr(val,&(ra->frac_attrs_total)); + } + } + PR_Unlock(ra->lock); + return return_value; +} + char ** -agmt_validate_replicated_attributes(Repl_Agmt *ra) +agmt_validate_replicated_attributes(Repl_Agmt *ra, int total) { static char* verbotten_attrs[] = { @@ -1302,7 +1423,19 @@ agmt_validate_replicated_attributes(Repl_Agmt *ra) }; char **retval = NULL; - char **frac_attrs = ra->frac_attrs; + char **frac_attrs = NULL; + + /* If checking for total update, use the total attr list + * if it exists. If oen is not set, use the incremental + * attr list. */ + if (total && ra->frac_attrs_total) + { + frac_attrs = ra->frac_attrs_total; + } + else + { + frac_attrs = ra->frac_attrs; + } /* Iterate over the frac attrs */ if (frac_attrs) diff --git a/ldap/servers/plugins/replication/repl5_agmtlist.c b/ldap/servers/plugins/replication/repl5_agmtlist.c index 34da6d0..8cc2cc3 100644 --- a/ldap/servers/plugins/replication/repl5_agmtlist.c +++ b/ldap/servers/plugins/replication/repl5_agmtlist.c @@ -425,7 +425,7 @@ agmtlist_modify_callback(Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry rc = SLAPI_DSE_CALLBACK_ERROR; } /* Check that there are no verboten attributes in the exclude list */ - denied_attrs = agmt_validate_replicated_attributes(agmt); + denied_attrs = agmt_validate_replicated_attributes(agmt, 0 /* incremental */); if (denied_attrs) { /* Report the error to the client */ @@ -441,6 +441,36 @@ agmtlist_modify_callback(Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry } } else if (slapi_attr_types_equivalent(mods[i]->mod_type, + type_nsds5ReplicatedAttributeListTotal)) + { + char **denied_attrs = NULL; + /* New set of excluded attributes */ + if (agmt_set_replicated_attributes_total_from_entry(agmt, e) != 0) + { + slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: " + "failed to update total update replicated attributes for agreement %s\n", + agmt_get_long_name(agmt)); + *returncode = LDAP_OPERATIONS_ERROR; + rc = SLAPI_DSE_CALLBACK_ERROR; + } + /* Check that there are no verboten attributes in the exclude list */ + denied_attrs = agmt_validate_replicated_attributes(agmt, 1 /* total */); + if (denied_attrs) + { + /* Report the error to the client */ + PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE, "attempt to exclude an illegal total update " + "attribute in a fractional agreement"); + slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: " + "attempt to exclude an illegal total update attribute in a fractional agreement\n"); + + *returncode = LDAP_UNWILLING_TO_PERFORM; + rc = SLAPI_DSE_CALLBACK_ERROR; + /* Free the deny list if we got one */ + slapi_ch_array_free(denied_attrs); + break; + } + } + else if (slapi_attr_types_equivalent(mods[i]->mod_type, "nsds5debugreplicatimeout")) { char *val = slapi_entry_attr_get_charptr(e, "nsds5debugreplicatimeout"); diff --git a/ldap/servers/plugins/replication/repl5_tot_protocol.c b/ldap/servers/plugins/replication/repl5_tot_protocol.c index ca151bf..5eeef5d 100644 --- a/ldap/servers/plugins/replication/repl5_tot_protocol.c +++ b/ldap/servers/plugins/replication/repl5_tot_protocol.c @@ -673,7 +673,7 @@ int send_entry (Slapi_Entry *e, void *cb_data) if (agmt_is_fractional(prp->agmt)) { - frac_excluded_attrs = agmt_get_fractional_attrs(prp->agmt); + frac_excluded_attrs = agmt_get_fractional_attrs_total(prp->agmt); } /* convert the entry to the on the wire format */ diff --git a/ldap/servers/plugins/replication/repl_globals.c b/ldap/servers/plugins/replication/repl_globals.c index f409be6..f0aea12 100644 --- a/ldap/servers/plugins/replication/repl_globals.c +++ b/ldap/servers/plugins/replication/repl_globals.c @@ -120,6 +120,7 @@ const char *type_nsds5ReplicaCredentials = "nsds5ReplicaCredentials"; const char *type_nsds5ReplicaBindMethod = "nsds5ReplicaBindMethod"; const char *type_nsds5ReplicaRoot = "nsds5ReplicaRoot"; const char *type_nsds5ReplicatedAttributeList = "nsds5ReplicatedAttributeList"; +const char *type_nsds5ReplicatedAttributeListTotal = "nsds5ReplicatedAttributeListTotal"; const char *type_nsds5ReplicaUpdateSchedule = "nsds5ReplicaUpdateSchedule"; const char *type_nsds5ReplicaInitialize = "nsds5BeginReplicaRefresh"; const char *type_nsds5ReplicaTimeout = "nsds5ReplicaTimeout";