static BOOLEAN _VmDirReplAttrConflictCheck( PVMDIR_ATTRIBUTE_METADATA pSupplierMetaData, PVMDIR_ATTRIBUTE_METADATA pConsumerMetaData ) { BOOLEAN bSupplierWon = FALSE; if ((pSupplierMetaData->version > pConsumerMetaData->version) || (pSupplierMetaData->version == pConsumerMetaData->version && VmDirStringNCompareA( pSupplierMetaData->pszOrigInvoId, pConsumerMetaData->pszOrigInvoId, VMDIR_GUID_STR_LEN, FALSE) > 0) || (pSupplierMetaData->version == pConsumerMetaData->version && VmDirStringNCompareA( pSupplierMetaData->pszOrigInvoId, pConsumerMetaData->pszOrigInvoId, VMDIR_GUID_STR_LEN, FALSE) == 0 && pSupplierMetaData->origUsn > pConsumerMetaData->origUsn)) { bSupplierWon = TRUE; } return bSupplierWon; }
static DWORD _VmDirSchemaCheckNameform( PVDIR_SCHEMA_CTX pCtx, PVDIR_ENTRY pEntry, PVDIR_SCHEMA_OC_DESC pStructOCDesc ) { DWORD dwError = 0; PSTR pszLocalErrorMsg = NULL; if ( !pCtx || !pStructOCDesc || !pEntry || !pEntry->dn.bvnorm_val ) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } #if 0 // should NOT enable this until we have all namform and structure rule defined if ( pStructOCDesc->usNumMustRDNs > 0 ) { // not yet support multi RDNs case. only check the first MUST RDN for now. size_t iLen = VmDirStringLenA(pStructOCDesc->ppszMustRDNs[0]); if ( VmDirStringNCompareA( pEntry->dn.bvnorm_val, pStructOCDesc->ppszMustRDNs[0], iLen, FALSE ) != 0 || pEntry->dn.bvnorm_val[iLen] != '=' ) { dwError = ERROR_INVALID_ENTRY; BAIL_ON_VMDIR_ERROR_WITH_MSG( dwError, pszLocalErrorMsg, "_VmDirSchemaCheckNameform: rdn must be (%s). (%d)", VDIR_SAFE_STRING( pStructOCDesc->ppszMustRDNs[0] ), dwError ); } } #endif cleanup: VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg); return dwError; error: if ( !pCtx->pszErrorMsg ) { pCtx->pszErrorMsg = pszLocalErrorMsg; pszLocalErrorMsg = NULL; pCtx->dwErrorCode = dwError; } goto cleanup; }
static BOOLEAN compareSubString( VDIR_SCHEMA_MATCH_TYPE type, PVDIR_BERVALUE pAssert, PVDIR_BERVALUE pBerv ) { BOOLEAN bRtn = FALSE; DWORD dwCnt = 0; size_t dwDelta = 0; if (!pAssert || !pBerv || pAssert->bvnorm_len > pBerv->bvnorm_len) { goto done; } dwDelta = pBerv->bvnorm_len - pAssert->bvnorm_len; switch (type) { case VDIR_SCHEMA_MATCH_SUBSTR_INIT: bRtn = (VmDirStringNCompareA(pAssert->bvnorm_val, pBerv->bvnorm_val, pAssert->bvnorm_len, TRUE) == 0); break; case VDIR_SCHEMA_MATCH_SUBSTR_FINAL: bRtn = (VmDirStringNCompareA(pAssert->bvnorm_val, pBerv->bvnorm_val + dwDelta, pAssert->bvnorm_len, TRUE) == 0); break; case VDIR_SCHEMA_MATCH_SUBSTR_ANY: // TODO, not efficient for (dwCnt = 1; dwCnt < dwDelta; dwCnt++) { if (VmDirStringNCompareA(pAssert->bvnorm_val, pBerv->bvnorm_val + dwCnt, pAssert->bvnorm_len, TRUE) == 0) { bRtn = TRUE; break; } } break; default: break; } done: return bRtn; }
static BOOLEAN compareString( VDIR_SCHEMA_MATCH_TYPE type, PVDIR_BERVALUE pAssert, PVDIR_BERVALUE pBerv ) { BOOLEAN bRtn = FALSE; size_t dwMinLen = 0; int iResult = 0; if (!pAssert || !pBerv || pAssert->bvnorm_len > pBerv->bvnorm_len) { goto done; } switch (type) { case VDIR_SCHEMA_MATCH_EQUAL: if (pAssert->bvnorm_len != pBerv->bvnorm_len) { goto done; } bRtn = (VmDirStringNCompareA(pAssert->bvnorm_val, pBerv->bvnorm_val, pAssert->lberbv.bv_len, TRUE) == 0); break; case VDIR_SCHEMA_MATCH_GE: dwMinLen = MIN(pAssert->bvnorm_len, pBerv->bvnorm_len); iResult = VmDirStringNCompareA(pAssert->bvnorm_val, pBerv->bvnorm_val, dwMinLen, TRUE); if ((iResult > 0) || (iResult == 0 && pAssert->bvnorm_len >= pBerv->bvnorm_len)) { bRtn = TRUE; } break; case VDIR_SCHEMA_MATCH_LE: dwMinLen = MIN(pAssert->bvnorm_len, pBerv->bvnorm_len); iResult = VmDirStringNCompareA(pAssert->bvnorm_val, pAssert->lberbv.bv_val, dwMinLen, TRUE); if ((iResult < 0) || (iResult == 0 && pAssert->bvnorm_len <= pBerv->bvnorm_len)) { bRtn = TRUE; } break; default: break; } done: return bRtn; }
/* * 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; }
BOOLEAN VmDirIsProtectedEntry( PVDIR_ENTRY pEntry ) { BOOLEAN bResult = FALSE; PCSTR pszDomainDn = NULL; PCSTR pszEntryDn = NULL; size_t domainDnLen = 0; size_t entryDnLen = 0; const CHAR szAdministrators[] = "cn=Administrators,cn=Builtin"; const CHAR szCertGroup[] = "cn=CAAdmins,cn=Builtin"; const CHAR szDCAdminsGroup[] = "cn=DCAdmins,cn=Builtin"; const CHAR szUsersGroup[] = "cn=Users,cn=Builtin"; const CHAR szAdministrator[] = "cn=Administrator,cn=Users"; if (pEntry == NULL) { goto error; } pszDomainDn = gVmdirServerGlobals.systemDomainDN.lberbv.bv_val; if (pszDomainDn == NULL) { goto error; } pszEntryDn = pEntry->dn.lberbv.bv_val; if (pszEntryDn == NULL) { goto error; } entryDnLen = strlen(pszEntryDn); domainDnLen = strlen(pszDomainDn); if (entryDnLen <= domainDnLen) { goto error; } if (pszEntryDn[(entryDnLen - domainDnLen) - 1] != ',') { goto error; } // Make sure system DN matches if (VmDirStringCompareA(&pszEntryDn[entryDnLen - domainDnLen], pszDomainDn, FALSE)) { goto error; } if (!VmDirStringNCompareA(pszEntryDn, szAdministrators, sizeof(szAdministrators) - 1, FALSE) || !VmDirStringNCompareA(pszEntryDn, szCertGroup, sizeof(szCertGroup) - 1, FALSE) || !VmDirStringNCompareA(pszEntryDn, szDCAdminsGroup, sizeof(szDCAdminsGroup) - 1, FALSE) || !VmDirStringNCompareA(pszEntryDn, szUsersGroup, sizeof(szUsersGroup) - 1, FALSE) || !VmDirStringNCompareA(pszEntryDn, szAdministrator, sizeof(szAdministrator) - 1, FALSE)) { bResult = TRUE; } error: return bResult; }
/* * Read schema definition from file * We ignore - * 1. DN/EntryDN * 2. ldapSyntax * 3. matchingRules */ static DWORD schemaReadFile( PCSTR pszSchemaFilePath, PSTR** pppszDescs, USHORT* pdwSize ) { static PSTR pszDNTag = "DN:"; static PSTR pszENTRYDNTag = "ENTRYDN:"; static PSTR pszSyntaxTag = "ldapSyntaxes:"; static PSTR pszMatchingRuleTag = "matchingRules:"; static PSTR pszName = "NAME "; DWORD dwError = 0; USHORT dwSize = 0; DWORD dwCnt = 100; size_t iOldLen = 0 ; size_t iNewLen = 0 ; PSTR* ppszDescs = NULL; PSTR pszTmp = NULL; char pbuf[2048] = {0}; FILE* fp = NULL; dwError = VmDirAllocateMemory( sizeof(*ppszDescs) * dwCnt, (PVOID*)&ppszDescs); 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; size_t len = VmDirStringLenA(pbuf)-1; if (pbuf[len] == '\n') { pbuf[len] = '\0'; } if ((pbuf[0] == '\0') || (pbuf[0] == '#') || (pbuf[0] != ' ' && (pszTag = VmDirStringChrA(pbuf, ':')) == NULL)) { continue; } if (VmDirStringNCompareA(pbuf, pszDNTag, VmDirStringLenA(pszDNTag), FALSE) == 0 || VmDirStringNCompareA(pbuf, pszENTRYDNTag, VmDirStringLenA(pszENTRYDNTag), FALSE) == 0 || VmDirStringNCompareA(pbuf, pszSyntaxTag, VmDirStringLenA(pszSyntaxTag), FALSE) == 0 || VmDirStringNCompareA(pbuf, pszMatchingRuleTag, VmDirStringLenA(pszMatchingRuleTag), FALSE) == 0) { continue; } if (dwCnt == dwSize + 1) { DWORD dwOldSize = dwCnt; dwCnt = dwCnt * 2; dwError = VmDirReallocateMemoryWithInit( ppszDescs, (PVOID*)&ppszDescs, dwCnt * sizeof(*ppszDescs), dwOldSize * sizeof(*ppszDescs)); BAIL_ON_VMDIR_ERROR(dwError); } if (pbuf[0] != ' ') { dwError = VmDirAllocateStringA(pbuf, &(ppszDescs[dwSize++])); BAIL_ON_VMDIR_ERROR(dwError); } else { // consolidate leading spaces into one char* pszNonSpace = pbuf+1; while (*pszNonSpace == ' ') { pszNonSpace++; } { // Normalising NAME field for everything attributeTypes,objectClasses,ditContentRules , i.e Removing multiple spaces if (VmDirStringNCompareA(pszNonSpace, pszName, VmDirStringLenA(pszName), TRUE) == 0) { _VmDirNormaliseNameField (pszNonSpace, VmDirStringLenA(pszNonSpace)); } iOldLen = VmDirStringLenA(ppszDescs[dwSize-1]); iNewLen = VmDirStringLenA(pszNonSpace-1); dwError = VmDirReallocateMemoryWithInit( ppszDescs[dwSize-1], (PVOID*)&pszTmp, sizeof(char) * (iOldLen + iNewLen + 1), sizeof(char) * iOldLen); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirCopyMemory( &pszTmp[iOldLen], sizeof(char) * (iOldLen + iNewLen + 1), &(pszNonSpace-1)[0], iNewLen ); BAIL_ON_VMDIR_ERROR(dwError); ppszDescs[dwSize-1] = pszTmp; pszTmp = NULL; } } } *pppszDescs = ppszDescs; *pdwSize = dwSize; cleanup: if (fp) { fclose(fp); } return dwError; error: *pppszDescs = NULL; *pdwSize = 0; if (ppszDescs) { VmDirFreeStringArrayA(ppszDescs); VMDIR_SAFE_FREE_MEMORY(ppszDescs); } goto cleanup; }
/* * convert schema file into entry */ DWORD VmDirSchemaInitalizeFileToEntry( PCSTR pszSchemaFilePath, PVDIR_ENTRY* ppEntry ) { DWORD dwError = 0; USHORT dwCnt = 0; PVDIR_ENTRY pEntry = NULL; PSTR pszTag = NULL; PSTR pszTagEnd = NULL; USHORT dwTag = 0; PSTR* ppszDescs = NULL; USHORT dwDescSize = 0; PSTR* ppszSyntaxes = NULL; USHORT dwSyntaxSize = 0; PSTR* ppszMRs = NULL; USHORT dwMRSize = 0; PVDIR_SCHEMA_CTX pCtx = NULL; if ( !pszSchemaFilePath || !ppEntry ) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } dwError = schemaReadFile( pszSchemaFilePath, &ppszDescs, &dwDescSize); BAIL_ON_VMDIR_ERROR(dwError); // sort ppszDescs by tag order (i.e. ats, ocs, syntax...) qsort(ppszDescs, dwDescSize, sizeof(*ppszDescs), schemaInitPPSTRCmp); dwError = VmDirSchemaCtxAcquire(&pCtx); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirAllocateMemory( sizeof(VDIR_ENTRY), (PVOID*)&pEntry); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirAllocateStringA( SUB_SCHEMA_SUB_ENTRY_DN, &pEntry->dn.lberbv.bv_val); BAIL_ON_VMDIR_ERROR(dwError); pEntry->dn.bOwnBvVal = TRUE; pEntry->dn.lberbv.bv_len = VmDirStringLenA(pEntry->dn.lberbv.bv_val); dwError = VmDirNormalizeDN( &(pEntry->dn), pCtx ); BAIL_ON_VMDIR_ERROR(dwError); pEntry->allocType = ENTRY_STORAGE_FORMAT_NORMAL; // load every thing from file except EntryDN, ldapSyntaxes and matchingRules { // By now, we know all PSTR have format - "tag: value" for (dwCnt=0; dwCnt < dwDescSize; dwCnt++) { PSTR pszNewTag = ppszDescs[dwCnt]; PSTR pszNewTagEnd = VmDirStringChrA(ppszDescs[dwCnt], ':'); if (pszTag == NULL) { pszTag = pszNewTag; pszTagEnd = pszNewTagEnd; dwTag = dwCnt; continue; } if (((pszTagEnd - pszTag) == (pszNewTagEnd - pszNewTag)) && VmDirStringNCompareA(pszTag, pszNewTag, pszTagEnd - pszTag, TRUE) == 0) { continue; } else { dwError = schemaInitFillAttrFromFile( pCtx, ppszDescs+dwTag, dwCnt - dwTag, pszTag, pszTagEnd - pszTag, pEntry); BAIL_ON_VMDIR_ERROR(dwError); pszTag = pszNewTag; pszTagEnd = pszNewTagEnd; dwTag = dwCnt; } } dwError = schemaInitFillAttrFromFile( pCtx, ppszDescs+dwTag, dwCnt - dwTag, pszTag, pszTagEnd - pszTag, pEntry); BAIL_ON_VMDIR_ERROR(dwError); } dwError = VdirSyntaxGetDefinition( &ppszSyntaxes, &dwSyntaxSize); BAIL_ON_VMDIR_ERROR(dwError); dwError = schemaInitFillAttrFromCache( pCtx, ppszSyntaxes, dwSyntaxSize, VDIR_ATTRIBUTE_LADPSYNTAXES, pEntry); BAIL_ON_VMDIR_ERROR(dwError); dwError = VdirMatchingRuleGetDefinition( &ppszMRs, &dwMRSize); BAIL_ON_VMDIR_ERROR(dwError); dwError = schemaInitFillAttrFromCache( pCtx, ppszMRs, dwMRSize, VDIR_ATTRIBUTE_MATCHINGRULES, pEntry); BAIL_ON_VMDIR_ERROR(dwError); pEntry->eId = SUB_SCEHMA_SUB_ENTRY_ID; // NOTE, entry is only partially constructed to bootstrap schema *ppEntry = pEntry; cleanup: if (pCtx) { VmDirSchemaCtxRelease(pCtx); } if (ppszDescs) { VmDirFreeStringArrayA(ppszDescs); VMDIR_SAFE_FREE_MEMORY(ppszDescs); } if (ppszSyntaxes) { VmDirFreeStringArrayA(ppszSyntaxes); VMDIR_SAFE_FREE_MEMORY(ppszSyntaxes); } if (ppszMRs) { VmDirFreeStringArrayA(ppszMRs); VMDIR_SAFE_FREE_MEMORY(ppszMRs); } return dwError; error: if (pEntry) { VmDirFreeEntry(pEntry); } goto cleanup; }