/* * Convenient function to add a single attribute to pEntry. */ DWORD VmDirEntryAddSingleValueAttribute( PVDIR_ENTRY pEntry, PCSTR pszAttrName, PCSTR pszAttrValue, size_t iAttrValueLen ) { DWORD dwError = 0; PVDIR_ATTRIBUTE pAttr = NULL; if (!pEntry || !pEntry->pSchemaCtx || !pszAttrName || !pszAttrValue || iAttrValueLen < 1) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } dwError = VmDirAttributeAllocate( pszAttrName, 1, pEntry->pSchemaCtx, &pAttr); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirAllocateMemory( iAttrValueLen + 1, // want string null terminated. (PVOID*)&pAttr->vals[0].lberbv.bv_val ); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirCopyMemory( pAttr->vals[0].lberbv.bv_val, (iAttrValueLen + 1), (PCVOID)pszAttrValue, iAttrValueLen ); BAIL_ON_VMDIR_ERROR(dwError); pAttr->vals[0].bOwnBvVal = TRUE; pAttr->vals[0].lberbv.bv_len = iAttrValueLen; dwError = VmDirEntryAddAttribute( pEntry, pAttr); BAIL_ON_VMDIR_ERROR(dwError); pAttr = NULL; cleanup: return dwError; error: if (pAttr) { VmDirFreeAttribute(pAttr); } goto cleanup; }
/* * Create an Attribute on the heap and establish its pATDesc * two memory allocate * 1. pAttribute * 2. pAttribute->vals (BerValue array is one more then requested) */ DWORD VmDirAttributeAllocate( PCSTR pszName, USHORT usBerSize, PVDIR_SCHEMA_CTX pCtx, PVDIR_ATTRIBUTE* ppOutAttr) { DWORD dwError = 0; PVDIR_ATTRIBUTE pAttr = NULL; if (!ppOutAttr) { return 0; } dwError = VmDirAllocateMemory( sizeof(VDIR_ATTRIBUTE), (PVOID*)&pAttr); BAIL_ON_VMDIR_ERROR(dwError); // add one more BerValue as Encode/Decode entry in data store layer needs it. dwError = VmDirAllocateMemory( sizeof(VDIR_BERVALUE) * (usBerSize + 1), (PVOID*)&pAttr->vals); BAIL_ON_VMDIR_ERROR(dwError); pAttr->numVals = usBerSize; pAttr->pATDesc = VmDirSchemaAttrNameToDesc( pCtx, pszName); if (!pAttr->pATDesc) { dwError = VMDIR_ERROR_NO_SUCH_ATTRIBUTE; BAIL_ON_VMDIR_ERROR(dwError); } // pAttr->type.lberbv.bv_val always store in-place pAttr->type.lberbv.bv_val = pAttr->pATDesc->pszName; pAttr->type.lberbv.bv_len = VmDirStringLenA(pAttr->type.lberbv.bv_val); *ppOutAttr = pAttr; cleanup: return dwError; error: if (pAttr) { VmDirFreeAttribute(pAttr); } VmDirLog( LDAP_DEBUG_ANY, "AllocateAttribute failed (%d)(%s)", dwError, VDIR_SAFE_STRING(pszName)); goto cleanup; }
static DWORD schemaInitFillAttrFromCache( PVDIR_SCHEMA_CTX pCtx, PSTR* ppszValues, USHORT dwValueSize, PSTR pszAttrName, PVDIR_ENTRY pEntry ) { DWORD dwError = 0; DWORD dwCnt = 0; VDIR_ATTRIBUTE* pAttr = NULL; dwError = VmDirAttributeAllocate( pszAttrName, dwValueSize, pCtx, &pAttr); BAIL_ON_VMDIR_ERROR(dwError); for (dwCnt = 0; dwCnt < dwValueSize; dwCnt++) { char* pszStr = &ppszValues[dwCnt][0]; //ignore leading spaces while (*pszStr == ' ') pszStr++; dwError = VmDirAllocateStringA( ppszValues[dwCnt], &pAttr->vals[dwCnt].lberbv.bv_val); BAIL_ON_VMDIR_ERROR(dwError); pAttr->vals[dwCnt].bOwnBvVal = TRUE; pAttr->vals[dwCnt].lberbv.bv_len = VmDirStringLenA(pAttr->vals[dwCnt].lberbv.bv_val); } dwError = VmDirEntryAddAttribute( pEntry, pAttr); BAIL_ON_VMDIR_ERROR(dwError); pAttr = NULL; cleanup: return dwError; error: if (pAttr) { VmDirFreeAttribute(pAttr); } goto cleanup; }
/* * FROM and TO Attributes use same schema context */ DWORD VmDirAttributeDup( PVDIR_ATTRIBUTE pAttr, PVDIR_ATTRIBUTE* ppDupAttr ) { DWORD dwError = 0; DWORD dwCnt = 0; PVDIR_ATTRIBUTE pAttribute = NULL; assert(pAttr && ppDupAttr); dwError = VmDirAllocateMemory( sizeof(VDIR_ATTRIBUTE), (PVOID*)&pAttribute); BAIL_ON_VMDIR_ERROR(dwError); // add one more BerValue as Encode/Decode entry in data store layer needs it. dwError = VmDirAllocateMemory( sizeof(VDIR_BERVALUE) * (pAttr->numVals + 1), (PVOID*)&pAttribute->vals); BAIL_ON_VMDIR_ERROR(dwError); for (dwCnt = 0 ; dwCnt < pAttr->numVals; dwCnt++) { dwError = VmDirBervalContentDup( &pAttr->vals[dwCnt], &pAttribute->vals[dwCnt]); BAIL_ON_VMDIR_ERROR(dwError); pAttribute->numVals = dwCnt + 1; } // use the same pATDesc and type from pAttr pAttribute->pATDesc = pAttr->pATDesc; // type.lberbv.bv_val always store in-place pAttribute->type.lberbv.bv_val = pAttr->pATDesc->pszName; pAttribute->type.lberbv.bv_len = VmDirStringLenA(pAttr->type.lberbv.bv_val); *ppDupAttr = pAttribute; cleanup: return dwError; error: if (pAttribute) { VmDirFreeAttribute(pAttribute); } goto cleanup; }
static DWORD _VmDirSchemaComputeAllowedChildClassesEffective( PVDIR_ENTRY pEntry, PVDIR_ATTRIBUTE* ppOutAttr ) { DWORD dwError = 0; PVDIR_SCHEMA_OC_DESC pStructureOCDesc = NULL; PVDIR_ATTRIBUTE pLocalAttr = NULL; int iCnt = 0; dwError = VmDirSchemaGetEntryStructureOCDesc( pEntry, &pStructureOCDesc ); BAIL_ON_VMDIR_ERROR(dwError); if ( !pStructureOCDesc ) { dwError = ERROR_INVALID_ENTRY; BAIL_ON_VMDIR_ERROR(dwError); } for (iCnt = 0; pStructureOCDesc->ppszAllowedChildOCs && pStructureOCDesc->ppszAllowedChildOCs[iCnt]; iCnt++) {} if (iCnt > 0) { dwError = VmDirAttributeAllocate( ATTR_ALLOWD_CHILD_CLASSES_EFFECTIVE, iCnt, pEntry->pSchemaCtx, &pLocalAttr); BAIL_ON_VMDIR_ERROR(dwError); for (iCnt = 0; pStructureOCDesc->ppszAllowedChildOCs[iCnt]; iCnt++) { dwError = VmDirAllocateStringA( pStructureOCDesc->ppszAllowedChildOCs[iCnt], &(pLocalAttr->vals[iCnt].lberbv_val)); BAIL_ON_VMDIR_ERROR(dwError); pLocalAttr->vals[iCnt].lberbv_len = VmDirStringLenA(pLocalAttr->vals[iCnt].lberbv_val); pLocalAttr->vals[iCnt].bOwnBvVal = TRUE; } } *ppOutAttr = pLocalAttr; cleanup: return dwError; error: VmDirFreeAttribute( pLocalAttr ); goto cleanup; }
/* * Remove an attribute of an entry. * Only handle ENTRY_STORAGE_FORMAT_NORMAL. */ DWORD VmDirEntryRemoveAttribute( PVDIR_ENTRY pEntry, PCSTR pszName ) { DWORD dwError = 0; PVDIR_ATTRIBUTE pAttr = NULL; PVDIR_ATTRIBUTE pPrevAttr = NULL; if (!pEntry || !pszName || pEntry->allocType != ENTRY_STORAGE_FORMAT_NORMAL) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } for (pAttr = pEntry->attrs; pAttr; pAttr = pAttr->next) { if (VmDirStringCompareA(pAttr->pATDesc->pszName, pszName, FALSE) == 0) { break; } pPrevAttr = pAttr; } if (pAttr) { if (pPrevAttr) { pPrevAttr->next = pAttr->next; } else { assert(pAttr == pEntry->attrs); pEntry->attrs = pAttr->next; } VmDirFreeAttribute(pAttr); } cleanup: return dwError; error: goto cleanup; }
/* * FROM and TO Attributes use same schema context */ DWORD VmDirAttributeDup( PVDIR_ATTRIBUTE pAttr, PVDIR_ATTRIBUTE* ppDupAttr ) { DWORD dwError = 0; DWORD dwCnt = 0; PVDIR_ATTRIBUTE pAttribute = NULL; if (!pAttr || !ppDupAttr) { BAIL_WITH_VMDIR_ERROR(dwError, VMDIR_ERROR_INVALID_PARAMETER); } dwError = VmDirAllocateMemory(sizeof(VDIR_ATTRIBUTE), (PVOID*)&pAttribute); BAIL_ON_VMDIR_ERROR(dwError); // add one more BerValue as Encode/Decode entry in data store layer needs it. dwError = VmDirAllocateMemory( sizeof(VDIR_BERVALUE) * (pAttr->numVals + 1), (PVOID*)&pAttribute->vals); BAIL_ON_VMDIR_ERROR(dwError); for (dwCnt = 0 ; dwCnt < pAttr->numVals; dwCnt++) { dwError = VmDirBervalContentDup(&pAttr->vals[dwCnt], &pAttribute->vals[dwCnt]); BAIL_ON_VMDIR_ERROR(dwError); pAttribute->numVals = dwCnt + 1; } // use the same pATDesc and type from pAttr pAttribute->pATDesc = pAttr->pATDesc; dwError = VmDirBervalContentDup(&pAttr->type, &pAttribute->type); BAIL_ON_VMDIR_ERROR(dwError); *ppDupAttr = pAttribute; cleanup: return dwError; error: VmDirFreeAttribute(pAttribute); VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "failed, error (%d)", dwError); goto cleanup; }
/* * Add an array of bervalue attribute values into an entry. */ DWORD VmDirEntryAddBervArrayAttribute( PVDIR_ENTRY pEntry, PCSTR pszAttrName, VDIR_BERVARRAY attrVals, USHORT usNumVals ) { DWORD dwError = 0; PVDIR_ATTRIBUTE pAttr = NULL; USHORT usCnt = 0; if (!pEntry || !pEntry->pSchemaCtx || !pszAttrName || !attrVals) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } if (usNumVals) { dwError = VmDirAttributeAllocate( pszAttrName, usNumVals, pEntry->pSchemaCtx, &pAttr); BAIL_ON_VMDIR_ERROR(dwError); for (usCnt=0; usCnt < usNumVals; usCnt++) { dwError = VmDirBervalContentDup( &attrVals[usCnt], &pAttr->vals[usCnt]); BAIL_ON_VMDIR_ERROR(dwError); } dwError = VmDirEntryAddAttribute(pEntry, pAttr); BAIL_ON_VMDIR_ERROR(dwError); } cleanup: return dwError; error: VmDirFreeAttribute(pAttr); goto cleanup; }
/* * replace attribute in pEntry if such attribute exists. * pEntry takes over ownership of pNewAttr if success. */ DWORD VmDirEntryReplaceAttribute( PVDIR_ENTRY pEntry, PVDIR_ATTRIBUTE pNewAttr) { DWORD dwError = 0; BOOLEAN bFound = FALSE; PVDIR_ATTRIBUTE pAttr = NULL; PVDIR_ATTRIBUTE pPriorAttr = NULL; assert ( pEntry && pEntry->allocType == ENTRY_STORAGE_FORMAT_NORMAL && pNewAttr); for ( pAttr = pEntry->attrs; pAttr; pPriorAttr = pAttr, pAttr = pAttr->next ) { if (0 == VmDirStringCompareA(pAttr->type.lberbv.bv_val, pNewAttr->type.lberbv.bv_val, FALSE)) { if ( pEntry->attrs == pAttr ) { pEntry->attrs = pNewAttr; } else { pPriorAttr->next = pNewAttr; } pNewAttr->next = pAttr->next; VmDirFreeAttribute(pAttr); bFound = TRUE; break; } } if ( bFound == FALSE ) { dwError = VMDIR_ERROR_NO_SUCH_ATTRIBUTE; } return dwError; }
void VmDirFreeEntryContent( VDIR_ENTRY * e ) { VmDirLog( LDAP_DEBUG_TRACE, "DeleteEntry: Begin" ); if ( e ) { VmDirLog( LDAP_DEBUG_TRACE, "DeleteEntry: DN = %s", e ? (e->dn.lberbv.bv_val ? e->dn.lberbv.bv_val : "") : "" ); if (e->pParentEntry) { VmDirFreeEntryContent(e->pParentEntry); VMDIR_SAFE_FREE_MEMORY(e->pParentEntry); } VmDirFreeLDAPDNContent( &(e->ldapDN) ); VmDirFreeBervalContent( &(e->dn) ); VmDirFreeBervalContent( &(e->pdn) ); VmDirFreeBervalContent( &(e->newpdn) ); if (e->allocType == ENTRY_STORAGE_FORMAT_PACK) { PVDIR_ATTRIBUTE pCurrAttr = NULL; PVDIR_ATTRIBUTE pTempAttr = NULL; pCurrAttr = e->attrs; while(pCurrAttr != NULL) { pTempAttr = pCurrAttr->next; VmDirFreeMetaData(pCurrAttr->pMetaData); pCurrAttr = pTempAttr; } VMDIR_SAFE_FREE_MEMORY( e->encodedEntry ); VmDirFreeBervalArrayContent(e->bvs, e->usNumBVs); VMDIR_SAFE_FREE_MEMORY( e->bvs ); VMDIR_SAFE_FREE_MEMORY( e->savedAttrsPtr ); } else if (e->allocType == ENTRY_STORAGE_FORMAT_NORMAL) { VDIR_ATTRIBUTE * currAttr = NULL; VDIR_ATTRIBUTE * tmpAttr = NULL; VMDIR_SAFE_FREE_MEMORY( e->encodedEntry ); for (currAttr = e->attrs; currAttr != NULL; ) { tmpAttr = currAttr->next; VmDirFreeAttribute(currAttr); currAttr = tmpAttr; } } if (e->pComputedAttrs) { VDIR_ATTRIBUTE * currAttr = NULL; VDIR_ATTRIBUTE * tmpAttr = NULL; for (currAttr = e->pComputedAttrs; currAttr != NULL; ) { tmpAttr = currAttr->next; VmDirFreeAttribute(currAttr); currAttr = tmpAttr; } } VmDirSchemaCtxRelease(e->pSchemaCtx); VmDirAclCtxContentFree(e->pAclCtx); VMDIR_SAFE_FREE_MEMORY(e->pAclCtx); VMDIR_SAFE_FREE_MEMORY(e->pszGuid); memset(e, 0, sizeof(*e)); } VmDirLog( LDAP_DEBUG_TRACE, "DeleteEntry: End" ); }
int VmDirModifyEntryCoreLogic( VDIR_OPERATION * pOperation, /* IN */ ModifyReq * modReq, /* IN */ ENTRYID entryId, /* IN */ BOOLEAN bNoRaftLog, /* IN */ VDIR_ENTRY * pEntry /* OUT */ ) { int retVal = LDAP_SUCCESS; PSTR pszLocalErrMsg = NULL; BOOLEAN bDnModified = FALSE; BOOLEAN bLeafNode = FALSE; PVDIR_ATTRIBUTE pAttrMemberOf = NULL; extern DWORD VmDirModifyRaftPreCommit(PVDIR_SCHEMA_CTX, ENTRYID, char *, PVDIR_MODIFICATION, PVDIR_OPERATION); retVal = pOperation->pBEIF->pfnBEIdToEntry( pOperation->pBECtx, pOperation->pSchemaCtx, entryId, pEntry, VDIR_BACKEND_ENTRY_LOCK_WRITE); BAIL_ON_VMDIR_ERROR(retVal); if (pOperation->pCondWriteCtrl) { retVal = VmDirMatchEntryWithFilter( pOperation, pEntry, pOperation->pCondWriteCtrl->value.condWriteCtrlVal.pszFilter); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "Conditional Write pre-conditions (%s) failed - (%d)", VDIR_SAFE_STRING(pOperation->pCondWriteCtrl->value.condWriteCtrlVal.pszFilter), retVal); } if (modReq->dn.lberbv.bv_val == NULL) // If not already set by the caller { // e.g. delete membership case via index lookup to get EID. retVal = VmDirBervalContentDup(&pEntry->dn, &modReq->dn); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "VmDirBervalContentDup failed - (%d)", retVal); } retVal = VmDirSrvAccessCheck( pOperation, &pOperation->conn->AccessInfo, pEntry, VMDIR_RIGHT_DS_WRITE_PROP); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "VmDirSrvAccessCheck failed - (%u)", retVal); // Apply modify operations to the current entry (in pack format) retVal = VmDirApplyModsToEntryStruct( pOperation->pSchemaCtx, modReq, pEntry, &bDnModified, &pszLocalErrMsg); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "ApplyModsToEntryStruct failed - (%d)(%s)", retVal, pszLocalErrMsg); if (bDnModified) { retVal = pOperation->pBEIF->pfnBEChkIsLeafEntry( pOperation->pBECtx, entryId, &bLeafNode); BAIL_ON_VMDIR_ERROR(retVal); if (bLeafNode == FALSE) { retVal = LDAP_NOT_ALLOWED_ON_NONLEAF; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "Rename of a non-leaf node is not allowed."); } // Verify not a member of any groups retVal = VmDirFindMemberOfAttribute(pEntry, &pAttrMemberOf); if (pAttrMemberOf && pAttrMemberOf->numVals > 0) { retVal = LDAP_UNWILLING_TO_PERFORM; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "Rename of a node with memberships is not allowed."); } } if (pOperation->opType != VDIR_OPERATION_TYPE_REPL) { // Schema check retVal = VmDirSchemaCheck(pEntry); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "Schema check failed - (%u)(%s)", retVal, VDIR_SAFE_STRING(VmDirSchemaCtxGetErrorMsg(pEntry->pSchemaCtx))); // check and read lock dn referenced entries retVal = pOperation->pBEIF->pfnBEChkDNReference(pOperation->pBECtx, pEntry); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "BECheckDnRef, (%u)(%s)", retVal, VDIR_SAFE_STRING(pOperation->pBECtx->pszBEErrorMsg)); } // Execute plugin logic that require final entry image. (Do this for both normal and repl routes) retVal = VmDirExecutePreModifyPlugins(pOperation, pEntry, retVal); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "PreModifyPlugins failed - (%u)", retVal); // Update DB retVal = pOperation->pBEIF->pfnBEEntryModify(pOperation->pBECtx, modReq->mods, pEntry); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "BEEntryModify, (%u)(%s)", retVal, VDIR_SAFE_STRING(pOperation->pBEErrorMsg)); if (bNoRaftLog == FALSE) { // Generate raft log only on the orignal Add/Modify/Delete, but not on the derived operation. // For instance, a delete may cause a Modify on the referenced entry which shouldn't // initiate a raft log generation. retVal = VmDirModifyRaftPreCommit( pEntry->pSchemaCtx, entryId, modReq->dn.bvnorm_val, modReq->mods, pOperation); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "VmDirModifyRaftPreCommit, (%u)(%s)", retVal, VDIR_SAFE_STRING(pOperation->pBEErrorMsg)); } cleanup: VmDirFreeAttribute(pAttrMemberOf); VMDIR_SAFE_FREE_MEMORY(pszLocalErrMsg); return retVal; error: if (retVal == VMDIR_LDAP_ERROR_PRE_CONDITION) { VMDIR_LOG_VERBOSE( LDAP_DEBUG_ANY, "CoreLogicModifyEntry failed, DN = %s, (%u)(%s)", VDIR_SAFE_STRING(modReq->dn.lberbv.bv_val), retVal, VDIR_SAFE_STRING(pszLocalErrMsg)); } else { VMDIR_LOG_ERROR( LDAP_DEBUG_ANY, "CoreLogicModifyEntry failed, DN = %s, (%u)(%s)", VDIR_SAFE_STRING(modReq->dn.lberbv.bv_val), retVal, VDIR_SAFE_STRING(pszLocalErrMsg)); } if (pOperation->ldapResult.pszErrMsg == NULL) { pOperation->ldapResult.pszErrMsg = pszLocalErrMsg; pszLocalErrMsg = NULL; } goto cleanup; }
/* * Simple (but not efficient) function to convert list of attribute,value * into an ADD_REQUEST type entry. * (e.g. ppszAttrList = { "objectclass","person", * "objectclass", "masterdiver", * "cn","my common name", * NULL}; */ static DWORD AttrListToEntry( PVDIR_SCHEMA_CTX pSchemaCtx, PSTR pszDN, PSTR* ppszAttrList, PVDIR_ENTRY pEntry) { DWORD dwError = 0; VDIR_ATTRIBUTE* pAttr = NULL; PSTR* ppszNext = NULL; assert(pSchemaCtx && pszDN && ppszAttrList && pEntry); pEntry->allocType = ENTRY_STORAGE_FORMAT_NORMAL; // establish entry schema context association pEntry->pSchemaCtx = VmDirSchemaCtxClone(pSchemaCtx); assert(pEntry->pSchemaCtx); dwError = VmDirAllocateStringA( pszDN, &pEntry->dn.lberbv.bv_val); BAIL_ON_VMDIR_ERROR(dwError); pEntry->dn.bOwnBvVal = TRUE; pEntry->dn.lberbv.bv_len = VmDirStringLenA(pEntry->dn.lberbv.bv_val); dwError = VmDirNormalizeDN( &(pEntry->dn), pSchemaCtx ); BAIL_ON_VMDIR_ERROR(dwError); for (ppszNext = ppszAttrList; *ppszNext && *(ppszNext+1); ppszNext += 2) { assert (!pAttr); if ( (*(ppszNext+1))[0] != '\0') // skip attribute with empty value { dwError = VmDirAttributeAllocate( *ppszNext, 1, pSchemaCtx, &pAttr); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirAllocateStringA( *(ppszNext+1), &pAttr->vals[0].lberbv.bv_val); BAIL_ON_VMDIR_ERROR(dwError); pAttr->vals[0].bOwnBvVal = TRUE; pAttr->vals[0].lberbv.bv_len = VmDirStringLenA(pAttr->vals[0].lberbv.bv_val); dwError = VmDirEntryAddAttribute( pEntry, pAttr); BAIL_ON_VMDIR_ERROR(dwError); pAttr = NULL; // pEntry takes over pAttr } } cleanup: return dwError; error: if (pAttr) { VmDirFreeAttribute(pAttr); } VmDirFreeEntryContent(pEntry); memset(pEntry, 0, sizeof(*pEntry)); goto cleanup; }
/* * 1) Find the attribute that holds attribute meta data. * 2) Attributes for usnCreated/usnChanged are updated with current local USN * 3) If we are doing a modify/delete, attribute meta data is checked to see supplier/consumer wins. * - If supplier attribute won, update its meta data with current local USN. * - If consumer wins don't write corresponding attribute. * - Special case: supplier lost for UsnChanged, replace the metaData with consumer's metaData. * 4) If no attribute metaData exists, create it. */ DWORD VmDirReplSetAttrNewMetaData( PVDIR_OPERATION pOperation, PVDIR_ENTRY pEntry, PLW_HASHMAP* ppMetaDataMap ) { DWORD dwError = LDAP_SUCCESS; PVDIR_ATTRIBUTE pCurrAttr = NULL; PVDIR_ATTRIBUTE pPrevAttr = NULL; PVDIR_ATTRIBUTE pAttrAttrMetaData = NULL; PLW_HASHMAP pMetaDataMap = NULL; if (!pOperation || !pEntry || !ppMetaDataMap) { BAIL_WITH_VMDIR_ERROR(dwError, VMDIR_ERROR_INVALID_PARAMETER); } for (pPrevAttr = NULL, pCurrAttr = pEntry->attrs; pCurrAttr; pPrevAttr = pCurrAttr, pCurrAttr = pCurrAttr->next) { if (VmDirStringCompareA(pCurrAttr->type.lberbv.bv_val, ATTR_ATTR_META_DATA, FALSE) == 0) { if (pPrevAttr == NULL) { pEntry->attrs = pCurrAttr->next; } else { pPrevAttr->next = pCurrAttr->next; } pAttrAttrMetaData = pCurrAttr; dwError = VmDirAttributeMetaDataToHashMap(pAttrAttrMetaData, &pMetaDataMap); BAIL_ON_VMDIR_ERROR(dwError); *ppMetaDataMap = pMetaDataMap; continue; } if (VmDirStringCompareA(pCurrAttr->type.lberbv.bv_val, ATTR_USN_CREATED, FALSE) == 0 || VmDirStringCompareA(pCurrAttr->type.lberbv.bv_val, ATTR_USN_CHANGED, FALSE) == 0) { char pszLocalUsn[VMDIR_MAX_USN_STR_LEN] = {'\0'}; size_t localUsnStrlen = 0; dwError = VmDirStringNPrintFA( pszLocalUsn, sizeof(pszLocalUsn), sizeof(pszLocalUsn) - 1, "%"PRId64, pOperation->pWriteQueueEle->usn); BAIL_ON_VMDIR_ERROR(dwError); localUsnStrlen = VmDirStringLenA(pszLocalUsn); VmDirFreeBervalContent(&pCurrAttr->vals[0]); dwError = VmDirAllocateAndCopyMemory(pszLocalUsn, localUsnStrlen, (PVOID*)&pCurrAttr->vals[0].lberbv.bv_val); BAIL_ON_VMDIR_ERROR(dwError); pCurrAttr->vals[0].lberbv.bv_len = localUsnStrlen; pCurrAttr->vals[0].bOwnBvVal = TRUE; continue; } } if (pAttrAttrMetaData == NULL) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s: attrMetaData attribute not present in Entry: %s", __FUNCTION__, pEntry->dn.lberbv.bv_val); BAIL_WITH_VMDIR_ERROR(dwError, LDAP_OPERATIONS_ERROR); } if (pOperation->reqCode == LDAP_REQ_MODIFY) { dwError = VmDirReplResolveConflicts( pOperation, pEntry, pMetaDataMap); BAIL_ON_VMDIR_ERROR(dwError); } dwError = _VmDirReplPopulateAttrNewMetaData( pEntry, pOperation->pWriteQueueEle->usn, pMetaDataMap); BAIL_ON_VMDIR_ERROR(dwError); cleanup: VmDirFreeAttribute(pAttrAttrMetaData); return dwError; error: goto cleanup; }
static DWORD schemaInitFillAttrFromFile( PVDIR_SCHEMA_CTX pCtx, PSTR* ppszDescs, USHORT dwDescSize, PSTR pszTag, size_t dwTagSize, PVDIR_ENTRY pEntry ) { DWORD dwError = 0; DWORD dwCnt = 0; VDIR_ATTRIBUTE* pAttr = NULL; pszTag[dwTagSize] = '\0'; dwError = VmDirAttributeAllocate( pszTag, dwDescSize, pCtx, &pAttr); pszTag[dwTagSize] = ':'; BAIL_ON_VMDIR_ERROR(dwError); for (dwCnt = 0; dwCnt < dwDescSize; dwCnt++) { char* pszStr = &ppszDescs[dwCnt][dwTagSize+1]; char* pszEndStr = &ppszDescs[dwCnt][VmDirStringLenA(ppszDescs[dwCnt])-1]; assert(ppszDescs[dwCnt][dwTagSize] == ':'); //ignore leading spaces while (*pszStr == ' ') pszStr++; //ignore trailing spaces while (*pszEndStr == ' ') pszEndStr--; *(pszEndStr+1) = '\0'; dwError = VmDirAllocateStringA( pszStr, &pAttr->vals[dwCnt].lberbv.bv_val); BAIL_ON_VMDIR_ERROR(dwError); pAttr->vals[dwCnt].bOwnBvVal = TRUE; pAttr->vals[dwCnt].lberbv.bv_len = VmDirStringLenA(pAttr->vals[dwCnt].lberbv.bv_val); } dwError = VmDirEntryAddAttribute( pEntry, pAttr); BAIL_ON_VMDIR_ERROR(dwError); pAttr = NULL; cleanup: return dwError; error: if (pAttr) { VmDirFreeAttribute(pAttr); } goto cleanup; }
DWORD VmDirGetUPNMemberships( PCSTR pszUpnName, PSTR **pppszMemberships, PDWORD pdwMemberships ) { DWORD dwError = 0; VDIR_ENTRY_ARRAY entryArray = {0}; VDIR_OPERATION searchOp = {0}; BOOLEAN bHasTxn = FALSE; PVDIR_ATTRIBUTE pMemberOf = NULL; PSTR *ppszMemberships = NULL; DWORD dwMemberships = 0; DWORD i = 0; if (IsNullOrEmptyString(pszUpnName) || pppszMemberships == NULL || pdwMemberships == NULL) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } dwError = VmDirSimpleEqualFilterInternalSearch( "", LDAP_SCOPE_SUBTREE, ATTR_KRB_UPN, pszUpnName, &entryArray); BAIL_ON_VMDIR_ERROR(dwError); if (entryArray.iSize == 0) { dwError = VMDIR_ERROR_ENTRY_NOT_FOUND; BAIL_ON_VMDIR_ERROR(dwError); } else if (entryArray.iSize > 1) { dwError = VMDIR_ERROR_DATA_CONSTRAINT_VIOLATION; BAIL_ON_VMDIR_ERROR(dwError); } dwError = VmDirInitStackOperation(&searchOp, VDIR_OPERATION_TYPE_INTERNAL, LDAP_REQ_SEARCH, NULL); BAIL_ON_VMDIR_ERROR(dwError); searchOp.pBEIF = VmDirBackendSelect(NULL); dwError = searchOp.pBEIF->pfnBETxnBegin(searchOp.pBECtx, VDIR_BACKEND_TXN_READ); BAIL_ON_VMDIR_ERROR(dwError); bHasTxn = TRUE; dwError = VmDirBuildMemberOfAttribute(&searchOp, entryArray.pEntry, &pMemberOf); BAIL_ON_VMDIR_ERROR(dwError); if (pMemberOf) { dwMemberships = pMemberOf->numVals; } if (dwMemberships) { dwError = VmDirAllocateMemory(dwMemberships * sizeof(PSTR), (PVOID)&ppszMemberships); BAIL_ON_VMDIR_ERROR(dwError); for (i = 0; i < dwMemberships; i++) { PCSTR pszMemberOf = pMemberOf->vals[i].lberbv.bv_val; dwError = VmDirAllocateStringA(pszMemberOf, &ppszMemberships[i]); BAIL_ON_VMDIR_ERROR(dwError); } } *pppszMemberships = ppszMemberships; *pdwMemberships = dwMemberships; cleanup: if (pMemberOf) { VmDirFreeAttribute(pMemberOf); } if (bHasTxn) { searchOp.pBEIF->pfnBETxnCommit(searchOp.pBECtx); } VmDirFreeOperationContent(&searchOp); VmDirFreeEntryArrayContent(&entryArray); return dwError; error: VmDirFreeMemberships(ppszMemberships, dwMemberships); goto cleanup; }
int VmDirReplResolveConflicts( PVDIR_OPERATION pOperation, PVDIR_ENTRY pEntry, PLW_HASHMAP pMetaDataMap ) { int retVal = LDAP_SUCCESS; int dbRetVal = 0; PSTR pszAttrType = NULL; DWORD dwConflictCnt = 0; LW_HASHMAP_ITER iter = LW_HASHMAP_ITER_INIT; LW_HASHMAP_PAIR pair = {NULL, NULL}; PVDIR_ATTRIBUTE pConsumerAttr = NULL; PVMDIR_ATTRIBUTE_METADATA pSupplierMetaData = NULL; PVMDIR_REPLICATION_METRICS pReplMetrics = NULL; if (!pOperation || !pEntry || !pMetaDataMap) { BAIL_WITH_VMDIR_ERROR(retVal, VMDIR_ERROR_INVALID_PARAMETER); } while (LwRtlHashMapIterate(pMetaDataMap, &iter, &pair)) { pszAttrType = (PSTR) pair.pKey; pSupplierMetaData = (PVMDIR_ATTRIBUTE_METADATA) pair.pValue; if (VmDirStringCompareA(pszAttrType, ATTR_OBJECT_GUID, FALSE) == 0) { continue; } VmDirFreeAttribute(pConsumerAttr); pConsumerAttr = NULL; retVal = VmDirAttributeAllocate(pszAttrType, 0, pOperation->pSchemaCtx, &pConsumerAttr); BAIL_ON_LDAP_ERROR( retVal, LDAP_OPERATIONS_ERROR, (pOperation->ldapResult.pszErrMsg), "VmDirAttributeAllocate failed", VDIR_SAFE_STRING(pOperation->pBEErrorMsg)); dbRetVal = pOperation->pBEIF->pfnBEGetAttrMetaData( pOperation->pBECtx, pConsumerAttr, pEntry->eId); if (dbRetVal) { switch (dbRetVal) { case ERROR_BACKEND_ATTR_META_DATA_NOTFOUND: //When a new attribute is being added // => Supplier attribute meta data WINS against consumer attribute meta data break; default: BAIL_ON_LDAP_ERROR( retVal, LDAP_OPERATIONS_ERROR, (pOperation->ldapResult.pszErrMsg), "pfnBEGetAttrMetaData failed - (%d)(%s)", dbRetVal, VDIR_SAFE_STRING(pOperation->pBEErrorMsg)); } } else { BOOLEAN bSupplierWon = FALSE; BOOLEAN bIsSameAttrValue = FALSE; PSZ_METADATA_BUF pszSupplierMetaData = {'\0'}; PSZ_METADATA_BUF pszConsumerMetaData = {'\0'}; bSupplierWon = _VmDirReplAttrConflictCheck( pSupplierMetaData, pConsumerAttr->pMetaData); bIsSameAttrValue = _VmDirIsBenignReplConflict( pEntry, pConsumerAttr); //Ignore error - used only for logging VmDirMetaDataSerialize(pSupplierMetaData, &pszSupplierMetaData[0]); VmDirMetaDataSerialize(pConsumerAttr->pMetaData, &pszConsumerMetaData[0]); if (bSupplierWon == FALSE) { if (VmDirStringCompareA(pszAttrType, ATTR_USN_CHANGED, FALSE) == 0) { // Need to keep usnChanged to advance localUSN for this replication change. retVal = VmDirMetaDataCopyContent(pConsumerAttr->pMetaData, pSupplierMetaData); BAIL_ON_VMDIR_ERROR(retVal); } else { VMDIR_FREE_REPL_ATTR_IN_CONFLICT(pSupplierMetaData); } dwConflictCnt++; if (!bIsSameAttrValue) { VMDIR_LOG_WARNING( VMDIR_LOG_MASK_ALL, "%s: supplier version loses." " pszAttrType: %s supplier attr meta: %s, consumer attr meta: %s ", __FUNCTION__, pEntry->dn.lberbv.bv_val, pszAttrType, pszSupplierMetaData, pszConsumerMetaData); } } else { VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL, "%s: supplier version wins." " pszAttrType: %s supplier attr meta: %s, consumer attr meta: %s ", __FUNCTION__, pEntry->dn.lberbv.bv_val, pszAttrType, pszSupplierMetaData, pszConsumerMetaData); } } } if (dwConflictCnt > 0) { if (VmDirReplMetricsCacheFind(pOperation->pszPartner, &pReplMetrics) == 0) { VmMetricsCounterAdd(pReplMetrics->pCountConflictResolved, dwConflictCnt); } } cleanup: VmDirFreeAttribute(pConsumerAttr); return retVal; ldaperror: error: VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "failed, error (%d)", retVal); goto cleanup; }
/* * Convert entry allocType from FORMAT_PACK to FORMAT_NORMAL */ DWORD VmDirEntryUnpack( PVDIR_ENTRY pEntry ) { DWORD dwError = 0; PVDIR_ATTRIBUTE pAttr = NULL; PVDIR_ATTRIBUTE pDupAttr = NULL; VDIR_ENTRY newEntry = {0}; assert(pEntry); if (pEntry->allocType != ENTRY_STORAGE_FORMAT_PACK) { return 0; } newEntry.allocType = ENTRY_STORAGE_FORMAT_NORMAL; newEntry.eId = pEntry->eId; dwError = VmDirBervalContentDup(&pEntry->dn, &newEntry.dn); BAIL_ON_VMDIR_ERROR(dwError); // pdn.lberbv.bv_val is always in-place of dn.lberbv.bv_val (compatible with DeleteEntry) if (pEntry->pdn.lberbv.bv_val && pEntry->pdn.lberbv.bv_len > 0) { newEntry.pdn.lberbv.bv_val = newEntry.dn.lberbv.bv_val + (pEntry->pdn.lberbv.bv_val - pEntry->dn.lberbv.bv_val); } // pdn.bvnorm_val is ok to heap allocated if (pEntry->pdn.bvnorm_val && pEntry->pdn.bvnorm_len > 0) { dwError = VmDirAllocateStringA( pEntry->pdn.bvnorm_val, &newEntry.pdn.bvnorm_val); BAIL_ON_VMDIR_ERROR(dwError); newEntry.pdn.bvnorm_len = VmDirStringLenA(newEntry.pdn.bvnorm_val); } // copy attribute for (pAttr = pEntry->attrs, pDupAttr = NULL; pAttr; pAttr = pAttr->next) { dwError = VmDirAttributeDup(pAttr, &pDupAttr); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirEntryAddAttribute(&newEntry, pDupAttr); BAIL_ON_VMDIR_ERROR(dwError); pDupAttr = NULL; } ///////////////////////////////////////////////////////////////////// // should never fail from here to the end ///////////////////////////////////////////////////////////////////// // takes over schema ctx (we copy attributes) newEntry.pSchemaCtx = pEntry->pSchemaCtx; assert(newEntry.pSchemaCtx); pEntry->pSchemaCtx = NULL; // TODO, other fields? // takes over pParentEntry newEntry.pParentEntry = pEntry->pParentEntry; pEntry->pParentEntry = NULL; // fee resources VmDirFreeEntryContent(pEntry); // takes over newEntry content VmDirCopyMemory(pEntry, sizeof(VDIR_ENTRY), &newEntry, sizeof(newEntry)); cleanup: return dwError; error: if (pDupAttr) { VmDirFreeAttribute(pDupAttr); } VmDirFreeEntryContent(&newEntry); 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; }