/* * reorder value of objectclass in pOCAttr->vals * 1. structureOC->parentOC->parentOC->....->TOP(not included) * expand parent objectclass if not supplied. * 2. aux OCs * We then store its values in this order in backend. */ static DWORD _VmDirSchemaReorderObjectClassAttr( PVDIR_ATTRIBUTE pOCAttr, PVDIR_SCHEMA_OC_DESC pStructureOCDesc, PVDIR_SCHEMA_OC_DESC* ppAuxOCDesc) { DWORD dwError = 0; int iCnt = 0; int iAUXCnt = 0; int iTotal = 0; PVDIR_BERVALUE pBerv = NULL; PVDIR_SCHEMA_OC_DESC pLocalDesc = pStructureOCDesc; if ( !pOCAttr || !pStructureOCDesc ) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } // number of structure objectclass (except top) for (iCnt = 0; pLocalDesc != NULL; pLocalDesc = pLocalDesc->pStructSupOC, iCnt++) {} // number of aux objectclass for (iAUXCnt = 0; ppAuxOCDesc && ppAuxOCDesc[iAUXCnt] != NULL; iAUXCnt++) {}; iTotal = iCnt + iAUXCnt; dwError = VmDirAllocateMemory( sizeof(VDIR_BERVALUE) * (iTotal + 1), (PVOID*)&pBerv); BAIL_ON_VMDIR_ERROR(dwError); // start with leaf structure objectclass and walk up the tree to top (NOT included) for (iCnt = 0, pLocalDesc = pStructureOCDesc; pLocalDesc != NULL; pLocalDesc = pLocalDesc->pStructSupOC, iCnt++) { PCSTR pszOrgName = NULL; unsigned int iTmp = 0; for (iTmp = 0; iTmp < pOCAttr->numVals; iTmp++) { if (VmDirStringCompareA( pLocalDesc->pszName, pOCAttr->vals[iTmp].lberbv_val, FALSE) == 0) { // keep whatever value provided from clients pszOrgName = pOCAttr->vals[iTmp].lberbv_val; break; } } dwError = VmDirAllocateStringA( pszOrgName ? pszOrgName : pLocalDesc->pszName, &(pBerv[iCnt].lberbv_val) ); BAIL_ON_VMDIR_ERROR(dwError); pBerv[iCnt].lberbv_len = VmDirStringLenA(pBerv[iCnt].lberbv_val); pBerv[iCnt].bOwnBvVal = TRUE; // TODO, Do we need to normalize value here? } // append aux objectclasses after structure objectclasses for (iAUXCnt = 0; ppAuxOCDesc && ppAuxOCDesc[iAUXCnt] != NULL; iAUXCnt++, iCnt++) { PCSTR pszOrgName = NULL; unsigned int iTmp = 0; for (iTmp = 0; iTmp < pOCAttr->numVals; iTmp++) { if (VmDirStringCompareA( ppAuxOCDesc[iAUXCnt]->pszName, pOCAttr->vals[iTmp].lberbv_val, FALSE) == 0) { // keep whatever value provided from clients pszOrgName = pOCAttr->vals[iTmp].lberbv_val; break; } } dwError = VmDirAllocateStringA( pszOrgName ? pszOrgName : ppAuxOCDesc[iAUXCnt]->pszName, &(pBerv[iCnt].lberbv_val) ); BAIL_ON_VMDIR_ERROR(dwError); pBerv[iCnt].lberbv_len = VmDirStringLenA(pBerv[iCnt].lberbv_val); pBerv[iCnt].bOwnBvVal = TRUE; // TODO, Do we need to normalize value here? } VmDirFreeBervalArrayContent( pOCAttr->vals, pOCAttr->numVals ); VMDIR_SAFE_FREE_MEMORY( pOCAttr->vals ); pOCAttr->vals = pBerv; pOCAttr->numVals = iTotal; cleanup: return dwError; error: VmDirFreeBervalArrayContent( pBerv, iTotal ); VMDIR_SAFE_FREE_MEMORY( pBerv ); goto cleanup; }
/* * read one schema element definition from file and normalize its definition. */ static DWORD _VmDirReadOneDefFromFile( FILE* fp, PVMDIR_STRING_LIST pStrList ) { DWORD dwError = 0; size_t iSize = VMDIR_SIZE_9216, iLen = 0; CHAR pDescBuf[VMDIR_SIZE_9216+1] = {0}; CHAR pbuf[VMDIR_SIZE_4096] = {0}; PCSTR pPrefix = "( "; size_t iPrefixLen = VmDirStringLenA(pPrefix); PSTR pOut = NULL; dwError = VmDirStringNCatA( pDescBuf+iLen, iSize-iLen, pPrefix, iPrefixLen); BAIL_ON_VMDIR_ERROR(dwError); iLen += iPrefixLen; while (fgets(pbuf, sizeof(pbuf), fp) != NULL) { size_t len = VmDirStringLenA(pbuf) - 1; if (pbuf[len] == '\n') { pbuf[len] = '\0'; } if ( pbuf[0] == '#') { continue; } if ( pbuf[0] == ' ') { dwError = VmDirStringNCatA( pDescBuf+iLen, iSize-iLen, pbuf, VmDirStringLenA(pbuf)); BAIL_ON_VMDIR_ERROR(dwError); iLen += VmDirStringLenA(pbuf); } else { break; } } if (pDescBuf[0] != '\0') { VmdDirNormalizeString(pDescBuf); dwError = VmDirAllocateStringA(pDescBuf, &pOut); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirStringListAdd(pStrList, pOut); BAIL_ON_VMDIR_ERROR(dwError); pOut = NULL; } cleanup: return dwError; error: VMDIR_SAFE_FREE_MEMORY(pOut); goto cleanup; }
/* * Create a new schema cache via pEntry, then active this cache. */ DWORD VmDirSchemaInitializeViaEntry( PVDIR_ENTRY pEntry ) { BOOLEAN bLoadOk = TRUE; BOOLEAN bInLock = FALSE; DWORD dwError = 0; PVDIR_SCHEMA_CTX pLiveCtx = NULL; PVDIR_SCHEMA_INSTANCE pInstance = NULL; PVDIR_SCHEMA_INSTANCE pLiveInstance = NULL; VMDIR_LOCK_MUTEX(bInLock, gVdirSchemaGlobals.mutex); // get reference to current schema, to clean up later pLiveInstance = gVdirSchemaGlobals.pSchema; pLiveCtx = gVdirSchemaGlobals.pCtx; // instantiate a schema cache - pInstance dwError = VdirSchemaInstanceInitViaEntry( pEntry, &pInstance); BAIL_ON_VMDIR_ERROR(dwError); gVdirSchemaGlobals.pSchema = pInstance; dwError = VdirSchemaCtxAcquireInLock(TRUE, &gVdirSchemaGlobals.pCtx); // add self reference BAIL_ON_VMDIR_ERROR(dwError); assert(gVdirSchemaGlobals.pCtx); VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "Startup schema instance (%p)", gVdirSchemaGlobals.pSchema); VMDIR_UNLOCK_MUTEX(bInLock, gVdirSchemaGlobals.mutex); cleanup: if (bLoadOk) { VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL, "Schema - AttributeTypes:(size=%d, nextid=%d) Objectclasses:(size=%d)", pEntry->pSchemaCtx->pSchema->ats.usNumATs, pEntry->pSchemaCtx->pSchema->ats.usNextId, pEntry->pSchemaCtx->pSchema->ocs.usNumOCs); } VMDIR_UNLOCK_MUTEX(bInLock, gVdirSchemaGlobals.mutex); if (pLiveCtx) { VmDirSchemaCtxRelease(pLiveCtx); } return dwError; error: if (pInstance) { VdirSchemaInstanceFree(pInstance); } gVdirSchemaGlobals.pSchema = pLiveInstance; gVdirSchemaGlobals.pCtx = pLiveCtx; pLiveCtx = NULL; bLoadOk = FALSE; goto cleanup; }
DWORD VmDirLocalAPIHandler( PVM_DIR_SECURITY_CONTEXT pSecurityContext, PBYTE pRequest, DWORD dwRequestSize, PBYTE * ppResponse, DWORD * pdwResponseSize ) { DWORD dwError = 0; UINT32 uApiType = 0; PBYTE pResponse = NULL; DWORD dwResponseSize = 0; if (dwRequestSize < sizeof(UINT32)) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR (dwError); } if (!pSecurityContext) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR (dwError); } uApiType = *((PUINT32)pRequest); switch(uApiType) { case VMDIR_IPC_INITIALIZE_HOST: dwError = VmDirIpcInitializeHost( pSecurityContext, pRequest, dwRequestSize, &pResponse, &dwResponseSize ); break; case VMDIR_IPC_INITIALIZE_TENANT: dwError = VmDirIpcInitializeTenant( pSecurityContext, pRequest, dwRequestSize, &pResponse, &dwResponseSize ); break; case VMDIR_IPC_FORCE_RESET_PASSWORD: dwError = VmDirIpcForceResetPassword( pSecurityContext, pRequest, dwRequestSize, &pResponse, &dwResponseSize ); break; case VMDIR_IPC_GET_SRP_SECRET: dwError = VmDirIpcGetSRPSecret( pSecurityContext, pRequest, dwRequestSize, &pResponse, &dwResponseSize ); break; case VMDIR_IPC_SET_SRP_SECRET: dwError = VmDirIpcSetSRPSecret( pSecurityContext, pRequest, dwRequestSize, &pResponse, &dwResponseSize ); break; case VMDIR_IPC_GENERATE_PASSWORD: dwError = VmDirIpcGeneratePassword( pSecurityContext, pRequest, dwRequestSize, &pResponse, &dwResponseSize ); break; case VMDIR_IPC_GET_SERVER_STATE: dwError = VmDirIpcGetServerState( pSecurityContext, pRequest, dwRequestSize, &pResponse, &dwResponseSize ); break; default: dwError = ERROR_INVALID_PARAMETER; break; } BAIL_ON_VMDIR_ERROR(dwError); *ppResponse = pResponse; *pdwResponseSize = dwResponseSize; cleanup: return dwError; error: if (ppResponse) { *ppResponse = NULL; } if (pdwResponseSize) { *pdwResponseSize = 0; } if (pResponse) { VMDIR_SAFE_FREE_MEMORY (pResponse); } 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; }
/* * Get the next available USN number. */ DWORD VmDirMDBGetNextUSN( PVDIR_BACKEND_CTX pBECtx, USN * pUsn) { DWORD dwError = 0; PVDIR_DB_TXN pTxn = NULL; PVDIR_DB_TXN pLocalTxn = NULL; VDIR_DB_DBT key = {0}; VDIR_DB_DBT value = {0}; unsigned char USNKeyBytes[sizeof( USN )] = {0}; unsigned char USNValueBytes[sizeof( USN )] = {0}; USN localUSN = 0; BOOLEAN bRevertUSN = FALSE; BOOLEAN bUnsetMaxUSN = TRUE; assert( pBECtx && pUsn ); pTxn = (PVDIR_DB_TXN)pBECtx->pBEPrivate; if (pTxn) { pLocalTxn = pTxn; } else { dwError = mdb_txn_begin( gVdirMdbGlobals.mdbEnv, BE_DB_PARENT_TXN_NULL, BE_DB_FLAGS_ZERO, &pLocalTxn ); BAIL_ON_VMDIR_ERROR(dwError); } key.mv_data = &USNKeyBytes[0]; MDBEntryIdToDBT(BE_MDB_USN_SEQ_KEY, &key); dwError = mdb_get(pLocalTxn, gVdirMdbGlobals.mdbSeqDBi, &key, &value); BAIL_ON_VMDIR_ERROR(dwError); assert( value.mv_size == sizeof(USN) ); localUSN = *((USN*)value.mv_data); *((USN*)&USNValueBytes[0]) = localUSN + 1; value.mv_size = sizeof(USN); value.mv_data = &USNValueBytes[0]; dwError = mdb_put(pLocalTxn, gVdirMdbGlobals.mdbSeqDBi, &key, &value, BE_DB_FLAGS_ZERO); BAIL_ON_VMDIR_ERROR(dwError); if (pBECtx->wTxnUSN == 0) { // capture and set outstanding USN within txn scope pBECtx->wTxnUSN = localUSN; dwError = VmDirBackendAddOutstandingUSN( pBECtx ); BAIL_ON_VMDIR_ERROR(dwError); bRevertUSN = TRUE; } else { // if BECtx has wTxnUSN already (nested txn), it should be smaller than new USN here. if (pBECtx->wTxnUSN >= localUSN) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "nested OP/TXN USN ordering logic error: (%ld)(%ld)", pBECtx->wTxnUSN, localUSN ); dwError = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR(dwError); } VmDirBackendSetMaxOutstandingUSN(pBECtx, localUSN); bUnsetMaxUSN = TRUE; } if (pLocalTxn != pTxn) { dwError = mdb_txn_commit(pLocalTxn); pLocalTxn = NULL; BAIL_ON_VMDIR_ERROR(dwError); } *pUsn = localUSN; cleanup: return dwError; error: if (bUnsetMaxUSN) { VmDirBackendSetMaxOutstandingUSN(pBECtx, localUSN - 1); } if (bRevertUSN) { VmDirBackendRemoveOutstandingUSN( pBECtx ); pBECtx->wTxnUSN = 0; } if (pLocalTxn && pLocalTxn != pTxn) { mdb_txn_abort(pLocalTxn); } VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "VmDirMDBGetNextUSN: failed with error (%d),(%s)", dwError, mdb_strerror(dwError) ); dwError = MDBToBackendError(dwError, 0, ERROR_BACKEND_ERROR, pBECtx, "GetNextUSN"); goto cleanup; }
/* MdbEIdToEntry: For a given entry ID, reads an entry from the entry DB. * * Returns: BE error - BACKEND_ERROR, BACKEND OPERATIONS, BACKEND_ENTRY_NOTFOUND * */ DWORD VmDirMDBEIdToEntry( PVDIR_BACKEND_CTX pBECtx, PVDIR_SCHEMA_CTX pSchemaCtx, ENTRYID eId, PVDIR_ENTRY pEntry, VDIR_BACKEND_ENTRY_LOCKTYPE entryLockType) { DWORD dwError = 0; VDIR_DB mdbDBi = 0; PVDIR_DB_TXN pTxn = NULL; VDIR_DB_DBT key = {0}; VDIR_DB_DBT value = {0}; unsigned char eIdBytes[sizeof( ENTRYID )] = {0}; unsigned char* pszBlob = NULL; assert(pBECtx && pBECtx->pBEPrivate && pSchemaCtx && pEntry); pTxn = (PVDIR_DB_TXN)pBECtx->pBEPrivate; mdbDBi = gVdirMdbGlobals.mdbEntryDB.pMdbDataFiles[0].mdbDBi; // Set key key.mv_data = &eIdBytes[0]; MDBEntryIdToDBT(eId, &key); if ((dwError = mdb_get(pTxn, mdbDBi, &key, &value) ) != 0) { dwError = MDBToBackendError(dwError, MDB_NOTFOUND, ERROR_BACKEND_ENTRY_NOTFOUND, pBECtx, "EIDToEntry"); BAIL_ON_VMDIR_ERROR( dwError ); } if ((dwError = VmDirAllocateMemory( value.mv_size, (PVOID *)&pszBlob)) != 0) { dwError = ERROR_BACKEND_OPERATIONS; BAIL_ON_VMDIR_ERROR( dwError ); } if ((dwError = VmDirCopyMemory(pszBlob, value.mv_size, value.mv_data, value.mv_size)) != 0) { dwError = ERROR_BACKEND_OPERATIONS; BAIL_ON_VMDIR_ERROR( dwError ); } // encodedEntry takes over pszBlob pEntry->encodedEntry = pszBlob; pszBlob = NULL; pEntry->eId = eId; dwError = VmDirDecodeEntry(pSchemaCtx, pEntry ); BAIL_ON_VMDIR_ERROR(dwError); cleanup: return dwError; error: VMDIR_LOG_ERROR( LDAP_DEBUG_BACKEND, "VmDirMDBEIdToEntry, eid(%u) failed (%u)", eId, dwError); VMDIR_SAFE_FREE_MEMORY(pszBlob); VmDirFreeEntryContent( pEntry ); VMDIR_SET_BACKEND_ERROR(dwError); // if dwError no in BE space, set to ERROR_BACKEND_ERROR goto cleanup; }
DWORD VmDirSASLSRPBindExt1( LDAP** ppLd, PCSTR pszURI, PCSTR pszUPN, PCSTR pszPass, int iTimeout ) { DWORD dwError = 0; int retVal = 0; PSTR pszLowerCaseUPN = NULL; LDAP* pLd = NULL; const int ldapVer = LDAP_VERSION3; const int iSaslNoCanon = 1; VMDIR_SASL_INTERACTIVE_DEFAULT srpDefault = {0}; int iCnt = 0; struct timeval optTimeout={0}; optTimeout.tv_usec = 0; optTimeout.tv_sec = iTimeout; if ( ppLd == NULL || pszURI == NULL || pszUPN == NULL || pszPass == NULL ) { dwError = VMDIR_ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } dwError = VmDirAllocASCIIUpperToLower( pszUPN, &pszLowerCaseUPN ); BAIL_ON_VMDIR_ERROR(dwError); srpDefault.pszAuthName = pszLowerCaseUPN; srpDefault.pszPass = pszPass; for (iCnt=0; iCnt<2; iCnt++) { retVal = ldap_initialize( &pLd, pszURI); BAIL_ON_SIMPLE_LDAP_ERROR(retVal); retVal = ldap_set_option(pLd, LDAP_OPT_PROTOCOL_VERSION, &ldapVer); BAIL_ON_SIMPLE_LDAP_ERROR(retVal); // turn off SASL hostname canonicalization for SRP mech retVal = ldap_set_option(pLd, LDAP_OPT_X_SASL_NOCANON, &iSaslNoCanon); BAIL_ON_SIMPLE_LDAP_ERROR(retVal); if (iTimeout > 0) { // timeout connect retVal = ldap_set_option(pLd, LDAP_OPT_NETWORK_TIMEOUT, (void *)&optTimeout); BAIL_ON_SIMPLE_LDAP_ERROR(retVal); } retVal = ldap_sasl_interactive_bind_s( pLd, NULL, "SRP", NULL, NULL, LDAP_SASL_QUIET, _VmDirSASLSRPInteraction, &srpDefault); if (retVal == LDAP_SERVER_DOWN || retVal == LDAP_TIMEOUT) { VmDirSleep(50); // pause 50 ms if ( pLd ) { ldap_unbind_ext_s(pLd, NULL, NULL); pLd = NULL; } continue; // if transient network error, retry once. } else { break; } } BAIL_ON_SIMPLE_LDAP_ERROR(retVal); // bail ldap_sasl_interactive_bind_s failure. *ppLd = pLd; cleanup: VMDIR_SAFE_FREE_MEMORY(pszLowerCaseUPN); return dwError; ldaperror: VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL, "_VmDirSASLSRPBind failed. (%d)(%s)", retVal, ldap_err2string(retVal) ); dwError = VmDirMapLdapError(retVal); error: if (retVal == 0) { VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL, "_VmDirSASLSRPBind failed. (%u)", dwError); } if ( pLd ) { ldap_unbind_ext_s( pLd, NULL, NULL); } goto cleanup; }
/* * Bind to a LDAP server via SSL port. * Require server certificate verification. * * In 5.5. mix mode, replication goes through ldaps port. */ DWORD VmDirSSLBind( LDAP** ppLd, PCSTR pszURI, PCSTR pszDN, PCSTR pszPassword ) { DWORD dwError = 0; int retVal = 0; LDAP* pLd = NULL; BerValue ldapBindPwd = {0}; const int ldapVer = LDAP_VERSION3; int iTLSDEMAND = LDAP_OPT_X_TLS_DEMAND; int iTLSMin = LDAP_OPT_X_TLS_PROTOCOL_TLS1_0; PSTR pszTrustCertFile = NULL; SSL_CTX* pSslCtx = NULL; if ( ppLd == NULL || pszURI == NULL ) { dwError = VMDIR_ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } // only allow ldaps traffic over SSL port if ( VmDirStringNCompareA( pszURI, VMDIR_LDAPS_PROTOCOL, 5, FALSE) != 0 ) { dwError = VMDIR_ERROR_ACCESS_DENIED; BAIL_ON_VMDIR_ERROR(dwError); } dwError = VmDirPrepareOpensslClientCtx( &pSslCtx, &pszTrustCertFile, pszURI ); BAIL_ON_VMDIR_ERROR(dwError); retVal = ldap_set_option( NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &iTLSDEMAND); BAIL_ON_SIMPLE_LDAP_ERROR(retVal); retVal = ldap_set_option(NULL, LDAP_OPT_X_TLS_PROTOCOL_MIN, &iTLSMin); BAIL_ON_SIMPLE_LDAP_ERROR(retVal); retVal = ldap_initialize(&pLd, pszURI); BAIL_ON_SIMPLE_LDAP_ERROR(retVal); retVal = ldap_set_option(pLd, LDAP_OPT_PROTOCOL_VERSION, &ldapVer); BAIL_ON_SIMPLE_LDAP_ERROR(retVal); retVal = ldap_set_option( pLd, LDAP_OPT_X_TLS_CTX, pSslCtx); BAIL_ON_SIMPLE_LDAP_ERROR(retVal); ldapBindPwd.bv_val = 0; ldapBindPwd.bv_len = 0; if (pszPassword) { ldapBindPwd.bv_val = (PSTR) pszPassword; ldapBindPwd.bv_len = (ULONG) VmDirStringLenA(pszPassword); } retVal = ldap_sasl_bind_s( pLd, pszDN, LDAP_SASL_SIMPLE, &ldapBindPwd, // ldaps with credentials NULL, NULL, NULL); BAIL_ON_SIMPLE_LDAP_ERROR(retVal); *ppLd = pLd; cleanup: if (pSslCtx) { SSL_CTX_free(pSslCtx); } VMDIR_SAFE_FREE_MEMORY(pszTrustCertFile); return dwError; ldaperror: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "VmDirSSLBind failed for %s %s. (%d)(%s)", pszURI, pszDN, retVal, ldap_err2string(retVal)); dwError = VmDirMapLdapError(retVal); error: if (retVal == 0) { VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL, "_VmDirSSLBind failed. (%u)", dwError); } if ( pLd ) { ldap_unbind_ext_s( pLd, NULL, NULL); } goto cleanup; }
/* * 1. entry must have one and only one structure object class (from same oc tree) * 2. auxiliary object class content rule compliance * 3. entry must have all MUST attributes * 4. entry may have allowed MAY attributes */ static DWORD _VmDirSchemaCheckEntryStructure( PVDIR_SCHEMA_CTX pCtx, PVDIR_ENTRY pEntry, PVDIR_ATTRIBUTE pOCAttr, BOOLEAN* pbPresentList ) { DWORD dwError = 0; unsigned int iCnt = 0; int iNumAuxOCs = 0; BOOLEAN bHasStructuralOC = FALSE; PVDIR_SCHEMA_OC_DESC pStructOCDesc = NULL; // leaf structural OC PVDIR_SCHEMA_OC_DESC* ppAuxOCDesc = NULL; assert(pCtx && pEntry && pOCAttr && pbPresentList); dwError = VmDirAllocateMemory( sizeof(PVDIR_SCHEMA_OC_DESC*) * (pOCAttr->numVals), (PVOID)&ppAuxOCDesc); BAIL_ON_VMDIR_ERROR(dwError); // walk through objectclass value to collect structure and aux ocs info for (iCnt = 0; iCnt < pOCAttr->numVals; iCnt++) { PVDIR_SCHEMA_OC_DESC pOCDesc = _VmDirSchemaCheckOCDescLookup(pCtx, pOCAttr->vals[iCnt].lberbv.bv_val); if (!pOCDesc) { VMDIR_SAFE_FREE_MEMORY(pCtx->pszErrorMsg); VmDirAllocateStringAVsnprintf( &pCtx->pszErrorMsg, "Objectclass (%s) is not defined in schema", VDIR_SAFE_STRING(pOCAttr->vals[iCnt].lberbv.bv_val)); VmDirLog( LDAP_DEBUG_ANY, "schemaCheckStructure: (%s)", VDIR_SAFE_STRING(pCtx->pszErrorMsg)); dwError = pCtx->dwErrorCode = ERROR_INVALID_ENTRY; BAIL_ON_VMDIR_ERROR(dwError); } switch (pOCDesc->type) { case VDIR_OC_STRUCTURAL: bHasStructuralOC = TRUE; if (!pStructOCDesc) { pStructOCDesc = pOCDesc; pEntry->pszStructureOC = pOCAttr->vals[iCnt].lberbv.bv_val; } else { // make sure they are from the same structure tree PVDIR_SCHEMA_OC_DESC pTmpOCDesc = pStructOCDesc; for (; pTmpOCDesc; pTmpOCDesc = pTmpOCDesc->pStructSupOC) { if (pTmpOCDesc == pOCDesc) { break; } } if (!pTmpOCDesc) // pOCDesc is NOT ancestor of pStructOCDesc { for (pTmpOCDesc = pOCDesc; pTmpOCDesc; pTmpOCDesc = pTmpOCDesc->pStructSupOC) { if (pTmpOCDesc == pStructOCDesc) { // reset pStructOCDesc pStructOCDesc = pOCDesc; pEntry->pszStructureOC = pOCAttr->vals[iCnt].lberbv.bv_val; break; } } } if (!pTmpOCDesc) { VMDIR_SAFE_FREE_MEMORY(pCtx->pszErrorMsg); VmDirAllocateStringAVsnprintf( &pCtx->pszErrorMsg, "Entry can have only one structure objectclass.", VDIR_SAFE_STRING(pOCDesc->pszName)); dwError = pCtx->dwErrorCode = ERROR_INVALID_ENTRY; BAIL_ON_VMDIR_ERROR(dwError); } } break; case VDIR_OC_AUXILIARY: ppAuxOCDesc[iNumAuxOCs] = pOCDesc; iNumAuxOCs++; break; default: // ABSTRACT object class break; } } // must have one structure oc if (bHasStructuralOC == FALSE) { VMDIR_SAFE_FREE_MEMORY(pCtx->pszErrorMsg); VmDirAllocateStringA( "Entry has no structural objectclass", &pCtx->pszErrorMsg); dwError = pCtx->dwErrorCode = ERROR_INVALID_ENTRY; BAIL_ON_VMDIR_ERROR(dwError); } // enforce obejctclass value storing order structureOC->parentOC->...->TOP(not included)->AUXOC.... dwError = _VmDirSchemaReorderObjectClassAttr( pOCAttr, pStructOCDesc, ppAuxOCDesc); BAIL_ON_VMDIR_ERROR(dwError); // enforce nameform (RDN) dwError = _VmDirSchemaCheckNameform( pCtx, pEntry, pStructOCDesc); BAIL_ON_VMDIR_ERROR(dwError); // content rule auxiliary constraint check if (iNumAuxOCs > 0) { dwError = _VmDirSchemaCheckContentRuleAuxOC( pCtx, pStructOCDesc, ppAuxOCDesc); BAIL_ON_VMDIR_ERROR(dwError); } { // must attributes check dwError = _VmDirSchemaCheckMustAttrPresent( pCtx, pStructOCDesc, pEntry, pbPresentList); BAIL_ON_VMDIR_ERROR(dwError); for (iCnt = 0; ppAuxOCDesc[iCnt]; iCnt++) { dwError = _VmDirSchemaCheckMustAttrPresent( pCtx, ppAuxOCDesc[iCnt], pEntry, pbPresentList); BAIL_ON_VMDIR_ERROR(dwError); } } { // may attributes check dwError = _VmDirSchemaCheckMayAttrPresent( pCtx, pStructOCDesc->ppAllMayATs, pEntry, pbPresentList); BAIL_ON_VMDIR_ERROR(dwError); for (iCnt = 0; ppAuxOCDesc[iCnt]; iCnt++) { dwError = _VmDirSchemaCheckMayAttrPresent( pCtx, ppAuxOCDesc[iCnt]->ppAllMayATs, pEntry, pbPresentList); BAIL_ON_VMDIR_ERROR(dwError); } } cleanup: VMDIR_SAFE_FREE_MEMORY(ppAuxOCDesc); return dwError; error: goto cleanup; }
/* * 1. must have objectclass value * 2. must have structural objectclass (done in schemaCheckStructure) * 3. must match contentrule allowed auxiliary objectclass definition * 4. must have all MUST attributes * 5. may have allowed MAY attributes */ static DWORD _VmDirSchemaCheckStructure( PVDIR_SCHEMA_CTX pCtx, PVDIR_ENTRY pEntry ) { DWORD dwError = 0; USHORT usCnt = 0; BOOLEAN* pbPresentList = NULL; DWORD numAttrs = 0; PVDIR_ATTRIBUTE pTmpAttr = NULL; VDIR_ATTRIBUTE* pOCAttr = NULL; for (pTmpAttr = pEntry->attrs; pTmpAttr != NULL; pTmpAttr = pTmpAttr->next) { numAttrs++; } if (numAttrs == 0) { pCtx->dwErrorCode = ERROR_INVALID_ENTRY; VMDIR_SAFE_FREE_MEMORY(pCtx->pszErrorMsg); dwError = VmDirAllocateStringA( "Entry has no attributes", &pCtx->pszErrorMsg); dwError = ERROR_INVALID_ENTRY; BAIL_ON_VMDIR_ERROR(dwError); } dwError = VmDirAllocateMemory( sizeof(BOOLEAN) * numAttrs, (PVOID*)&pbPresentList); BAIL_ON_VMDIR_ERROR(dwError); pOCAttr = _VmDirchemaCheckFindObjectClass(pCtx, pEntry); if (!pOCAttr || pOCAttr->numVals < 1) { pCtx->dwErrorCode = ERROR_INVALID_ENTRY; VMDIR_SAFE_FREE_MEMORY(pCtx->pszErrorMsg); dwError = VmDirAllocateStringA("Entry has no objectclass",&pCtx->pszErrorMsg); dwError = ERROR_INVALID_ENTRY; BAIL_ON_VMDIR_ERROR(dwError); } dwError = _VmDirSchemaCheckEntryStructure( pCtx, pEntry, pOCAttr, pbPresentList); BAIL_ON_VMDIR_ERROR(dwError); { // all VDIR_ATTRIBUTE_USER_APPLICATION attribute should be marked PVDIR_ATTRIBUTE pAttr = NULL; for (usCnt = 0, pAttr = pEntry->attrs; usCnt < numAttrs; usCnt++, pAttr = pAttr->next) { if (!pbPresentList[usCnt] && pAttr->pATDesc->usage == VDIR_ATTRIBUTETYPE_USER_APPLICATIONS) { VMDIR_SAFE_FREE_MEMORY(pCtx->pszErrorMsg); dwError = VmDirAllocateStringAVsnprintf( &pCtx->pszErrorMsg, "Attribute (%s) not allowed", VDIR_SAFE_STRING(pAttr->type.lberbv.bv_val)); dwError = pCtx->dwErrorCode = ERROR_INVALID_ENTRY; BAIL_ON_VMDIR_ERROR(dwError); } } } cleanup: VMDIR_SAFE_FREE_MEMORY(pbPresentList); return dwError; error: goto cleanup; }
/* * Per structure objectclass, verify contentrule auxiliary object class */ static DWORD _VmDirSchemaCheckContentRuleAuxOC( PVDIR_SCHEMA_CTX pCtx, PVDIR_SCHEMA_OC_DESC pStructureOCDesc, PVDIR_SCHEMA_OC_DESC* ppAuxOCDesc ) { DWORD dwError = 0; int iCnt = 0; BOOLEAN bHasAllowedAuxOC = FALSE; assert(pCtx && pStructureOCDesc && ppAuxOCDesc); if (pCtx->pSchema->contentRules.usNumContents == 0) { // schema no content rule support goto cleanup; } bHasAllowedAuxOC = pStructureOCDesc->ppAllowedAuxOCs ? TRUE : FALSE; if (!bHasAllowedAuxOC && ppAuxOCDesc[0]) { // entry structure oc has NO allowedAuxOCs but entry now has aux ocs dwError = ERROR_INVALID_ENTRY; BAIL_ON_VMDIR_ERROR(dwError); } for (; ppAuxOCDesc[iCnt]; iCnt++) { int iIdx = 0; for (;pStructureOCDesc->ppAllowedAuxOCs[iIdx]; iIdx++) { if (pStructureOCDesc->ppAllowedAuxOCs[iIdx] == ppAuxOCDesc[iCnt]) { break; } } if (pStructureOCDesc->ppAllowedAuxOCs[iIdx] == NULL) { // entry aux oc not found in allowed list from content rule dwError = ERROR_INVALID_ENTRY; BAIL_ON_VMDIR_ERROR(dwError); } } cleanup: return dwError; error: pCtx->dwErrorCode = ERROR_INVALID_ENTRY; VMDIR_SAFE_FREE_MEMORY(pCtx->pszErrorMsg); VmDirAllocateStringAVsnprintf( &pCtx->pszErrorMsg, "Aux objectclass (%s) is not allowed.", VDIR_SAFE_STRING(ppAuxOCDesc[iCnt]->pszName)); VmDirLog( LDAP_DEBUG_ANY, "%s", VDIR_SAFE_STRING(pCtx->pszErrorMsg)); goto cleanup; }
static DWORD _VmDirSchemaCheckSyntaxAndDimension( PVDIR_SCHEMA_CTX pCtx, PVDIR_ENTRY pEntry ) { DWORD dwError = 0; VDIR_ATTRIBUTE* pAttr = NULL; for (pAttr = pEntry->attrs; pAttr; pAttr = pAttr->next) { USHORT usCnt = 0; if (pAttr->pATDesc->bSingleValue && pAttr->numVals != 1) { pCtx->dwErrorCode = ERROR_INVALID_ENTRY; VMDIR_SAFE_FREE_MEMORY(pCtx->pszErrorMsg); dwError = VmDirAllocateStringAVsnprintf( &pCtx->pszErrorMsg, "Attribute (%s) can have at most one value", VDIR_SAFE_STRING(pAttr->type.lberbv.bv_val)); dwError = ERROR_INVALID_ENTRY; BAIL_ON_VMDIR_ERROR(dwError); } for (usCnt = 0; usCnt < pAttr->numVals; usCnt++) { if (pAttr->pATDesc->uiMaxSize > 0) { //TODO, for server control/manipulate attribute, we should exclude this restriction // as they no longer in their original form. (e.g. userPassword) if (pAttr->vals[usCnt].lberbv.bv_len > pAttr->pATDesc->uiMaxSize) { VMDIR_SAFE_FREE_MEMORY(pCtx->pszErrorMsg); VmDirAllocateStringAVsnprintf( // ignore error &pCtx->pszErrorMsg, "Attribute (%s) value too long, max (%d) allowed.", VDIR_SAFE_STRING(pAttr->type.lberbv.bv_val), pAttr->pATDesc->uiMaxSize); dwError = pCtx->dwErrorCode = LDAP_CONSTRAINT_VIOLATION; BAIL_ON_VMDIR_ERROR(dwError); } } dwError = VmDirSchemaBervalSyntaxCheck( pCtx, pAttr->pATDesc, &pAttr->vals[usCnt]); BAIL_ON_VMDIR_ERROR(dwError); } } cleanup: return dwError; error: VmDirLog( LDAP_DEBUG_ANY, "%s", VDIR_SAFE_STRING(pCtx->pszErrorMsg)); goto cleanup; }
/* * Entry schema check dit structure rule */ DWORD VmDirSchemaCheckDITStructure( PVDIR_SCHEMA_CTX pCtx, PVDIR_ENTRY pParentEntry, PVDIR_ENTRY pEntry ) { DWORD dwError = 0; unsigned int iCnt = 0; BOOLEAN bParentAllowed = FALSE; PVDIR_ATTRIBUTE pParentOCAttr = NULL; PVDIR_SCHEMA_OC_DESC pStructureOCDesc = NULL; VDIR_SCHEMA_OC_DESC ocKey = {0}; assert(pCtx && pEntry); // BUBBUG - bypass checking until we define castle structure rules goto cleanup; if (pCtx->pSchema->structureRules.usNumStructures == 0) { // schema has no structure rule defined goto cleanup; } if (!pEntry->pszStructureOC) { VMDIR_SAFE_FREE_MEMORY(pCtx->pszErrorMsg); dwError = VmDirAllocateStringAVsnprintf( &pCtx->pszErrorMsg, "Entry has no structure objectclass/pszStructureOC."); dwError = pCtx->dwErrorCode = ERROR_INVALID_ENTRY; BAIL_ON_VMDIR_ERROR(dwError); } ocKey.pszName = pEntry->pszStructureOC; pStructureOCDesc = (PVDIR_SCHEMA_OC_DESC) bsearch( &ocKey, pCtx->pSchema->ocs.pOCSortName, pCtx->pSchema->ocs.usNumOCs, sizeof(VDIR_SCHEMA_OC_DESC), VdirSchemaPOCNameCmp); if (!pStructureOCDesc) { VMDIR_SAFE_FREE_MEMORY(pCtx->pszErrorMsg); dwError = VmDirAllocateStringAVsnprintf( &pCtx->pszErrorMsg, "Structure oc (%s) not defined.", VDIR_SAFE_STRING(pEntry->pszStructureOC)); dwError = pCtx->dwErrorCode = ERROR_INVALID_ENTRY; BAIL_ON_VMDIR_ERROR(dwError); } if (pParentEntry) { pParentOCAttr = _VmDirchemaCheckFindObjectClass(pCtx, pParentEntry); } if (pParentOCAttr) { if (pStructureOCDesc->ppszAllowedParentOCs) { // loop through parent object class to check allowedParentsOCs //TODO, we can arrange structure object class to be the first to eliminate loop. for (iCnt = 0; iCnt < pParentOCAttr->numVals; iCnt++) { int iIdx = 0; for (;pStructureOCDesc->ppszAllowedParentOCs[iIdx]; iIdx++) { if (VmDirStringCompareA(pParentOCAttr->vals[iCnt].lberbv.bv_val, pStructureOCDesc->ppszAllowedParentOCs[iIdx], FALSE) == 0) { // allowed under this parent bParentAllowed = TRUE; break; } } if (pStructureOCDesc->ppszAllowedParentOCs[iIdx] != NULL) { break; } } } } else { if (pStructureOCDesc->bAllowedParentRoot == TRUE) { // allowed under root bParentAllowed = TRUE; } } if (!bParentAllowed) { VMDIR_SAFE_FREE_MEMORY(pCtx->pszErrorMsg); dwError = VmDirAllocateStringAVsnprintf( &pCtx->pszErrorMsg, "(%s) not allowed under its parent", VDIR_SAFE_STRING(pEntry->pszStructureOC)); dwError = pCtx->dwErrorCode = ERROR_INVALID_ENTRY; BAIL_ON_VMDIR_ERROR(dwError); } cleanup: return dwError; error: goto cleanup; }
VOID VdcadminTestSASLClient( VOID ) { DWORD dwError = 0; char pszServerHost[SIZE_256] = {0}; char pszServerPort[SIZE_256] = {0}; char pszServerSSLPort[SIZE_256] = {0}; char pszBindDN[SIZE_256] = {0}; char pszBindUPN[SIZE_256] = {0}; char pszPassword[SIZE_256] = {0}; PSTR pszLDAPURI = NULL; PSTR pszLDAPSURI = NULL; VmDirReadString( "Please enter LDAP server host: ", pszServerHost, SIZE_256, FALSE); VmDirReadString( "Please enter LDAP server port: ", pszServerPort, SIZE_256, FALSE); VmDirReadString( "Please enter LDAP server SSL port: ", pszServerSSLPort, SIZE_256, FALSE); VmDirReadString( "Please enter LDAP Bind DN: ", pszBindDN, SIZE_256, FALSE); VmDirReadString( "Please enter LDAP Bind UPN: ", pszBindUPN, SIZE_256, FALSE); VmDirReadString( "Please enter LDAP Bind password: "******"\n"); dwError = VmDirAllocateStringAVsnprintf( &pszLDAPURI, "ldap://%s:%s", pszServerHost[0] != '\0' ? pszServerHost : "localhost", pszServerPort); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirAllocateStringAVsnprintf( &pszLDAPSURI, "ldaps://%s:%s", pszServerHost[0] != '\0' ? pszServerHost : "localhost", pszServerSSLPort); BAIL_ON_VMDIR_ERROR(dwError); _VdcadminClientTestSimpleBind( pszLDAPURI, pszBindDN, pszPassword ); _VdcadminClientTestSimpleSSLBind( pszLDAPSURI, pszBindDN, pszPassword ); _VdcadminClientTestSRPBind( pszLDAPURI, pszBindUPN, pszPassword ); _VdcadminClientTestGSSAPIBind( pszLDAPURI ); cleanup: memset(pszPassword, 0, sizeof(pszPassword)); VMDIR_SAFE_FREE_MEMORY(pszLDAPURI); VMDIR_SAFE_FREE_MEMORY(pszLDAPSURI); return; error: printf("TestVdcadminSASLClient failed. (%d)\n", dwError); goto cleanup; }
DWORD VmDirSafeLDAPBindToPort( LDAP** ppLd, PCSTR pszHost, DWORD dwPort, PCSTR pszUPN, PCSTR pszPassword, int iTimeout ) { DWORD dwError = 0; LDAP* pLd = NULL; char ldapURI[VMDIR_MAX_LDAP_URI_LEN + 1] = {0}; DWORD dwLdapPort = DEFAULT_LDAP_PORT_NUM; DWORD dwTmpLdapPort = 0; if (ppLd == NULL || pszHost == NULL || pszUPN == NULL || pszPassword == NULL) { dwError = VMDIR_ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } if (dwPort) { dwLdapPort = dwPort; } else if (VmDirGetRegKeyValueDword( VMDIR_CONFIG_PARAMETER_V1_KEY_PATH, VMDIR_REG_KEY_LDAP_PORT, &dwTmpLdapPort, DEFAULT_LDAP_PORT_NUM) == ERROR_SUCCESS) { dwLdapPort = dwTmpLdapPort; } if ( VmDirIsIPV6AddrFormat( pszHost ) ) { dwError = VmDirStringPrintFA( ldapURI, sizeof(ldapURI)-1, "%s://[%s]:%d", VMDIR_LDAP_PROTOCOL, pszHost, dwLdapPort); } else { dwError = VmDirStringPrintFA( ldapURI, sizeof(ldapURI)-1, "%s://%s:%d", VMDIR_LDAP_PROTOCOL, pszHost, dwLdapPort); } BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirSASLSRPBindExt1( &pLd, &(ldapURI[0]), pszUPN, pszPassword, iTimeout); BAIL_ON_VMDIR_ERROR(dwError); *ppLd = pLd; cleanup: return dwError; error: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s to (%s) failed. SRP(%d)", __FUNCTION__, ldapURI, dwError ); if ( pLd ) { ldap_unbind_ext_s( pLd, NULL, NULL); } goto cleanup; }
/* * Before modify schema cache, make sure new schema is valid. * 1. schema of pEntry must be live one * 2. create new schema instance via pEntry * 3. check active and new schema compatibility * NOT compatible - reject this operation * Compatible but NO semantic chnage - update schema entry * Compatible and has semantic chnage - update schema entry and cache * 4. make new instance pending in gVdirSchemaGlobals */ DWORD VmDirSchemaCacheModifyPrepare( PVDIR_OPERATION pOperation, VDIR_MODIFICATION* pMods, PVDIR_ENTRY pSchemaEntry ) { DWORD dwError = 0; BOOLEAN bInLock = FALSE; PSTR pszLocalErrMsg = NULL; BOOLEAN bOwnNewInstance = FALSE; BOOLEAN bCompatible = FALSE; // schema compatible BOOLEAN bNeedCachePatch = FALSE; // schema semantic/cache change PVDIR_SCHEMA_INSTANCE pNewInstance = NULL; // DO NOT free, pEntry should take over it. PVDIR_SCHEMA_INSTANCE pEntryOrgSchemaInstance = NULL; if ( !pMods || !pSchemaEntry || !pOperation ) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } { PVDIR_MODIFICATION pLocalMods = NULL; PCSTR immutableList[] = VDIR_IMMUTABLE_SCHEMA_ELEMENT_INITIALIZER; int iImmutableSize = sizeof(immutableList)/sizeof(immutableList[0]); for (pLocalMods = pMods; pLocalMods; pLocalMods = pLocalMods->next) { BOOLEAN bImmutableElement = _VmDirIsNameInCaseIgnoreList( pLocalMods->attr.pATDesc->pszName, immutableList, iImmutableSize); if ( bImmutableElement ) { dwError = ERROR_OPERATION_NOT_PERMITTED; BAIL_ON_VMDIR_ERROR_WITH_MSG(dwError, pszLocalErrMsg, "modify (%s) not allowed", pLocalMods->attr.pATDesc->pszName); } } } // make sure pEntry uses live schema if (! vdirIsLiveSchema(pSchemaEntry->pSchemaCtx->pSchema)) { dwError = LDAP_UNWILLING_TO_PERFORM; BAIL_ON_VMDIR_ERROR_WITH_MSG(dwError, pszLocalErrMsg, "Out dated schema"); } pEntryOrgSchemaInstance = pSchemaEntry->pSchemaCtx->pSchema; // instantiate a schema cache - pNewInstance // If this call succeed, do NOT free pNewInstance. pEntry->pSchemaCtx takes it over. dwError = VdirSchemaInstanceInitViaEntry( pSchemaEntry, &pNewInstance); if ( dwError != 0 && pSchemaEntry->pSchemaCtx->pSchema != pNewInstance ) { // we still own pNewInstance and need to free it. bOwnNewInstance = TRUE; } BAIL_ON_VMDIR_ERROR_WITH_MSG(dwError, pszLocalErrMsg, "Entry to schema instance failed (%d)", dwError); // check if two instances are compatible and if schema patching is needed dwError = VmDirSchemaInstancePatchCheck( pEntryOrgSchemaInstance, pNewInstance, &bCompatible, &bNeedCachePatch); BAIL_ON_VMDIR_ERROR_WITH_MSG(dwError, pszLocalErrMsg, "VmDirSchemaInstancePatch (%d)", dwError); if ( !bCompatible ) { dwError = LDAP_UNWILLING_TO_PERFORM; BAIL_ON_VMDIR_ERROR_WITH_MSG(dwError, pszLocalErrMsg, "Schema NOT compatible (%d)", dwError); } if ( !bNeedCachePatch ) { // no semantic change, just update schema entry VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "Prepare schema entry update"); } else { // need schema entry and cache update VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "Prepare schema entry and instance update (%p)", pNewInstance); } VMDIR_LOCK_MUTEX(bInLock, gVdirSchemaGlobals.mutex); if ( bNeedCachePatch ) { gVdirSchemaGlobals.bHasPendingChange = TRUE; } VMDIR_UNLOCK_MUTEX(bInLock, gVdirSchemaGlobals.mutex); cleanup: VMDIR_UNLOCK_MUTEX(bInLock, gVdirSchemaGlobals.mutex); VMDIR_SAFE_FREE_MEMORY(pszLocalErrMsg); return dwError; error: if ( bOwnNewInstance ) { VdirSchemaInstanceFree( pNewInstance ); } VMDIR_SET_LDAP_RESULT_ERROR( &pOperation->ldapResult, dwError, pszLocalErrMsg ); goto cleanup; }
DWORD VmDirAnonymousLDAPBindWithTimeout( LDAP** ppLd, PCSTR pszLdapURI, int timeout ) { DWORD dwError = 0; int retVal = 0; const int ldapVer = LDAP_VERSION3; BerValue ldapBindPwd = {0}; LDAP* pLocalLd = NULL; struct timeval nettimeout = {0}; if (ppLd == NULL || pszLdapURI == NULL) { dwError = VMDIR_ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } retVal = ldap_initialize( &pLocalLd, pszLdapURI); BAIL_ON_SIMPLE_LDAP_ERROR(retVal); retVal = ldap_set_option( pLocalLd, LDAP_OPT_PROTOCOL_VERSION, &ldapVer); BAIL_ON_SIMPLE_LDAP_ERROR(retVal); if (timeout > 0) { nettimeout.tv_sec = timeout; // timeout connect retVal = ldap_set_option(pLocalLd, LDAP_OPT_NETWORK_TIMEOUT, (void *)&nettimeout); BAIL_ON_SIMPLE_LDAP_ERROR(retVal); } ldapBindPwd.bv_val = NULL; ldapBindPwd.bv_len = 0; retVal = ldap_sasl_bind_s( pLocalLd, "", LDAP_SASL_SIMPLE, &ldapBindPwd, // no credentials NULL, NULL, NULL); BAIL_ON_SIMPLE_LDAP_ERROR(retVal); *ppLd = pLocalLd; cleanup: return dwError; ldaperror: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "VmDirAnonymousLDAPBind to (%s) failed. (%d)(%s)", VDIR_SAFE_STRING(pszLdapURI), retVal, ldap_err2string(retVal) ); dwError = VmDirMapLdapError(retVal); error: if (retVal == 0) { VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL, "VmDirAnonymousLDAPBind to (%s) failed. (%u)", VDIR_SAFE_STRING(pszLdapURI), dwError); } if (pLocalLd) { ldap_unbind_ext_s( pLocalLd, NULL, NULL); } goto cleanup; }
/* MdbAddEntry: Creates an entry in the MDB DBs. * * Returns: BE error codes. * */ DWORD VmDirMDBAddEntry( PVDIR_BACKEND_CTX pBECtx, PVDIR_ENTRY pEntry) { DWORD dwError = 0; ENTRYID entryId = 0; VDIR_DB_TXN* pTxn = NULL; VDIR_BERVALUE encodedEntry = VDIR_BERVALUE_INIT; VDIR_ATTRIBUTE * nextAttr = NULL; assert( pEntry && pBECtx && pBECtx->pBEPrivate ); pTxn = (PVDIR_DB_TXN)pBECtx->pBEPrivate; dwError = VmDirEncodeEntry( pEntry, &encodedEntry ); BAIL_ON_VMDIR_ERROR(dwError); if (pEntry->eId != 0) // Reserved entries have eId already { entryId = pEntry->eId; } else { VDIR_DB_DBT EIDkey = {0}; VDIR_DB_DBT EIDvalue = {0}; unsigned char EIDKeyBytes[sizeof( ENTRYID )] = {0}; unsigned char EIDValueBytes[sizeof( ENTRYID )] = {0}; EIDkey.mv_data = &EIDKeyBytes[0]; MDBEntryIdToDBT(BE_MDB_ENTRYID_SEQ_KEY, &EIDkey); dwError = mdb_get(pTxn, gVdirMdbGlobals.mdbSeqDBi, &EIDkey, &EIDvalue); BAIL_ON_VMDIR_ERROR(dwError); assert( EIDvalue.mv_size == sizeof(ENTRYID) ); entryId = *((ENTRYID*)EIDvalue.mv_data); *((ENTRYID*)&EIDValueBytes[0]) = entryId + 1; EIDvalue.mv_data = &EIDValueBytes[0]; EIDvalue.mv_size = sizeof(ENTRYID); dwError = mdb_put(pTxn, gVdirMdbGlobals.mdbSeqDBi, &EIDkey, &EIDvalue, BE_DB_FLAGS_ZERO); BAIL_ON_VMDIR_ERROR(dwError); } assert( entryId > 0 ); if ((dwError = MDBCreateParentIdIndex(pBECtx, &(pEntry->pdn), entryId)) != 0) { dwError = MDBToBackendError(dwError, ERROR_BACKEND_ENTRY_NOTFOUND, ERROR_BACKEND_PARENT_NOTFOUND, pBECtx, "CreateParentIdIndex"); BAIL_ON_VMDIR_ERROR( dwError ); } // Update DN index first. this make sure we always return ERROR_BACKEND_ENTRY_EXISTS in such case. for (nextAttr = pEntry->attrs; nextAttr != NULL; nextAttr = nextAttr->next) { if (VmDirStringCompareA(nextAttr->type.lberbv.bv_val, ATTR_DN, FALSE) == 0) { // make sure we store normalized DN value. dwError = VmDirNormalizeDN( &(nextAttr->vals[0]), pEntry->pSchemaCtx ); BAIL_ON_VMDIR_ERROR(dwError); if ((dwError = MdbUpdateIndicesForAttr( pTxn, &(nextAttr->type), nextAttr->vals, nextAttr->numVals, entryId, BE_INDEX_OP_TYPE_CREATE)) != 0) { dwError = MDBToBackendError( dwError, MDB_KEYEXIST, ERROR_BACKEND_ENTRY_EXISTS, pBECtx, VDIR_SAFE_STRING(nextAttr->vals[0].bvnorm_val)); BAIL_ON_VMDIR_ERROR( dwError ); } if ((dwError = MdbUpdateAttrMetaData( pTxn, nextAttr, entryId, BE_INDEX_OP_TYPE_CREATE )) != 0) { dwError = MDBToBackendError(dwError, 0, ERROR_BACKEND_ERROR, pBECtx, "UpdateDNAttrMetaData"); BAIL_ON_VMDIR_ERROR( dwError ); } } } // Update remaining indices for (nextAttr = pEntry->attrs; nextAttr != NULL; nextAttr = nextAttr->next) { if (VmDirStringCompareA(nextAttr->type.lberbv.bv_val, ATTR_DN, FALSE) != 0) { if ((dwError = MdbUpdateIndicesForAttr( pTxn, &(nextAttr->type), nextAttr->vals, nextAttr->numVals, entryId, BE_INDEX_OP_TYPE_CREATE)) != 0) { dwError = MDBToBackendError( dwError, MDB_KEYEXIST, ERROR_BACKEND_CONSTRAINT, pBECtx, VDIR_SAFE_STRING(nextAttr->type.lberbv.bv_val)); BAIL_ON_VMDIR_ERROR( dwError ); } if ((dwError = MdbUpdateAttrMetaData( pTxn, nextAttr, entryId, BE_INDEX_OP_TYPE_CREATE )) != 0) { dwError = MDBToBackendError(dwError, 0, ERROR_BACKEND_ERROR, pBECtx, VDIR_SAFE_STRING(nextAttr->type.lberbv.bv_val)); BAIL_ON_VMDIR_ERROR( dwError ); } } } // Update entry/blob database if ((dwError = MdbCreateEIDIndex(pTxn, entryId, &encodedEntry, TRUE /* 1st time new entry creation */)) != 0) { dwError = MDBToBackendError(dwError, MDB_KEYEXIST, ERROR_BACKEND_CONSTRAINT, pBECtx, "CreateEIDIndex"); BAIL_ON_VMDIR_ERROR( dwError ); } cleanup: VMDIR_SAFE_FREE_MEMORY( encodedEntry.lberbv.bv_val ); return dwError; error: // TODO set pBECtx->pszBEErrorMsg? VMDIR_LOG_ERROR( LDAP_DEBUG_BACKEND, "BEAddEntry DN (%s), (%u)(%s)", VDIR_SAFE_STRING(pEntry->dn.lberbv.bv_val), dwError, VDIR_SAFE_STRING(pBECtx->pszBEErrorMsg)); VMDIR_SET_BACKEND_ERROR(dwError); // if dwError no in BE space, set to ERROR_BACKEND_ERROR goto cleanup; }
static DWORD VmDirSrvInitKrb( PVDIR_SCHEMA_CTX pSchemaCtx, PCSTR pszFQDomainName, PCSTR pszDomainDN ) { DWORD dwError = 0; PSTR pszRealmName = NULL; PBYTE pMasterKey = NULL; DWORD dwMasterKeyLen = 0; PBYTE pEncMasterKey = NULL; DWORD dwEncMasterKeyLen = 0; PSTR pszTgtUPN = NULL; PSTR pszTgtCN = NULL; PSTR pszTgtPasswd = NULL; PSTR pszKMUPN = NULL; PSTR pszKMPasswd = NULL; PSTR pszKMDN = NULL; VDIR_BERVALUE bervMKey = VDIR_BERVALUE_INIT; VDIR_BERVALUE bervEncMKey = VDIR_BERVALUE_INIT; assert (pSchemaCtx && pszFQDomainName && pszDomainDN ); dwError = VmDirKrbRealmNameNormalize(pszFQDomainName, &pszRealmName); BAIL_ON_VMDIR_ERROR(dwError); // create krb master key dwError = VmKdcGenerateMasterKey( &pMasterKey, &dwMasterKeyLen, &pEncMasterKey, &dwEncMasterKeyLen); BAIL_ON_VMDIR_ERROR(dwError); bervMKey.lberbv.bv_val = pMasterKey; bervMKey.lberbv.bv_len = dwMasterKeyLen; bervEncMKey.lberbv.bv_val = pEncMasterKey; bervEncMKey.lberbv.bv_len = dwEncMasterKeyLen; // add krb master key to domain entry dwError = VmDirInternalEntryAttributeReplace( pSchemaCtx, pszDomainDN, ATTR_KRB_MASTER_KEY, &bervMKey); BAIL_ON_VMDIR_ERROR(dwError); // init gVmdirKrbGlobals (to cache krbMKey), which is needed in VmDirCreateAccount below. dwError = VmDirKrbInit(); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirAllocateStringAVsnprintf( &pszTgtUPN, "krbtgt/%s@%s", pszRealmName, pszRealmName); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirAllocateStringAVsnprintf( &pszTgtCN, "krbtgt/%s", pszRealmName); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmKdcGenerateRandomPassword( VMDIR_KDC_RANDOM_PWD_LEN, &pszTgtPasswd); BAIL_ON_VMDIR_ERROR(dwError); // create krbtgt principal dwError = VmDirCreateAccount( pszTgtUPN, pszTgtCN, pszTgtPasswd, NULL); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirAllocateStringAVsnprintf( &pszKMUPN, "K/M@%s", pszRealmName); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmKdcGenerateRandomPassword( VMDIR_KDC_RANDOM_PWD_LEN, &pszKMPasswd); BAIL_ON_VMDIR_ERROR(dwError); // create K/M principal dwError = VmDirCreateAccount( pszKMUPN, "K/M", // TODO, cn=k/M for now pszKMPasswd, NULL); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirUPNToAccountDN( pszKMUPN, "cn", "K/M", &pszKMDN); BAIL_ON_VMDIR_ERROR(dwError); // K/M principal need special ATTR_KRB_PRINCIPAL - encoded master key/pEncMasterKey dwError = VmDirInternalEntryAttributeReplace( pSchemaCtx, pszKMDN, ATTR_KRB_PRINCIPAL_KEY, &bervEncMKey); BAIL_ON_VMDIR_ERROR(dwError); cleanup: VMDIR_SAFE_FREE_MEMORY(pMasterKey); VMDIR_SAFE_FREE_MEMORY(pEncMasterKey); VMDIR_SAFE_FREE_MEMORY(pszTgtUPN); VMDIR_SAFE_FREE_MEMORY(pszTgtCN); VMDIR_SAFE_FREE_MEMORY(pszTgtPasswd); VMDIR_SAFE_FREE_MEMORY(pszKMUPN); VMDIR_SAFE_FREE_MEMORY(pszKMPasswd); VMDIR_SAFE_FREE_MEMORY(pszRealmName); VMDIR_SAFE_FREE_MEMORY(pszKMDN); return dwError; error: goto cleanup; }
/* MdbModifyEntry: Updates an entry in the MDB DBs. * * Returns: BE error codes. * */ DWORD VmDirMDBModifyEntry( PVDIR_BACKEND_CTX pBECtx, VDIR_MODIFICATION* pMods, PVDIR_ENTRY pEntry ) { DWORD dwError = 0; VDIR_BERVALUE newEncodedEntry = VDIR_BERVALUE_INIT; VDIR_MODIFICATION * mod = NULL; PVDIR_DB_TXN pTxn = NULL; assert( pBECtx && pBECtx->pBEPrivate && pMods && pEntry ); pTxn = (PVDIR_DB_TXN)pBECtx->pBEPrivate; dwError = VmDirEncodeEntry( pEntry, &newEncodedEntry ); BAIL_ON_VMDIR_ERROR(dwError); VMDIR_SAFE_FREE_MEMORY( pEntry->encodedEntry ); // entry takes over the responsibility to free newEncodedEntry.lberbv.bv_val pEntry->encodedEntry = (unsigned char *)newEncodedEntry.lberbv.bv_val; // Create/Delete appropriate indices for indexed attributes. for (mod = pMods; mod != NULL; mod = mod->next) { if (mod->ignore) { continue; } switch (mod->operation) { case MOD_OP_ADD: if ((dwError = MdbUpdateIndicesForAttr( pTxn, &(mod->attr.type), mod->attr.vals, mod->attr.numVals, pEntry->eId, BE_INDEX_OP_TYPE_CREATE)) != 0) { dwError = MDBToBackendError( dwError, MDB_KEYEXIST, ERROR_BACKEND_CONSTRAINT, pBECtx, VDIR_SAFE_STRING(mod->attr.type.lberbv.bv_val)); BAIL_ON_VMDIR_ERROR( dwError ); } break; case MOD_OP_DELETE: if ((dwError = MdbUpdateIndicesForAttr( pTxn, &(mod->attr.type), mod->attr.vals, mod->attr.numVals, pEntry->eId, BE_INDEX_OP_TYPE_DELETE )) != 0) { dwError = MDBToBackendError(dwError, 0, ERROR_BACKEND_ERROR, pBECtx, VDIR_SAFE_STRING(mod->attr.type.lberbv.bv_val)); BAIL_ON_VMDIR_ERROR( dwError ); } break; case MOD_OP_REPLACE: default: assert( FALSE ); } if ((dwError = MdbUpdateAttrMetaData( pTxn, &(mod->attr), pEntry->eId, BE_INDEX_OP_TYPE_UPDATE )) != 0) { dwError = MDBToBackendError(dwError, 0, ERROR_BACKEND_ERROR, pBECtx, VDIR_SAFE_STRING(mod->attr.type.lberbv.bv_val)); BAIL_ON_VMDIR_ERROR( dwError ); } } // Update Entry DB. if ((dwError = MdbCreateEIDIndex(pTxn, pEntry->eId, &newEncodedEntry, FALSE /* update current eId key */)) != 0) { dwError = MDBToBackendError(dwError, 0, ERROR_BACKEND_ERROR, pBECtx, "CreateEIDIndex"); BAIL_ON_VMDIR_ERROR( dwError ); } cleanup: return dwError; error: VMDIR_SET_BACKEND_ERROR(dwError); // if dwError no in BE space, set to ERROR_BACKEND_ERROR VMDIR_LOG_ERROR(LDAP_DEBUG_BACKEND, "ModifyEntry failed: error=%d,DN=%s", dwError, VDIR_SAFE_STRING(pEntry->dn.lberbv.bv_val)); goto cleanup; }
DWORD VmDirSrvSetupHostInstance( PCSTR pszFQDomainName, PCSTR pszUsername, PCSTR pszPassword, PCSTR pszSiteName, PCSTR pszReplURI, UINT32 firstReplCycleMode ) { DWORD dwError = 0; PCSTR pszDelObjsContainerName = "Deleted Objects"; PCSTR pszConfigContainerName = VMDIR_CONFIGURATION_CONTAINER_NAME; PCSTR pszCAContainerName = VMDIR_CA_CONTAINER_NAME; PCSTR pszSitesContainerName = VMDIR_SITES_RDN_VAL; PCSTR pszSiteContainerName = "Default-First-Site"; PCSTR pszServersContainerName = VMDIR_SERVERS_CONTAINER_NAME; PCSTR pszReplAgrsContainerName = VMDIR_REPL_AGRS_CONTAINER_NAME; PCSTR pszDCsContainerName = VMDIR_DOMAIN_CONTROLLERS_RDN_VAL; PCSTR pszComputersContainerName = VMDIR_COMPUTERS_RDN_VAL; PCSTR pszMSAsContainerName = VMDIR_MSAS_RDN_VAL; PSTR pszDomainDN = NULL; PSTR pszDelObjsContainerDN = NULL; // CN=Deleted Objects,<domain DN> PSTR pszConfigContainerDN = NULL; // CN=Configuration,<domain DN> PSTR pszCAContainerDN = NULL; // CN=Certificate-Authorities,CN=Configuration,<domain DN> PSTR pszSitesContainerDN = NULL; // CN=Sites,<configuration DN> PSTR pszSiteContainerDN = NULL; // CN=<Site-Name>,<Sites container DN> PSTR pszServersContainerDN = NULL; // CN=Servers,<Site container DN> PSTR pszServerDN = NULL; // CN=<fully qualified host name>,<Servers container DN> PSTR pszReplAgrsContainerDN = NULL; // CN=Replication Agreements,<Server DN> PSTR pszReplAgrDN = NULL; // labeledURI=<ldap://192.165.226.127>,<ReplAgrsContainerDN> PSTR pszDCsContainerDN = NULL; // OU=Domain Controllers,<domain DN> PSTR pszComputersContainerDN = NULL; // OU=Computers,<domain DN> PSTR pszDCAccountDN = NULL; // CN=<fully qualified host name>,OU=Domain Controllers,<domain DN> PSTR pszDCAccountUPN = NULL; // <hostname>@<domain name> PSTR pszComputerAccountDN = NULL; // CN=<fully qualified host name>,OU=Domain Computers,<domain DN> PSTR pszMSAsDN = NULL; // CN=<Managed Service Accounts>,<domain DN> PSTR pszUpperCaseFQDomainName = NULL; PSTR pszLowerCaseHostName = NULL; PSTR pszDefaultAdminDN = NULL; PVDIR_SCHEMA_CTX pSchemaCtx = NULL; char pszHostName[VMDIR_MAX_HOSTNAME_LEN]; VDIR_BERVALUE bv = VDIR_BERVALUE_INIT; BOOLEAN bInLockReplCycle = FALSE; PVMDIR_REPLICATION_AGREEMENT pReplAgr = NULL; BOOLEAN bInLock = FALSE; PSTR pszUserDN = NULL; PCSTR pszUsersContainerName = "Users"; PSTR pszUsersContainerDN = NULL; // CN=Users,<domain DN> VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL, "Setting up a host instance (%s).", VDIR_SAFE_STRING(pszFQDomainName)); if (pszSiteName) { pszSiteContainerName = pszSiteName; } // If joining another node, copy schema from the partner first. if (!IsNullOrEmptyString(pszReplURI)) { dwError = VmDirCopyPartnerSchema( pszFQDomainName, pszUsername, pszPassword, pszReplURI); BAIL_ON_VMDIR_ERROR(dwError); } dwError = VmDirSchemaCtxAcquire( &pSchemaCtx ); BAIL_ON_VMDIR_ERROR(dwError); // Construct important DNs and create the persisted DSE Root entry // Domain DN dwError = VmDirSrvCreateDomainDN( pszFQDomainName, &pszDomainDN ); BAIL_ON_VMDIR_ERROR(dwError); // Deleted objects container DN dwError = VmDirSrvCreateDN( pszDelObjsContainerName, pszDomainDN, &pszDelObjsContainerDN ); BAIL_ON_VMDIR_ERROR(dwError); // Configuration container DN dwError = VmDirSrvCreateDN( pszConfigContainerName, pszDomainDN, &pszConfigContainerDN ); BAIL_ON_VMDIR_ERROR(dwError); // Domain Controllers container DN dwError = VmDirAllocateStringAVsnprintf(&pszDCsContainerDN, "%s=%s,%s", ATTR_OU, pszDCsContainerName, pszDomainDN); BAIL_ON_VMDIR_ERROR(dwError); // Domain Computers container DN dwError = VmDirAllocateStringAVsnprintf(&pszComputersContainerDN, "%s=%s,%s", ATTR_OU, pszComputersContainerName, pszDomainDN); BAIL_ON_VMDIR_ERROR(dwError); // Sites container DN dwError = VmDirSrvCreateDN( pszSitesContainerName, pszConfigContainerDN, &pszSitesContainerDN ); BAIL_ON_VMDIR_ERROR(dwError); // Certificate-Authorities container DN dwError = VmDirSrvCreateDN( pszCAContainerName, pszConfigContainerDN, &pszCAContainerDN ); BAIL_ON_VMDIR_ERROR(dwError); // Particular site container DN dwError = VmDirSrvCreateDN( pszSiteContainerName, pszSitesContainerDN, &pszSiteContainerDN ); BAIL_ON_VMDIR_ERROR(dwError); // Servers within the site container DN dwError = VmDirSrvCreateDN( pszServersContainerName, pszSiteContainerDN, &pszServersContainerDN ); BAIL_ON_VMDIR_ERROR(dwError); // This server DN // vdcpromo sets this key. dwError = VmDirGetRegKeyValue( VMDIR_CONFIG_PARAMETER_KEY_PATH, VMDIR_REG_KEY_DC_ACCOUNT, pszHostName, sizeof(pszHostName)-1); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirAllocASCIIUpperToLower( pszHostName, &pszLowerCaseHostName ); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirSrvCreateDN( pszLowerCaseHostName, pszServersContainerDN, &pszServerDN ); BAIL_ON_VMDIR_ERROR(dwError); // Domain controller account DN dwError = VmDirSrvCreateDN( pszLowerCaseHostName, pszDCsContainerDN, &pszDCAccountDN ); BAIL_ON_VMDIR_ERROR(dwError); // Domain controller account UPN dwError = VmDirAllocASCIILowerToUpper( pszFQDomainName, &pszUpperCaseFQDomainName ); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirAllocateStringAVsnprintf(&pszDCAccountUPN, "%s@%s", pszLowerCaseHostName, pszUpperCaseFQDomainName ); BAIL_ON_VMDIR_ERROR(dwError); // Computer account DN dwError = VmDirSrvCreateDN( pszLowerCaseHostName, pszComputersContainerDN, &pszComputerAccountDN ); BAIL_ON_VMDIR_ERROR(dwError); // Replication agreements container DN dwError = VmDirSrvCreateDN( pszReplAgrsContainerName, pszServerDN, &pszReplAgrsContainerDN ); BAIL_ON_VMDIR_ERROR(dwError); // Managed Service Accounts container DN dwError = VmDirSrvCreateDN( pszMSAsContainerName, pszDomainDN, &pszMSAsDN ); BAIL_ON_VMDIR_ERROR(dwError); // Default administrator DN dwError = VmDirAllocateStringAVsnprintf( &pszDefaultAdminDN, "cn=%s,cn=%s,%s", pszUsername, pszUsersContainerName, pszDomainDN ); BAIL_ON_VMDIR_ERROR(dwError); if (firstReplCycleMode != FIRST_REPL_CYCLE_MODE_USE_COPIED_DB) { // Modify persisted DSE Root entry dwError = VmDirSrvModifyPersistedDSERoot( pSchemaCtx, pszDomainDN, pszConfigContainerDN, SCHEMA_NAMING_CONTEXT_DN, SUB_SCHEMA_SUB_ENTRY_DN, pszServerDN, pszDefaultAdminDN, pszDCAccountDN, pszDCAccountUPN, pszDelObjsContainerDN, (PSTR) pszSiteContainerName ); } BAIL_ON_VMDIR_ERROR(dwError); // set gVmdirServerGlobals.bvDefaultAdminDN dwError = VmDirAllocateBerValueAVsnprintf( &gVmdirServerGlobals.bvDefaultAdminDN, "%s", pszDefaultAdminDN); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirNormalizeDN( &gVmdirServerGlobals.bvDefaultAdminDN, pSchemaCtx); BAIL_ON_VMDIR_ERROR(dwError); // set systemDomainDN dwError = VmDirAllocateBerValueAVsnprintf( &gVmdirServerGlobals.systemDomainDN, "%s", pszDomainDN); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirNormalizeDN( &gVmdirServerGlobals.systemDomainDN, pSchemaCtx); BAIL_ON_VMDIR_ERROR(dwError); // set serverObjDN dwError = VmDirAllocateBerValueAVsnprintf( &gVmdirServerGlobals.serverObjDN, "%s", pszServerDN); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirNormalizeDN( &gVmdirServerGlobals.serverObjDN, pSchemaCtx); BAIL_ON_VMDIR_ERROR(dwError); // set dcAccountDN dwError = VmDirAllocateBerValueAVsnprintf( &gVmdirServerGlobals.dcAccountDN, "%s", pszDCAccountDN); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirNormalizeDN( &gVmdirServerGlobals.dcAccountDN, pSchemaCtx); BAIL_ON_VMDIR_ERROR(dwError); // set dcAccountUPN dwError = VmDirAllocateBerValueAVsnprintf( &gVmdirServerGlobals.dcAccountUPN, "%s", pszDCAccountUPN); BAIL_ON_VMDIR_ERROR(dwError); // Set replInterval and replPageSize gVmdirServerGlobals.replInterval = VmDirStringToIA(VMDIR_DEFAULT_REPL_INTERVAL); gVmdirServerGlobals.replPageSize = VmDirStringToIA(VMDIR_DEFAULT_REPL_PAGE_SIZE); // Set utdVector VmDirFreeBervalContent(&bv); bv.lberbv.bv_val = ""; bv.lberbv.bv_len = 0; dwError = VmDirBervalContentDup( &bv, &gVmdirServerGlobals.utdVector ); BAIL_ON_VMDIR_ERROR(dwError); // Set delObjsContainerDN VmDirFreeBervalContent(&bv); bv.lberbv.bv_val = pszDelObjsContainerDN; bv.lberbv.bv_len = VmDirStringLenA( bv.lberbv.bv_val ); dwError = VmDirBervalContentDup( &bv, &gVmdirServerGlobals.delObjsContainerDN ); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirNormalizeDN(&gVmdirServerGlobals.delObjsContainerDN, pSchemaCtx); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirAllocateStringA( pszSiteContainerName, &gVmdirServerGlobals.pszSiteName); BAIL_ON_VMDIR_ERROR(dwError); // Create Administrator DN dwError = VmDirSrvCreateDN( pszUsersContainerName, pszDomainDN, &pszUsersContainerDN); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirSrvCreateUserDN( pszUsername, pszUsersContainerDN, &pszUserDN); BAIL_ON_VMDIR_ERROR(dwError); // set DomainControllerGroupDN for first,second+ host setup dwError = VmDirAllocateBerValueAVsnprintf( &gVmdirServerGlobals.bvDCGroupDN, "cn=%s,cn=%s,%s", VMDIR_DC_GROUP_NAME, VMDIR_BUILTIN_CONTAINER_NAME, pszDomainDN); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirNormalizeDN( &(gVmdirServerGlobals.bvDCGroupDN), pSchemaCtx); BAIL_ON_VMDIR_ERROR(dwError); // set DCClientGroupDN for first,second+ host setup dwError = VmDirAllocateBerValueAVsnprintf( &gVmdirServerGlobals.bvDCClientGroupDN, "cn=%s,cn=%s,%s", VMDIR_DCCLIENT_GROUP_NAME, VMDIR_BUILTIN_CONTAINER_NAME, pszDomainDN); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirNormalizeDN( &(gVmdirServerGlobals.bvDCClientGroupDN), pSchemaCtx); BAIL_ON_VMDIR_ERROR(dwError); // set ServicesRootDN for first,second+ host setup dwError = VmDirAllocateBerValueAVsnprintf( &gVmdirServerGlobals.bvServicesRootDN, "cn=%s,%s", VMDIR_SERVICES_CONTAINER_NAME, pszDomainDN); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirNormalizeDN( &(gVmdirServerGlobals.bvServicesRootDN), pSchemaCtx); BAIL_ON_VMDIR_ERROR(dwError); if (IsNullOrEmptyString(pszReplURI)) // 1st directory instance is being setup { // Set gVmdirServerGlobals.serverId FIRST, so that correct SID can be generated for the objects added subsequently. gVmdirServerGlobals.serverId = 1; dwError = VmDirSrvSetupDomainInstance( pSchemaCtx, TRUE, TRUE, pszFQDomainName, pszDomainDN, pszUsername, pszPassword ); BAIL_ON_VMDIR_ERROR(dwError); // Create Deleted Objects container dwError = VmDirSrvCreateContainerWithEID( pSchemaCtx, pszDelObjsContainerDN, pszDelObjsContainerName, DEL_ENTRY_CONTAINER_ENTRY_ID ); BAIL_ON_VMDIR_ERROR(dwError); // Create Domain Controllers container dwError = VmDirSrvCreateOUContainer( pSchemaCtx, pszDCsContainerDN, pszDCsContainerName ); BAIL_ON_VMDIR_ERROR(dwError); // Create Computers container dwError = VmDirSrvCreateOUContainer( pSchemaCtx, pszComputersContainerDN, pszComputersContainerName ); BAIL_ON_VMDIR_ERROR(dwError); // Create Managed Service Accounts container dwError = VmDirSrvCreateContainer( pSchemaCtx, pszMSAsDN, pszMSAsContainerName ); BAIL_ON_VMDIR_ERROR(dwError); // Create Configuration container dwError = VmDirSrvCreateConfigContainer( pSchemaCtx, pszConfigContainerDN, pszConfigContainerName ); BAIL_ON_VMDIR_ERROR(dwError); // Create Certificate-Authorities container dwError = VmDirSrvCreateContainer( pSchemaCtx, pszCAContainerDN, pszCAContainerName ); BAIL_ON_VMDIR_ERROR(dwError); // Create Sites container dwError = VmDirSrvCreateContainer( pSchemaCtx, pszSitesContainerDN, pszSitesContainerName ); BAIL_ON_VMDIR_ERROR(dwError); /* // Create Site-Name container dwError = VmDirSrvCreateContainer( pSchemaCtx, pszSiteContainerDN, pszSiteContainerName ); BAIL_ON_VMDIR_ERROR(dwError); // Create Servers container dwError = VmDirSrvCreateContainer( pSchemaCtx, pszServersContainerDN, pszServersContainerName ); BAIL_ON_VMDIR_ERROR(dwError); */ // Create Site-Name container, Servers container, and THE Server object dwError = VmDirSrvCreateServerObj( pSchemaCtx ); BAIL_ON_VMDIR_ERROR(dwError); // Create Replication Agreements container dwError = VmDirSrvCreateReplAgrsContainer( pSchemaCtx ); BAIL_ON_VMDIR_ERROR(dwError); // 1st replica => no replication agreements => 1st replication cycle done VMDIR_LOCK_MUTEX(bInLockReplCycle, gVmdirGlobals.replCycleDoneMutex); VmDirConditionSignal(gVmdirGlobals.replCycleDoneCondition); VMDIR_UNLOCK_MUTEX(bInLockReplCycle, gVmdirGlobals.replCycleDoneMutex); } else { dwError = VmDirAllocateStringAVsnprintf( &pszReplAgrDN, "labeledURI=%s,%s", pszReplURI, pszReplAgrsContainerDN ); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirConstructReplAgr( pSchemaCtx, pszReplURI, VMDIR_DEFAULT_REPL_LAST_USN_PROCESSED, pszReplAgrDN, &pReplAgr ); BAIL_ON_VMDIR_ERROR(dwError); gFirstReplCycleMode = firstReplCycleMode; VMDIR_LOCK_MUTEX(bInLock, gVmdirGlobals.replAgrsMutex); pReplAgr->next = gVmdirReplAgrs; gVmdirReplAgrs = pReplAgr; // ownership transfer // wake up replication thread waiting on the existence // of a replication agreement. VmDirConditionSignal(gVmdirGlobals.replAgrsCondition); VMDIR_UNLOCK_MUTEX(bInLock, gVmdirGlobals.replAgrsMutex); } cleanup: if (pSchemaCtx) { VmDirSchemaCtxRelease(pSchemaCtx); } VMDIR_SAFE_FREE_MEMORY(pszDomainDN); VMDIR_SAFE_FREE_MEMORY(pszDelObjsContainerDN); VMDIR_SAFE_FREE_MEMORY(pszConfigContainerDN); VMDIR_SAFE_FREE_MEMORY(pszCAContainerDN); VMDIR_SAFE_FREE_MEMORY(pszSitesContainerDN); VMDIR_SAFE_FREE_MEMORY(pszSiteContainerDN); VMDIR_SAFE_FREE_MEMORY(pszServersContainerDN); VMDIR_SAFE_FREE_MEMORY(pszServerDN); VMDIR_SAFE_FREE_MEMORY(pszReplAgrsContainerDN); VMDIR_SAFE_FREE_MEMORY(pszReplAgrDN); VMDIR_SAFE_FREE_MEMORY(pszDCsContainerDN); VMDIR_SAFE_FREE_MEMORY(pszDCAccountDN); VMDIR_SAFE_FREE_MEMORY(pszDCAccountUPN); VMDIR_SAFE_FREE_MEMORY(pszComputersContainerDN); VMDIR_SAFE_FREE_MEMORY(pszComputerAccountDN); VMDIR_SAFE_FREE_MEMORY(pszMSAsDN); VMDIR_SAFE_FREE_MEMORY(pszUpperCaseFQDomainName); VMDIR_SAFE_FREE_MEMORY(pszUsersContainerDN); VMDIR_SAFE_FREE_MEMORY(pszUserDN); VMDIR_SAFE_FREE_MEMORY(pszDefaultAdminDN); VMDIR_SAFE_FREE_MEMORY(pszLowerCaseHostName); VmDirFreeBervalContent(&bv); return dwError; error: VmDirLog(LDAP_DEBUG_ANY, "VmDirSrvSetupHostInstance failed. Error(%u)", dwError); goto cleanup; }
/* * 1. remove extra spaces (i.e. collapse spaces into one) * 2. if bIsCaseIgnore, change to lower case * 3. if NO change in value, *ppOutBerv is NULL */ static DWORD normalizeString( BOOLEAN bIsCaseIgnore, PVDIR_BERVALUE pBerv ) { DWORD dwError = 0; DWORD dwCnt = 0; DWORD dwNewSize = 0; BOOLEAN bIsValueChanged = FALSE; char plocalBuf[128] = {0}; char* pBuf = &plocalBuf[0]; assert(pBerv); if (pBerv->bvnorm_val && pBerv->lberbv.bv_val != pBerv->bvnorm_val) { // cleanup bvnorm val/len VMDIR_SAFE_FREE_MEMORY(pBerv->bvnorm_val); pBerv->bvnorm_len = 0; } if (pBerv->lberbv.bv_len > 127) { dwError = VmDirAllocateMemory( sizeof(char) * pBerv->lberbv.bv_len + 1, (PVOID*)&pBuf); } for (dwCnt = 0; dwCnt < pBerv->lberbv.bv_len; dwCnt++) { if (! VDIR_ASCII_SPACE(pBerv->lberbv.bv_val[dwCnt])) { break; } } if (dwCnt != 0) { // consolidate leading spaces to just one pBuf[dwNewSize++] = ' '; } for (;dwCnt < pBerv->lberbv.bv_len; dwCnt++) { if (VDIR_ASCII_SPACE(pBerv->lberbv.bv_val[dwCnt])) { if ((dwCnt < pBerv->lberbv.bv_len - 1 && !VDIR_ASCII_SPACE(pBerv->lberbv.bv_val[dwCnt+1])) || (dwCnt == pBerv->lberbv.bv_len -1)) { pBuf[dwNewSize] = pBerv->lberbv.bv_val[dwCnt]; if (bIsCaseIgnore) { VIDR_ASCII_UPPER_TO_LOWER(pBuf[dwNewSize], bIsValueChanged); } dwNewSize++; } // skip extra middle and trailing spaces } else { pBuf[dwNewSize] = pBerv->lberbv.bv_val[dwCnt]; if (bIsCaseIgnore) { VIDR_ASCII_UPPER_TO_LOWER(pBuf[dwNewSize], bIsValueChanged); } dwNewSize++; } } if (dwNewSize == pBerv->lberbv.bv_len && !bIsValueChanged) { // value == normalized value, point to self pBerv->bvnorm_val = pBerv->lberbv.bv_val; pBerv->bvnorm_len = pBerv->lberbv.bv_len; } else { dwError = VmDirAllocateStringA( pBuf, &pBerv->bvnorm_val); BAIL_ON_VMDIR_ERROR(dwError); pBerv->bvnorm_len = dwNewSize; } cleanup: if (pBuf != &plocalBuf[0]) { VMDIR_SAFE_FREE_MEMORY(pBuf); } return dwError; error: goto cleanup; }
static DWORD VmDirSrvSetupDomainInstance( PVDIR_SCHEMA_CTX pSchemaCtx, BOOLEAN bSetupHost, BOOLEAN bFirstNodeBootstrap, PCSTR pszFQDomainName, PCSTR pszDomainDN, PCSTR pszUsername, PCSTR pszPassword ) { DWORD dwError = 0; PCSTR pszUsersContainerName = "Users"; PCSTR pszBuiltInContainerName = "Builtin"; PCSTR pszFSPsContainerName = FSP_CONTAINER_RDN_ATTR_VALUE; PCSTR pszBuiltInUsersGroupName = "Users"; PCSTR pszBuiltInAdministratorsGroupName = "Administrators"; PSTR pszUsersContainerDN = NULL; // CN=Users,<domain DN> PSTR pszBuiltInContainerDN = NULL; // CN=BuiltIn,<domain DN> PSTR pszFSPsContainerDN = NULL; // CN=ForeignSecurityPrincipals,<domain DN> PSTR pszUserDN = NULL; PSTR pszBuiltInUsersGroupDN = NULL; PSTR pszBuiltInAdministratorsGroupDN = NULL; PSTR pszDefaultPasswdLockoutPolicyDN = NULL; PSTR pszDCGroupDN = NULL; PSTR pszDCClientGroupDN = NULL; PSTR pszCertGroupDN = NULL; PSTR pszTenantRealmName = NULL; PSECURITY_DESCRIPTOR_RELATIVE pSecDescRel = NULL; ULONG ulSecDescRel = 0; SECURITY_INFORMATION SecInfo = 0; PSTR pszAdminSid = NULL; PSTR pszBuiltInUsersGroupSid = NULL; PSTR pszAdminsGroupSid = NULL; PSTR pszAdminUserKrbUPN = NULL; int i = 0; int startOfRdnInd = 0; // Create host/tenant domain dwError = VmDirSrvCreateDomain(pSchemaCtx, bSetupHost, pszDomainDN); BAIL_ON_VMDIR_ERROR(dwError); // Create Users container dwError = VmDirSrvCreateDN( pszUsersContainerName, pszDomainDN, &pszUsersContainerDN); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirSrvCreateContainer( pSchemaCtx, pszUsersContainerDN, pszUsersContainerName); BAIL_ON_VMDIR_ERROR(dwError); // Create Builtin container dwError = VmDirSrvCreateDN( pszBuiltInContainerName, pszDomainDN, &pszBuiltInContainerDN); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirSrvCreateBuiltinContainer( pSchemaCtx, pszBuiltInContainerDN, pszBuiltInContainerName ); BAIL_ON_VMDIR_ERROR(dwError); // Create ForeignSecurityPrincipals container dwError = VmDirSrvCreateDN( pszFSPsContainerName, pszDomainDN, &pszFSPsContainerDN); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirSrvCreateContainer( pSchemaCtx, pszFSPsContainerDN, pszFSPsContainerName); BAIL_ON_VMDIR_ERROR(dwError); if (bSetupHost) { // only do this for the very first node startup. if (bFirstNodeBootstrap) { dwError = VmDirSrvInitKrb(pSchemaCtx, pszFQDomainName, pszDomainDN); BAIL_ON_VMDIR_ERROR(dwError); // prepare administrator krb UPN for the very first node dwError = VmDirAllocateStringAVsnprintf( &pszAdminUserKrbUPN, "%s@%s", pszUsername, gVmdirKrbGlobals.pszRealm); BAIL_ON_VMDIR_ERROR(dwError); } } else { // setup tenant scenario. // Though we only support system domain kdc, we need UPN for SRP to function. dwError = VmDirKrbRealmNameNormalize(pszFQDomainName, &pszTenantRealmName); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirAllocateStringAVsnprintf( &pszAdminUserKrbUPN, "%s@%s", pszUsername, pszTenantRealmName); BAIL_ON_VMDIR_ERROR(dwError); } // Create Admin user dwError = VmDirSrvCreateUserDN( pszUsername, pszUsersContainerDN, &pszUserDN); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirGenerateWellknownSid(pszDomainDN, VMDIR_DOMAIN_USER_RID_ADMIN, &pszAdminSid); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirSrvCreateUser( pSchemaCtx, (bSetupHost && bFirstNodeBootstrap) ? DEFAULT_ADMINISTRATOR_ENTRY_ID : 0, pszUsername, pszUsername, pszFQDomainName, pszUsername, pszPassword, pszUserDN, pszAdminSid, pszAdminUserKrbUPN); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirSetAdministratorPasswordNeverExpires(); BAIL_ON_VMDIR_ERROR(dwError); // Create BuiltInUsers group dwError = VmDirAllocateStringAVsnprintf( &pszBuiltInUsersGroupDN, "cn=%s,%s", pszBuiltInUsersGroupName, pszBuiltInContainerDN); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirGenerateWellknownSid(pszDomainDN, VMDIR_DOMAIN_ALIAS_RID_USERS, &pszBuiltInUsersGroupSid); BAIL_ON_VMDIR_ERROR(dwError); // // Create the user group for tenant setup or for first host setup. // if (bSetupHost == FALSE || bFirstNodeBootstrap == TRUE) { dwError = VmDirSrvCreateBuiltInUsersGroup( pSchemaCtx, pszBuiltInUsersGroupName, pszBuiltInUsersGroupDN, pszUserDN, pszBuiltInUsersGroupSid); BAIL_ON_VMDIR_ERROR(dwError); } // Create BuiltInAdministrators group dwError = VmDirAllocateStringAVsnprintf( &pszBuiltInAdministratorsGroupDN, "cn=%s,%s", pszBuiltInAdministratorsGroupName, pszBuiltInContainerDN); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirGenerateWellknownSid(pszDomainDN, VMDIR_DOMAIN_ALIAS_RID_ADMINS, &pszAdminsGroupSid); BAIL_ON_VMDIR_ERROR(dwError); // // Create the admin group for tenant setup or for first host setup. // if (bSetupHost == FALSE || bFirstNodeBootstrap == TRUE) { dwError = VmDirSrvCreateBuiltInAdminGroup( pSchemaCtx, pszBuiltInAdministratorsGroupName, pszBuiltInAdministratorsGroupDN, pszUserDN, pszAdminsGroupSid ); BAIL_ON_VMDIR_ERROR(dwError); } // // Create DCadmins/DCClients/CERTAdmins groups only for the very first // host setup. // if ( bSetupHost && bFirstNodeBootstrap ) { // create DCAdmins Group dwError = VmDirAllocateStringAVsnprintf( &pszDCGroupDN, "cn=%s,%s", VMDIR_DC_GROUP_NAME, pszBuiltInContainerDN); BAIL_ON_VMDIR_ERROR(dwError); dwError = _VmDirSrvCreateBuiltInGroup( pSchemaCtx, VMDIR_DC_GROUP_NAME, pszDCGroupDN); BAIL_ON_VMDIR_ERROR(dwError); // create DCClients Group dwError = VmDirAllocateStringAVsnprintf( &pszDCClientGroupDN, "cn=%s,%s", VMDIR_DCCLIENT_GROUP_NAME, pszBuiltInContainerDN); BAIL_ON_VMDIR_ERROR(dwError); dwError = _VmDirSrvCreateBuiltInGroup( pSchemaCtx, VMDIR_DCCLIENT_GROUP_NAME, pszDCClientGroupDN); BAIL_ON_VMDIR_ERROR(dwError); // create CertAdmins Group dwError = VmDirAllocateStringAVsnprintf( &pszCertGroupDN, "cn=%s,%s", VMDIR_CERT_GROUP_NAME, pszBuiltInContainerDN); BAIL_ON_VMDIR_ERROR(dwError); dwError = _VmDirSrvCreateBuiltInCertGroup( pSchemaCtx, VMDIR_CERT_GROUP_NAME, pszCertGroupDN, pszUserDN, // member: default administrator pszDCGroupDN, // member: DCAdmins group pszDCClientGroupDN); // member: DCClients group BAIL_ON_VMDIR_ERROR(dwError); } // Set up SD for the entries created during instance set up // Default allows administrator VMDIR_ENTRY_ALL_ACCESS, // oneself VMDIR_ENTRY_GENERIC_WRITE dwError = VmDirSrvCreateDefaultSecDescRel( pszUserDN, pszAdminsGroupSid, &pSecDescRel, &ulSecDescRel, &SecInfo); BAIL_ON_VMDIR_ERROR(dwError); // add the same sd for all the objects created during instance set-up // Set SD for the Domain objects for (i = (int) VmDirStringLenA(pszDomainDN) - 1; i >= 0; i-- ) { if (i == 0 || pszDomainDN[i] == RDN_SEPARATOR_CHAR) { startOfRdnInd = (i == 0) ? 0 : i + 1 /* for , */; dwError = VmDirSetSecurityDescriptorForDn( (PSTR)pszDomainDN + startOfRdnInd, SecInfo, pSecDescRel, ulSecDescRel); BAIL_ON_VMDIR_ERROR(dwError); } } dwError = VmDirSetSecurityDescriptorForDn( (PSTR)pszDomainDN, SecInfo, pSecDescRel, ulSecDescRel); BAIL_ON_VMDIR_ERROR(dwError); // Set SD for the administrator object dwError = VmDirSetSecurityDescriptorForDn( pszUserDN, SecInfo, pSecDescRel, ulSecDescRel); BAIL_ON_VMDIR_ERROR(dwError); // Set SD for Users container dwError = VmDirSetSecurityDescriptorForDn( pszUsersContainerDN, SecInfo, pSecDescRel, ulSecDescRel); BAIL_ON_VMDIR_ERROR(dwError); // Set SD for Builtin container dwError = VmDirSetSecurityDescriptorForDn( pszBuiltInContainerDN, SecInfo, pSecDescRel, ulSecDescRel); BAIL_ON_VMDIR_ERROR(dwError); // Set SD for ForeignSecurityPrincipals container dwError = VmDirSetSecurityDescriptorForDn( pszFSPsContainerDN, SecInfo, pSecDescRel, ulSecDescRel); BAIL_ON_VMDIR_ERROR(dwError); if (bSetupHost == FALSE || bFirstNodeBootstrap == TRUE) { // Set SD for BuiltInUsers group dwError = VmDirSetSecurityDescriptorForDn( pszBuiltInUsersGroupDN, SecInfo, pSecDescRel, ulSecDescRel); BAIL_ON_VMDIR_ERROR(dwError); // Set SD for BuiltInAdministrators group dwError = VmDirSetSecurityDescriptorForDn( pszBuiltInAdministratorsGroupDN, SecInfo, pSecDescRel, ulSecDescRel); BAIL_ON_VMDIR_ERROR(dwError); } if ( bSetupHost && bFirstNodeBootstrap ) { // Set SD for BuiltIn DC group dwError = VmDirSetSecurityDescriptorForDn( pszDCGroupDN, SecInfo, pSecDescRel, ulSecDescRel); BAIL_ON_VMDIR_ERROR(dwError); // Set SD for BuiltIn DCClients group dwError = VmDirSetSecurityDescriptorForDn(pszDCClientGroupDN, SecInfo, pSecDescRel, ulSecDescRel); BAIL_ON_VMDIR_ERROR(dwError); // Set SD for BuiltIn Cert group dwError = VmDirSetSecurityDescriptorForDn( pszCertGroupDN, SecInfo, pSecDescRel, ulSecDescRel); BAIL_ON_VMDIR_ERROR(dwError); } // Create default password and lockout policy dwError = VmDirSrvCreateDN( PASSWD_LOCKOUT_POLICY_DEFAULT_CN, pszDomainDN, &pszDefaultPasswdLockoutPolicyDN ); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirSrvCreateDefaultPasswdPolicy(pSchemaCtx, pszDefaultPasswdLockoutPolicyDN); BAIL_ON_VMDIR_ERROR(dwError); // Set SD for Password lockout policy object dwError = VmDirSetSecurityDescriptorForDn( pszDefaultPasswdLockoutPolicyDN, SecInfo, pSecDescRel, ulSecDescRel); BAIL_ON_VMDIR_ERROR(dwError); cleanup: VMDIR_SAFE_FREE_MEMORY(pszUsersContainerDN); VMDIR_SAFE_FREE_MEMORY(pszBuiltInContainerDN); VMDIR_SAFE_FREE_MEMORY(pszFSPsContainerDN); VMDIR_SAFE_FREE_MEMORY(pszUserDN); VMDIR_SAFE_FREE_MEMORY(pszBuiltInUsersGroupDN); VMDIR_SAFE_FREE_MEMORY(pszBuiltInAdministratorsGroupDN); VMDIR_SAFE_FREE_MEMORY(pszDefaultPasswdLockoutPolicyDN); VMDIR_SAFE_FREE_MEMORY(pszDCGroupDN); VMDIR_SAFE_FREE_MEMORY(pszDCClientGroupDN); VMDIR_SAFE_FREE_MEMORY(pszCertGroupDN); VMDIR_SAFE_FREE_MEMORY(pszTenantRealmName); VMDIR_SAFE_FREE_MEMORY(pSecDescRel); VMDIR_SAFE_FREE_MEMORY(pszAdminSid); VMDIR_SAFE_FREE_MEMORY(pszBuiltInUsersGroupSid); VMDIR_SAFE_FREE_MEMORY(pszAdminsGroupSid); VMDIR_SAFE_FREE_MEMORY(pszAdminUserKrbUPN); return dwError; error: VmDirLog(LDAP_DEBUG_ANY, "VmDirSrvSetupDomainInstance failed. Error(%u)", dwError); goto cleanup; }
/* * Read schema definition from file * We only care for * attributetypes * objectclasses * ditcontentrules * attributeindices */ DWORD VmDirReadSchemaFile( PCSTR pszSchemaFilePath, PVMDIR_STRING_LIST* ppAtStrList, PVMDIR_STRING_LIST* ppOcStrList, PVMDIR_STRING_LIST* ppCrStrList, PVMDIR_STRING_LIST* ppIdxStrList ) { DWORD dwError = 0; CHAR pbuf[1024] = {0}; FILE* fp = NULL; PVMDIR_STRING_LIST pAtStrList = NULL; PVMDIR_STRING_LIST pOcStrList = NULL; PVMDIR_STRING_LIST pCrStrList = NULL; PVMDIR_STRING_LIST pIdxStrList = NULL; if (!pszSchemaFilePath || !ppAtStrList || !ppOcStrList || !ppCrStrList || !ppIdxStrList) { BAIL_WITH_VMDIR_ERROR(dwError, VMDIR_ERROR_INVALID_PARAMETER); } dwError = VmDirStringListInitialize(&pAtStrList, 2048); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirStringListInitialize(&pOcStrList, 512); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirStringListInitialize(&pCrStrList, 512); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirStringListInitialize(&pIdxStrList, 16); BAIL_ON_VMDIR_ERROR(dwError); #ifndef _WIN32 fp = fopen(pszSchemaFilePath, "r"); #else if (fopen_s(&fp, pszSchemaFilePath, "r") != 0) { fp = NULL; } #endif if (NULL == fp) { dwError = errno; VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "Open schema file (%s) failed. Error (%d)", pszSchemaFilePath, dwError); BAIL_ON_VMDIR_ERROR(dwError); } while (fgets(pbuf, sizeof(pbuf), fp) != NULL) { PSTR pszTag = NULL; if ((pbuf[0] == '\n') || (pbuf[0] == '#') || (pbuf[0] != ' ' && (pszTag = VmDirStringChrA(pbuf, ':')) == NULL)) { continue; } if (IS_ATTRIBUTETYPES_TAG(pbuf)) { dwError = _VmDirReadOneDefFromFile(fp, pAtStrList); BAIL_ON_VMDIR_ERROR(dwError); } else if (IS_OBJECTCLASSES_TAG(pbuf)) { dwError = _VmDirReadOneDefFromFile(fp, pOcStrList); BAIL_ON_VMDIR_ERROR(dwError); } else if (IS_CONTENTRULES_TAG(pbuf)) { dwError = _VmDirReadOneDefFromFile(fp, pCrStrList); BAIL_ON_VMDIR_ERROR(dwError); } else if (IS_ATTRIBUTEINDICES_TAG(pbuf)) { dwError = _VmDirReadOneDefFromFile(fp, pIdxStrList); BAIL_ON_VMDIR_ERROR(dwError); } else { continue; } } *ppAtStrList = pAtStrList; *ppOcStrList = pOcStrList; *ppCrStrList = pCrStrList; *ppIdxStrList = pIdxStrList; cleanup: if (fp) { fclose(fp); } return dwError; error: VmDirStringListFree(pAtStrList); VmDirStringListFree(pOcStrList); VmDirStringListFree(pCrStrList); VmDirStringListFree(pIdxStrList); goto cleanup; }
static DWORD VmDirSrvModifyPersistedDSERoot( PVDIR_SCHEMA_CTX pSchemaCtx, PSTR pszRootNamingContextDN, PSTR pszConfigNamingContextDN, PSTR pszSchemaNamingContextDN, PSTR pszSubSchemaSubEntryDN, PSTR pszServerDN, PSTR pszDefaultAdminDN, PSTR pszDCAccountDN, PSTR pszDCAccountUPN, PSTR pszDelObjsContainerDN, PSTR pszSiteName ) { DWORD dwError = 0; PSTR ppszPersistedDSERootAttrs[] = { ATTR_ROOT_DOMAIN_NAMING_CONTEXT, pszRootNamingContextDN, ATTR_DEFAULT_NAMING_CONTEXT, pszRootNamingContextDN, ATTR_CONFIG_NAMING_CONTEXT, pszConfigNamingContextDN, ATTR_SCHEMA_NAMING_CONTEXT, pszSchemaNamingContextDN, ATTR_SUB_SCHEMA_SUB_ENTRY, pszSubSchemaSubEntryDN, ATTR_NAMING_CONTEXTS, pszRootNamingContextDN, ATTR_NAMING_CONTEXTS, pszConfigNamingContextDN, ATTR_NAMING_CONTEXTS, pszSchemaNamingContextDN, ATTR_SERVER_NAME, pszServerDN, ATTR_DEFAULT_ADMIN_DN, pszDefaultAdminDN, ATTR_DC_ACCOUNT_DN, pszDCAccountDN, ATTR_DC_ACCOUNT_UPN, pszDCAccountUPN, ATTR_DEL_OBJS_CONTAINER, pszDelObjsContainerDN, ATTR_SITE_NAME, pszSiteName, NULL }; VDIR_OPERATION op = {0}; PSTR pszLocalErrMsg = NULL; VDIR_BERVALUE bvDSERootDN = VDIR_BERVALUE_INIT; int i = 0; dwError = VmDirInitStackOperation( &op, VDIR_OPERATION_TYPE_INTERNAL, LDAP_REQ_MODIFY, NULL ); BAIL_ON_VMDIR_ERROR_WITH_MSG( dwError, pszLocalErrMsg, "VmDirSrvModifyPersistedDSERoot: VmDirInitStackOperation failed with error code: %d.", dwError ); // Setup target DN bvDSERootDN.lberbv.bv_val = PERSISTED_DSE_ROOT_DN; bvDSERootDN.lberbv.bv_len = VmDirStringLenA( bvDSERootDN.lberbv.bv_val ); dwError = VmDirNormalizeDN( &bvDSERootDN, op.pSchemaCtx); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirBervalContentDup( &bvDSERootDN, &op.reqDn ); BAIL_ON_VMDIR_ERROR_WITH_MSG( dwError, pszLocalErrMsg, "VmDirSrvModifyPersistedDSERoot: BervalContentDup failed with error code: %d.", dwError ); op.pBEIF = VmDirBackendSelect(op.reqDn.lberbv.bv_val); assert(op.pBEIF); dwError = VmDirBervalContentDup( &op.reqDn, &op.request.modifyReq.dn ); BAIL_ON_VMDIR_ERROR_WITH_MSG( dwError, pszLocalErrMsg, "VmDirSrvModifyPersistedDSERoot: BervalContentDup failed with error code: %d.", dwError ); // Setup mods for (i = 0; ppszPersistedDSERootAttrs[i] != NULL; i += 2 ) { dwError = VmDirAppendAMod( &op, MOD_OP_REPLACE, ppszPersistedDSERootAttrs[i], (int) VmDirStringLenA(ppszPersistedDSERootAttrs[i]), ppszPersistedDSERootAttrs[i + 1], VmDirStringLenA(ppszPersistedDSERootAttrs[i + 1]) ); BAIL_ON_VMDIR_ERROR_WITH_MSG( dwError, pszLocalErrMsg, "VmDirSrvModifyPersistedDSERoot: VmDirAppendAMod failed with error code: %d.", dwError ); } dwError = VmDirAppendAMod( &op, MOD_OP_DELETE, ATTR_INVOCATION_ID, ATTR_INVOCATION_ID_LEN, gVmdirServerGlobals.invocationId.lberbv.bv_val, gVmdirServerGlobals.invocationId.lberbv.bv_len ); BAIL_ON_VMDIR_ERROR_WITH_MSG( dwError, pszLocalErrMsg, "VmDirSrvModifyPersistedDSERoot: VmDirAppendAMod failed with error code: %d.", dwError ); // Modify dwError = VmDirInternalModifyEntry( &op ); BAIL_ON_VMDIR_ERROR_WITH_MSG( dwError, pszLocalErrMsg, "VmDirSrvModifyPersistedDSERoot: InternalModifyEntry failed. DN: %s, Error code: %d, Error string: %s", op.reqDn.lberbv.bv_val, dwError, VDIR_SAFE_STRING( op.ldapResult.pszErrMsg ) ); cleanup: VmDirFreeBervalContent(&bvDSERootDN); VmDirFreeOperationContent(&op); VMDIR_SAFE_FREE_MEMORY(pszLocalErrMsg); return dwError; error: VmDirLog(LDAP_DEBUG_ANY, VDIR_SAFE_STRING(pszLocalErrMsg) ); goto cleanup; }
/* UnionCandidates: Take a union of 2 candidates lists. * */ static void UnionCandidates( VDIR_CANDIDATES ** srcCandidates, VDIR_CANDIDATES ** dstCandidates) { DWORD dwError = 0; VDIR_CANDIDATES * resCandidates = NULL; int i = 0; int j = 0; VmDirLog( LDAP_DEBUG_TRACE, "UnionCandidates: Begin" ); assert( srcCandidates != NULL && *srcCandidates != NULL && dstCandidates != NULL && *dstCandidates != NULL ); assert( (*srcCandidates)->positive == (*dstCandidates)->positive ); if ((*srcCandidates)->size == 0) { goto done; } if ((*dstCandidates)->size == 0) { DeleteCandidates( dstCandidates ); *dstCandidates = *srcCandidates; *srcCandidates = NULL; goto done; } if ((*dstCandidates)->eIdsSorted == FALSE) { qsort ( (*dstCandidates)->eIds, (*dstCandidates)->size, sizeof( ENTRYID ), _VmDirCompareEntryIds ); (*dstCandidates)->eIdsSorted = TRUE; } if ((*srcCandidates)->eIdsSorted == FALSE) { qsort ( (*srcCandidates)->eIds, (*srcCandidates)->size, sizeof( ENTRYID ), _VmDirCompareEntryIds ); (*srcCandidates)->eIdsSorted = TRUE; } resCandidates = NewCandidates( (*srcCandidates)->size + (*dstCandidates)->size, (*srcCandidates)->positive ); for (i = 0, j = 0; (i < (*srcCandidates)->size) && (j < (*dstCandidates)->size); ) { if ((*srcCandidates)->eIds[i] < (*dstCandidates)->eIds[j]) { dwError = VmDirAddToCandidates( resCandidates, (*srcCandidates)->eIds[i]); BAIL_ON_VMDIR_ERROR(dwError); i++; continue; } if ((*dstCandidates)->eIds[j] < (*srcCandidates)->eIds[i]) { dwError = VmDirAddToCandidates( resCandidates, (*dstCandidates)->eIds[j]); BAIL_ON_VMDIR_ERROR(dwError); j++; continue; } dwError = VmDirAddToCandidates( resCandidates, (*dstCandidates)->eIds[j]); BAIL_ON_VMDIR_ERROR(dwError); i++; j++; } for (; i < (*srcCandidates)->size; i++) { dwError = VmDirAddToCandidates( resCandidates, (*srcCandidates)->eIds[i]); BAIL_ON_VMDIR_ERROR(dwError); } for (; j < (*dstCandidates)->size; j++) { dwError = VmDirAddToCandidates( resCandidates, (*dstCandidates)->eIds[j]); BAIL_ON_VMDIR_ERROR(dwError); } resCandidates->eIdsSorted = TRUE; DeleteCandidates( dstCandidates ); *dstCandidates = resCandidates; done: VmDirLog( LDAP_DEBUG_TRACE, "UnionCandidates: End" ); return; error: DeleteCandidates( dstCandidates ); resCandidates->size = 0; *dstCandidates = resCandidates; goto done; }
static VOID _VdcadminClientTestSimpleSSLBind( PCSTR pszLDAPSURI, PCSTR pszDefaultBindDN, PCSTR pszDefaultPasswd ) { DWORD dwError = 0; int ldap_version_3 = LDAP_VERSION3; int iTLSNever = LDAP_OPT_X_TLS_NEVER; int iTLSMin = LDAP_OPT_X_TLS_PROTOCOL_TLS1_0; LDAP * pLD = NULL; BerValue ldapBindPwd = {0}; dwError = ldap_initialize( &pLD, pszLDAPSURI ); /* Set LDAP V3 protocol version */ ldap_set_option( pLD, LDAP_OPT_PROTOCOL_VERSION, &ldap_version_3 ); ldap_set_option(NULL, LDAP_OPT_X_TLS_PROTOCOL_MIN, &iTLSMin); ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &iTLSNever); dwError = ldap_sasl_bind_s( pLD, "", LDAP_SASL_SIMPLE, &ldapBindPwd, // no credentials NULL, NULL, NULL); BAIL_ON_VMDIR_ERROR(dwError); printf("%s (ANONYMOUS) bind succeeded.\n", pszLDAPSURI); ldapBindPwd.bv_val = (PSTR)pszDefaultPasswd; ldapBindPwd.bv_len = strlen( pszDefaultPasswd ); dwError = ldap_sasl_bind_s( pLD, pszDefaultBindDN, LDAP_SASL_SIMPLE, &ldapBindPwd, // ldaps with credentials NULL, NULL, NULL); BAIL_ON_VMDIR_ERROR(dwError); printf("%s (%s) bind succeeded.\n\n", pszLDAPSURI, VDIR_SAFE_STRING(pszDefaultBindDN) ); cleanup: if (pLD) { dwError = ldap_unbind_ext_s( pLD, NULL, NULL); } return; error: printf("\n\n++++++++++++++++++++ %s SSL bind failed. (%d)(%s)\n\n", pszLDAPSURI, dwError, ldap_err2string(dwError)); goto cleanup; }
/* * Bootstrap initial schema from default data. * Not a full schema as ones that initialize from file or entry, * but with limited information that we can bootstrap schema entry from * data store or file. * 1. pSchema->ats.pSortName (in sort order) * 1.1 pSchema->ats.pSortName(pszName, usIdMap) * 2. pSchema->ats.dwNumATs * 3. pSchema->ats.ppSortIdMap (in sort order) * 4. pSchema-> bIsBootStrapSchema = TRUE * 5. pSchema->usNextId = 100 * * gVdirSchemaGlobals.pInstances[0] = bootstrap schema * */ DWORD VmDirSchemaLibInit( VOID ) { BOOLEAN bInLock = FALSE; DWORD dwError = 0; DWORD dwCnt = 0; PVDIR_SCHEMA_INSTANCE pSchema = NULL; PSTR OCTable[] = VDIR_SCHEMA_BOOTSTRP_OC_INITIALIZER; VDIR_SCHEMA_BOOTSTRAP_TABLE ATTable[] = VDIR_SCHEMA_BOOTSTRP_ATTR_INITIALIZER; // initialize gVdirSchemaGlobals dwError = VmDirAllocateMutex(&gVdirSchemaGlobals.mutex); BAIL_ON_VMDIR_ERROR(dwError); dwError = VdirSchemaInstanceAllocate( &pSchema, sizeof(ATTable)/sizeof(ATTable[0]), sizeof(OCTable)/sizeof(OCTable[0]), 0, // no content rule in bootstrap 0, // no structure rule in bootstrap 0); // no fnameforma in bootstrap BAIL_ON_VMDIR_ERROR(dwError); for (dwCnt = 0 ; dwCnt < sizeof(ATTable)/sizeof(ATTable[0]); dwCnt++) { dwError = VmDirSchemaParseStrToATDesc( ATTable[dwCnt].pszDesc, pSchema->ats.pATSortName+dwCnt); BAIL_ON_VMDIR_ERROR(dwError); pSchema->ats.pATSortName[dwCnt].usAttrID = ATTable[dwCnt].usAttrID; } qsort(pSchema->ats.pATSortName, pSchema->ats.usNumATs, sizeof(VDIR_SCHEMA_AT_DESC), VdirSchemaPATNameCmp); dwError = VmDirAllocateMemory( sizeof(PVDIR_SCHEMA_AT_DESC) * pSchema->ats.usNumATs, (PVOID*)&pSchema->ats.ppATSortIdMap); BAIL_ON_VMDIR_ERROR(dwError); for (dwCnt = 0 ; dwCnt < sizeof(ATTable)/sizeof(ATTable[0]); dwCnt++) { pSchema->ats.ppATSortIdMap[pSchema->ats.pATSortName[dwCnt].usAttrID -1] = &pSchema->ats.pATSortName[dwCnt]; } pSchema-> bIsBootStrapSchema = TRUE; pSchema->ats.usNextId = MAX_RESERVED_ATTR_ID_MAP + 1; dwError = VdirSyntaxLoad(); BAIL_ON_VMDIR_ERROR(dwError); dwError = VdirMatchingRuleLoad(); BAIL_ON_VMDIR_ERROR(dwError); VMDIR_LOCK_MUTEX(bInLock, gVdirSchemaGlobals.mutex); gVdirSchemaGlobals.pSchema = pSchema; dwError = VdirSchemaCtxAcquireInLock(TRUE, &gVdirSchemaGlobals.pCtx); // add self reference BAIL_ON_VMDIR_ERROR(dwError); assert(gVdirSchemaGlobals.pCtx); VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL, "Startup bootstrap schema instance (%p)", gVdirSchemaGlobals.pSchema); cleanup: VMDIR_UNLOCK_MUTEX(bInLock, gVdirSchemaGlobals.mutex); return dwError; error: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "VmDirSchemaLibInit failed (%d)", dwError); gVdirSchemaGlobals.pSchema = NULL; if (pSchema) { VdirSchemaInstanceFree(pSchema); } goto cleanup; }
DWORD VmDirLdapSchemaInit( PVDIR_LDAP_SCHEMA* ppSchema ) { DWORD dwError = 0; PVDIR_LDAP_SCHEMA pSchema = NULL; if (!ppSchema) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } dwError = VmDirAllocateMemory( sizeof(VDIR_LDAP_SCHEMA), (PVOID*)&pSchema); BAIL_ON_VMDIR_ERROR(dwError); dwError = LwRtlCreateHashMap(&pSchema->attributeTypes, LwRtlHashDigestPstrCaseless, LwRtlHashEqualPstrCaseless, NULL); BAIL_ON_VMDIR_ERROR(dwError); dwError = LwRtlCreateHashMap(&pSchema->objectClasses, LwRtlHashDigestPstrCaseless, LwRtlHashEqualPstrCaseless, NULL); BAIL_ON_VMDIR_ERROR(dwError); dwError = LwRtlCreateHashMap(&pSchema->contentRules, LwRtlHashDigestPstrCaseless, LwRtlHashEqualPstrCaseless, NULL); BAIL_ON_VMDIR_ERROR(dwError); dwError = LwRtlCreateHashMap(&pSchema->structureRules, LwRtlHashDigestPstrCaseless, LwRtlHashEqualPstrCaseless, NULL); BAIL_ON_VMDIR_ERROR(dwError); dwError = LwRtlCreateHashMap(&pSchema->nameForms, LwRtlHashDigestPstrCaseless, LwRtlHashEqualPstrCaseless, NULL); BAIL_ON_VMDIR_ERROR(dwError); *ppSchema = pSchema; cleanup: return dwError; error: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s failed, error (%d)", __FUNCTION__, dwError ); VmDirFreeLdapSchema(pSchema); goto cleanup; }