/** 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 ); } } }