Пример #1
0
/* a fixed time string comparision function */
BOOLEAN
VmDirIsValidSecret(
    PCSTR pszTheirs,
    PCSTR pszOurs
    )
{
    ULONG ret = 0;
    int  len = 0;
    int  i = 0;
    PCSTR p = NULL;

    if (pszOurs == NULL)
    {
        return FALSE;
    }

    len = VmDirStringLenA(pszOurs);
    if (pszTheirs == NULL || VmDirStringLenA(pszTheirs) != len)
    {
        ret = 1;
        p = pszOurs;
    } else
    {
        p = pszTheirs;
    }

    for (i = len - 1; i >= 0; i--)
       ret |= p[i] ^ pszOurs[i];
    return ret == 0;
}
Пример #2
0
int
VmDirCreateRequestVoteCtrl(
    PVDIR_REQUEST_VOTE_CONTROL_VALUE pRequestVoteCtrlValue,
    LDAPControl*    pRequestVoteCtrl
    )
{
    int             retVal = LDAP_SUCCESS;
    BerElement*     pBer = NULL;
    BerValue        candidateIdBV = {0};
    BerValue        lastLogIndexBV = {0};

    if (!pRequestVoteCtrlValue || !pRequestVoteCtrl)
    {
        BAIL_WITH_VMDIR_ERROR(retVal, VMDIR_ERROR_INVALID_PARAMETER);
    }

    if ((pBer = ber_alloc()) == NULL)
    {
        BAIL_WITH_VMDIR_ERROR(retVal, VMDIR_ERROR_NO_MEMORY);
    }

    candidateIdBV.bv_val = pRequestVoteCtrlValue->candidateId;
    candidateIdBV.bv_len = VmDirStringLenA(pRequestVoteCtrlValue->candidateId);

    retVal = VmDirAllocateStringPrintf(&lastLogIndexBV.bv_val, "%"PRIu64, pRequestVoteCtrlValue->lastLogIndex);
    BAIL_ON_VMDIR_ERROR( retVal );
    lastLogIndexBV.bv_len = VmDirStringLenA(lastLogIndexBV.bv_val);

    if ( ber_printf( pBer, "{iOOi}", pRequestVoteCtrlValue->term, &candidateIdBV,
                    &lastLogIndexBV, pRequestVoteCtrlValue->lastLogTerm) == -1)
    {
        VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "%s: ber_printf failed.", __FUNCTION__ );
        BAIL_WITH_VMDIR_ERROR(retVal, VMDIR_ERROR_NO_MEMORY);
    }

    memset( pRequestVoteCtrl, 0, sizeof( LDAPControl ));
    pRequestVoteCtrl->ldctl_oid = LDAP_REQUEST_VOTE_CONTROL;
    pRequestVoteCtrl->ldctl_iscritical = '1';
    if (ber_flatten2(pBer, &pRequestVoteCtrl->ldctl_value, 1))
    {
        BAIL_WITH_VMDIR_ERROR(retVal, VMDIR_ERROR_NO_MEMORY);
    }

cleanup:
    VMDIR_SAFE_FREE_MEMORY(lastLogIndexBV.bv_val);
    if (pBer)
    {
        ber_free(pBer, 1);
    }
    return retVal;

