summaryrefslogtreecommitdiffstats
path: root/ldap/servers/plugins/replication/repl_controls.c
diff options
context:
space:
mode:
Diffstat (limited to 'ldap/servers/plugins/replication/repl_controls.c')
-rw-r--r--ldap/servers/plugins/replication/repl_controls.c337
1 files changed, 337 insertions, 0 deletions
diff --git a/ldap/servers/plugins/replication/repl_controls.c b/ldap/servers/plugins/replication/repl_controls.c
new file mode 100644
index 00000000..ae1cb119
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl_controls.c
@@ -0,0 +1,337 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "slapi-plugin.h"
+#include "repl5.h"
+#include "repl.h" /* For LDAP_CONTROL_REPL_MODRDN_EXTRAMODS */
+
+/*
+ * repl_controls.c - convenience functions for creating and
+ * decoding controls that implement 5.0-style replication
+ * protocol operations.
+ *
+ * TODO: Send modrdn mods with modrdn operation
+ * Fix ber_printf() and ber_scanf() format strings - some are
+ * the wrong types.
+ */
+
+/*
+ * Return a pointer to a NSDS50ReplUpdateInfoControl.
+ * The control looks like this:
+ *
+ * NSDS50ReplUpdateInfoControl ::= SEQUENCE {
+ * uuid OCTET STRING,
+ * csn OCTET STRING,
+ * OPTIONAL [new]superior-uuid OCTET STRING
+ * OPTIONAL modrdn_mods XXXggood WHAT TYPE???
+ * }
+ */
+int
+create_NSDS50ReplUpdateInfoControl(const char *uuid,
+ const char *superior_uuid, const CSN *csn,
+ LDAPMod **modrdn_mods, LDAPControl **ctrlp)
+{
+ int retval;
+ BerElement *tmp_bere = NULL;
+ struct berval tmpval = {0};
+ char csn_str[CSN_STRSIZE];
+
+ if (NULL == ctrlp)
+ {
+ retval = LDAP_PARAM_ERROR;
+ goto loser;
+ }
+ else
+ {
+ if ((tmp_bere = ber_alloc()) == NULL)
+ {
+ retval = LDAP_NO_MEMORY;
+ goto loser;
+ }
+ else
+ {
+ /* Stuff uuid and csn into BerElement */
+ if (ber_printf(tmp_bere, "{") == -1)
+ {
+ retval = LDAP_ENCODING_ERROR;
+ goto loser;
+ }
+
+ /* Stuff uuid of this entry into BerElement */
+ if (ber_printf(tmp_bere, "s", uuid) == -1)
+ {
+ retval = LDAP_ENCODING_ERROR;
+ goto loser;
+ }
+
+ /* Stuff csn of this change into BerElement */
+ csn_as_string(csn, PR_FALSE, csn_str);
+ if (ber_printf(tmp_bere, "s", csn_str) == -1)
+ {
+ retval = LDAP_ENCODING_ERROR;
+ goto loser;
+ }
+
+ /* If present, stuff uuid of parent entry into BerElement */
+ if (NULL != superior_uuid)
+ {
+ if (ber_printf(tmp_bere, "s", superior_uuid) == -1)
+ {
+ retval = LDAP_ENCODING_ERROR;
+ goto loser;
+ }
+ }
+
+ /* If present, add the modrdn mods */
+ if (NULL != modrdn_mods)
+ {
+ int i;
+ if (ber_printf(tmp_bere, "{" ) == -1)
+ {
+ retval = LDAP_ENCODING_ERROR;
+ goto loser;
+ }
+ /* for each modification to be performed... */
+ for (i = 0; NULL != modrdn_mods[i]; i++)
+ {
+ if (ber_printf(tmp_bere, "{e{s[V]}}",
+ modrdn_mods[i]->mod_op & ~LDAP_MOD_BVALUES,
+ modrdn_mods[i]->mod_type, modrdn_mods[i]->mod_bvalues ) == -1)
+ {
+ retval = LDAP_ENCODING_ERROR;
+ goto loser;
+ }
+ }
+ if (ber_printf(tmp_bere, "}") == -1)
+ {
+ retval = LDAP_ENCODING_ERROR;
+ goto loser;
+ }
+ }
+
+ /* Close the sequence */
+ if (ber_printf(tmp_bere, "}") == -1)
+ {
+ retval = LDAP_ENCODING_ERROR;
+ goto loser;
+ }
+
+ retval = slapi_build_control( REPL_NSDS50_UPDATE_INFO_CONTROL_OID,
+ tmp_bere, 1 /* is critical */, ctrlp);
+ }
+ }
+loser:
+ if (NULL != tmp_bere)
+ {
+ ber_free(tmp_bere, 1);
+ tmp_bere = NULL;
+ }
+ return retval;
+}
+
+
+/*
+ * Destroy a ReplUpdateInfoControl and set the pointer to NULL.
+ */
+void
+destroy_NSDS50ReplUpdateInfoControl(LDAPControl **ctrlp)
+{
+ if (NULL != ctrlp && NULL != *ctrlp)
+ {
+ ldap_control_free(*ctrlp);
+ *ctrlp = NULL;
+ }
+}
+
+
+
+
+/*
+ * Look through the array of controls. If an NSDS50ReplUpdateInfoControl
+ * is present, decode it and return pointers to the broken-out
+ * components. The caller is responsible for freeing pointers to
+ * the returned objects. The caller may indicate that it is not
+ * interested in any of the output parameters by passing NULL
+ * for that parameter.
+ *
+ * Returns 0 if the control is not present, 1 if it is present, and
+ * -1 if an error occurs.
+ */
+int
+decode_NSDS50ReplUpdateInfoControl(LDAPControl **controlsp,
+ char **uuid, char **superior_uuid,
+ CSN **csn, LDAPMod ***modrdn_mods)
+{
+ struct berval *ctl_value = NULL;
+ int iscritical = 0;
+ int rc = -1;
+ struct berval uuid_val = {0};
+ struct berval superior_uuid_val = {0};
+ struct berval csn_val = {0};
+ BerElement *tmp_bere = NULL;
+ Slapi_Mods modrdn_smods;
+ PRBool got_modrdn_mods = PR_FALSE;
+ unsigned long len;
+
+ slapi_mods_init(&modrdn_smods, 4);
+ if (slapi_control_present(controlsp, REPL_NSDS50_UPDATE_INFO_CONTROL_OID,
+ &ctl_value, &iscritical))
+ {
+ if ((tmp_bere = ber_init(ctl_value)) == NULL)
+ {
+ rc = -1;
+ goto loser;
+ }
+ if (ber_scanf(tmp_bere, "{oo", &uuid_val, &csn_val) == -1)
+ {
+ rc = -1;
+ goto loser;
+ }
+ if (ber_peek_tag(tmp_bere, &len) == LBER_OCTETSTRING)
+ {
+ /* The optional superior_uuid is present */
+ if (ber_scanf(tmp_bere, "o", &superior_uuid_val) == -1)
+ {
+ rc = -1;
+ goto loser;
+ }
+ }
+ if (ber_peek_tag(tmp_bere, &len) == LBER_SEQUENCE)
+ {
+ unsigned long emtag, emlen;
+ char *emlast;
+
+ for ( emtag = ber_first_element( tmp_bere, &emlen, &emlast );
+ emtag != LBER_ERROR && emtag != LBER_END_OF_SEQORSET;
+ emtag = ber_next_element( tmp_bere, &emlen, emlast ))
+ {
+ struct berval **embvals;
+ long op;
+ char *type;
+ if ( ber_scanf( tmp_bere, "{i{a[V]}}", &op, &type, &embvals ) == LBER_ERROR )
+ {
+ rc = -1;
+ goto loser;
+ }
+ slapi_mods_add_modbvps(&modrdn_smods, op, type, embvals);
+ free( type );
+ ber_bvecfree( embvals );
+ }
+ got_modrdn_mods = PR_TRUE;
+ }
+ if (ber_scanf(tmp_bere, "}") == -1)
+ {
+ rc = -1;
+ goto loser;
+ }
+
+ if (NULL != uuid)
+ {
+ *uuid = slapi_ch_malloc(uuid_val.bv_len + 1);
+ strncpy(*uuid, uuid_val.bv_val, uuid_val.bv_len);
+ (*uuid)[uuid_val.bv_len] = '\0';
+ }
+
+ if (NULL != csn)
+ {
+ char *csnstr = slapi_ch_malloc(csn_val.bv_len + 1);
+ strncpy(csnstr, csn_val.bv_val, csn_val.bv_len);
+ csnstr[csn_val.bv_len] = '\0';
+ *csn = csn_new_by_string(csnstr);
+ slapi_ch_free((void **)&csnstr);
+ }
+
+ if (NULL != superior_uuid && NULL != superior_uuid_val.bv_val)
+ {
+ *superior_uuid = slapi_ch_malloc(superior_uuid_val.bv_len + 1);
+ strncpy(*superior_uuid, superior_uuid_val.bv_val,
+ superior_uuid_val.bv_len);
+ (*superior_uuid)[superior_uuid_val.bv_len] = '\0';
+ }
+
+ if (NULL != modrdn_mods && got_modrdn_mods)
+ {
+ *modrdn_mods = slapi_mods_get_ldapmods_passout(&modrdn_smods);
+ }
+ slapi_mods_done(&modrdn_smods);
+
+ rc = 1;
+ }
+ else
+ {
+ rc = 0;
+ }
+loser:
+ /* XXXggood free CSN here if allocated */
+
+ if (NULL != tmp_bere)
+ {
+ ber_free(tmp_bere, 1);
+ tmp_bere = NULL;
+ }
+ if (NULL != uuid_val.bv_val)
+ {
+ ldap_memfree(uuid_val.bv_val);
+ uuid_val.bv_val = NULL;
+ }
+ if (NULL != superior_uuid_val.bv_val)
+ {
+ ldap_memfree(superior_uuid_val.bv_val);
+ superior_uuid_val.bv_val = NULL;
+ }
+ if (NULL != csn_val.bv_val)
+ {
+ ldap_memfree(csn_val.bv_val);
+ csn_val.bv_val = NULL;
+ }
+ return rc;
+}
+
+
+
+void
+add_repl_control_mods( Slapi_PBlock *pb, Slapi_Mods *smods )
+{
+ struct berval *embvp;
+ LDAPControl **controls = NULL;
+
+ slapi_pblock_get( pb, SLAPI_REQCONTROLS, &controls);
+ if ( slapi_control_present( controls,
+ LDAP_CONTROL_REPL_MODRDN_EXTRAMODS,
+ &embvp, NULL ))
+ {
+ if ( embvp != NULL && embvp->bv_len > 0 && embvp->bv_val != NULL )
+ {
+ /* Parse the extramods stuff */
+ long op;
+ char *type;
+ unsigned long emlen;
+ unsigned long emtag;
+ char *emlast;
+ BerElement *ember = ber_init( embvp );
+ if ( ember != NULL )
+ {
+ for ( emtag = ber_first_element( ember, &emlen, &emlast );
+ emtag != LBER_ERROR && emtag != LBER_END_OF_SEQORSET;
+ emtag = ber_next_element( ember, &emlen, emlast ))
+ {
+ struct berval **embvals;
+ if ( ber_scanf( ember, "{i{a[V]}}", &op, &type, &embvals ) == LBER_ERROR )
+ {
+ continue;
+ /* GGOODREPL I suspect this will cause two sets of lastmods attr values
+ to end up in the entry. We need to remove the old ones.
+ */
+ }
+ slapi_mods_add_modbvps( smods, op, type, embvals);
+ free( type );
+ ber_bvecfree( embvals );
+ }
+ }
+ ber_free( ember, 1 );
+ }
+ }
+}