/* * NormalizeMods: * 1. Normalize attribute values present in the modifications list. * 2. Make sure no duplicate value */ int VmDirNormalizeMods( PVDIR_SCHEMA_CTX pSchemaCtx, PVDIR_MODIFICATION pMods, PSTR* ppszErrorMsg ) { int retVal = LDAP_SUCCESS; PVDIR_MODIFICATION pMod = NULL; unsigned int i = 0; PSTR pszDupAttributeName = NULL; PSTR pszLocalErrorMsg = NULL; for (pMod = pMods; pMod != NULL; pMod = pMod->next) { if (pMod->attr.pATDesc == NULL && (pMod->attr.pATDesc = VmDirSchemaAttrNameToDesc(pSchemaCtx, pMod->attr.type.lberbv.bv_val)) == NULL ) { retVal = VMDIR_ERROR_UNDEFINED_TYPE; BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, (pszLocalErrorMsg), "Undefined attribute (%s)", VDIR_SAFE_STRING(pMod->attr.type.lberbv.bv_val)); } for (i=0; i < pMod->attr.numVals; i++) { retVal = VmDirSchemaBervalNormalize(pSchemaCtx, pMod->attr.pATDesc, &pMod->attr.vals[i]); BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, (pszLocalErrorMsg), "attribute value normalization failed (%s)(%.*s)", VDIR_SAFE_STRING(pMod->attr.pATDesc->pszName), VMDIR_MIN(pMod->attr.vals[i].lberbv.bv_len, VMDIR_MAX_LOG_OUTPUT_LEN), VDIR_SAFE_STRING(pMod->attr.vals[i].lberbv.bv_val)); } // Make sure we have no duplicate value in mod->attr retVal = VmDirAttributeDupValueCheck(&pMod->attr, &pszDupAttributeName); BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, (pszLocalErrorMsg), "attribute (%s) has duplicate value", VDIR_SAFE_STRING(pszDupAttributeName)); } cleanup: if (ppszErrorMsg) { *ppszErrorMsg = pszLocalErrorMsg; } else { VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg); } return retVal; error: goto cleanup; }
/* * This is NOT RFC 4514 compliance. * * 1. separate into RDNs * 2. for each RDN, normalize value based on its syntax * (does not handle multi-value RDN case) * remove all leading/trailing spaces * 3. reconstruct DN based on RDNs */ DWORD VmDirNormalizeDN( PVDIR_BERVALUE pBerv, PVDIR_SCHEMA_CTX pSchemaCtx ) { DWORD dwError = 0; PSTR pszTmpDN = NULL; PSTR* ppszRDNs = NULL; PSTR* ppszNormRDNs = NULL; int iNumRDNs = 0; int iCnt = 0; size_t iNormDNSize = 0; PVDIR_SCHEMA_CTX pCtx = pSchemaCtx; if (!pBerv || !pBerv->lberbv.bv_val) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } // Already normalized. => Nothing to be done. if ( pBerv->bvnorm_val != NULL ) { dwError = 0; goto cleanup; } // Nothing to be normalized for the ROOT DN if (pBerv->lberbv.bv_len == 0) { pBerv->bvnorm_val = pBerv->lberbv.bv_val; pBerv->bvnorm_len = 0; dwError = 0; goto cleanup; } if (pCtx == NULL) { dwError = VmDirSchemaCtxAcquire(&pCtx); BAIL_ON_VMDIR_ERROR(dwError); } // make a local copy dwError = VmDirAllocateStringA( pBerv->lberbv.bv_val, &pszTmpDN); BAIL_ON_VMDIR_ERROR(dwError); dwError = VdirSchemaInPlaceDN2RDNs( pszTmpDN, &ppszRDNs, &iNumRDNs); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirAllocateMemory( sizeof(PSTR) * (iNumRDNs + 1), (PVOID)&ppszNormRDNs); BAIL_ON_VMDIR_ERROR(dwError); for (iCnt=0; ppszRDNs[iCnt] && iCnt < iNumRDNs; iCnt++) { size_t iNameLen = 0 ; VDIR_BERVALUE berval = VDIR_BERVALUE_INIT; PVDIR_SCHEMA_AT_DESC pATDesc = NULL; char* pChar = VmDirStringChrA(ppszRDNs[iCnt], '='); if (!pChar) { dwError = ERROR_INVALID_DN; BAIL_ON_VMDIR_ERROR(dwError); } *pChar = '\0'; iNameLen = VmDirStringLenA(ppszRDNs[iCnt]); // attribute name - remove all leading/trailing spaces while (ppszRDNs[iCnt][iNameLen-1] == ' ') { ppszRDNs[iCnt][iNameLen-1] = '\0'; iNameLen--; assert(iNameLen > 0); // MIN 1 char for name } while (ppszRDNs[iCnt][0] == ' ') { ppszRDNs[iCnt]++; } pATDesc = VmDirSchemaAttrNameToDesc(pCtx, ppszRDNs[iCnt]); if (!pATDesc) { dwError = ERROR_INVALID_DN; BAIL_ON_VMDIR_ERROR(dwError); } berval.lberbv.bv_val = pChar+1; berval.lberbv.bv_len = VmDirStringLenA(berval.lberbv.bv_val); dwError = VmDirSchemaBervalNormalize(pCtx, pATDesc, &berval); BAIL_ON_VMDIR_ERROR(dwError); if (berval.bvnorm_len == 0) { dwError = ERROR_INVALID_DN; BAIL_ON_VMDIR_ERROR(dwError); } if (berval.lberbv.bv_val == berval.bvnorm_val) { dwError = VmDirAllocateStringA( berval.lberbv.bv_val, &ppszNormRDNs[iCnt]); BAIL_ON_VMDIR_ERROR(dwError); } else { // ppszNormRDNs takes over bvnorm_val ppszNormRDNs[iCnt] = berval.bvnorm_val; } iNormDNSize = iNormDNSize + berval.bvnorm_len + (pChar - ppszRDNs[iCnt]) + 2; } // Reconstruct normalized DN VMDIR_SAFE_FREE_MEMORY(pBerv->bvnorm_val); pBerv->bvnorm_len = 0; dwError = VmDirAllocateMemory( sizeof(char) * (iNormDNSize+1), (PVOID)&pBerv->bvnorm_val); BAIL_ON_VMDIR_ERROR(dwError); for (iCnt = 0; ppszNormRDNs[iCnt] && iCnt < iNumRDNs; iCnt++) { size_t iValueLen = VmDirStringLenA(ppszNormRDNs[iCnt]); int iValueOffset = 0; // attribute value - remove leading/trailing spaces while (ppszNormRDNs[iCnt][iValueOffset] == ' ') { iValueOffset++; assert(iValueOffset < iValueLen); } while (ppszNormRDNs[iCnt][iValueLen-1] == ' ') { ppszNormRDNs[iCnt][iValueLen-1] = '\0'; iValueLen--; assert(iValueLen > 0); } // attribute name to lower case { char* pToLower = NULL; for (pToLower = ppszRDNs[iCnt]; *pToLower != '\0'; pToLower++) { *pToLower = (char) tolower(*pToLower); } } VmDirStringCatA(pBerv->bvnorm_val, (iNormDNSize+1), ppszRDNs[iCnt]); VmDirStringCatA(pBerv->bvnorm_val, (iNormDNSize+1), "="); VmDirStringCatA(pBerv->bvnorm_val, (iNormDNSize+1), ppszNormRDNs[iCnt]+iValueOffset); if (iCnt + 1 < iNumRDNs) { VmDirStringCatA(pBerv->bvnorm_val, (iNormDNSize+1), ","); } } pBerv->bvnorm_len = VmDirStringLenA(pBerv->bvnorm_val); cleanup: if (pCtx && pCtx != pSchemaCtx) { VmDirSchemaCtxRelease(pCtx); } VMDIR_SAFE_FREE_MEMORY(pszTmpDN); VMDIR_SAFE_FREE_MEMORY(ppszRDNs); // ppszRDNs[i] is in place of pszTmpDN VmDirFreeStringArrayA(ppszNormRDNs); VMDIR_SAFE_FREE_MEMORY(ppszNormRDNs); return dwError; error: goto cleanup; }
/* * TODO, to generalize, we should create a strToFilter(pszFilter, &pOutFilter); */ DWORD VmDirSimpleEqualFilterInternalSearch( PCSTR pszBaseDN, int searchScope, PCSTR pszAttrName, PCSTR pszAttrValue, PVDIR_ENTRY_ARRAY pEntryArray ) { DWORD dwError = 0; VDIR_OPERATION searchOP = {0}; VDIR_BERVALUE bervDN = VDIR_BERVALUE_INIT; PVDIR_FILTER pFilter = NULL; if ( !pszBaseDN || !pszAttrName || !pszAttrValue || !pEntryArray ) { dwError = VMDIR_ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } dwError = VmDirInitStackOperation( &searchOP, VDIR_OPERATION_TYPE_INTERNAL, LDAP_REQ_SEARCH, NULL ); BAIL_ON_VMDIR_ERROR(dwError); bervDN.lberbv.bv_val = (PSTR)pszBaseDN; bervDN.lberbv.bv_len = VmDirStringLenA(pszBaseDN); searchOP.pBEIF = VmDirBackendSelect( pszBaseDN ); assert(searchOP.pBEIF); dwError = VmDirBervalContentDup( &bervDN, &searchOP.reqDn); BAIL_ON_VMDIR_ERROR(dwError); searchOP.request.searchReq.scope = searchScope; { dwError = VmDirAllocateMemory( sizeof( VDIR_FILTER ), (PVOID*)&pFilter ); BAIL_ON_VMDIR_ERROR(dwError); pFilter->choice = LDAP_FILTER_EQUALITY; pFilter->filtComp.ava.type.lberbv.bv_val = (PSTR)pszAttrName; pFilter->filtComp.ava.type.lberbv.bv_len = VmDirStringLenA(pszAttrName); pFilter->filtComp.ava.pATDesc = VmDirSchemaAttrNameToDesc( searchOP.pSchemaCtx, pszAttrName); if (pFilter->filtComp.ava.pATDesc == NULL) { dwError = VMDIR_ERROR_NO_SUCH_ATTRIBUTE; BAIL_ON_VMDIR_ERROR( dwError ); } pFilter->filtComp.ava.value.lberbv.bv_val = (PSTR)pszAttrValue; pFilter->filtComp.ava.value.lberbv.bv_len = VmDirStringLenA(pszAttrValue); dwError = VmDirSchemaBervalNormalize( // TODO, may want to have filter code to do this? searchOP.pSchemaCtx, // so caller does not have to handle this. pFilter->filtComp.ava.pATDesc, &(pFilter->filtComp.ava.value) ); BAIL_ON_VMDIR_ERROR(dwError); pFilter->next = NULL; } //TODO, ideally, we should take pszFilter and dwError = VmDirStrToFilter(pszFilter, &pFilter); searchOP.request.searchReq.filter = pFilter; pFilter = NULL; // search request takes over pFilter dwError = VmDirInternalSearch( &searchOP ); BAIL_ON_VMDIR_ERROR(dwError); // caller takes over searchOP.internalSearchEntryArray contents pEntryArray->iSize = searchOP.internalSearchEntryArray.iSize; pEntryArray->pEntry = searchOP.internalSearchEntryArray.pEntry; searchOP.internalSearchEntryArray.iSize = 0; searchOP.internalSearchEntryArray.pEntry = NULL; cleanup: VmDirFreeOperationContent(&searchOP); if (pFilter) { DeleteFilter(pFilter); } return dwError; error: goto cleanup; }
/* * Tweak indices entry to append building flag to newly added values. * e.g. user add a new index attribute "myuid eq unique" * we want to save it as "myuid eq unique (buildingflag)" instead. */ DWORD VdirIndexingEntryAppendFlag( VDIR_MODIFICATION* pMods, PVDIR_ENTRY pEntry) { DWORD dwError = 0; DWORD dwCnt = 0; PSTR pszNewStr = NULL; PVDIR_ATTRIBUTE pAttr = NULL; assert(pMods && pEntry && pEntry->allocType == ENTRY_STORAGE_FORMAT_NORMAL); // unpack entry, so we can manipulate its contents. dwError = VmDirEntryUnpack(pEntry); BAIL_ON_VMDIR_ERROR(dwError); pAttr = VmDirFindAttrByName(pEntry, ATTR_INDEX_DESC); if (!pAttr) { dwError = ERROR_INVALID_ENTRY; BAIL_ON_VMDIR_ERROR(dwError); } for (dwCnt = 0; dwCnt < pAttr->numVals; dwCnt++) { DWORD iIdx = 0; for (iIdx = 0; iIdx < pMods->attr.numVals; iIdx++) { if (0 == VmDirStringCompareA(pAttr->vals[dwCnt].lberbv.bv_val, pMods->attr.vals[iIdx].lberbv.bv_val, FALSE)) { dwError = VmDirAllocateStringAVsnprintf( &pszNewStr, "%s %s", pAttr->vals[dwCnt].lberbv.bv_val, ATTR_INDEX_BUILDING_FLAG); BAIL_ON_VMDIR_ERROR(dwError); VmDirFreeBervalArrayContent(&pAttr->vals[dwCnt], 1); pAttr->vals[dwCnt].lberbv.bv_val = pszNewStr; pszNewStr = NULL; pAttr->vals[dwCnt].bOwnBvVal = TRUE; pAttr->vals[dwCnt].lberbv.bv_len = VmDirStringLenA(pAttr->vals[dwCnt].lberbv.bv_val); dwError = VmDirSchemaBervalNormalize( pEntry->pSchemaCtx, pAttr->pATDesc, &pAttr->vals[dwCnt]); BAIL_ON_VMDIR_ERROR(dwError); } } } cleanup: return dwError; error: VMDIR_SAFE_FREE_MEMORY(pszNewStr); goto cleanup; }
static int LoadReplicationAgreements() { // Load my Replication Agreements VDIR_OPERATION op = {0}; PVDIR_FILTER replAgrFilter = NULL; DWORD dwError = 0; int iCnt = 0; VmDirLog( LDAP_DEBUG_TRACE, "LoadReplicationAgreements: Begin" ); if ( gVmdirServerGlobals.serverObjDN.lberbv.bv_val != NULL ) { dwError = VmDirInitStackOperation( &op, VDIR_OPERATION_TYPE_INTERNAL, LDAP_REQ_SEARCH, NULL ); BAIL_ON_VMDIR_ERROR(dwError); op.pBEIF = VmDirBackendSelect( gVmdirServerGlobals.serverObjDN.lberbv.bv_val ); assert(op.pBEIF); if (VmDirBervalContentDup( &gVmdirServerGlobals.serverObjDN, &op.reqDn ) != 0) { VmDirLog( LDAP_DEBUG_ANY, "LoadReplicationAgreements: BervalContentDup failed." ); dwError = -1; BAIL_ON_VMDIR_ERROR( dwError ); } op.request.searchReq.scope = LDAP_SCOPE_SUBTREE; if (VmDirAllocateMemory( sizeof( VDIR_FILTER ), (PVOID *)&replAgrFilter ) != 0) { VmDirLog( LDAP_DEBUG_ANY, "LoadReplicationAgreements: VmDirAllocateMemory failed. " ); dwError = -1; BAIL_ON_VMDIR_ERROR( dwError ); } op.request.searchReq.filter = replAgrFilter; replAgrFilter->choice = LDAP_FILTER_EQUALITY; replAgrFilter->filtComp.ava.type.lberbv.bv_val = ATTR_OBJECT_CLASS; replAgrFilter->filtComp.ava.type.lberbv.bv_len = ATTR_OBJECT_CLASS_LEN; if ((replAgrFilter->filtComp.ava.pATDesc = VmDirSchemaAttrNameToDesc( op.pSchemaCtx, replAgrFilter->filtComp.ava.type.lberbv.bv_val)) == NULL) { dwError = -1; VmDirLog( LDAP_DEBUG_ANY, "LoadReplicationAgreements: Getting pATDesc for ATTR_OBJECT_CLASS failed " "(hmm... STRANGE). " ); BAIL_ON_VMDIR_ERROR( dwError ); } replAgrFilter->filtComp.ava.value.lberbv.bv_val = OC_REPLICATION_AGREEMENT; replAgrFilter->filtComp.ava.value.lberbv.bv_len = OC_REPLICATION_AGREEMENT_LEN; if (VmDirSchemaBervalNormalize( op.pSchemaCtx, replAgrFilter->filtComp.ava.pATDesc, &(replAgrFilter->filtComp.ava.value) ) != LDAP_SUCCESS) { dwError = -1; VmDirLog( LDAP_DEBUG_ANY, "LoadReplicationAgreements: Attribute value normalization failed for " "filter type = %s", replAgrFilter->filtComp.ava.type.lberbv.bv_val ); BAIL_ON_VMDIR_ERROR( dwError ); } replAgrFilter->next = NULL; if ((dwError = VmDirInternalSearch( &op )) != 0) { VmDirLog( LDAP_DEBUG_ANY, "LoadReplicationAgreements: InternalSearch for Replication Agreements failed. " "Error code: %d, Error string: %s", dwError, VDIR_SAFE_STRING(op.ldapResult.pszErrMsg)); dwError = -1; BAIL_ON_VMDIR_ERROR( dwError ); } // load all replication agreements for (iCnt=0; iCnt < op.internalSearchEntryArray.iSize; iCnt++) { dwError = ProcessReplicationAgreementEntry( op.internalSearchEntryArray.pEntry + iCnt ); BAIL_ON_VMDIR_ERROR( dwError ); } VmDirPopulateInvocationIdInReplAgr(); } cleanup: VmDirFreeOperationContent(&op); VmDirLog( LDAP_DEBUG_TRACE, "LoadReplicationAgreements: End" ); return dwError; error: goto cleanup; }
/* * DelAttrValsFromEntryStruct: Deletes a complete attribute or specific attribute values from the entry. * Assumption: This function assumes/asserts that the modAttr does exist in the entry. * */ static int DelAttrValsFromEntryStruct( PVDIR_SCHEMA_CTX pSchemaCtx, VDIR_ENTRY * e, VDIR_ATTRIBUTE * modAttr, PSTR* ppszErrorMsg ) { int retVal = LDAP_SUCCESS; VDIR_ATTRIBUTE * prevAttr = NULL; VDIR_ATTRIBUTE * currAttr = NULL; VDIR_ATTRIBUTE * eAttr = NULL; unsigned int i = 0; unsigned int j = 0; PSTR pszLocalErrorMsg = NULL; assert(e->allocType == ENTRY_STORAGE_FORMAT_NORMAL); // Locate which attribute (values) we are trying to delete for (currAttr = e->attrs; currAttr != NULL; prevAttr = currAttr, currAttr = currAttr->next) { if (VmDirStringCompareA(modAttr->type.lberbv.bv_val, currAttr->type.lberbv.bv_val, FALSE) == 0) { break; } } assert(currAttr != NULL); eAttr = currAttr; // Normalize eAttr values for (i = 0; i < eAttr->numVals; i++) { retVal = VmDirSchemaBervalNormalize(pSchemaCtx, eAttr->pATDesc, &eAttr->vals[i]); BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, (pszLocalErrorMsg), "normalize (%s)(%.*s)", VDIR_SAFE_STRING(eAttr->pATDesc->pszName), VMDIR_MIN(eAttr->vals[i].lberbv.bv_len, VMDIR_MAX_LOG_OUTPUT_LEN), VDIR_SAFE_STRING(eAttr->vals[i].lberbv.bv_val)); } if (modAttr->numVals == 1 && eAttr->pATDesc->bSingleValue && (VmDirStringCompareA(eAttr->pATDesc->pszName, ATTR_MODIFYTIMESTAMP, FALSE) == 0 || VmDirStringCompareA(eAttr->pATDesc->pszName, ATTR_CREATETIMESTAMP, FALSE) == 0 || VmDirStringCompareA(eAttr->pATDesc->pszName, ATTR_CREATORS_NAME, FALSE) == 0 || VmDirStringCompareA(eAttr->pATDesc->pszName, ATTR_MODIFIERS_NAME, FALSE) == 0)) { /* Force deleting the attribute value whether or not the value matches. * A raft follower may alter the timestamps/creator locally, e.g. rollback vmwAttrUniquenessScope, * which may fail to remove the value if it doesn't match that value seen at the raft leader. */ VmDirFreeBervalContent(&modAttr->vals[0]); modAttr->numVals = 0; } // Complete attribute is to be deleted. if (modAttr->numVals == 0) { // Make a copy of BerValues into modAttr so that these values can be used to delete from the index, // if it is an indexed attribute. VMDIR_SAFE_FREE_MEMORY(modAttr->vals); retVal = VmDirAllocateMemory((eAttr->numVals + 1) * sizeof(VDIR_BERVALUE), (PVOID *)&modAttr->vals); BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, (pszLocalErrorMsg), "no memory"); for (i = 0; i < eAttr->numVals; i++) { VmDirBervalContentDup(&eAttr->vals[i], &modAttr->vals[i]); } modAttr->numVals = eAttr->numVals; // Adjust the "next" pointer of the attribute before the attribute being deleted. => Altering the attribute // chain. if (prevAttr == NULL) // if it is the first attribute { e->attrs = eAttr->next; } else { prevAttr->next = eAttr->next; } VmDirFreeAttribute(eAttr); } else // Specific attribute values need to be deleted. { // Check if all attribute values that are being deleted exist in the Attribute for (i=0; i < modAttr->numVals; i++) { // modAttr values are already normalized. assert(modAttr->vals[i].bvnorm_val); for (j = 0; j < eAttr->numVals; j++) { // eAttr values are already normalized. assert(eAttr->vals[j].bvnorm_val); if (modAttr->vals[i].bvnorm_len == eAttr->vals[j].bvnorm_len && memcmp(modAttr->vals[i].bvnorm_val, eAttr->vals[j].bvnorm_val, modAttr->vals[i].bvnorm_len) == 0) { break; } } if (j == eAttr->numVals) // did not find a match { retVal = VMDIR_ERROR_NO_SUCH_ATTRIBUTE; BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, (pszLocalErrorMsg), "Attribute (%s) value (%.*s) being deleted does not exist.", VDIR_SAFE_STRING(modAttr->type.lberbv.bv_val), VMDIR_MIN(modAttr->vals[i].lberbv.bv_len, VMDIR_MAX_LOG_OUTPUT_LEN), VDIR_SAFE_STRING(modAttr->vals[i].lberbv.bv_val)); } } // All values are being deleted. => Delete the whole attribute if (modAttr->numVals == eAttr->numVals) { // Adjust the "next" pointer of the attribute before the attribute being deleted. => Altering the attribute // chain. if (prevAttr == NULL) // if it is the first attribute { e->attrs = eAttr->next; } else { prevAttr->next = eAttr->next; } VmDirFreeAttribute(eAttr); } else { RemoveAttrVals(eAttr, modAttr); } } cleanup: if (ppszErrorMsg) { *ppszErrorMsg = pszLocalErrorMsg; } else { VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg); } return retVal; error: goto cleanup; }
static int CheckIfAnAttrValAlreadyExists( PVDIR_SCHEMA_CTX pSchemaCtx, VDIR_ATTRIBUTE * eAttr, VDIR_ATTRIBUTE * modAttr, PSTR* ppszErrorMsg ) { int retVal = LDAP_SUCCESS; unsigned int i = 0; unsigned int j = 0; PSTR pszLocalErrorMsg = NULL; for (i=0; i < eAttr->numVals; i++) { retVal = VmDirSchemaBervalNormalize(pSchemaCtx, modAttr->pATDesc, // Assumption: modAttr type is same as eAttr type &eAttr->vals[i]) ; BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, (pszLocalErrorMsg), "normalize (%s)(%.*s)", VDIR_SAFE_STRING(modAttr->pATDesc->pszName), VMDIR_MIN(eAttr->vals[i].lberbv.bv_len, VMDIR_MAX_LOG_OUTPUT_LEN), VDIR_SAFE_STRING(eAttr->vals[i].lberbv.bv_val)); for (j = 0; j < modAttr->numVals; j++) { // modAttr values are already normalized. assert(modAttr->vals[j].bvnorm_val); if (eAttr->vals[i].bvnorm_len == modAttr->vals[j].bvnorm_len && memcmp(eAttr->vals[i].bvnorm_val, modAttr->vals[j].bvnorm_val, modAttr->vals[j].bvnorm_len) == 0) { break; } } if (j != modAttr->numVals) // found a match in middle { retVal = VMDIR_ERROR_TYPE_OR_VALUE_EXISTS; BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, (pszLocalErrorMsg), "Attribute (%s) value (%.*s) exists", VDIR_SAFE_STRING(modAttr->pATDesc->pszName), VMDIR_MIN(eAttr->vals[i].lberbv.bv_len, VMDIR_MAX_LOG_OUTPUT_LEN), VDIR_SAFE_STRING(eAttr->vals[i].lberbv.bv_val)); } } cleanup: if (ppszErrorMsg) { *ppszErrorMsg = pszLocalErrorMsg; } else { VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg); } return retVal; error: goto cleanup; }