error:
    VmDirFreeCtrlContent(pRequestVoteCtrl);
    goto cleanup;
}
Пример #3
0
//Add one more single value replace mod onto the LdapOp's mods
DWORD
VmDirAddModSingleAttributeReplace(
    PVDIR_OPERATION     pLdapOp,
    PCSTR               pszNormDN,
    PCSTR               pszAttrName,
    PVDIR_BERVALUE      pBervAttrValue
    )
{
    DWORD               dwError = 0;
    PVDIR_MODIFICATION  pMod = NULL;

    if (!pszNormDN || !pszAttrName || !pBervAttrValue)
    {
        dwError = VMDIR_ERROR_INVALID_PARAMETER;
        BAIL_ON_VMDIR_ERROR(dwError);
    }

    pLdapOp->reqDn.lberbv.bv_val = (PSTR)pszNormDN;
    pLdapOp->reqDn.lberbv.bv_len = VmDirStringLenA(pszNormDN);

    dwError = VmDirAllocateMemory(sizeof(*pMod)*1, (PVOID)&pMod);
    BAIL_ON_VMDIR_ERROR(dwError);

    pMod->operation = MOD_OP_REPLACE;
    dwError = VmDirModAddSingleValueAttribute(
            pMod,
            pLdapOp->pSchemaCtx,
            pszAttrName,
            pBervAttrValue->lberbv.bv_val,
            pBervAttrValue->lberbv.bv_len);
    BAIL_ON_VMDIR_ERROR(dwError);

    pLdapOp->request.modifyReq.dn.lberbv.bv_val = (PSTR)pszNormDN;
    pLdapOp->request.modifyReq.dn.lberbv.bv_len = VmDirStringLenA(pszNormDN);
    pMod->next = pLdapOp->request.modifyReq.mods;
    pLdapOp->request.modifyReq.mods = pMod;
    pLdapOp->request.modifyReq.numMods++;
    pMod = NULL;

cleanup:

    if (pMod)
    {
        VmDirModificationFree(pMod);
    }

    return dwError;

error:
    goto cleanup;
}
Пример #4
0
static
DWORD
VmDirRegConfigMultiStringToDwords(
    PCSTR   pszValues,
    PDWORD* ppdwValues,
    DWORD*  pdwValuesLen
    )
{
    DWORD dwError = 0;
    PDWORD pdwValues = NULL;
    DWORD dwValuesLen = 0;
    DWORD dwCount = 0;
    PCSTR pszIter = NULL;

    if (pszValues)
    {
        pszIter = pszValues;
        while (pszIter != NULL && *pszIter != '\0')
        {
            dwValuesLen++;

            pszIter += VmDirStringLenA(pszIter) + 1;
        }

        /* Allocate space for one even if no space is really needed,
         * that way we have a valid pointer.
         */
        dwError = VmDirAllocateMemory(sizeof(DWORD) * (dwValuesLen == 0 ? 1 : dwValuesLen), (PVOID)&pdwValues);
        BAIL_ON_VMDIR_ERROR(dwError);

        pszIter = pszValues;
        while (pszIter != NULL && *pszIter != '\0')
        {
            DWORD dwVal = atoi(pszIter);
            pdwValues[dwCount++] = dwVal;
            pszIter += VmDirStringLenA(pszIter) + 1;
        }
    }

    *ppdwValues = pdwValues;
    *pdwValuesLen = dwValuesLen;

cleanup:
    return dwError;

error:
    VMDIR_SAFE_FREE_MEMORY(pdwValues);
    goto cleanup;
}
Пример #5
0
DWORD
VmDirDeleteEntryViaDN(
    PCSTR   pszDN
    )
{
    DWORD dwError = 0;
    VDIR_OPERATION op = {0};
    DeleteReq *dr = NULL;

    if (IsNullOrEmptyString(pszDN))
    {
        BAIL_WITH_VMDIR_ERROR(dwError, VMDIR_ERROR_INVALID_PARAMETER);
    }

    dwError = VmDirInitStackOperation(&op, VDIR_OPERATION_TYPE_INTERNAL, LDAP_REQ_DELETE, NULL);
    BAIL_ON_VMDIR_ERROR(dwError);

    op.pBEIF = VmDirBackendSelect(NULL);
    op.reqDn.lberbv_val = (PSTR)pszDN;
    op.reqDn.lberbv_len = VmDirStringLenA(pszDN);

    dr = &op.request.deleteReq;
    dr->dn.lberbv.bv_val = op.reqDn.lberbv.bv_val;
    dr->dn.lberbv.bv_len = op.reqDn.lberbv.bv_len;

    dwError = VmDirInternalDeleteEntry(&op);
    BAIL_ON_VMDIR_ERROR(dwError);

cleanup:
    VmDirFreeOperationContent(&op);
    return dwError;
error:
    goto cleanup;
}
Пример #6
0
static
DWORD
_CreateCopyOperation(
        LDAPMessage *pEntry,
        PVDIR_OPERATION pLdapOp
        )
{
    DWORD dwError = 0;

    dwError = VmDirInitStackOperation(
            pLdapOp,
            VDIR_OPERATION_TYPE_REPL,
            LDAP_REQ_MODIFY,
            NULL);
    BAIL_ON_VMDIR_ERROR(dwError);

    pLdapOp->pBEIF = VmDirBackendSelect(NULL);
    assert(pLdapOp->pBEIF);

    pLdapOp->reqDn.lberbv.bv_val = SUB_SCHEMA_SUB_ENTRY_DN;
    pLdapOp->reqDn.lberbv.bv_len = VmDirStringLenA(SUB_SCHEMA_SUB_ENTRY_DN);
    pLdapOp->request.modifyReq.dn.lberbv.bv_val = pLdapOp->reqDn.lberbv.bv_val;
    pLdapOp->request.modifyReq.dn.lberbv.bv_len = pLdapOp->reqDn.lberbv.bv_len;

cleanup:
    return dwError;

error:
    VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL,
            "%s,%d failed, error(%d)", __FUNCTION__, __LINE__, dwError );

    goto cleanup;
}
Пример #7
0
/*
 * Allocate string into pDupBerval
 */
DWORD
VmDirStringToBervalContent(
    PCSTR              pszBerval,
    PVDIR_BERVALUE     pDupBerval
    )
{
    DWORD    dwError = 0;

    VmDirFreeBervalContent(pDupBerval);

    dwError = VmDirAllocateStringA(pszBerval, &pDupBerval->lberbv.bv_val);
    BAIL_ON_VMDIR_ERROR(dwError);

    pDupBerval->bOwnBvVal = TRUE;

    pDupBerval->lberbv.bv_len = VmDirStringLenA(pDupBerval->lberbv.bv_val);

cleanup:

    return dwError;

error:

    VmDirFreeBervalContent(pDupBerval);

    goto cleanup;
}
Пример #8
0
/*
 * Convenient function to add a single "string" type attribute to pEntry.
 */
