BOOLEAN VmDirEntryIsObjectclass( PVDIR_ENTRY pEntry, PCSTR pszOCName ) { BOOLEAN bResult = FALSE; unsigned int iCnt = 0; if (pEntry && pszOCName) { PVDIR_ATTRIBUTE pAttrOC = VmDirFindAttrByName(pEntry, ATTR_OBJECT_CLASS); for (iCnt = 0; (pAttrOC != NULL) && (iCnt < pAttrOC->numVals); iCnt++) { if (VmDirStringCompareA( pAttrOC->vals[iCnt].lberbv.bv_val, pszOCName, FALSE) == 0) { bResult = TRUE; break; } } } return bResult; }
/* * Called during entry add * * grouptype : * http://msdn.microsoft.com/en-us/library/windows/desktop/ms675935%28v=vs.85%29.aspx Value Description 1 (0x00000001) Specifies a group that is created by the system. 2 (0x00000002) Specifies a group with global scope. 4 (0x00000004) Specifies a group with domain local scope. 8 (0x00000008) Specifies a group with universal scope. 16 (0x00000010) Specifies an APP_BASIC group for Windows Server Authorization Manager. 32 (0x00000020) Specifies an APP_QUERY group for Windows Server Authorization Manager. 2147483648 (0x80000000) Specifies a security group. If this flag is not set, then the group is a distribution group. Currently, Lotus only supports global scope (2). */ DWORD VmDirPluginGroupTypePreAdd( PVDIR_OPERATION pOperation, PVDIR_ENTRY pEntry, DWORD dwPriorResult ) { DWORD dwError = 0; PSTR pszLocalErrorMsg = NULL; if ( pOperation->opType != VDIR_OPERATION_TYPE_REPL && TRUE == VmDirIsEntryWithObjectclass(pEntry, OC_GROUP) ) { PVDIR_ATTRIBUTE pAttrGroupType = VmDirFindAttrByName(pEntry, ATTR_GROUPTYPE); if (pAttrGroupType == NULL) { dwError = VmDirEntryAddSingleValueStrAttribute(pEntry, ATTR_GROUPTYPE, GROUPTYPE_GLOBAL_SCOPE); BAIL_ON_VMDIR_ERROR(dwError); } else { if ( pAttrGroupType->numVals != 1 // grouptype is a single value attribute || VmDirStringCompareA( VDIR_SAFE_STRING( pAttrGroupType->vals[0].lberbv.bv_val), GROUPTYPE_GLOBAL_SCOPE, FALSE) != 0 ) { dwError = ERROR_INVALID_ENTRY; BAIL_ON_VMDIR_ERROR_WITH_MSG( dwError, pszLocalErrorMsg, "invalid or unsupported grouptype (%s)", VDIR_SAFE_STRING( pAttrGroupType->vals[0].lberbv.bv_val)); } } } cleanup: VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg); return dwError; error: VmDirLog( LDAP_DEBUG_ANY, "Group check: (%d)(%s)", dwError, VDIR_SAFE_STRING(pszLocalErrorMsg)); VMDIR_APPEND_ERROR_MSG(pOperation->ldapResult.pszErrMsg, pszLocalErrorMsg); goto cleanup; }
/* * Set SRP Identifier's secret on existing entry with Password set */ DWORD VmDirSRPSetIdentityData( PCSTR pszUPN, PCSTR pszClearTextPassword ) { DWORD dwError = 0; VDIR_OPERATION op = {0}; PSTR pszLocalErrMsg = NULL; VDIR_ENTRY_ARRAY entryArray = {0}; PVDIR_ENTRY pEntry = NULL; PVDIR_ATTRIBUTE pAttrSecret = NULL; VDIR_BERVALUE bvUPN = VDIR_BERVALUE_INIT; VDIR_BERVALUE bvClearTextPassword = VDIR_BERVALUE_INIT; VDIR_BERVALUE bervSecretBlob = VDIR_BERVALUE_INIT; if ( IsNullOrEmptyString(pszUPN) || IsNullOrEmptyString(pszClearTextPassword) ) { dwError = VMDIR_ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } bvUPN.lberbv_val = (PSTR)pszUPN; bvUPN.lberbv_len = VmDirStringLenA(pszUPN); bvClearTextPassword.lberbv_val = (PSTR)pszClearTextPassword; bvClearTextPassword.lberbv_len = VmDirStringLenA(pszClearTextPassword); dwError = VmDirSimpleEqualFilterInternalSearch( "", LDAP_SCOPE_SUBTREE, ATTR_KRB_UPN, pszUPN, &entryArray); BAIL_ON_VMDIR_ERROR(dwError); if (entryArray.iSize == 1) { pAttrSecret = VmDirFindAttrByName(&(entryArray.pEntry[0]), ATTR_SRP_SECRET); if (pAttrSecret) { dwError = VMDIR_ERROR_ENTRY_ALREADY_EXIST; BAIL_ON_VMDIR_ERROR(dwError); } } else { dwError = VMDIR_ERROR_DATA_CONSTRAINT_VIOLATION; BAIL_ON_VMDIR_ERROR(dwError); } pEntry = &(entryArray.pEntry[0]); dwError = VdirPasswordCheck(&bvClearTextPassword, pEntry); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirSRPCreateSecret(&bvUPN, &bvClearTextPassword, &bervSecretBlob); BAIL_ON_VMDIR_ERROR(dwError); if (pEntry->allocType == ENTRY_STORAGE_FORMAT_PACK) { dwError = VmDirEntryUnpack( pEntry ); BAIL_ON_VMDIR_ERROR(dwError); } dwError = VmDirInitStackOperation( &op, VDIR_OPERATION_TYPE_INTERNAL, LDAP_REQ_MODIFY, NULL); BAIL_ON_VMDIR_ERROR_WITH_MSG(dwError, pszLocalErrMsg, "VmDirSRPSetIdentityData: VmDirInitStackOperation failed: %u", dwError); op.pBEIF = VmDirBackendSelect(NULL); assert(op.pBEIF); op.reqDn.lberbv.bv_val = pEntry->dn.lberbv.bv_val; op.reqDn.lberbv.bv_len = pEntry->dn.lberbv.bv_len; op.request.modifyReq.dn.lberbv = op.reqDn.lberbv; dwError = VmDirAppendAMod( &op, MOD_OP_ADD, ATTR_SRP_SECRET, ATTR_SRP_SECRET_LEN, bervSecretBlob.lberbv_val, bervSecretBlob.lberbv_len); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirInternalModifyEntry(&op); BAIL_ON_VMDIR_ERROR(dwError); cleanup: VmDirFreeBervalContent(&bervSecretBlob); VmDirFreeEntryArrayContent(&entryArray); VmDirFreeOperationContent(&op); return dwError; error: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "VmDirSRPSetIdentityData (%s) failed, (%u)", VDIR_SAFE_STRING(pszUPN), dwError); goto cleanup; }
/* * Retrieve SRP Identifier's secret and salt */ DWORD VmDirSRPGetIdentityData( PCSTR pszUPN, PBYTE* ppByteSecret, DWORD* pdwSecretLen ) { DWORD dwError = 0; PVDIR_ATTRIBUTE pAttrSecret = NULL; VDIR_ENTRY_ARRAY entryArray = {0}; PBYTE pLocalSecret = NULL; if ( IsNullOrEmptyString(pszUPN) || ppByteSecret == NULL || pdwSecretLen == NULL ) { dwError = VMDIR_ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } dwError = VmDirSimpleEqualFilterInternalSearch( "", LDAP_SCOPE_SUBTREE, ATTR_KRB_UPN, pszUPN, &entryArray); BAIL_ON_VMDIR_ERROR(dwError); if (entryArray.iSize == 1) { pAttrSecret = VmDirFindAttrByName(&(entryArray.pEntry[0]), ATTR_SRP_SECRET); if (!pAttrSecret) { dwError = VMDIR_ERROR_NO_SUCH_ATTRIBUTE; BAIL_ON_VMDIR_ERROR(dwError); } dwError = VmDirAllocateAndCopyMemory( pAttrSecret->vals[0].lberbv_val, pAttrSecret->vals[0].lberbv_len, (PVOID*)&pLocalSecret); BAIL_ON_VMDIR_ERROR(dwError); } else if (entryArray.iSize == 0) { dwError = VMDIR_ERROR_ENTRY_NOT_FOUND; BAIL_ON_VMDIR_ERROR(dwError); } else { dwError = VMDIR_ERROR_DATA_CONSTRAINT_VIOLATION; BAIL_ON_VMDIR_ERROR(dwError); } *ppByteSecret = pLocalSecret; *pdwSecretLen = (DWORD) (pAttrSecret->vals[0].lberbv_len); cleanup: VmDirFreeEntryArrayContent(&entryArray); return dwError; error: VMDIR_SAFE_FREE_MEMORY( pLocalSecret ); VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "VmDirSRPGetIdentityData (%s) failed, (%u)", VDIR_SAFE_STRING(pszUPN), dwError); goto cleanup; }
DWORD VmDirEntryIsAttrAllowed( PVDIR_ENTRY pEntry, PSTR pszAttrName, PBOOLEAN pbMust, PBOOLEAN pbMay ) { DWORD dwError = 0; DWORD i = 0; PVDIR_ATTRIBUTE pAttrOC = NULL; PVDIR_SCHEMA_OC_DESC pOCDesc = NULL; PLW_HASHMAP pAllMustAttrMap = NULL; PLW_HASHMAP pAllMayAttrMap = NULL; if (!pEntry || IsNullOrEmptyString(pszAttrName)) { dwError = VMDIR_ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } dwError = LwRtlCreateHashMap(&pAllMustAttrMap, LwRtlHashDigestPstrCaseless, LwRtlHashEqualPstrCaseless, NULL); BAIL_ON_VMDIR_ERROR(dwError); dwError = LwRtlCreateHashMap(&pAllMayAttrMap, LwRtlHashDigestPstrCaseless, LwRtlHashEqualPstrCaseless, NULL); BAIL_ON_VMDIR_ERROR(dwError); pAttrOC = VmDirFindAttrByName(pEntry, ATTR_OBJECT_CLASS); for (i = 0; pAttrOC && i < pAttrOC->numVals; i++) { dwError = VmDirSchemaOCNameToDescriptor( pEntry->pSchemaCtx, pAttrOC->vals[i].lberbv.bv_val, &pOCDesc); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirSchemaClassGetAllMustAttrs( pEntry->pSchemaCtx, pOCDesc, pAllMustAttrMap); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirSchemaClassGetAllMayAttrs( pEntry->pSchemaCtx, pOCDesc, pAllMayAttrMap); BAIL_ON_VMDIR_ERROR(dwError); } if (pbMust) { *pbMust = FALSE; if (LwRtlHashMapFindKey(pAllMustAttrMap, NULL, pszAttrName) == 0) { *pbMust = TRUE; } } if (pbMay) { *pbMay = FALSE; if (LwRtlHashMapFindKey(pAllMayAttrMap, NULL, pszAttrName) == 0) { *pbMay = TRUE; } } cleanup: LwRtlHashMapClear(pAllMustAttrMap, VmDirNoopHashMapPairFree, NULL); LwRtlFreeHashMap(&pAllMustAttrMap); LwRtlHashMapClear(pAllMayAttrMap, VmDirNoopHashMapPairFree, NULL); LwRtlFreeHashMap(&pAllMayAttrMap); return dwError; error: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s failed, error (%d)", __FUNCTION__, dwError ); goto cleanup; }
/* This function re-instantiates the current vmdir instance with a * foreign (MDB) database file. It is triggered by running vdcadmintool * with option 8. Before this action, a foreign database files must be copied * onto diretory mdb_home_dir/partner/ which may include mdb WAL files under * xlogs/. See PR 1995325 for the functional spec and use cases. */ DWORD VmDirSrvServerReset( PDWORD pServerResetState ) { int i = 0; DWORD dwError = 0; VDIR_ENTRY_ARRAY entryArray = {0}; const char *dbHomeDir = VMDIR_DB_DIR; PVDIR_SCHEMA_CTX pSchemaCtx = NULL; BOOLEAN bWriteInvocationId = FALSE; PSTR pszConfigurationContainerDn = NULL; PSTR pszDomainControllerContainerDn = NULL; PSTR pszManagedServiceAccountContainerDn = NULL; DEQUE computers = {0}; PSTR pszComputer = NULL; PVDIR_ATTRIBUTE pAttrUPN = NULL; BOOLEAN bMdbWalEnable = FALSE; VmDirGetMdbWalEnable(&bMdbWalEnable); //swap current vmdir database file with the foriegn one under partner/ dwError = _VmDirSwapDB(dbHomeDir, bMdbWalEnable); BAIL_ON_VMDIR_ERROR(dwError); //Delete Computers (domain controller accounts) under Domain Controller container dwError = VmDirAllocateStringPrintf(&pszDomainControllerContainerDn, "ou=%s,%s", VMDIR_DOMAIN_CONTROLLERS_RDN_VAL, gVmdirServerGlobals.systemDomainDN.lberbv_val); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirSimpleEqualFilterInternalSearch(pszDomainControllerContainerDn, LDAP_SCOPE_ONE, ATTR_OBJECT_CLASS, OC_COMPUTER, &entryArray); BAIL_ON_VMDIR_ERROR(dwError); if(entryArray.iSize > 0) { for (i = 0; i < entryArray.iSize; i++) { pAttrUPN = VmDirFindAttrByName(&entryArray.pEntry[i], ATTR_KRB_UPN); if (pAttrUPN) { PSTR pPc = NULL; dwError = VmDirAllocateStringA(pAttrUPN->vals[0].lberbv_val, &pPc); dequePush(&computers, pPc); } dwError = VmDirDeleteEntry(&entryArray.pEntry[i]); BAIL_ON_VMDIR_ERROR(dwError); } } VmDirFreeEntryArrayContent(&entryArray); /* Delete all entries in the subtree under Configuration container * (e.g. under cn=Configuration,dc=vmware,dc=com). * This will remove the old replication topology */ dwError = VmDirAllocateStringPrintf(&pszConfigurationContainerDn, "cn=%s,%s", VMDIR_CONFIGURATION_CONTAINER_NAME, gVmdirServerGlobals.systemDomainDN.lberbv_val); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirSimpleEqualFilterInternalSearch(pszConfigurationContainerDn, LDAP_SCOPE_SUBTREE, ATTR_OBJECT_CLASS, OC_DIR_SERVER, &entryArray); BAIL_ON_VMDIR_ERROR(dwError); if (entryArray.iSize > 0) { for (i = 0; i < entryArray.iSize; i++) { /* Delete all replication agreement entries for a server and * the server it self under the configuration/site container */ dwError = VmDirInternalDeleteTree(entryArray.pEntry[i].dn.lberbv_val); BAIL_ON_VMDIR_ERROR(dwError); } } VmDirFreeEntryArrayContent(&entryArray); //Delete ManagedServiceAccount entries that are associated with any of the domain controllers dwError = VmDirAllocateStringPrintf(&pszManagedServiceAccountContainerDn, "cn=%s,%s", VMDIR_MSAS_RDN_VAL, gVmdirServerGlobals.systemDomainDN.lberbv_val); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirSimpleEqualFilterInternalSearch(pszManagedServiceAccountContainerDn, LDAP_SCOPE_ONE, ATTR_OBJECT_CLASS, OC_MANAGED_SERVICE_ACCOUNT, &entryArray); BAIL_ON_VMDIR_ERROR(dwError); if (entryArray.iSize > 0) { for (i = 0; i < entryArray.iSize; i++) { PDEQUE_NODE p = NULL; pAttrUPN = VmDirFindAttrByName(&entryArray.pEntry[i], ATTR_KRB_UPN); for(p = computers.pHead; p != NULL; p = p->pNext) { if (VmDirStringCaseStrA(pAttrUPN->vals[0].lberbv_val, p->pElement) != NULL) { dwError = VmDirDeleteEntry(&entryArray.pEntry[i]); BAIL_ON_VMDIR_ERROR(dwError); break; } } } } dwError = VmDirSchemaCtxAcquire(&pSchemaCtx ); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirSrvCreateServerObj(pSchemaCtx); BAIL_ON_VMDIR_ERROR(dwError); //Create server and replication entries for the current instance // on top of the (cleaned up) foreign database. dwError = VmDirSrvCreateReplAgrsContainer(pSchemaCtx); BAIL_ON_VMDIR_ERROR(dwError); dwError = _VmDirPatchDSERoot(pSchemaCtx); BAIL_ON_VMDIR_ERROR(dwError); VmDirSchemaCtxRelease(pSchemaCtx); pSchemaCtx = NULL; dwError = LoadServerGlobals(&bWriteInvocationId); BAIL_ON_VMDIR_ERROR(dwError); cleanup: if (pSchemaCtx) { VmDirSchemaCtxRelease(pSchemaCtx); } VmDirFreeEntryArrayContent(&entryArray); VMDIR_SAFE_FREE_MEMORY(pszConfigurationContainerDn); VMDIR_SAFE_FREE_MEMORY(pszDomainControllerContainerDn); while(!dequeIsEmpty(&computers)) { dequePopLeft(&computers, (PVOID*)&pszComputer); VMDIR_SAFE_FREE_MEMORY(pszComputer); } 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 DWORD _VmKdcGetKrbUPNKey( PSTR pszUpnName, PBYTE* ppKeyBlob, DWORD* pSize ) { DWORD dwError = 0; PVDIR_ATTRIBUTE pKrbUPNKey = NULL; PBYTE pRetUPNKey = NULL; VDIR_ENTRY_ARRAY entryArray = {0}; if (IsNullOrEmptyString(pszUpnName) || !ppKeyBlob || !pSize ) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_VMKDC_ERROR(dwError); } dwError = VmDirSimpleEqualFilterInternalSearch( "", LDAP_SCOPE_SUBTREE, ATTR_KRB_UPN, pszUpnName, &entryArray); BAIL_ON_VMKDC_ERROR(dwError); if (entryArray.iSize == 1) { pKrbUPNKey = VmDirFindAttrByName(&(entryArray.pEntry[0]), ATTR_KRB_PRINCIPAL_KEY); if (!pKrbUPNKey) { dwError = ERROR_NO_PRINC; BAIL_ON_VMKDC_ERROR(dwError); } dwError = VmDirAllocateAndCopyMemory( pKrbUPNKey->vals[0].lberbv.bv_val, pKrbUPNKey->vals[0].lberbv.bv_len, (PVOID*)& pRetUPNKey ); BAIL_ON_VMKDC_ERROR(dwError); *ppKeyBlob = pRetUPNKey; *pSize = (DWORD) pKrbUPNKey->vals[0].lberbv.bv_len; pRetUPNKey = NULL; } else { dwError = ERROR_NO_PRINC; BAIL_ON_VMKDC_ERROR(dwError); } cleanup: VmDirFreeEntryArrayContent(&entryArray); return dwError; error: VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "_VmKdcGetKrbUPNKey: failed (%u)(%s)", dwError, VDIR_SAFE_STRING(pszUpnName)); VMKDC_SAFE_FREE_MEMORY(pRetUPNKey); // keep error code space to KDC specific dwError = ERROR_NO_PRINC; goto cleanup; }
DWORD VmDirGetKrbUPNKey( PSTR pszUpnName, PBYTE* ppKeyBlob, DWORD* pSize ) { DWORD dwError = 0; PVDIR_ATTRIBUTE pKrbUPNKey = NULL; PBYTE pRetUPNKey = NULL; VDIR_ENTRY_ARRAY entryArray = {0}; if (IsNullOrEmptyString(pszUpnName) || !ppKeyBlob || !pSize ) { dwError = VMDIR_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 == 1) { pKrbUPNKey = VmDirFindAttrByName(&(entryArray.pEntry[0]), ATTR_KRB_PRINCIPAL_KEY); if (!pKrbUPNKey) { dwError = VMDIR_ERROR_NO_SUCH_ATTRIBUTE; BAIL_ON_VMDIR_ERROR(dwError); } dwError = VmDirAllocateMemory( pKrbUPNKey->vals[0].lberbv.bv_len, (PVOID*)&pRetUPNKey ); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirCopyMemory( pRetUPNKey, pKrbUPNKey->vals[0].lberbv.bv_len, pKrbUPNKey->vals[0].lberbv.bv_val, pKrbUPNKey->vals[0].lberbv.bv_len ); BAIL_ON_VMDIR_ERROR(dwError); *ppKeyBlob = pRetUPNKey; *pSize = (DWORD) pKrbUPNKey->vals[0].lberbv.bv_len; pRetUPNKey = NULL; } else { dwError = VMDIR_ERROR_ENTRY_NOT_FOUND; BAIL_ON_VMDIR_ERROR(dwError); } cleanup: VmDirFreeEntryArrayContent(&entryArray); return dwError; error: VMDIR_LOG_ERROR( LDAP_DEBUG_RPC, "VmDirGetKrbUPNKey failed. (%u)(%s)", dwError, VDIR_SAFE_STRING(pszUpnName)); VMDIR_SAFE_FREE_MEMORY(pRetUPNKey); goto cleanup; }
int VmDirApplyModsToEntryStruct( PVDIR_SCHEMA_CTX pSchemaCtx, ModifyReq * modReq, PVDIR_ENTRY pEntry, PBOOLEAN pbDnModified, PSTR* ppszErrorMsg ) { int retVal = LDAP_SUCCESS; VDIR_MODIFICATION * currMod = NULL; VDIR_MODIFICATION * prevMod = NULL; PSTR pszLocalErrorMsg = NULL; if (pSchemaCtx == NULL || modReq == NULL || pEntry == NULL || ppszErrorMsg == NULL) { retVal = VMDIR_ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(retVal); } if (pEntry->allocType == ENTRY_STORAGE_FORMAT_PACK) { retVal = VmDirEntryUnpack(pEntry); BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, (pszLocalErrorMsg), "EntryUnpack failed failed (%s)", VDIR_SAFE_STRING(pEntry->dn.lberbv.bv_val)); } for (currMod = modReq->mods; currMod != NULL; ) { switch (currMod->operation) { case MOD_OP_ADD: { PVDIR_ATTRIBUTE attr = VmDirFindAttrByName(pEntry, currMod->attr.type.lberbv.bv_val); if (attr == NULL) // New attribute case { retVal = AddAttrToEntryStruct(pEntry, &(currMod->attr)); BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, (pszLocalErrorMsg), "AddAttrToEntryStruct failed (%s)", VDIR_SAFE_STRING(currMod->attr.type.lberbv.bv_val)); } else // Add values to an existing attribute case. { retVal = CheckIfAnAttrValAlreadyExists(pSchemaCtx, attr, &(currMod->attr), &pszLocalErrorMsg); BAIL_ON_VMDIR_ERROR(retVal); retVal = AddAttrValsToEntryStruct(pEntry, attr, &(currMod->attr), &pszLocalErrorMsg); BAIL_ON_VMDIR_ERROR(retVal); } prevMod = currMod; currMod = currMod->next; break; } case MOD_OP_DELETE: { PVDIR_ATTRIBUTE attr = VmDirFindAttrByName(pEntry, currMod->attr.type.lberbv.bv_val); if (attr == NULL) // Attribute to be deleted does not exist in the entry { if (currMod->attr.numVals == 0) // If whole attribute is to be deleted, ignore this mod. { currMod->ignore = TRUE; } else // If some specific attribute values are to be deleted from the attribute => error case { retVal = VMDIR_ERROR_NO_SUCH_ATTRIBUTE; BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, (pszLocalErrorMsg), "Attribute (%s) being deleted does not exists.", VDIR_SAFE_STRING(currMod->attr.type.lberbv.bv_val)); } } else { retVal = DelAttrValsFromEntryStruct(pSchemaCtx, pEntry, &(currMod->attr), &pszLocalErrorMsg); if ((retVal == VMDIR_ERROR_NO_SUCH_ATTRIBUTE) && (VmDirStringCompareA(currMod->attr.type.lberbv.bv_val, ATTR_USER_PASSWORD, FALSE) == 0)) { // for user password change, the old password supplied != existing record retVal = VMDIR_ERROR_USER_INVALID_CREDENTIAL; } BAIL_ON_VMDIR_ERROR(retVal); } prevMod = currMod; currMod = currMod->next; break; } case MOD_OP_REPLACE: { // RFC 4511: Section 4.6: // replace: replace all existing values of the modification attribute with the new values listed, // creating the attribute if it did not already exist. A replace with no value will delete the entire // attribute if it exists, and it is ignored if the attribute does not exist. if (currMod->attr.numVals == 0) { currMod->operation = MOD_OP_DELETE; continue; // re-process the current altered modification } else { VDIR_MODIFICATION * newDelMod = NULL; PVDIR_ATTRIBUTE attr = VmDirFindAttrByName(pEntry, currMod->attr.type.lberbv.bv_val); if (attr == NULL) // New attribute case { currMod->operation = MOD_OP_ADD; continue; // re-process the current altered modification } else // Real replace attribute values case { // If DN is being modified, may need to re-parent if (VmDirStringCompareA(attr->type.lberbv.bv_val, ATTR_DN, FALSE) == 0) { if (pbDnModified) { *pbDnModified = TRUE; } retVal = GenerateNewParent(pEntry, &(currMod->attr)); BAIL_ON_VMDIR_ERROR(retVal); } // Setup Delete attribute and Add attribute mods. Change currMod->operation to ADD, and // insert a DELETE mod for this attribute before this mod. currMod->operation = MOD_OP_ADD; retVal = VmDirAllocateMemory(sizeof(VDIR_MODIFICATION), (PVOID *)&newDelMod); BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, (pszLocalErrorMsg), "no memory"); newDelMod->operation = MOD_OP_DELETE; newDelMod->attr.pATDesc = currMod->attr.pATDesc; newDelMod->attr.type.lberbv.bv_val = currMod->attr.type.lberbv.bv_val; newDelMod->attr.type.lberbv.bv_len = currMod->attr.type.lberbv.bv_len; newDelMod->next = currMod; currMod = newDelMod; if (prevMod == NULL) { modReq->mods = currMod; } else { prevMod->next = currMod; } continue; } } break; } default: assert(FALSE); } } cleanup: if (ppszErrorMsg) { *ppszErrorMsg = pszLocalErrorMsg; } else { VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg); } return retVal; error: goto cleanup; }