/* VmDirMDBDNToEntry: For a given entry DN, reads an entry from the entry DB. * * Returns: BE error - BACKEND_ERROR, BACKEND OPERATIONS, BACKEND_ENTRY_NOTFOUND * */ DWORD VmDirMDBDNToEntry( PVDIR_BACKEND_CTX pBECtx, PVDIR_SCHEMA_CTX pSchemaCtx, VDIR_BERVALUE* pDn, PVDIR_ENTRY pEntry, VDIR_BACKEND_ENTRY_LOCKTYPE entryLockType) { DWORD dwError = LDAP_SUCCESS; ENTRYID eId = {0}; // make sure we look up normalized dn value dwError = VmDirNormalizeDN( pDn, pSchemaCtx ); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirMDBDNToEntryId( pBECtx, pDn, &eId ); BAIL_ON_VMDIR_ERROR( dwError ); dwError = VmDirMDBEIdToEntry( pBECtx, pSchemaCtx, eId, pEntry, entryLockType ); BAIL_ON_VMDIR_ERROR( dwError ); cleanup: return dwError; error: VMDIR_LOG_ERROR( LDAP_DEBUG_BACKEND, "BEDNToEntry DN (%s) failed, (%u)(%s)", VDIR_SAFE_STRING( pDn->bvnorm_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; }
DWORD VmDirGetKrbMasterKey( PSTR pszFQDN, // [in] FQDN PBYTE* ppKeyBlob, DWORD* pSize ) { DWORD dwError = 0; PBYTE pRetMasterKey = NULL; if (IsNullOrEmptyString(pszFQDN) || !ppKeyBlob || !pSize ) { dwError = VMDIR_ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } // Currently, we only support single krb realm. // Global cache gVmdirKrbGlobals is initialized during startup stage. if (VmDirStringCompareA( pszFQDN, VDIR_SAFE_STRING(gVmdirKrbGlobals.pszRealm), FALSE) != 0) { dwError = VMDIR_ERROR_INVALID_REALM; BAIL_ON_VMDIR_ERROR(dwError); } dwError = VmDirAllocateMemory( gVmdirKrbGlobals.bervMasterKey.lberbv.bv_len, (PVOID*)&pRetMasterKey ); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirCopyMemory ( pRetMasterKey, gVmdirKrbGlobals.bervMasterKey.lberbv.bv_len, gVmdirKrbGlobals.bervMasterKey.lberbv.bv_val, gVmdirKrbGlobals.bervMasterKey.lberbv.bv_len ); BAIL_ON_VMDIR_ERROR(dwError); *ppKeyBlob = pRetMasterKey; *pSize = (DWORD) gVmdirKrbGlobals.bervMasterKey.lberbv.bv_len; pRetMasterKey = NULL; cleanup: return dwError; error: VMDIR_LOG_ERROR( LDAP_DEBUG_RPC, "VmDirGetKrbMasterKey failed. (%u)(%s)", dwError, VDIR_SAFE_STRING(pszFQDN)); VMDIR_SAFE_FREE_MEMORY(pRetMasterKey); goto cleanup; }
/* * NormalizeMods: * 1. Normalize attribute values present in the modifications list. * 2. Make sure no duplicate value */ int VmDirNormalizeMods( PVDIR_SCHEMA_CTX pSchemaCtx, PVDIR_MODIFICATION pMods, PSTR* ppszErrorMsg ) { int retVal = LDAP_SUCCESS; PVDIR_MODIFICATION pMod = NULL; unsigned int i = 0; PSTR pszDupAttributeName = NULL; PSTR pszLocalErrorMsg = NULL; for (pMod = pMods; pMod != NULL; pMod = pMod->next) { if (pMod->attr.pATDesc == NULL && (pMod->attr.pATDesc = VmDirSchemaAttrNameToDesc(pSchemaCtx, pMod->attr.type.lberbv.bv_val)) == NULL ) { retVal = VMDIR_ERROR_UNDEFINED_TYPE; BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, (pszLocalErrorMsg), "Undefined attribute (%s)", VDIR_SAFE_STRING(pMod->attr.type.lberbv.bv_val)); } for (i=0; i < pMod->attr.numVals; i++) { retVal = VmDirSchemaBervalNormalize(pSchemaCtx, pMod->attr.pATDesc, &pMod->attr.vals[i]); BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, (pszLocalErrorMsg), "attribute value normalization failed (%s)(%.*s)", VDIR_SAFE_STRING(pMod->attr.pATDesc->pszName), VMDIR_MIN(pMod->attr.vals[i].lberbv.bv_len, VMDIR_MAX_LOG_OUTPUT_LEN), VDIR_SAFE_STRING(pMod->attr.vals[i].lberbv.bv_val)); } // Make sure we have no duplicate value in mod->attr retVal = VmDirAttributeDupValueCheck(&pMod->attr, &pszDupAttributeName); BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, (pszLocalErrorMsg), "attribute (%s) has duplicate value", VDIR_SAFE_STRING(pszDupAttributeName)); } cleanup: if (ppszErrorMsg) { *ppszErrorMsg = pszLocalErrorMsg; } else { VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg); } return retVal; error: goto cleanup; }
/* 4.2.2. Bind Response The Bind response is defined as follows. BindResponse ::= [APPLICATION 1] SEQUENCE { COMPONENTS OF LDAPResult, serverSaslCreds [7] OCTET STRING OPTIONAL } */ VOID VmDirSendSASLBindResponse( PVDIR_OPERATION pOperation ) { DWORD dwError = 0; BerElementBuffer berbuf; BerElement * ber = (BerElement *) &berbuf; PVDIR_LDAP_RESULT pResult = &(pOperation->ldapResult); ber_tag_t respType = GetResultTag(pOperation->reqCode); (void) memset( (char *)&berbuf, '\0', sizeof( BerElementBuffer )); ber_init2( ber, NULL, LBER_USE_DER ); VMDIR_LOG_INFO( LDAP_DEBUG_ARGS, "VmDirSendLdapResponse: code (%d), Error (%d)(%s)", respType, pResult->errCode, VDIR_SAFE_STRING(pResult->pszErrMsg)); dwError = ber_printf( ber, "{it{ess" /*"}}"*/, pOperation->msgId, // message sequence id GetResultTag(pOperation->reqCode), // ldap response type pResult->errCode, // ldap return code e.g. LDAP_SASL_CONNTINUE pResult->matchedDn.lberbv.bv_len > 0 ? pResult->matchedDn.lberbv.bv_val : "", VDIR_SAFE_STRING(pResult->pszErrMsg)); // error text detail BAIL_ON_LBER_ERROR(dwError); // Send back TAG and SASL reply blob // NOTE, not exactly sure if we ever need to send Tag but WITHOUT blob reply if blob is empty. // but this should NOT happen in GSSAPI scenario. if ( pResult->replyInfo.type == REP_SASL && pResult->replyInfo.replyData.bvSaslReply.lberbv.bv_len > 0 ) { dwError = ber_printf( ber, "tO", LDAP_TAG_SASL_RES_CREDS, &pResult->replyInfo.replyData.bvSaslReply.lberbv ); BAIL_ON_LBER_ERROR(dwError); } dwError = ber_printf( ber, "N}N}" ); BAIL_ON_LBER_ERROR(dwError); dwError = WriteBerOnSocket( pOperation->conn, ber ); BAIL_ON_VMDIR_ERROR(dwError); cleanup: ber_free_buf( ber ); return; error: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "lber error (%d)", dwError); goto cleanup; }
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; }
/* MdbDeleteEntry: Deletes an entry in the MDB DBs. * * Returns: BE error codes. * */ DWORD VmDirMDBDeleteEntry( PVDIR_BACKEND_CTX pBECtx, PVDIR_MODIFICATION pMods, PVDIR_ENTRY pEntry ) { DWORD dwError = 0; VDIR_MODIFICATION * mod = NULL; PVDIR_DB_TXN pTxn = NULL; assert( pBECtx && pBECtx->pBEPrivate && pMods && pEntry ); pTxn = (PVDIR_DB_TXN)pBECtx->pBEPrivate; // Delete child from the parentId index dwError = MDBDeleteParentIdIndex( pBECtx, &(pEntry->pdn), pEntry->eId ); BAIL_ON_VMDIR_ERROR(dwError); for (mod = pMods; mod != NULL; mod = mod->next) { switch (mod->operation) { case MOD_OP_DELETE: if ((dwError = MdbUpdateIndicesForAttr( pBECtx->pBE, pTxn, &(pEntry->dn), &(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; default: assert( FALSE ); } } // Delete Entry Blob if ((dwError = MDBDeleteEntryBlob(pBECtx, pEntry->eId)) != 0) { dwError = MDBToBackendError(dwError, 0, ERROR_BACKEND_ERROR, pBECtx, "MDBDeleteEntryBlob"); 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, "VmDirMDBDeleteEntry: failed: error=%d,DN=%s", dwError, VDIR_SAFE_STRING(pEntry->dn.lberbv.bv_val)); goto cleanup; }
DWORD VmDirSchemaBervalSyntaxCheck( PVDIR_SCHEMA_CTX pCtx, PVDIR_SCHEMA_AT_DESC pATDesc, PVDIR_BERVALUE pBerv ) { DWORD dwError = 0; if (!pCtx || !pATDesc || !pBerv) { if (pCtx) { pCtx->dwErrorCode = ERROR_INVALID_PARAMETER; VMDIR_SAFE_FREE_MEMORY(pCtx->pszErrorMsg); dwError = VmDirAllocateStringA( "No descriptor or value", &pCtx->pszErrorMsg); } dwError = ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } //TODO, if NO pSyntax, i.e. this syntax is NOT supported yet. // just bypass checking and move on. if (pATDesc->pSyntax && pATDesc->pSyntax->pValidateFunc(pBerv) == FALSE) { pCtx->dwErrorCode = ERROR_INVALID_SYNTAX; VMDIR_SAFE_FREE_MEMORY(pCtx->pszErrorMsg); dwError = VmDirAllocateStringAVsnprintf( &pCtx->pszErrorMsg, "%s value (%s) is not a valid (%s) syntax", pATDesc->pszName, VDIR_SAFE_STRING(pBerv->lberbv.bv_val), VDIR_SAFE_STRING(pATDesc->pszSyntaxName)); dwError = ERROR_INVALID_SYNTAX; BAIL_ON_VMDIR_ERROR(dwError); } cleanup: return dwError; error: goto cleanup; }
/* MdbCheckRefIntegrity: Checks for the attributes that have referential integrity constraint set, that the DN attribute * values refer to existing objects. * * Returns: BE error codes. * */ DWORD VmDirMDBCheckRefIntegrity( PVDIR_BACKEND_CTX pBECtx, PVDIR_ENTRY pEntry) { DWORD dwError = 0; VDIR_ATTRIBUTE * attr = NULL; assert( pBECtx && pBECtx->pBEPrivate && pEntry ); for (attr = pEntry->attrs; attr; attr = attr->next) { // SJ-TBD: Instead of checking referential integrity for hard coded attributes, we should have a // proprietary flag e.g. X-constraint in the attribute schema definition if (VmDirStringCompareA(attr->type.lberbv.bv_val, ATTR_MEMBER, FALSE) == 0) { unsigned int i = 0; ENTRYID eId = 0; for (; i < attr->numVals; i++) { // Lookup in the DN index. if ((dwError = VmDirNormalizeDN( &(attr->vals[i]), pEntry->pSchemaCtx)) != 0) { dwError = ERROR_BACKEND_OPERATIONS; BAIL_ON_VMDIR_ERROR( dwError ); } if ((dwError = VmDirMDBDNToEntryId( pBECtx, &(attr->vals[i]), &eId )) != 0) { dwError = MDBToBackendError(dwError, ERROR_BACKEND_ENTRY_NOTFOUND, ERROR_BACKEND_CONSTRAINT, pBECtx, VDIR_SAFE_STRING(attr->vals[i].lberbv.bv_val)); BAIL_ON_VMDIR_ERROR( dwError ); } } } } cleanup: return dwError; error: // TODO set pBECtx->pszBEErrorMsg VMDIR_LOG_ERROR( LDAP_DEBUG_BACKEND, "BE DN (%s) reference check, error (%u)(%s)", pEntry->dn.lberbv_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; }
/* * Called during entry add * * grouptype : * http://msdn.microsoft.com/en-us/library/windows/desktop/ms675935%28v=vs.85%29.aspx Value Description 1 (0x00000001) Specifies a group that is created by the system. 2 (0x00000002) Specifies a group with global scope. 4 (0x00000004) Specifies a group with domain local scope. 8 (0x00000008) Specifies a group with universal scope. 16 (0x00000010) Specifies an APP_BASIC group for Windows Server Authorization Manager. 32 (0x00000020) Specifies an APP_QUERY group for Windows Server Authorization Manager. 2147483648 (0x80000000) Specifies a security group. If this flag is not set, then the group is a distribution group. Currently, Lotus only supports global scope (2). */ DWORD VmDirPluginGroupTypePreAdd( PVDIR_OPERATION pOperation, PVDIR_ENTRY pEntry, DWORD dwPriorResult ) { DWORD dwError = 0; PSTR pszLocalErrorMsg = NULL; if ( pOperation->opType != VDIR_OPERATION_TYPE_REPL && TRUE == VmDirIsEntryWithObjectclass(pEntry, OC_GROUP) ) { PVDIR_ATTRIBUTE pAttrGroupType = VmDirFindAttrByName(pEntry, ATTR_GROUPTYPE); if (pAttrGroupType == NULL) { dwError = VmDirEntryAddSingleValueStrAttribute(pEntry, ATTR_GROUPTYPE, GROUPTYPE_GLOBAL_SCOPE); BAIL_ON_VMDIR_ERROR(dwError); } else { if ( pAttrGroupType->numVals != 1 // grouptype is a single value attribute || VmDirStringCompareA( VDIR_SAFE_STRING( pAttrGroupType->vals[0].lberbv.bv_val), GROUPTYPE_GLOBAL_SCOPE, FALSE) != 0 ) { dwError = ERROR_INVALID_ENTRY; BAIL_ON_VMDIR_ERROR_WITH_MSG( dwError, pszLocalErrorMsg, "invalid or unsupported grouptype (%s)", VDIR_SAFE_STRING( pAttrGroupType->vals[0].lberbv.bv_val)); } } } cleanup: VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg); return dwError; error: VmDirLog( LDAP_DEBUG_ANY, "Group check: (%d)(%s)", dwError, VDIR_SAFE_STRING(pszLocalErrorMsg)); VMDIR_APPEND_ERROR_MSG(pOperation->ldapResult.pszErrMsg, pszLocalErrorMsg); goto cleanup; }
static DWORD _VmDirReplDCConnectInit( PVMDIR_REPLICATION_AGREEMENT pReplAgr ) { DWORD dwError = 0; pReplAgr->dcConn.connType = DC_CONNECTION_TYPE_REPL; pReplAgr->dcConn.creds.bUseDCAccountCreds = TRUE; pReplAgr->dcConn.dwConnectTimeoutSec = gVmdirGlobals.dwLdapConnectTimeoutSec; dwError = VmDirAllocateStringA(pReplAgr->pszHostname, &pReplAgr->dcConn.pszHostname); BAIL_ON_VMDIR_ERROR(dwError); // spawn background thread to handle connection VmDirInitDCConnThread(&pReplAgr->dcConn); cleanup: return dwError; error: pReplAgr->isDeleted = TRUE; VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s: %s error code (%d)", __FUNCTION__, VDIR_SAFE_STRING(pReplAgr->ldapURI), dwError); goto cleanup; }
static VOID VmDirRegConfigHandleClose( PVMDIR_CONFIG_CONNECTION_HANDLE pCfgHandle ) { #ifndef _WIN32 if (pCfgHandle->hConnection) { if (pCfgHandle->hKey) { DWORD dwError = RegCloseKey( pCfgHandle->hConnection, pCfgHandle->hKey); if (dwError != 0) { // Do not bail, best effort to cleanup. VmDirLog( LDAP_DEBUG_ANY, "RegCloseKey failed, Error code: (%u)(%s)", dwError, VDIR_SAFE_STRING(LwWin32ErrorToName(dwError))); } } RegCloseServer(pCfgHandle->hConnection); } #else if (pCfgHandle->hKey) { RegCloseKey(pCfgHandle->hKey); } #endif VMDIR_SAFE_FREE_MEMORY(pCfgHandle); }
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; }
/* * 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; }
int VmDirFirstReplicationCycle( PCSTR pszHostname, VMDIR_REPLICATION_AGREEMENT * pReplAgr) { int retVal = LDAP_SUCCESS; PSTR pszLocalErrorMsg = NULL; BOOLEAN bWriteInvocationId = FALSE; BOOLEAN bHasXlog = FALSE; #ifndef _WIN32 const char *dbHomeDir = VMDIR_DB_DIR; #else _TCHAR dbHomeDir[MAX_PATH]; size_t last_char_pos = 0; const char fileSeperator = '\\'; retVal = VmDirMDBGetHomeDir(dbHomeDir); BAIL_ON_VMDIR_ERROR ( retVal ); last_char_pos = strlen(dbHomeDir) - 1; if (dbHomeDir[last_char_pos] == fileSeperator) { dbHomeDir[last_char_pos] = '\0'; } #endif assert( gFirstReplCycleMode == FIRST_REPL_CYCLE_MODE_COPY_DB ); retVal = _VmDirGetRemoteDBUsingRPC(pszHostname, dbHomeDir, &bHasXlog); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "VmDirFirstReplicationCycle: _VmDirGetRemoteDBUsingRPC() call failed with error: %d", retVal ); retVal = _VmDirSwapDB(dbHomeDir, bHasXlog); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "VmDirFirstReplicationCycle: _VmDirSwapDB() call failed, error: %d.", retVal ); VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL, "Remote DB copied from %s, and swapped successfully", pszHostname); // Wrap up the 1st replication cycle by updating replication cookies. retVal = _VmDirWrapUpFirstReplicationCycle( pszHostname, pReplAgr ); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "VmDirFirstReplicationCycle: _VmDirWrapUpFirstReplicationCycle() call failed, error: %d.", retVal ); retVal = LoadServerGlobals(&bWriteInvocationId); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "VmDirFirstReplicationCycle: LoadServerGlobals call failed, error: %d.", retVal ); cleanup: VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg); return retVal; error: retVal = LDAP_OPERATIONS_ERROR; VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s", VDIR_SAFE_STRING(pszLocalErrorMsg) ); goto cleanup; }
/* * Mark MUST attributes presented. */ static DWORD _VmDirSchemaCheckMustAttrPresent( PVDIR_SCHEMA_CTX pCtx, PVDIR_SCHEMA_OC_DESC pOCDesc, PVDIR_ENTRY pEntry, PBOOLEAN pbPresentList ) { DWORD dwError = 0; int iCnt = 0; assert(pCtx && pOCDesc && pEntry && pbPresentList); for (iCnt = 0; pOCDesc->ppAllMustATs[iCnt] != NULL; iCnt++) { int iIdx = 0; PVDIR_ATTRIBUTE pAttr = pEntry->attrs; for (iIdx = 0; pAttr != NULL; pAttr = pAttr->next, iIdx++) { if (pAttr->pATDesc->usAttrID == pOCDesc->ppAllMustATs[iCnt]->usAttrID) { pbPresentList[iIdx] = TRUE; // find must attribute break; } } // ignore missing "nTSecurityDescriptor" must attribute for now. // ADSI needs it to be a must attribute. However, it is NOT easy/clean to make and // enforce this change in Lotus. (e.g. in VmDirInteralAddEntry, schema check is called // prior to SD generation currently.) // TODO, clean up SD generation in bootstratp/promo/normal paths. if ( pAttr == NULL && VmDirStringCompareA( pOCDesc->ppAllMustATs[iCnt]->pszName, ATTR_OBJECT_SECURITY_DESCRIPTOR, FALSE) != 0 ) { VMDIR_SAFE_FREE_MEMORY(pCtx->pszErrorMsg); VmDirAllocateStringAVsnprintf(&pCtx->pszErrorMsg, "Missing must attribute (%s)", VDIR_SAFE_STRING(pOCDesc->ppAllMustATs[iCnt]->pszName)); VmDirLog( LDAP_DEBUG_ANY, "%s", pCtx->pszErrorMsg); dwError = pCtx->dwErrorCode = ERROR_INVALID_ENTRY; BAIL_ON_VMDIR_ERROR(dwError); } } error: return dwError; }
VOID VdcadminSetVmdirState( VOID ) { DWORD dwError = 0; char pszState[SIZE_256] = {0}; PSTR pszLocalErrorMsg = NULL; PVMDIR_SERVER_CONTEXT hServer = NULL; VDIR_SERVER_STATE vmdirState = VMDIRD_STATE_NORMAL; VmDirReadString( "Enter state (NORMAL|READ_ONLY): ", pszState, SIZE_256, FALSE); if ( VmDirStringCompareA( pszState, "NORMAL", FALSE) == 0 ) { vmdirState = VMDIRD_STATE_NORMAL; } else if ( VmDirStringCompareA( pszState, "READ_ONLY", FALSE) == 0 ) { vmdirState = VMDIRD_STATE_READ_ONLY; } else { dwError = VMDIR_ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } if (g_hServer) { hServer = g_hServer; } dwError = VmDirSetState(hServer, vmdirState ); BAIL_ON_VMDIR_ERROR_WITH_MSG( dwError, (pszLocalErrorMsg), "VmDirSetState() failed. error(%u)", dwError ); printf("\n\n State of Vmdir set to %s\n\n", pszState); cleanup: VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg); return; error: printf("\n SetVmDirState failed: %s\n", VDIR_SAFE_STRING(pszLocalErrorMsg)); goto cleanup; }
DWORD VmDirLogSearchRequest( SearchReq* pSReq, ber_len_t iNumAttr ) { DWORD dwError = 0; PSTR pszLogMsg = NULL; size_t currLen = 0; size_t msgSize = 0; int iCnt = 0; assert(pSReq); for ( iCnt = 0, msgSize = 0; iCnt<iNumAttr; iCnt++ ) { msgSize += pSReq->attrs[iCnt].lberbv.bv_len + 2 /* for a ',' and ' ' */; } dwError = VmDirAllocateMemory( msgSize + 1, (PVOID *)&pszLogMsg ); BAIL_ON_VMDIR_ERROR(dwError); for ( iCnt = 0, currLen = 0; iCnt<iNumAttr; iCnt++ ) { VmDirStringNPrintFA( pszLogMsg + currLen, (msgSize + 1 - currLen), msgSize, "%s, ", pSReq->attrs[iCnt].lberbv.bv_val); currLen += pSReq->attrs[iCnt].lberbv.bv_len + 2; } pszLogMsg[currLen - 2] = '\0'; VMDIR_LOG_VERBOSE( LDAP_DEBUG_ARGS, " Required attributes: %s", pszLogMsg ); cleanup: VMDIR_SAFE_FREE_MEMORY( pszLogMsg ); return dwError; error: VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "VmDirLogSearchRequest: dwError: %lu, msgSize: %lu, iNumAttr: %lu", dwError, msgSize, iNumAttr); for ( iCnt = 0; iCnt<iNumAttr; iCnt++ ) { VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, " attr[%d] len: %lu, val: \"%.*s\"", iCnt, pSReq->attrs[iCnt].lberbv.bv_len, 256, VDIR_SAFE_STRING(pSReq->attrs[iCnt].lberbv.bv_val)); } goto cleanup; }
/* MdbDeleteEntry: Deletes an entry in the MDB DBs. * * Returns: BE error codes. * */ DWORD VmDirMDBDeleteEntry( PVDIR_BACKEND_CTX pBECtx, PVDIR_MODIFICATION pMods, PVDIR_ENTRY pEntry ) { DWORD dwError = 0; assert( pBECtx && pBECtx->pBEPrivate && pEntry ); // Delete child from the parentId index dwError = MDBDeleteParentIdIndex( pBECtx, &(pEntry->pdn), pEntry->eId ); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirMDBModifyEntry( pBECtx, pMods, pEntry); BAIL_ON_VMDIR_ERROR( dwError ); if ((dwError = MDBCreateParentIdIndex( pBECtx, &(gVmdirServerGlobals.delObjsContainerDN), pEntry->eId )) != 0) { dwError = MDBToBackendError(dwError, ERROR_BACKEND_ENTRY_NOTFOUND, ERROR_BACKEND_PARENT_NOTFOUND, pBECtx, "CreateParentIdIndex"); BAIL_ON_VMDIR_ERROR( dwError ); } cleanup: return dwError; error: VMDIR_LOG_ERROR( LDAP_DEBUG_BACKEND, "BEDeleteEntry DN (%s) failed, (%u)(%s)", VDIR_SAFE_STRING( pEntry->dn.bvnorm_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 AddAttrValsToEntryStruct( VDIR_ENTRY * e, VDIR_ATTRIBUTE * eAttr, // Entry attribute to be updated with new attribute values VDIR_ATTRIBUTE * modAttr, // Modify attribute containing new attribute values PSTR* ppszErrMsg ) { unsigned int i = 0; unsigned int j = 0; DWORD dwError = ERROR_SUCCESS; PSTR pszErrMsg = NULL; assert(e->allocType == ENTRY_STORAGE_FORMAT_NORMAL); if ((size_t)eAttr->numVals + (size_t)modAttr->numVals > UINT16_MAX) { dwError = VMDIR_ERROR_DATA_CONSTRAINT_VIOLATION; BAIL_ON_VMDIR_ERROR_WITH_MSG(dwError, (pszErrMsg), "Too many %s attribute values, max %u allowed.", VDIR_SAFE_STRING(eAttr->type.lberbv_val), UINT16_MAX); } dwError = VmDirReallocateMemoryWithInit(eAttr->vals, (PVOID*)(&(eAttr->vals)), (eAttr->numVals + modAttr->numVals + 1) * sizeof(VDIR_BERVALUE), (eAttr->numVals + 1) * sizeof(VDIR_BERVALUE)); BAIL_ON_VMDIR_ERROR(dwError); for (i = 0, j = eAttr->numVals; i < modAttr->numVals; i++, j++) { dwError = VmDirBervalContentDup(&modAttr->vals[i], &eAttr->vals[j]); BAIL_ON_VMDIR_ERROR(dwError); } memset(&(eAttr->vals[j]), 0, sizeof(VDIR_BERVALUE)); // set last BerValue.lberbv.bv_val to NULL; eAttr->numVals += modAttr->numVals; cleanup: VMDIR_SAFE_FREE_MEMORY(pszErrMsg); return dwError; error: if (ppszErrMsg) { *ppszErrMsg = pszErrMsg; pszErrMsg = NULL; } goto cleanup; }
static int _VmDirInternalNormalSearch( VDIR_OPERATION * pOperation ) { int retVal = LDAP_SUCCESS; PSTR pszLocalErrMsg = NULL; ENTRYID eStartingId = 0; // should never happen - there are asserts in calling function if (pOperation == NULL) { BAIL_WITH_VMDIR_ERROR(retVal, VMDIR_ERROR_INVALID_PARAMETER); } retVal = BuildCandidateList(pOperation, pOperation->request.searchReq.filter, eStartingId); BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, pszLocalErrMsg, "BuildCandidateList failed."); if (pOperation->request.searchReq.filter->computeResult == FILTER_RES_TRUE) { retVal = VMDIR_ERROR_UNWILLING_TO_PERFORM; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "Full scan of Entry DB is required. Refine your search."); } retVal = VmDirProcessCandidateList(pOperation); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "VmDirProcessCandidateList failed. (%u)(%s)", retVal, VDIR_SAFE_STRING(pOperation->ldapResult.pszErrMsg)); cleanup: VMDIR_SAFE_FREE_MEMORY(pszLocalErrMsg); return retVal; error: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s failed, error(%d)", __FUNCTION__, retVal); goto cleanup; }
DWORD VmDirSchemaCheckSetAttrDesc( PVDIR_SCHEMA_CTX pCtx, PVDIR_ENTRY pEntry ) { DWORD dwError = 0; VDIR_ATTRIBUTE* pAttr = NULL; assert(pCtx && pEntry); for (pAttr = pEntry->attrs; pAttr; pAttr = pAttr->next) { if (!pAttr->pATDesc) { if (VmDirStringCompareA( pAttr->type.lberbv.bv_val, ATTR_VMW_ORGANIZATION_GUID, FALSE ) == 0) { continue; // going to delete this attribute any way. } if (VmDirStringCompareA( pAttr->type.lberbv.bv_val, ATTR_VMW_OBJECT_SECURITY_DESCRIPTOR, FALSE ) == 0) { pAttr->pATDesc = VmDirSchemaAttrNameToDesc(pCtx, ATTR_OBJECT_SECURITY_DESCRIPTOR); } else { pAttr->pATDesc = VmDirSchemaAttrNameToDesc(pCtx, pAttr->type.lberbv.bv_val); } if (!pAttr->pATDesc) { pCtx->dwErrorCode = ERROR_INVALID_SCHEMA; VMDIR_SAFE_FREE_MEMORY(pCtx->pszErrorMsg); dwError = VmDirAllocateStringAVsnprintf( &pCtx->pszErrorMsg, "Attribute (%s) is not defined in schema", VDIR_SAFE_STRING(pAttr->type.lberbv.bv_val)); dwError = ERROR_INVALID_SCHEMA; BAIL_ON_VMDIR_ERROR(dwError); } } } error: return dwError; }
DWORD VmDirSrvSetupTenantInstance( PCSTR pszFQDomainName, PCSTR pszUsername, PCSTR pszPassword ) { DWORD dwError = 0; PSTR pszDomainDN = NULL; PVDIR_SCHEMA_CTX pSchemaCtx = NULL; VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL, "Setting up a tenant instance (%s).", VDIR_SAFE_STRING(pszFQDomainName)); dwError = VmDirSrvCreateDomainDN(pszFQDomainName, &pszDomainDN); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirSchemaCtxAcquire(&pSchemaCtx); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirSrvSetupDomainInstance( pSchemaCtx, FALSE, FALSE, pszFQDomainName, pszDomainDN, pszUsername, pszPassword); BAIL_ON_VMDIR_ERROR(dwError); cleanup: VMDIR_SAFE_FREE_MEMORY(pszDomainDN); if (pSchemaCtx) { VmDirSchemaCtxRelease(pSchemaCtx); } return dwError; error: VmDirLog(LDAP_DEBUG_ANY, "VmDirSrvSetupTenantInstance failed. Error(%u)", dwError); goto cleanup; }
VOID VdcadminGetVmdirState( VOID ) { DWORD dwError = 0; PCSTR pszState = NULL; PSTR pszLocalErrorMsg = NULL; PVMDIR_SERVER_CONTEXT hServer = NULL; UINT32 vmdirState = 0; if (g_hServer) { hServer = g_hServer; } dwError = VmDirGetState(hServer, &vmdirState ); BAIL_ON_VMDIR_ERROR_WITH_MSG( dwError, (pszLocalErrorMsg), "VmDirGetState() failed. error(%u)", dwError ); switch (vmdirState) { case VMDIRD_STATE_UNDEFINED: pszState = "Undefined"; break; case VMDIRD_STATE_STARTUP: pszState = "Startup"; break; case VMDIRD_STATE_READ_ONLY: pszState = "Read only"; break; case VMDIRD_STATE_NORMAL: pszState = "Normal" ; break; case VMDIRD_STATE_SHUTDOWN: pszState = "Shutdown"; break; } printf("\n\n VmDir State is - %s\n\n", pszState); cleanup: VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg); return; error: printf("\n GetVmDirState failed: %s\n", VDIR_SAFE_STRING(pszLocalErrorMsg)); goto cleanup; }
static DWORD _VmDirNormaliseNameField( PSTR pszSource , size_t dwLen ) { DWORD i = 0; DWORD j = 0; DWORD dwError = 0; DWORD dwState = 0; for (i=0 ; i<dwLen ;i++ ) { if (pszSource[i] == ' ') { if (dwState == 0 ) { pszSource[j++] = pszSource[i]; dwState = 1; } else { // Do Nothing , Ignore Extra Spaces .. } } else { pszSource[j++] = pszSource[i]; dwState = 0; } } pszSource[j++] = '\0' ; VMDIR_LOG_DEBUG( VMDIR_LOG_MASK_ALL, "Formatted NAME string is - %s", VDIR_SAFE_STRING(pszSource) ); return dwError ; }
/* * Error map from MDB to BE space * If no map specified, ERROR_BACKEND_ERROR is returned. * * BECtx.dwBEErrorCode is set to the first mdb error encountered * BECtx.pszBEErrorMsg is set to the first mdb error text encountered * * NOTE, this could be called multiple times during one LDAP level operation. * The last one counts. */ DWORD MDBToBackendError( DWORD dwMdbError, DWORD dwFromMdbError, DWORD dwToBEError, PVDIR_BACKEND_CTX pBECtx, PCSTR pszErrorContext) { DWORD dwError = 0; assert(pBECtx); if (dwMdbError != 0) { pBECtx->dwBEErrorCode = dwMdbError; VMDIR_SAFE_FREE_MEMORY(pBECtx->pszBEErrorMsg); // ignore error VmDirAllocateStringPrintf( &pBECtx->pszBEErrorMsg, "(%s)(%s)", mdb_strerror(dwMdbError), VDIR_SAFE_STRING(pszErrorContext)); if (dwMdbError == dwFromMdbError) { dwError = dwToBEError; } // check if the error is caused by one of raft callbacks // if yes return the same error else if (IS_VMDIR_ERROR_SPACE(dwMdbError)) { dwError = dwMdbError; } else { dwError = ERROR_BACKEND_ERROR; } } return dwError; }
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; }
// Protects key from being created more than once static VOID _VmDirInitThreadContextOnce(VOID) { DWORD dwError = 0; PSTR pszLocalErrorMsg = NULL; dwError = pthread_key_create(&pThreadContext->threadLogContext, NULL); BAIL_ON_VMDIR_ERROR_WITH_MSG(dwError, (pszLocalErrorMsg), "pthread_key_create failed on threadLogContext"); dwError = pthread_key_create(&pThreadContext->threadTxnContext, NULL); BAIL_ON_VMDIR_ERROR_WITH_MSG(dwError, (pszLocalErrorMsg), "pthread_key_create failed on threadTxnContext"); cleanup: VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg); return; error: VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "%s: %s errcode %d", __func__, VDIR_SAFE_STRING(pszLocalErrorMsg), dwError); VMDIR_SAFE_FREE_MEMORY(pThreadContext); goto cleanup; }
int VmDirPerformBind( PVDIR_OPERATION pOperation ) { BindReq * pBindReq = &(pOperation->request.bindReq); int retVal = LDAP_SUCCESS; ber_len_t berLen = 0; ber_tag_t berTag = 0; BOOLEAN bResultAlreadySent = FALSE; memset( pBindReq, 0, sizeof( BindReq )); if (ber_scanf( pOperation->ber, "{imt", &pOperation->protocol, &(pOperation->reqDn.lberbv), &pBindReq->method ) == LBER_ERROR ) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "PerformBind: ber_scanf failed" ); BAIL_ON_STATIC_LDAP_ERROR( retVal, LDAP_PROTOCOL_ERROR, (pOperation->ldapResult.pszErrMsg), "Decoding error while parsing protocol version, bind DN, bind method."); } VMDIR_LOG_VERBOSE( LDAP_DEBUG_ARGS, "Bind Request (%s): Protocol version: %d, Bind DN: \"%s\", Method: %ld", pOperation->conn->szClientIP, pOperation->protocol, pOperation->reqDn.lberbv.bv_val, pBindReq->method ); if (pOperation->protocol != LDAP_VERSION3) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "PerformBind: Non-ldap-v3 version." ); BAIL_ON_STATIC_LDAP_ERROR( retVal, LDAP_PROTOCOL_ERROR, (pOperation->ldapResult.pszErrMsg), "Currently, only LDAP V3 is supported."); } switch (pBindReq->method) { case LDAP_AUTH_SIMPLE: if ( ber_scanf( pOperation->ber, "m}", &(pBindReq->cred.lberbv) ) == LBER_ERROR ) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "PerformBind: ber_scanf failed" ); BAIL_ON_STATIC_LDAP_ERROR( retVal, LDAP_PROTOCOL_ERROR, (pOperation->ldapResult.pszErrMsg), "Decoding error while parsing simple credentials."); } break; case LDAP_AUTH_SASL: if ( ber_scanf( pOperation->ber, "{m" /*}*/, &(pBindReq->bvMechanism.lberbv) ) == LBER_ERROR) { BAIL_ON_STATIC_LDAP_ERROR( retVal, LDAP_PROTOCOL_ERROR, (pOperation->ldapResult.pszErrMsg), "Decoding error while parsing sasl mechanism."); } berTag = ber_peek_tag( pOperation->ber, &berLen ); if ( berTag == LDAP_TAG_LDAPCRED ) { if ( ber_scanf( pOperation->ber, "m", &(pBindReq->cred.lberbv)) == LBER_ERROR ) { BAIL_ON_STATIC_LDAP_ERROR( retVal, LDAP_PROTOCOL_ERROR, (pOperation->ldapResult.pszErrMsg), "Decoding error while parsing sasl creds."); } } if ( ber_scanf( pOperation->ber, /*{{*/ "}}" ) == LBER_ERROR ) { BAIL_ON_STATIC_LDAP_ERROR( retVal, LDAP_PROTOCOL_ERROR, (pOperation->ldapResult.pszErrMsg), "Decoding error."); } break; default: BAIL_ON_STATIC_LDAP_ERROR( retVal, LDAP_UNWILLING_TO_PERFORM, (pOperation->ldapResult.pszErrMsg), "bind method not supported."); } retVal = VmDirMLBind( pOperation ); bResultAlreadySent = TRUE; if (retVal && retVal != LDAP_SASL_BIND_IN_PROGRESS) { VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "Bind Request Failed (%s) error %u: Protocol version: %d, Bind DN: \"%s\", Method: %ld", pOperation->conn->szClientIP, retVal, pOperation->protocol, VDIR_SAFE_STRING(pOperation->reqDn.lberbv.bv_val), pBindReq->method ); } BAIL_ON_SIMPLE_LDAP_ERROR(retVal); cleanup: return retVal; ldaperror: pOperation->ldapResult.errCode = retVal; if (retVal != LDAP_NOTICE_OF_DISCONNECT && bResultAlreadySent == FALSE) { VmDirSendLdapResult( pOperation ); } 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; }
/* 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; }