DWORD
VmDirEntryAddSingleValueStrAttribute(
    PVDIR_ENTRY pEntry,
    PCSTR pszAttrName,
    PCSTR pszAttrValue)
{
    DWORD       dwError = 0;

    if (!pEntry || !pEntry->pSchemaCtx || !pszAttrName || !pszAttrValue)
    {
        dwError = ERROR_INVALID_PARAMETER;
        BAIL_ON_VMDIR_ERROR(dwError);
    }

    dwError = VmDirEntryAddSingleValueAttribute(
            pEntry,
            pszAttrName,
            pszAttrValue,
            VmDirStringLenA(pszAttrValue));
    BAIL_ON_VMDIR_ERROR(dwError);

error:

    return dwError;
}
Пример #9
0
static
DWORD
VmDirRegConfigMultiStringToStrList(
    PCSTR               pszValues,
    PVMDIR_STRING_LIST* ppStrList
    )
{
    DWORD               dwError = 0;
    DWORD               dwValuesLen = 0;
    PCSTR               pszIter = NULL;
    PVMDIR_STRING_LIST  pStrList = NULL;

    if (pszValues)
    {
        pszIter = pszValues;
        while (pszIter != NULL && *pszIter != '\0')
        {
            dwValuesLen++;

            pszIter += VmDirStringLenA(pszIter) + 1;
        }

        dwError = VmDirStringListInitialize(&pStrList, dwValuesLen);
        BAIL_ON_VMDIR_ERROR(dwError);

        pszIter = pszValues;
        while (pszIter != NULL && *pszIter != '\0')
        {
            dwError = VmDirStringListAddStrClone(pszIter, pStrList);
            BAIL_ON_VMDIR_ERROR(dwError);

            pszIter += VmDirStringLenA(pszIter) + 1;
        }

        *ppStrList = pStrList; pStrList = NULL;
    }

cleanup:
    if (pStrList)
    {
        VmDirStringListFree(pStrList);
    }
    return dwError;

error:
    goto cleanup;
}
Пример #10
0
DWORD
VmDirSimpleEntryDeleteAttribute(
    PCSTR   pszDN,
    PCSTR   pszAttr
    )
{
    DWORD   dwError = 0;
    size_t  dnlen = 0;
    size_t  attrlen = 0;
    VDIR_OPERATION  ldapOp = {0};

    if (IsNullOrEmptyString(pszDN) || IsNullOrEmptyString(pszAttr))
    {
        BAIL_WITH_VMDIR_ERROR(dwError, VMDIR_ERROR_INVALID_PARAMETER);
    }

    dwError = VmDirInitStackOperation(
            &ldapOp,
            VDIR_OPERATION_TYPE_INTERNAL,
            LDAP_REQ_MODIFY,
            NULL);
    BAIL_ON_VMDIR_ERROR(dwError);

    dnlen = VmDirStringLenA(pszDN);
    attrlen = VmDirStringLenA(pszAttr);

    ldapOp.pBEIF = VmDirBackendSelect(NULL);
    ldapOp.reqDn.lberbv_val = (PSTR)pszDN;
    ldapOp.reqDn.lberbv_len = dnlen;

    ldapOp.request.modifyReq.dn.lberbv_val = ldapOp.reqDn.lberbv_val;
    ldapOp.request.modifyReq.dn.lberbv_len = ldapOp.reqDn.lberbv_len;

    dwError = VmDirAppendAMod(
            &ldapOp, MOD_OP_DELETE, pszAttr, attrlen, NULL, 0);
    BAIL_ON_VMDIR_ERROR(dwError);

    dwError = VmDirInternalModifyEntry(&ldapOp);
    BAIL_ON_VMDIR_ERROR(dwError);

cleanup:
    VmDirFreeOperationContent(&ldapOp);
    return dwError;

error:
    goto cleanup;
}
Пример #11
0
/*
 * Create an Attribute on the heap and establish its pATDesc
 * two memory allocate
 * 1. pAttribute
 * 2. pAttribute->vals (BerValue array is one more then requested)
 */
