/* * 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; }
/* * 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; }
/* * 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; }