static DWORD _VmGetHighestCommittedUSN( PSTR* ppszHighestCommittedUSN ) { DWORD dwError = 0; USN usn = 0; USN nextUSN = 0; VDIR_ENTRY_ARRAY entryArray = {0}; PSTR pszUSN = NULL; VDIR_BACKEND_CTX beCtx = {0}; beCtx.pBE = VmDirBackendSelect(NULL); assert(beCtx.pBE); dwError = beCtx.pBE->pfnBEGetNextUSN(&beCtx, &nextUSN); BAIL_ON_VMDIR_ERROR(dwError); for (usn=nextUSN; usn > 1LL; usn--) { VMDIR_SAFE_FREE_MEMORY(pszUSN); VmDirFreeEntryArrayContent(&entryArray); dwError = VmDirAllocateStringPrintf(&pszUSN, "%" PRId64, usn); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirSimpleEqualFilterInternalSearch( "", LDAP_SCOPE_SUBTREE, ATTR_USN_CHANGED, pszUSN, &entryArray); BAIL_ON_VMDIR_ERROR(dwError); if (entryArray.iSize == 1 ) { break; } } if (usn == 0) { BAIL_WITH_VMDIR_ERROR(dwError, VMDIR_ERROR_INVALID_STATE); } *ppszHighestCommittedUSN = pszUSN; pszUSN = NULL; cleanup: VMDIR_SAFE_FREE_MEMORY(pszUSN); VmDirFreeEntryArrayContent(&entryArray); VmDirBackendCtxContentFree(&beCtx); return dwError; error: VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "error (%u), start USN %" PRId64, dwError, nextUSN); goto cleanup; }
static int _VmGetHighestCommittedUSN( USN startUsn, USN *hcUsn) { DWORD dwError = 0; USN usn = 0; VDIR_ENTRY_ARRAY entryArray = {0}; PSTR usnStr = NULL; for (usn=startUsn; usn > 1LL; usn--) { VMDIR_SAFE_FREE_MEMORY(usnStr); VmDirFreeEntryArrayContent(&entryArray); dwError = VmDirAllocateStringPrintf(&usnStr, "%" PRId64, usn); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirSimpleEqualFilterInternalSearch( "", LDAP_SCOPE_SUBTREE, ATTR_USN_CHANGED, usnStr, &entryArray); BAIL_ON_VMDIR_ERROR(dwError); if (entryArray.iSize == 1 ) { *hcUsn = usn; goto cleanup; } } dwError = LDAP_OPERATIONS_ERROR; goto error; cleanup: VMDIR_SAFE_FREE_MEMORY(usnStr); VmDirFreeEntryArrayContent(&entryArray); return dwError; error: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "_VmGetHighestCommittedUSN: fail to find an entry with USN <= %" PRId64, startUsn); goto cleanup; }
void VmDirFreeEntryArray( PVDIR_ENTRY_ARRAY pEntryAry ) { if (pEntryAry) { VmDirFreeEntryArrayContent(pEntryAry); VMDIR_SAFE_FREE_MEMORY(pEntryAry); } }
void VmDirFreeOperationContent( PVDIR_OPERATION op ) { DWORD dwError = ERROR_SUCCESS; if (op) { if (op->pSchemaCtx) { VmDirSchemaCtxRelease(op->pSchemaCtx); } if (op->syncDoneCtrl) { PLW_HASHTABLE_NODE pNode = NULL; LW_HASHTABLE_ITER iter = LW_HASHTABLE_ITER_INIT; UptoDateVectorEntry * pUtdVectorEntry = NULL; SyncDoneControlValue * syncDoneCtrlVal = &op->syncDoneCtrl->value.syncDoneCtrlVal; while ((pNode = LwRtlHashTableIterate(syncDoneCtrlVal->htUtdVector, &iter))) { dwError = LwRtlHashTableRemove(syncDoneCtrlVal->htUtdVector, pNode); assert( dwError == 0 ); pUtdVectorEntry = LW_STRUCT_FROM_FIELD(pNode, UptoDateVectorEntry, Node); VmDirFreeBervalContent( &pUtdVectorEntry->invocationId ); VMDIR_SAFE_FREE_MEMORY( pUtdVectorEntry ); } LwRtlFreeHashTable(&syncDoneCtrlVal->htUtdVector); assert( syncDoneCtrlVal->htUtdVector == NULL ); VMDIR_SAFE_FREE_MEMORY( op->syncDoneCtrl ); } if (op->pCondWriteCtrl) { VMDIR_SAFE_FREE_MEMORY(op->pCondWriteCtrl->value.condWriteCtrlVal.pszFilter); } if (op->reqControls) { DeleteControls(&(op->reqControls)); } switch (op->reqCode) { case LDAP_REQ_BIND: VmDirFreeBindRequest(&op->request.bindReq, FALSE); if (op->ldapResult.replyInfo.type == REP_SASL) { VmDirFreeBervalContent( &(op->ldapResult.replyInfo.replyData.bvSaslReply) ); } break; case LDAP_REQ_ADD: VmDirFreeAddRequest(&op->request.addReq, FALSE); break; case LDAP_REQ_SEARCH: VmDirFreeSearchRequest(&op->request.searchReq, FALSE); break; case LDAP_REQ_MODIFY: case LDAP_REQ_MODDN: VmDirFreeModifyRequest(&op->request.modifyReq, FALSE); break; case LDAP_REQ_DELETE: VmDirFreeDeleteRequest(&op->request.deleteReq, FALSE); if (op->request.modifyReq.numMods > 0) { //A raft follower needs to create a modifyReq for Delete OP VmDirFreeModifyRequest(&op->request.modifyReq, FALSE); } break; default: break; } VmDirFreeEntryArrayContent(&(op->internalSearchEntryArray)); VmDirFreeBervalContent( &(op->reqDn) ); VMDIR_SAFE_FREE_MEMORY(op->ldapResult.pszErrMsg); VmDirBackendCtxFree(op->pBECtx); VMDIR_SAFE_FREE_MEMORY(op->pszFilters); if ( op->opType == VDIR_OPERATION_TYPE_INTERNAL ) { // internal op owns dummy conn for ACL check VmDirDeleteConnection( &(op->conn)); // passing &conn to be freed seems a bit strange } } }
/* * Set vmwPasswordNeverExpires (if it doesn't have a value) to TRUE * on the domain administrator's account. */ DWORD VmDirSetAdministratorPasswordNeverExpires( VOID ) { DWORD dwError = 0; PCSTR pszDomainDn = NULL; const CHAR szAdministrator[] = "cn=Administrator,cn=Users"; const CHAR szTrue[] = "TRUE"; PSTR pszAdministratorDn = NULL; VDIR_OPERATION op = {0}; PSTR pszLocalErrMsg = NULL; VDIR_ENTRY_ARRAY entryArray = {0}; PVDIR_ENTRY pEntry = NULL; VDIR_BERVALUE bervBlob = VDIR_BERVALUE_INIT; pszDomainDn = gVmdirServerGlobals.systemDomainDN.lberbv.bv_val; if (pszDomainDn == NULL) { dwError = ERROR_INVALID_STATE; BAIL_ON_VMDIR_ERROR(dwError); } dwError = VmDirAllocateStringPrintf(&pszAdministratorDn, "%s,%s", szAdministrator, pszDomainDn); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirSimpleEqualFilterInternalSearch( pszDomainDn, LDAP_SCOPE_SUBTREE, ATTR_DN, pszAdministratorDn, &entryArray); BAIL_ON_VMDIR_ERROR(dwError); if (entryArray.iSize != 1) { dwError = VMDIR_ERROR_DATA_CONSTRAINT_VIOLATION; BAIL_ON_VMDIR_ERROR(dwError); } pEntry = &(entryArray.pEntry[0]); 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, "VmDirSetAdministratorPasswordNeverExpire: 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; bervBlob.lberbv.bv_val = (PSTR) szTrue; bervBlob.lberbv.bv_len = strlen(szTrue); dwError = VmDirAppendAMod( &op, MOD_OP_REPLACE, ATTR_PASSWORD_NEVER_EXPIRES, ATTR_PASSWORD_NEVER_EXPIRES_LEN, bervBlob.lberbv_val, bervBlob.lberbv_len); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirInternalModifyEntry(&op); BAIL_ON_VMDIR_ERROR(dwError); cleanup: VmDirFreeEntryArrayContent(&entryArray); VmDirFreeOperationContent(&op); VMDIR_SAFE_FREE_STRINGA(pszAdministratorDn); return dwError; error: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "VmDirSetAdministratorPasswordNeverExpires failed, (%u)", dwError); 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; }
static DWORD ProcessPreValidatedEntries( PVDIR_OPERATION pOperation, DWORD dwEntryCount, ENTRYID *pValidatedEntries ) { DWORD i = 0; DWORD dwError = 0; DWORD dwSentEntries = 0; BOOLEAN bInternalSearch = FALSE; BOOLEAN bStoreRsltInMem = FALSE; VDIR_ENTRY srEntry = {0}; PVDIR_ENTRY pSrEntry = NULL; if (dwEntryCount == 0) { goto cleanup; } bInternalSearch = pOperation->opType == VDIR_OPERATION_TYPE_INTERNAL; bStoreRsltInMem = pOperation->request.searchReq.bStoreRsltInMem; if (bInternalSearch || bStoreRsltInMem) { VmDirFreeEntryArrayContent(&pOperation->internalSearchEntryArray); dwError = VmDirAllocateMemory( sizeof(VDIR_ENTRY) * (dwEntryCount + 1), (PVOID*)&pOperation->internalSearchEntryArray.pEntry); BAIL_ON_VMDIR_ERROR(dwError); } for (; i < dwEntryCount; ++i) { pSrEntry = bInternalSearch || bStoreRsltInMem ? (pOperation->internalSearchEntryArray.pEntry + pOperation->internalSearchEntryArray.iSize) : &srEntry; dwError = pOperation->pBEIF->pfnBESimpleIdToEntry( pValidatedEntries[i], pSrEntry); if (dwError != 0) { // Ignore errors resolving ENTRYIDs. VMDIR_LOG_WARNING( VMDIR_LOG_MASK_ALL, "%s pfnBESimpleIdToEntry EID(%u), error (%u)", __FUNCTION__, pValidatedEntries[i], dwError); continue; } dwError = VmDirBuildComputedAttribute(pOperation, pSrEntry); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirSendSearchEntry(pOperation, pSrEntry); if (dwError == VMDIR_ERROR_INSUFFICIENT_ACCESS) { VMDIR_LOG_WARNING( VMDIR_LOG_MASK_ALL, "Access deny on search entry result [%s,%d] (bindedDN-%s) (targetDn-%s)", __FILE__, __LINE__, pOperation->conn->AccessInfo.pszBindedDn, pSrEntry->dn.lberbv.bv_val); // make sure search continues dwError = 0; } BAIL_ON_VMDIR_ERROR(dwError); if (pSrEntry->bSearchEntrySent) { dwSentEntries++; if (bInternalSearch || bStoreRsltInMem) { pOperation->internalSearchEntryArray.iSize++; pSrEntry = NULL; // EntryArray takes over *pSrEntry content } } VmDirFreeEntryContent(pSrEntry); pSrEntry = NULL; } dwError = SetPagedSearchCookie( pOperation, pValidatedEntries[dwEntryCount - 1], 0); BAIL_ON_VMDIR_ERROR(dwError); cleanup: pOperation->dwSentEntries = dwSentEntries; VmDirFreeEntryContent(pSrEntry); return dwError; error: goto cleanup; }
/* * Searches the direct group entry to confirm membership * Set pAccessRoleBitmap based on getAccessInfo to avoid redundent internal search. */ DWORD VmDirIsDirectMemberOf( PSTR pszBindDN, UINT32 getAccessInfo, UINT32 *pAccessRoleBitmap, PBOOLEAN pbIsMemberOf ) { DWORD dwError = 0; BOOLEAN bIsMemberOf = FALSE; VDIR_ENTRY_ARRAY entryResultArray = {0}; PSTR pszGroupDN = NULL; if (!pbIsMemberOf || !pAccessRoleBitmap) { dwError = VMDIR_ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } if (getAccessInfo == VDIR_ACCESS_DCGROUP_MEMBER_INFO) { if (*pAccessRoleBitmap & VDIR_ACCESS_DCGROUP_MEMBER_VALID_INFO) { *pbIsMemberOf = (*pAccessRoleBitmap & VDIR_ACCESS_IS_DCGROUP_MEMBER) != 0; goto cleanup; } pszGroupDN = gVmdirServerGlobals.bvDCGroupDN.lberbv_val; } else if (getAccessInfo == VDIR_ACCESS_DCCLIENT_GROUP_MEMBER_INFO) { if (*pAccessRoleBitmap & VDIR_ACCESS_DCCLIENT_GROUP_MEMBER_VALID_INFO) { *pbIsMemberOf = (*pAccessRoleBitmap & VDIR_ACCESS_IS_DCCLIENT_GROUP_MEMBER) != 0; goto cleanup; } pszGroupDN = gVmdirServerGlobals.bvDCClientGroupDN.lberbv_val; } else { dwError = VMDIR_ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } if (pszGroupDN == NULL || pszBindDN == NULL) { *pbIsMemberOf = FALSE; goto cleanup; } VMDIR_LOG_VERBOSE(VMDIR_LOG_MASK_ALL, "VmDirIsDirectMemberOf: internal search for dn %s op %d", pszBindDN, getAccessInfo); dwError = VmDirSimpleEqualFilterInternalSearch( pszGroupDN, LDAP_SCOPE_BASE, ATTR_MEMBER, pszBindDN, &entryResultArray); BAIL_ON_VMDIR_ERROR(dwError); if ( entryResultArray.iSize > 0) { bIsMemberOf = TRUE; } if (getAccessInfo == VDIR_ACCESS_DCGROUP_MEMBER_INFO) { *pAccessRoleBitmap |= VDIR_ACCESS_DCGROUP_MEMBER_VALID_INFO; if (bIsMemberOf) { *pAccessRoleBitmap |= VDIR_ACCESS_IS_DCGROUP_MEMBER; } } else { *pAccessRoleBitmap |= VDIR_ACCESS_DCCLIENT_GROUP_MEMBER_VALID_INFO; if (bIsMemberOf) { *pAccessRoleBitmap |= VDIR_ACCESS_IS_DCCLIENT_GROUP_MEMBER; } } *pbIsMemberOf = bIsMemberOf; cleanup: VmDirFreeEntryArrayContent(&entryResultArray); return dwError; error: *pbIsMemberOf = FALSE; goto cleanup; }
static int VmDirProcessCandidateList( VDIR_OPERATION * pOperation ) { int retVal = LDAP_SUCCESS; int i = 0; VDIR_CANDIDATES * cl = pOperation->request.searchReq.filter->candidates; VDIR_ENTRY srEntry = {0}; VDIR_ENTRY * pSrEntry = NULL; int numSentEntries = 0; BOOLEAN bExternalSearch = FALSE; BOOLEAN bInternalSearch = FALSE; BOOLEAN bStoreRsltInMem = FALSE; BOOLEAN bPageResultsCtrl = FALSE; DWORD dwPageSize = 0; ENTRYID lastEID = 0; /* * If the page size is greater than or equal to the sizeLimit value, * the server should ignore the control as the request can be satisfied in a single page. */ if (pOperation->showPagedResultsCtrl && (pOperation->request.searchReq.sizeLimit == 0 || pOperation->showPagedResultsCtrl->value.pagedResultCtrlVal.pageSize < (DWORD)pOperation->request.searchReq.sizeLimit)) { VmDirLog( LDAP_DEBUG_TRACE, "showPagedResultsCtrl applies to this query." ); bPageResultsCtrl = TRUE; dwPageSize = pOperation->showPagedResultsCtrl->value.pagedResultCtrlVal.pageSize; lastEID = atoll(pOperation->showPagedResultsCtrl->value.pagedResultCtrlVal.cookie); pOperation->showPagedResultsCtrl->value.pagedResultCtrlVal.cookie[0] = '\0'; VmDirSortCandidateList(cl); // sort candidate list if not yet sorted } bExternalSearch = pOperation->opType == VDIR_OPERATION_TYPE_EXTERNAL; bInternalSearch = pOperation->opType == VDIR_OPERATION_TYPE_INTERNAL; bStoreRsltInMem = pOperation->request.searchReq.bStoreRsltInMem; if (cl && cl->size > 0) { if (bInternalSearch || bStoreRsltInMem) { //TODO, we should have a hard limit on the cl->size we handle VmDirFreeEntryArrayContent(&pOperation->internalSearchEntryArray); retVal = VmDirAllocateMemory( sizeof(VDIR_ENTRY) * cl->size, (PVOID*)&pOperation->internalSearchEntryArray.pEntry); BAIL_ON_VMDIR_ERROR(retVal); } for (i = 0, numSentEntries = 0; (i < cl->size) && (pOperation->request.searchReq.sizeLimit == 0 /* unlimited */ || numSentEntries < pOperation->request.searchReq.sizeLimit); i++) { if (bExternalSearch && VmDirdState() == VMDIRD_STATE_SHUTDOWN && pOperation->syncReqCtrl == NULL) { retVal = LDAP_UNAVAILABLE; // stop all external search ops, except replication pull goto cleanup; } if (!gVmdirGlobals.bPagedSearchReadAhead) { //skip entries we sent before in sorted cl->eIds. if (bPageResultsCtrl && cl->eIds[i] <= lastEID) { continue; } } pSrEntry = bInternalSearch || bStoreRsltInMem ? (pOperation->internalSearchEntryArray.pEntry + pOperation->internalSearchEntryArray.iSize) : &srEntry; retVal = pOperation->pBEIF->pfnBEIdToEntry( pOperation->pBECtx, pOperation->pSchemaCtx, cl->eIds[i], pSrEntry, VDIR_BACKEND_ENTRY_LOCK_READ); if (retVal) { // Ignore BdbEIdToEntry errors. VMDIR_LOG_WARNING( VMDIR_LOG_MASK_ALL, "ProcessCandiateList BEIdToEntry EID(%u), error (%u)", cl->eIds[i], retVal); continue; } if (CheckIfEntryPassesFilter(pOperation, pSrEntry, pOperation->request.searchReq.filter) == FILTER_RES_TRUE) { BOOLEAN bSendEntry = TRUE; CHAR sha1Digest[SHA_DIGEST_LENGTH] = {0}; retVal = VmDirBuildComputedAttribute( pOperation, pSrEntry ); BAIL_ON_VMDIR_ERROR( retVal ); if (pOperation->digestCtrl) { retVal = VmDirEntrySHA1Digest(pSrEntry, sha1Digest); BAIL_ON_VMDIR_ERROR(retVal); if (memcmp(sha1Digest, pOperation->digestCtrl->value.digestCtrlVal.sha1Digest, SHA_DIGEST_LENGTH) == 0) { bSendEntry = FALSE; VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL,"%s digest match %s", __FUNCTION__, pSrEntry->dn.lberbv.bv_val); } else { VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL,"%s digest mismatch %s", __FUNCTION__, pSrEntry->dn.lberbv.bv_val); } } if (bSendEntry) { retVal = VmDirSendSearchEntry(pOperation, pSrEntry); if (retVal == VMDIR_ERROR_INSUFFICIENT_ACCESS) { VMDIR_LOG_WARNING( VMDIR_LOG_MASK_ALL, "Access deny on search entry result [%s,%d] (bindedDN-%s) (targetDn-%s)\n", __FILE__, __LINE__, pOperation->conn->AccessInfo.pszBindedDn, pSrEntry->dn.lberbv.bv_val); // make sure search continues retVal = 0; } BAIL_ON_VMDIR_ERROR( retVal ); if (pSrEntry->bSearchEntrySent) { numSentEntries++; if (bInternalSearch || bStoreRsltInMem) { pOperation->internalSearchEntryArray.iSize++; pSrEntry = NULL; // EntryArray takes over *pSrEntry content if (pOperation->internalSearchEntryArray.iSize > gVmdirServerGlobals.dwMaxInternalSearchLimit) { BAIL_WITH_VMDIR_ERROR(retVal, VMDIR_ERROR_INTERNAL_SEARCH_LIMIT); } } } } } //We have sent one page size of entries, so we can break here if (bPageResultsCtrl && numSentEntries == dwPageSize) { retVal = SetPagedSearchCookie(pOperation, cl->eIds[i], i); BAIL_ON_VMDIR_ERROR(retVal); break; } VmDirFreeEntryContent( pSrEntry ); pSrEntry = NULL; // Reset to NULL so that DeleteEntry is no-op. } VMDIR_LOG_VERBOSE( LDAP_DEBUG_FILTER, "(%d) candiates processed and (%d) entries sent", cl->size, numSentEntries); } if ( pOperation->request.searchReq.sizeLimit && numSentEntries < pOperation->request.searchReq.sizeLimit && pOperation->pBECtx->iPartialCandidates) { retVal = LDAP_UNWILLING_TO_PERFORM; VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "ProcessCandiateList may return none or paritial requested entries with sizelimit %d", pOperation->request.searchReq.sizeLimit); } #ifndef REPLICATION_V2 retVal = VmDirUpdateSyncDoneCtl( pOperation, numSentEntries); BAIL_ON_VMDIR_ERROR(retVal); #endif cleanup: pOperation->dwSentEntries = numSentEntries; VmDirFreeEntryContent(pSrEntry); return retVal; error: VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "ProcessCandiateList failed. (%u)", retVal); 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; }
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; }
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; }
static int ProcessCandidateList( VDIR_OPERATION * pOperation ) { int retVal = LDAP_SUCCESS; int i = 0; VDIR_CANDIDATES * cl = pOperation->request.searchReq.filter->candidates; VDIR_ENTRY srEntry = {0}; VDIR_ENTRY * pSrEntry = NULL; int numSentEntries = 0; BOOLEAN bInternalSearch = FALSE; BOOLEAN bPageResultsCtrl = FALSE; DWORD dwPageSize = 0; ENTRYID lastEID = 0; /* * If the page size is greater than or equal to the sizeLimit value, * the server should ignore the control as the request can be satisfied in a single page. */ if (pOperation->showPagedResultsCtrl && (pOperation->request.searchReq.sizeLimit == 0 || pOperation->showPagedResultsCtrl->value.pagedResultCtrlVal.pageSize < (DWORD)pOperation->request.searchReq.sizeLimit)) { VmDirLog( LDAP_DEBUG_TRACE, "showPagedResultsCtrl applies to this query." ); bPageResultsCtrl = TRUE; dwPageSize = pOperation->showPagedResultsCtrl->value.pagedResultCtrlVal.pageSize; lastEID = atoi(pOperation->showPagedResultsCtrl->value.pagedResultCtrlVal.cookie); pOperation->showPagedResultsCtrl->value.pagedResultCtrlVal.cookie[0] = '\0'; } if (cl && cl->size > 0) { if (pOperation->opType == VDIR_OPERATION_TYPE_INTERNAL) { //TODO, we should have a hard limit on the cl->size we handle bInternalSearch = TRUE; VmDirFreeEntryArrayContent(&pOperation->internalSearchEntryArray); retVal = VmDirAllocateMemory( sizeof(VDIR_ENTRY) * cl->size, (PVOID*)&pOperation->internalSearchEntryArray.pEntry); BAIL_ON_VMDIR_ERROR(retVal); } for (i = 0, numSentEntries = 0; (i < cl->size) && VmDirdState() != VMDIRD_STATE_SHUTDOWN && (pOperation->request.searchReq.sizeLimit == 0 /* unlimited */ || numSentEntries < pOperation->request.searchReq.sizeLimit); i++) { //skip entries we sent before if (bPageResultsCtrl && lastEID > 0) { if (cl->eIds[i] == lastEID) { lastEID = 0; } continue; } VMDIR_LOG_DEBUG( LDAP_DEBUG_FILTER, "ProcessCandidateList EID(%u)", cl->eIds[i]); pSrEntry = bInternalSearch ? (pOperation->internalSearchEntryArray.pEntry + pOperation->internalSearchEntryArray.iSize) : &srEntry; retVal = pOperation->pBEIF->pfnBEIdToEntry( pOperation->pBECtx, pOperation->pSchemaCtx, cl->eIds[i], pSrEntry, VDIR_BACKEND_ENTRY_LOCK_READ); if (retVal == 0) { if (CheckIfEntryPassesFilter( pOperation, pSrEntry, pOperation->request.searchReq.filter) == FILTER_RES_TRUE) { retVal = VmDirBuildComputedAttribute( pOperation, pSrEntry ); BAIL_ON_VMDIR_ERROR( retVal ); if (bInternalSearch) { pOperation->internalSearchEntryArray.iSize++; pSrEntry = NULL; // EntryArray takes over *pSrEntry content } else { retVal = VmDirSendSearchEntry( pOperation, pSrEntry ); if (retVal == VMDIR_ERROR_INSUFFICIENT_ACCESS) { VMDIR_LOG_WARNING( VMDIR_LOG_MASK_ALL, "Access deny on search entry result [%s,%d] (bindedDN-%s) (targetDn-%s)\n", __FILE__, __LINE__, pOperation->conn->AccessInfo.pszBindedDn, pSrEntry->dn.lberbv.bv_val); // make sure search continues retVal = 0; } BAIL_ON_VMDIR_ERROR( retVal ); if (pSrEntry->bSearchEntrySent) { numSentEntries++; } } } //We have sent one page size of entries, so we can break here if (bPageResultsCtrl && numSentEntries == dwPageSize){ retVal = VmDirStringPrintFA( pOperation->showPagedResultsCtrl->value.pagedResultCtrlVal.cookie, VMDIR_MAX_I64_ASCII_STR_LEN, "%u", pSrEntry->eId); BAIL_ON_VMDIR_ERROR( retVal ); break; } VmDirFreeEntryContent( pSrEntry ); pSrEntry = NULL; // Reset to NULL so that DeleteEntry is no-op. } else { // Ignore BdbEIdToEntry errors. VMDIR_LOG_WARNING( VMDIR_LOG_MASK_ALL, "ProcessCandiateList BEIdToEntry EID(%u), error (%u)", cl->eIds[i], retVal); retVal = 0; } } VMDIR_LOG_VERBOSE( LDAP_DEBUG_FILTER, "(%d) candiates processed and (%d) entries sent", cl->size, numSentEntries); } if ( pOperation->request.searchReq.sizeLimit && numSentEntries < pOperation->request.searchReq.sizeLimit && pOperation->pBECtx->iPartialCandidates) { retVal = LDAP_UNWILLING_TO_PERFORM; VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "ProcessCandiateList may return none or paritial requested entries with sizelimit %d", pOperation->request.searchReq.sizeLimit); } cleanup: pOperation->dwSentEntries = numSentEntries; VmDirFreeEntryContent( pSrEntry ); return retVal; error: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "ProcessCandiateList failed. (%u)", retVal); goto cleanup; }