DWORD
VmDirAttributeAllocate(
    PCSTR   pszName,
    USHORT  usBerSize,
    PVDIR_SCHEMA_CTX pCtx,
    PVDIR_ATTRIBUTE* ppOutAttr)
{
    DWORD    dwError = 0;
    PVDIR_ATTRIBUTE    pAttr = NULL;

    if (!ppOutAttr)
    {
        return 0;
    }

    dwError = VmDirAllocateMemory(
            sizeof(VDIR_ATTRIBUTE),
            (PVOID*)&pAttr);
    BAIL_ON_VMDIR_ERROR(dwError);

    // add one more BerValue as Encode/Decode entry in data store layer needs it.
    dwError = VmDirAllocateMemory(
            sizeof(VDIR_BERVALUE) * (usBerSize + 1),
            (PVOID*)&pAttr->vals);
    BAIL_ON_VMDIR_ERROR(dwError);

    pAttr->numVals = usBerSize;

    pAttr->pATDesc = VmDirSchemaAttrNameToDesc(
                    pCtx,
                    pszName);
    if (!pAttr->pATDesc)
    {
        dwError = VMDIR_ERROR_NO_SUCH_ATTRIBUTE;
        BAIL_ON_VMDIR_ERROR(dwError);
    }

    // pAttr->type.lberbv.bv_val always store in-place
    pAttr->type.lberbv.bv_val = pAttr->pATDesc->pszName;
    pAttr->type.lberbv.bv_len = VmDirStringLenA(pAttr->type.lberbv.bv_val);

    *ppOutAttr = pAttr;

cleanup:

    return dwError;

error:

    if (pAttr)
    {
        VmDirFreeAttribute(pAttr);
    }

    VmDirLog( LDAP_DEBUG_ANY, "AllocateAttribute failed (%d)(%s)",
              dwError, VDIR_SAFE_STRING(pszName));

    goto cleanup;
}
Пример #12
0
DWORD
VmDirAppendAMod(
    PVDIR_OPERATION   pOperation,
    int               modOp,
    char *            attrName,
    int               attrNameLen,
    char *            attrVal,
    size_t            attrValLen
    )
{
    DWORD          dwError = 0;
    VDIR_MODIFICATION * mod = NULL;
    ModifyReq *    modReq = &(pOperation->request.modifyReq);

    VmDirLog( LDAP_DEBUG_TRACE, "appendAMod: Begin, entry DN = %s", modReq->dn.lberbv.bv_val );

    dwError = VmDirAllocateMemory( sizeof( VDIR_MODIFICATION ), (PVOID *)&(mod) );
    BAIL_ON_VMDIR_ERROR( dwError );

    mod->operation = modOp;

    mod->attr.next = NULL;
    if ((mod->attr.pATDesc = VmDirSchemaAttrNameToDesc( pOperation->pSchemaCtx, attrName)) == NULL)
    {
        VmDirLog( LDAP_DEBUG_ANY, "appendAMod: VmDirSchemaAttrNameToDesc failed.");
        dwError = -1; /* Any value except 0 should do. */
        BAIL_ON_VMDIR_ERROR( dwError );
    }
    mod->attr.type.lberbv.bv_val = mod->attr.pATDesc->pszName;
    mod->attr.type.lberbv.bv_len = VmDirStringLenA(mod->attr.pATDesc->pszName);

    dwError = VmDirAllocateMemory( 2 * sizeof( VDIR_BERVALUE ), (PVOID *)&(mod->attr.vals) );
    BAIL_ON_VMDIR_ERROR( dwError );

    if ( attrVal && attrValLen > 0 )
    {
        dwError = VmDirAllocateMemory( attrValLen + 1, (PVOID *)&(mod->attr.vals[0].lberbv.bv_val) );
        BAIL_ON_VMDIR_ERROR( dwError );

        dwError = VmDirCopyMemory( mod->attr.vals[0].lberbv.bv_val, attrValLen + 1, attrVal, attrValLen);
        BAIL_ON_VMDIR_ERROR( dwError );

        mod->attr.vals[0].lberbv.bv_len = attrValLen;
        mod->attr.vals[0].bOwnBvVal = TRUE;

        mod->attr.numVals = 1;
    }

    mod->next = modReq->mods;
    modReq->mods = mod;
    modReq->numMods++;

cleanup:
    VmDirLog( LDAP_DEBUG_TRACE, "appendAMod: End." );
    return dwError;

error:
    goto cleanup;
}
Пример #13
0
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;
}
Пример #14
0
DWORD
VmDirMDBSimpleDnToEntry(
    PSTR        pszEntryDN,
    PVDIR_ENTRY pEntry
    )
{
    DWORD               dwError = 0;
    PVDIR_SCHEMA_CTX    pSchemaCtx = NULL;
    VDIR_BERVALUE       entryDn = VDIR_BERVALUE_INIT;
    VDIR_BACKEND_CTX    mdbBECtx = {0};
    BOOLEAN             bHasTxn = FALSE;

    assert(pEntry);

    dwError = VmDirSchemaCtxAcquire(&pSchemaCtx);
    BAIL_ON_VMDIR_ERROR(dwError);

    entryDn.lberbv.bv_val = pszEntryDN;
    entryDn.lberbv.bv_len = VmDirStringLenA(entryDn.lberbv.bv_val);

    dwError = VmDirMDBTxnBegin(&mdbBECtx, VDIR_BACKEND_TXN_READ);
    BAIL_ON_VMDIR_ERROR(dwError);
    bHasTxn = TRUE;

    dwError = VmDirMDBDNToEntry(    &mdbBECtx,
                                    pSchemaCtx,
                                    &entryDn,
                                    pEntry,
                                    VDIR_BACKEND_ENTRY_LOCK_READ);
    BAIL_ON_VMDIR_ERROR(dwError);

    dwError = VmDirMDBTxnCommit(&mdbBECtx);
    bHasTxn = FALSE;
    BAIL_ON_VMDIR_ERROR(dwError);

cleanup:

    if (pSchemaCtx)
    {
        VmDirSchemaCtxRelease(pSchemaCtx);
    }

    mdbBECtx.pBEPrivate = NULL;
    VmDirBackendCtxContentFree(&mdbBECtx);
    VmDirFreeBervalContent(&entryDn);

    return dwError;

error:

    if (bHasTxn)
    {
        VmDirMDBTxnAbort(&mdbBECtx);
    }

    goto cleanup;
}
Пример #15
0
/*
 * Convenient function to add a single attribute to pMod.
 *
 * Currently, only handle adding content to EMPTY pMod->attr and use with
 * pMod->operation = MOD_OP_REPLACE or MOD_OP_ADD or MOD_OP_DELETE
 * to manipulate ONE attribute value
 *
 */
DWORD
VmDirModAddSingleValueAttribute(
    PVDIR_MODIFICATION      pMod,
    PVDIR_SCHEMA_CTX        pSchemaCtx,
    PCSTR                   pszAttrName,
    PCSTR                   pszAttrValue,
    size_t                  iAttrValueLen
    )
{
    DWORD dwError = 0;

    if (!pMod || pMod->attr.pATDesc || pMod->attr.vals || !pSchemaCtx ||
        !pszAttrName || !pszAttrValue || iAttrValueLen < 1)
    {
        dwError = ERROR_INVALID_PARAMETER;
        BAIL_ON_VMDIR_ERROR(dwError);
    }

    // add one more BerValue as Encode/Decode entry in data store layer needs it.
    dwError = VmDirAllocateMemory(
                    sizeof(VDIR_BERVALUE) * (1 + 1),
                    (PVOID*)&pMod->attr.vals);
    BAIL_ON_VMDIR_ERROR(dwError);
    pMod->attr.numVals = 1;

    pMod->attr.pATDesc = VmDirSchemaAttrNameToDesc(pSchemaCtx, pszAttrName);
    if (!pMod->attr.pATDesc)
    {
        dwError = ERROR_NO_SCHEMA;
        BAIL_ON_VMDIR_ERROR(dwError);
    }

    // pAttr->type.lberbv.bv_val always store in-place
    pMod->attr.type.lberbv.bv_val = pMod->attr.pATDesc->pszName;
    pMod->attr.type.lberbv.bv_len = VmDirStringLenA(pMod->attr.type.lberbv.bv_val);

    dwError = VmDirAllocateMemory(
                    iAttrValueLen + 1,                  // want string null terminated.
                    (PVOID*)&pMod->attr.vals[0].lberbv.bv_val );
    BAIL_ON_VMDIR_ERROR(dwError);

    dwError = VmDirCopyMemory( pMod->attr.vals[0].lberbv.bv_val, iAttrValueLen + 1, (PCVOID)pszAttrValue, iAttrValueLen );
    BAIL_ON_VMDIR_ERROR(dwError);

    pMod->attr.vals[0].bOwnBvVal = TRUE;
    pMod->attr.vals[0].lberbv.bv_len = iAttrValueLen;

cleanup:

    return dwError;

error:

    // pMod owns the memory allocated in this function.

    goto cleanup;
}
Пример #16
0
static
DWORD
schemaInitFillAttrFromCache(
    PVDIR_SCHEMA_CTX    pCtx,
    PSTR*    ppszValues,
    USHORT   dwValueSize,
    PSTR     pszAttrName,
    PVDIR_ENTRY   pEntry
    )
{
    DWORD dwError = 0;
    DWORD dwCnt = 0;
    VDIR_ATTRIBUTE* pAttr = NULL;

    dwError = VmDirAttributeAllocate(
            pszAttrName,
            dwValueSize,
            pCtx,
            &pAttr);
    BAIL_ON_VMDIR_ERROR(dwError);

    for (dwCnt = 0; dwCnt < dwValueSize; dwCnt++)
    {
        char* pszStr = &ppszValues[dwCnt][0];

        //ignore leading spaces
        while (*pszStr == ' ') pszStr++;

        dwError = VmDirAllocateStringA(
                ppszValues[dwCnt],
                &pAttr->vals[dwCnt].lberbv.bv_val);
        BAIL_ON_VMDIR_ERROR(dwError);

        pAttr->vals[dwCnt].bOwnBvVal = TRUE;
        pAttr->vals[dwCnt].lberbv.bv_len = VmDirStringLenA(pAttr->vals[dwCnt].lberbv.bv_val);
    }

    dwError = VmDirEntryAddAttribute(
            pEntry,
            pAttr);
    BAIL_ON_VMDIR_ERROR(dwError);
    pAttr = NULL;

cleanup:

    return dwError;

error:

    if (pAttr)
    {
        VmDirFreeAttribute(pAttr);
    }

    goto cleanup;
}
Пример #17
0
DWORD
VmDirConfigSetDefaultSiteandLduGuid(
    PCSTR pszDefaultSiteGuid,
    PCSTR pszDefaultLduGuid
    )
#ifndef _WIN32
{
    DWORD   dwError = 0;

    if (IsNullOrEmptyString(pszDefaultSiteGuid) || IsNullOrEmptyString(pszDefaultLduGuid))
    {
        dwError = ERROR_INVALID_PARAMETER;
        BAIL_ON_VMDIR_ERROR(dwError);
    }

    dwError = RegUtilSetValue(
                NULL,
                HKEY_THIS_MACHINE,
                VMDIR_CONFIG_PARAMETER_KEY_PATH,
                NULL,
                VMDIR_REG_KEY_SITE_GUID,
                REG_SZ,
                (PVOID)pszDefaultSiteGuid,
                VmDirStringLenA(pszDefaultSiteGuid)+1);
    BAIL_ON_VMDIR_ERROR(dwError);

    dwError = RegUtilSetValue(
                NULL,
                HKEY_THIS_MACHINE,
                VMDIR_CONFIG_PARAMETER_KEY_PATH,
                NULL,
                VMDIR_REG_KEY_LDU_GUID,
                REG_SZ,
                (PVOID)pszDefaultLduGuid,
                VmDirStringLenA(pszDefaultLduGuid)+1);
    BAIL_ON_VMDIR_ERROR(dwError);

cleanup:
    return dwError;
error:
    VmDirLog(LDAP_DEBUG_ANY, "VmDirConfigSetDefaultSiteandLduGuid failed with error (%u)", dwError);
    goto cleanup;
}
Пример #18
0
static
DWORD
_VmDirSchemaAttrReplaceValue(
    PVDIR_ATTRIBUTE pAttr,
    PCSTR           pszMatchSubstr,
    PCSTR           pszValue
    )
{
#define MAX_BUF_SIZE_256    256

    DWORD       dwError = 0;
    unsigned    iCnt = 0;
    CHAR        pszBuf[MAX_BUF_SIZE_256] = {0};

    dwError = VmDirStringPrintFA( pszBuf, MAX_BUF_SIZE_256 -1 , "NAME '%s' ", pszMatchSubstr );
    BAIL_ON_VMDIR_ERROR(dwError);

    for (iCnt = 0; iCnt < pAttr->numVals; iCnt++)
    {
        if ( VmDirCaselessStrStrA( pAttr->vals[iCnt].lberbv_val, pszBuf ) != NULL )
        {
            if ( VmDirStringCompareA( VDIR_SAFE_STRING(pAttr->vals[iCnt].lberbv_val),
                                      pszValue,
                                      FALSE ) != 0
                                      )
            {
                VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "Merge schema, replace old - %s",
                                VDIR_SAFE_STRING(pAttr->vals[iCnt].lberbv_val));
                VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "Merge schema, replace new - %s", pszValue );
            }

            VMDIR_LOG_DEBUG( VMDIR_LOG_MASK_ALL, "Merge schema, replace old - %s",
                             VDIR_SAFE_STRING(pAttr->vals[iCnt].lberbv_val));
            VmDirFreeBervalContent( &(pAttr->vals[iCnt]) );

            dwError = VmDirAllocateStringA( pszValue, &(pAttr->vals[iCnt].lberbv_val) );
            BAIL_ON_VMDIR_ERROR(dwError);
            pAttr->vals[iCnt].lberbv_len = VmDirStringLenA( pszValue );
            pAttr->vals[iCnt].bOwnBvVal = TRUE;

            VMDIR_LOG_DEBUG( VMDIR_LOG_MASK_ALL, "Merge schema, replace new - %s",
                             VDIR_SAFE_STRING(pAttr->vals[iCnt].lberbv_val));

            break;
        }
    }

cleanup:

    return dwError;

error:

    goto cleanup;
}
Пример #19
0
/*
 * pEntry is created from a difference instance of schema.
 * Path it to use new instance it now associates with.
 * 1. inpalce menory of pAttr->type
 * 2. pEntry->pSchemaCtx
 */
static
DWORD
_VmDirSchemaInitFixBootstrapEntry(
    PVDIR_SCHEMA_INSTANCE   pSchema,
    PVDIR_ENTRY             pEntry
    )
{
    DWORD               dwError = 0;
    VDIR_ATTRIBUTE*     pAttr = NULL;
    PVDIR_SCHEMA_CTX    pNewCtx = NULL;

    dwError = VmDirAllocateMemory( sizeof(*pNewCtx), (PVOID)&pNewCtx );
    BAIL_ON_VMDIR_ERROR(dwError);

    // create the very first ctx for pSchema
    pNewCtx->pSchema = pSchema;
    pNewCtx->pSchema->usRefCount++;

    // switch pEntry to use the new schema instance it creates.
    VmDirSchemaCtxRelease(pEntry->pSchemaCtx);
    pEntry->pSchemaCtx = pNewCtx;
    pNewCtx = NULL;

    for (pAttr = pEntry->attrs; pAttr; pAttr = pAttr->next)
    {
        USHORT usId = pAttr->pATDesc->usAttrID;
        PVDIR_SCHEMA_AT_DESC pResult = pSchema->ats.ppATSortIdMap[usId - 1];

        if (!pResult)
        {   // this should never happen as attribute ID never change once it is assigned.
            dwError = ERROR_INVALID_SCHEMA;
            BAIL_ON_VMDIR_ERROR(dwError);
        }

        // patch Attribute.pATDesc
        pAttr->pATDesc = pResult;

        // patch Attribute.type in-place storage as well
        pAttr->type.lberbv.bv_val = pResult->pszName;
        pAttr->type.lberbv.bv_len = VmDirStringLenA(pAttr->type.lberbv.bv_val);
    }

cleanup:

    return dwError;

error:

    if ( pNewCtx )
    {
        VmDirSchemaCtxRelease( pNewCtx );
    }

    goto cleanup;
}
Пример #20
0
static
DWORD
_VmDirSchemaComputeAllowedChildClassesEffective(
    PVDIR_ENTRY         pEntry,
    PVDIR_ATTRIBUTE*    ppOutAttr
    )
{
    DWORD                   dwError = 0;
    PVDIR_SCHEMA_OC_DESC    pStructureOCDesc = NULL;
    PVDIR_ATTRIBUTE         pLocalAttr = NULL;
    int                     iCnt = 0;

    dwError = VmDirSchemaGetEntryStructureOCDesc( pEntry,
                                                   &pStructureOCDesc );
    BAIL_ON_VMDIR_ERROR(dwError);
    if ( !pStructureOCDesc )
    {
        dwError = ERROR_INVALID_ENTRY;
        BAIL_ON_VMDIR_ERROR(dwError);
    }

    for (iCnt = 0; pStructureOCDesc->ppszAllowedChildOCs && pStructureOCDesc->ppszAllowedChildOCs[iCnt]; iCnt++) {}

    if (iCnt > 0)
    {
        dwError = VmDirAttributeAllocate( ATTR_ALLOWD_CHILD_CLASSES_EFFECTIVE,
                                          iCnt,
                                          pEntry->pSchemaCtx,
                                          &pLocalAttr);
        BAIL_ON_VMDIR_ERROR(dwError);

        for (iCnt = 0; pStructureOCDesc->ppszAllowedChildOCs[iCnt]; iCnt++)
        {
            dwError = VmDirAllocateStringA( pStructureOCDesc->ppszAllowedChildOCs[iCnt],
                                            &(pLocalAttr->vals[iCnt].lberbv_val));
            BAIL_ON_VMDIR_ERROR(dwError);

            pLocalAttr->vals[iCnt].lberbv_len = VmDirStringLenA(pLocalAttr->vals[iCnt].lberbv_val);
            pLocalAttr->vals[iCnt].bOwnBvVal = TRUE;
        }
    }

    *ppOutAttr = pLocalAttr;

cleanup:

    return dwError;

error:

    VmDirFreeAttribute( pLocalAttr );

    goto cleanup;
}
Пример #21
0
/*
 * FROM and TO Attributes use same schema context
 */
DWORD
VmDirAttributeDup(
    PVDIR_ATTRIBUTE  pAttr,
    PVDIR_ATTRIBUTE* ppDupAttr
    )
{
    DWORD   dwError = 0;
    DWORD   dwCnt = 0;
    PVDIR_ATTRIBUTE    pAttribute = NULL;

    assert(pAttr && ppDupAttr);

    dwError = VmDirAllocateMemory(
            sizeof(VDIR_ATTRIBUTE),
            (PVOID*)&pAttribute);
    BAIL_ON_VMDIR_ERROR(dwError);

    // add one more BerValue as Encode/Decode entry in data store layer needs it.
    dwError = VmDirAllocateMemory(
            sizeof(VDIR_BERVALUE) * (pAttr->numVals + 1),
            (PVOID*)&pAttribute->vals);
    BAIL_ON_VMDIR_ERROR(dwError);

    for (dwCnt = 0 ; dwCnt < pAttr->numVals; dwCnt++)
    {
        dwError = VmDirBervalContentDup(
                &pAttr->vals[dwCnt],
                &pAttribute->vals[dwCnt]);
        BAIL_ON_VMDIR_ERROR(dwError);

        pAttribute->numVals = dwCnt + 1;
    }

    // use the same pATDesc and type from pAttr
    pAttribute->pATDesc = pAttr->pATDesc;
    // type.lberbv.bv_val always store in-place
    pAttribute->type.lberbv.bv_val = pAttr->pATDesc->pszName;
    pAttribute->type.lberbv.bv_len = VmDirStringLenA(pAttr->type.lberbv.bv_val);

    *ppDupAttr = pAttribute;

cleanup:

    return dwError;

error:

    if (pAttribute)
    {
        VmDirFreeAttribute(pAttribute);
    }

    goto cleanup;
}
Пример #22
0
static
DWORD
_VmDirSimpleEntryCreateInBEWithGuid(
    PVDIR_BACKEND_INTERFACE pBE,
    PVDIR_SCHEMA_CTX        pSchemaCtx,
    PSTR*                   ppszEntryInitializer,
    PSTR                    pszDN,
    ENTRYID                 ulEntryId,
    PSTR                    pszGuid /* Optional */
    )
{
    DWORD                   dwError = 0;
    VDIR_OPERATION          ldapOp = {0};

    dwError = VmDirInitStackOperation( &ldapOp,
                                       VDIR_OPERATION_TYPE_INTERNAL,
                                       LDAP_REQ_ADD,
                                       pSchemaCtx );
    BAIL_ON_VMDIR_ERROR(dwError);

    ldapOp.pBEIF = pBE;
    assert(ldapOp.pBEIF);

    ldapOp.reqDn.lberbv.bv_val = pszDN;
    ldapOp.reqDn.lberbv.bv_len = VmDirStringLenA(pszDN);

    dwError = AttrListToEntry(
            pSchemaCtx,
            pszDN,
            ppszEntryInitializer,
            ldapOp.request.addReq.pEntry);
    BAIL_ON_VMDIR_ERROR(dwError);

    ldapOp.request.addReq.pEntry->eId = ulEntryId;

    if (!IsNullOrEmptyString(pszGuid))
    {
        dwError = VmDirAllocateStringA(pszGuid, &ldapOp.request.addReq.pEntry->pszGuid);
        BAIL_ON_VMDIR_ERROR(dwError);
    }

    dwError = VmDirInternalAddEntry(&ldapOp);
    BAIL_ON_VMDIR_ERROR(dwError);

cleanup:
    VmDirFreeOperationContent(&ldapOp);

    return dwError;

error:

    goto cleanup;
}
Пример #23
0
/*
 * pszString is expected to be a multistring.
 * A multistring consists of a list of zero or more non-empty nul-terminated
 * strings in which the list is terminated with nul.
 *
 * Examples:
 *    A list with one string ("abc"):  abc\0\0
 *    A list with two strings ("abc", "d"): abc\0d\0\0
 *    An empty list:  \0
 *    An INVALID multistring (No string may be empty):   abc\0\0\dce\0\0
 *
 * Note that some believe all multistrings are 'double terminated'; the
 * empty list is not.
 *
 */
DWORD
VmDirAllocateMultiStringA(
    PCSTR   pszString,
    PSTR*   ppszString
    )
{
    DWORD  dwError = 0;
    PCSTR  pszIter = NULL;
    PSTR   pszNewString = NULL;
    size_t dwLen = 0;

    if (!pszString || !ppszString)
    {
        if (ppszString) { *ppszString = NULL; }
        return VMDIR_ERROR_INVALID_PARAMETER;
    }

    pszIter = pszString;
    while (*pszIter != '\0')
    {
        pszIter += VmDirStringLenA(pszIter) + 1;
    }
    dwLen = (pszIter - pszString) + 1;

    dwError = VmDirAllocateMemory(dwLen, (PVOID*)&pszNewString);
    BAIL_ON_VMDIR_ERROR(dwError);

#ifndef _WIN32
    memcpy(pszNewString, pszString, dwLen);
#else
    memcpy_s(pszNewString, dwLen, pszString, dwLen);
#endif
    *ppszString = pszNewString;

cleanup:

    return dwError;

error:

    VMDIR_SAFE_FREE_MEMORY(pszNewString);

    goto cleanup;
}
Пример #24
0
static
int
_VmDirSASLSRPInteraction(
    LDAP *      pLd,
    unsigned    flags,
    void *      pDefaults,
    void *      pIn
    )
{
    sasl_interact_t*                pInteract = pIn;
    PVMDIR_SASL_INTERACTIVE_DEFAULT pDef = pDefaults;

    while( (pDef != NULL) && (pInteract->id != SASL_CB_LIST_END) )
    {

        switch( pInteract->id )
        {
        case SASL_CB_GETREALM:
                pInteract->defresult = pDef->pszRealm;
                break;
        case SASL_CB_AUTHNAME:
                pInteract->defresult = pDef->pszAuthName;
                break;
        case SASL_CB_PASS:
                pInteract->defresult = pDef->pszPass;
                break;
        case SASL_CB_USER:
                pInteract->defresult = pDef->pszUser;
                break;
        default:
                break;
        }

        pInteract->result = (pInteract->defresult) ? pInteract->defresult : "";
        pInteract->len    = (unsigned int) VmDirStringLenA( pInteract->result );

        pInteract++;
    }

    return LDAP_SUCCESS;
}
Пример #25
0
DWORD
VmDirKrbRealmNameNormalize(
    PCSTR       pszName,
    PSTR*       ppszNormalizeName
    )
{
    DWORD       dwError = 0;
    PSTR        pszRealmName = NULL;

    if ( !pszName  ||  !ppszNormalizeName)
    {
        dwError = ERROR_INVALID_PARAMETER;
        BAIL_ON_VMDIR_ERROR(dwError);
    }

    dwError = VmDirAllocateStringA(pszName, &pszRealmName);
    BAIL_ON_VMDIR_ERROR(dwError);

    {
        size_t iCnt=0;
        size_t iLen = VmDirStringLenA(pszRealmName);

        for (iCnt = 0; iCnt < iLen; iCnt++)
        {
            VMDIR_ASCII_LOWER_TO_UPPER(pszRealmName[iCnt]);
        }
    }

    *ppszNormalizeName = pszRealmName;

cleanup:

    return dwError;

error:

    VmDirFreeMemory(pszRealmName);
    goto cleanup;
}
Пример #26
0
DWORD
VmDirResetPassword(
    PCSTR       pszUPN,
    PCSTR       pszNewPassword
    )
{
    DWORD               dwError = 0;
    VDIR_BERVALUE       bvPassword = VDIR_BERVALUE_INIT;
    PSTR                pszDN = NULL;

    if ( IsNullOrEmptyString(pszUPN) || IsNullOrEmptyString(pszNewPassword) )
    {
        dwError = VMDIR_ERROR_INVALID_PARAMETER;
        BAIL_ON_VMDIR_ERROR(dwError);
    }

    dwError = VmDirUPNToDN( pszUPN, &pszDN );
    BAIL_ON_VMDIR_ERROR(dwError);

    bvPassword.lberbv_val = (PSTR)pszNewPassword;
    bvPassword.lberbv_len = VmDirStringLenA(pszNewPassword);
    dwError = VmDirInternalEntryAttributeReplace( NULL,
                                                  pszDN,
                                                  ATTR_USER_PASSWORD,
                                                  &bvPassword);
    BAIL_ON_VMDIR_ERROR(dwError);

cleanup:

    VmDirFreeBervalContent(&bvPassword);

    return dwError;

error:

    VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "VmDirResetPassword (%s) failed, (%u)",
                              VDIR_SAFE_STRING(pszUPN), dwError);
    goto cleanup;
}
Пример #27
0
/*
 * Convenient function to add a single "string" type attribute to pMod.
 */
DWORD
VmDirModAddSingleStrValueAttribute(
    PVDIR_MODIFICATION      pMod,
    PVDIR_SCHEMA_CTX        pSchemaCtx,
    PCSTR                   pszAttrName,
    PCSTR                   pszAttrValue
    )
{
    DWORD       dwError = 0;

    dwError = VmDirModAddSingleValueAttribute(
                    pMod,
                    pSchemaCtx,
                    pszAttrName,
                    pszAttrValue,
                    pszAttrValue ? VmDirStringLenA(pszAttrValue) : 0);
    BAIL_ON_VMDIR_ERROR(dwError);

error:

    return dwError;
}
Пример #28
0
DWORD
VmDirAllocateStringA(
    PCSTR   pszString,
    PSTR*   ppszString
    )
{
    DWORD  dwError = 0;
    PSTR   pszNewString = NULL;
    size_t dwLen = 0;

    if (!pszString || !ppszString)
    {
        if (ppszString) { *ppszString = NULL; }
        return 0;
    }

    dwLen = VmDirStringLenA(pszString);
    // + 1 for \'0'
    dwError = VmDirAllocateMemory(dwLen + 1, (PVOID*)&pszNewString);
    BAIL_ON_VMDIR_ERROR(dwError);

#ifndef _WIN32
    memcpy(pszNewString, pszString, dwLen);
#else
    memcpy_s(pszNewString, (dwLen + 1), pszString, dwLen);
#endif
    *ppszString = pszNewString;

cleanup:

    return dwError;

error:

    VMDIR_SAFE_FREE_MEMORY(pszNewString);

    goto cleanup;
}
Пример #29
0
/*
 * 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;
}
Пример #30
0
/*
 * 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;
}