int VmDirPerformRename( PVDIR_OPERATION pOperation ) { ModifyReq * modReq = &(pOperation->request.modifyReq); int retVal = LDAP_SUCCESS; PVDIR_LDAP_RESULT pResult = &(pOperation->ldapResult); ber_len_t size = 0; PSTR pszLocalErrorMsg = NULL; if (!_VmDirIsRenameSupported()) { pResult->errCode = retVal = LDAP_UNWILLING_TO_PERFORM; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrorMsg, "Operation is not enabled on this server or is not supported at this domain fuctional level."); } // Get entry DN. 'm' => reqDn.bv_val points to DN within (in-place) ber if ( ber_scanf( pOperation->ber, "{mmb", &modReq->dn, &modReq->newrdn, &modReq->bDeleteOldRdn) == LBER_ERROR ) { VMDIR_LOG_ERROR( LDAP_DEBUG_ARGS, "VmDirPerformRename: ber_scanf failed" ); pResult->errCode = LDAP_PROTOCOL_ERROR; retVal = LDAP_NOTICE_OF_DISCONNECT; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Decoding error while parsing the target DN"); } if (ber_peek_tag(pOperation->ber, &size) == LDAP_TAG_NEWSUPERIOR) { if ( ber_scanf(pOperation->ber, "m", &modReq->newSuperior ) == LBER_ERROR ) { pResult->errCode = LDAP_PROTOCOL_ERROR; retVal = LDAP_NOTICE_OF_DISCONNECT; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Decoding error while parsing newSuperior"); } } if ( ber_scanf( pOperation->ber, "}") == LBER_ERROR ) { VMDIR_LOG_ERROR( LDAP_DEBUG_ARGS, "PerformRename: ber_scanf failed" ); pResult->errCode = LDAP_PROTOCOL_ERROR; retVal = LDAP_NOTICE_OF_DISCONNECT; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Decoding error while parsing the end of message."); } retVal = pResult->errCode = VmDirMLModify( pOperation ); BAIL_ON_VMDIR_ERROR(retVal); cleanup: if (retVal != LDAP_NOTICE_OF_DISCONNECT) { VmDirSendLdapResult( pOperation ); } VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg); return retVal; error: VMDIR_APPEND_ERROR_MSG(pResult->pszErrMsg, pszLocalErrorMsg); goto cleanup; }
static int _ParseCondWriteControlVal( VDIR_OPERATION * pOp, BerValue * pControlBer, // Input: control value encoded as ber VDIR_CONDWRITE_CONTROL_VALUE * pCtrlVal, // Output VDIR_LDAP_RESULT * pLdapResult // Output ) { int retVal = LDAP_SUCCESS; BerElementBuffer berbuf; BerElement * ber = (BerElement *)&berbuf; PSTR pszLocalErrorMsg = NULL; PSTR pszCondFilter = NULL; if (!pOp) { retVal = LDAP_PROTOCOL_ERROR; BAIL_ON_VMDIR_ERROR( retVal ); } ber_init2( ber, pControlBer, LBER_USE_DER ); /* * https://confluence.eng.vmware.com/display/LIG/Conditional+LDAP+Write+Operation * * The ConditionalWriteControl is a null terminated STRING wrapping the BER-encoded version of the following SEQUENCE: * * ControlValue ::= SEQUENCE { * ConditionalWriteFilter OCTET STRING * } */ if (ber_scanf(ber, "{a}", &pszCondFilter) == LBER_ERROR) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s: ber_scanf failed while parsing filter value", __FUNCTION__); pLdapResult->errCode = LDAP_PROTOCOL_ERROR; retVal = LDAP_NOTICE_OF_DISCONNECT; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Error in reading conditional write control filter"); } retVal = VmDirAllocateStringA(pszCondFilter, &(pCtrlVal->pszFilter)); BAIL_ON_VMDIR_ERROR(retVal); cleanup: if (pszCondFilter) { ber_memfree(pszCondFilter); } VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg); return retVal; error: VMDIR_APPEND_ERROR_MSG(pLdapResult->pszErrMsg, pszLocalErrorMsg); 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 int DeleteRefAttributesValue( VDIR_OPERATION * pOperation, VDIR_BERVALUE * dn ) { int retVal = LDAP_SUCCESS; VDIR_FILTER * f = NULL; VDIR_CANDIDATES * cl = NULL; VDIR_ENTRY groupEntry = {0}; VDIR_ENTRY * pGroupEntry = NULL; int i = 0; VDIR_MODIFICATION mod = {0}; ModifyReq mr; VDIR_BERVALUE delVals[2]; PSTR pszLocalErrorMsg = NULL; assert( pOperation != NULL && pOperation->pBEIF != NULL && dn != NULL); retVal = VmDirNormalizeDN( dn, pOperation->pSchemaCtx ); BAIL_ON_VMDIR_ERROR( retVal ); // Set filter retVal = VmDirAllocateMemory( sizeof( VDIR_FILTER ), (PVOID *)&f); BAIL_ON_VMDIR_ERROR( retVal ); f->choice = LDAP_FILTER_EQUALITY; f->filtComp.ava.type.lberbv.bv_val = ATTR_MEMBER; f->filtComp.ava.type.lberbv.bv_len = ATTR_MEMBER_LEN; f->filtComp.ava.value = *dn; if ((f->filtComp.ava.pATDesc = VmDirSchemaAttrNameToDesc( pOperation->pSchemaCtx, ATTR_MEMBER)) == NULL) { retVal = VMDIR_ERROR_NO_SUCH_ATTRIBUTE; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "undefined attribute (%s)", VDIR_SAFE_STRING(ATTR_MEMBER)); } // Set ModifyReq structure memset(&mr, 0, sizeof(ModifyReq)); mod.operation = MOD_OP_DELETE; mod.attr.type.lberbv.bv_val = ATTR_MEMBER; mod.attr.type.lberbv.bv_len = ATTR_MEMBER_LEN; mod.attr.pATDesc = f->filtComp.ava.pATDesc; mod.attr.next = NULL; delVals[0] = *dn; memset(&(delVals[1]), 0, sizeof(VDIR_BERVALUE)); mod.attr.vals = delVals; mod.attr.numVals = 1; mod.next = NULL; mr.mods = &mod; mr.numMods = 1; retVal = pOperation->pBEIF->pfnBEGetCandidates( pOperation->pBECtx, f); if ( retVal != 0 ) { if (retVal == VMDIR_ERROR_BACKEND_ENTRY_NOTFOUND) { retVal = LDAP_SUCCESS; // no member refer to this DN. return ok/0 } else { retVal = VMDIR_ERROR_GENERIC; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "DeleteRefAttributesValue: Building group list (BdbGetCandidates()) failed."); } } else { cl = f->candidates; for (i = 0; i < cl->size; i++) { pGroupEntry = &groupEntry; if ((retVal = VmDirModifyEntryCoreLogic( pOperation, &mr, cl->eIds[i], pGroupEntry)) != 0) { switch (retVal) { case VMDIR_ERROR_BACKEND_PARENT_NOTFOUND: case VMDIR_ERROR_BACKEND_ENTRY_NOTFOUND: case VMDIR_ERROR_ENTRY_NOT_FOUND: continue; default: // Including LDAP_LOCK_DEADLOCK, which is handled by the caller BAIL_ON_VMDIR_ERROR( retVal ); } } VmDirFreeBervalContent( &(mr.dn) ); // VmDirModifyEntryCoreLogic fill in DN if not exists VmDirFreeEntryContent( pGroupEntry ); pGroupEntry = NULL; // Reset to NULL so that DeleteEntry is no-op. } } cleanup: memset(&(f->filtComp.ava.value), 0, sizeof(VDIR_BERVALUE)); // Since ava.value is NOT owned by filter. DeleteFilter( f ); VmDirFreeEntryContent( pGroupEntry ); VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg); return retVal; error: VMDIR_APPEND_ERROR_MSG(pOperation->ldapResult.pszErrMsg, pszLocalErrorMsg); goto cleanup; }
static int _ParsePagedResultControlVal( VDIR_OPERATION * op, BerValue * controlValue, // Input: control value encoded as ber VDIR_PAGED_RESULT_CONTROL_VALUE * pageResultCtrlVal, // Output VDIR_LDAP_RESULT * lr // Output ) { int retVal = LDAP_SUCCESS; BerElementBuffer berbuf; BerElement * ber = (BerElement *)&berbuf; PSTR pszLocalErrorMsg = NULL; PSTR pszCookie = NULL; VMDIR_LOG_DEBUG( LDAP_DEBUG_TRACE, "_ParsePagedResultControlVal: Start." ); if (!op) { retVal = LDAP_PROTOCOL_ERROR; BAIL_ON_VMDIR_ERROR( retVal ); } ber_init2( ber, controlValue, LBER_USE_DER ); /* http://www.ietf.org/rfc/rfc2696.txt * * The searchControlValue is an OCTET STRING wrapping the BER-encoded version of the following SEQUENCE: * * realSearchControlValue ::= SEQUENCE { * size INTEGER (0..maxInt), * -- requested page size from client * -- result set size estimate from server * cookie OCTET STRING } */ if (ber_scanf(ber, "{ia}", &pageResultCtrlVal->pageSize, &pszCookie) == LBER_ERROR) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "_ParsePagedResultControlVal: ber_scanf failed while parsing " "pageSize and cookie in the page result control value" ); lr->errCode = LDAP_PROTOCOL_ERROR; retVal = LDAP_NOTICE_OF_DISCONNECT; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Error in reading pageSize and cookie in the page result control value"); } if (pageResultCtrlVal->pageSize == 0) { retVal = LDAP_CANCELLED; VMDIR_LOG_DEBUG( LDAP_DEBUG_TRACE, "Search query was cancelled."); BAIL_ON_VMDIR_ERROR(retVal); } VmDirStringNCpyA( pageResultCtrlVal->cookie, VMDIR_ARRAY_SIZE(pageResultCtrlVal->cookie), pszCookie, VMDIR_ARRAY_SIZE(pageResultCtrlVal->cookie) - 1); VMDIR_LOG_DEBUG( LDAP_DEBUG_TRACE, "pageSize:%d", pageResultCtrlVal->pageSize ); VMDIR_LOG_DEBUG( LDAP_DEBUG_TRACE, "cookie:%s", pageResultCtrlVal->cookie ); cleanup: if (pszCookie) { ber_memfree(pszCookie); } // Even in the error case, syncDoneCtrl should be freed during operation delete. VMDIR_LOG_DEBUG( LDAP_DEBUG_TRACE, "_ParsePagedResultControlVal: End." ); VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg); return retVal; error: VMDIR_APPEND_ERROR_MSG(lr->pszErrMsg, pszLocalErrorMsg); goto cleanup; }
int ParseRequestControls( VDIR_OPERATION * op, VDIR_LDAP_RESULT * lr ) { int retVal = LDAP_SUCCESS; ber_tag_t tag = LBER_ERROR; ber_len_t len = 0; char * endOfCtrlsMarker = NULL; VDIR_LDAP_CONTROL ** control = &(op->reqControls); BerValue lberBervType = {0}; BerValue lberBervCtlValue = {0}; PSTR pszLocalErrorMsg = NULL; VMDIR_LOG_DEBUG( LDAP_DEBUG_TRACE, "ParseRequestControls: Begin." ); *control = NULL; #ifndef _WIN32 if (ber_pvt_ber_remaining(op->ber) != 0) #else if (LBER_DEFAULT != ber_peek_tag (op->ber, &len)) #endif { if (ber_peek_tag( op->ber, &len ) != LDAP_TAG_CONTROLS ) { lr->errCode = LDAP_PROTOCOL_ERROR; retVal = LDAP_NOTICE_OF_DISCONNECT; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "ParseRequestControls: Request controls expected, but something else is there in the PDU."); } // Get controls. ber_first_element => skip the sequence header, set the cursor at the 1st control in the SEQ of SEQ for( tag = ber_first_element( op->ber, &len, &endOfCtrlsMarker ); tag != LBER_ERROR; tag = ber_next_element( op->ber, &len, endOfCtrlsMarker ) ) { // m => in-place if (ber_scanf( op->ber, "{m", &lberBervType ) == LBER_ERROR) { lr->errCode = LDAP_PROTOCOL_ERROR; retVal = LDAP_NOTICE_OF_DISCONNECT; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "ParseRequestControls Error in reading control type from the PDU."); } if ( VmDirLogGetMask() & LDAP_DEBUG_ARGS) { VMDIR_LOG_INFO( LDAP_DEBUG_ARGS, " Request Control: %s", lberBervType.bv_val ); } if (VmDirAllocateMemory( sizeof( VDIR_LDAP_CONTROL), (PVOID *)control ) != 0) { retVal = lr->errCode = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "ParseRequestControls: VmDirAllocateMemory failed"); } // type points into in-place ber and does NOT own its content (*control)->type = lberBervType.bv_val; (*control)->criticality = FALSE; tag = ber_peek_tag( op->ber, &len ); if (tag == LBER_BOOLEAN) { ber_int_t criticality; if (ber_scanf( op->ber, "b", &criticality) == LBER_ERROR) { lr->errCode = LDAP_PROTOCOL_ERROR; retVal = LDAP_NOTICE_OF_DISCONNECT; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "ParseRequestControls: Error in reading control criticality from the PDU."); } if (criticality) { (*control)->criticality = TRUE; } tag = ber_peek_tag( op->ber, &len ); } if (tag == LBER_OCTETSTRING) { if (ber_scanf( op->ber, "m", &lberBervCtlValue) == LBER_ERROR) { lr->errCode = LDAP_PROTOCOL_ERROR; retVal = LDAP_NOTICE_OF_DISCONNECT; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "ParseRequestControls: ber_scanf failed while parsing the control value."); } } // SJ-TBD: Make sure that the control appears only once in the request, and it is present only in a search // request if (VmDirStringCompareA( (*control)->type, LDAP_CONTROL_SYNC, TRUE ) == 0) { if (VmDirdGetRunMode() != VMDIR_RUNMODE_NORMAL) { // Why block out-bound replication when catching up during restore mode? // // Reason: Partners have high-water-mark (lastLocalUsn) corresponding to this replica that is being // restored. If out-bound replication is not blocked while restore/catching-up is going on, originating // or replicated updates (if this replica is the only partner) made between the current-local-usn and // high-water-marks, that partners remember, will not get replicated out (even if the invocationId // has been fixed/changed). retVal = lr->errCode = LDAP_UNWILLING_TO_PERFORM; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "ParseRequestControls: Server not in normal mode, not allowing outward replication."); } if ((retVal = ParseSyncRequestControlVal( op, &lberBervCtlValue, &((*control)->value.syncReqCtrlVal), lr)) != LDAP_SUCCESS) { BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "ParseRequestControls: ParseSyncRequestControlVal failed."); } op->syncReqCtrl = *control; } if (VmDirStringCompareA( (*control)->type, VDIR_LDAP_CONTROL_SHOW_DELETED_OBJECTS, TRUE ) == 0) { op->showDeletedObjectsCtrl = *control; } if (VmDirStringCompareA( (*control)->type, VDIR_LDAP_CONTROL_SHOW_MASTER_KEY, TRUE ) == 0) { op->showMasterKeyCtrl = *control; } if (VmDirStringCompareA((*control)->type, LDAP_CONTROL_CONSISTENT_WRITE, TRUE ) == 0) { op->strongConsistencyWriteCtrl = *control; } if (VmDirStringCompareA((*control)->type, VDIR_LDAP_CONTROL_MANAGEDDSAIT, TRUE ) == 0) { op->manageDsaITCtrl = *control; } if (VmDirStringCompareA( (*control)->type, LDAP_CONTROL_PAGEDRESULTS, TRUE ) == 0) { retVal = _ParsePagedResultControlVal( op, &lberBervCtlValue, &((*control)->value.pagedResultCtrlVal), lr); if (retVal != LDAP_SUCCESS) { BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "ParseRequestControls: _ParsePagedResultControlVal failed."); } op->showPagedResultsCtrl = *control; } if (VmDirStringCompareA( (*control)->type, LDAP_CONTROL_CONDITIONAL_WRITE, TRUE ) == 0) { retVal = _ParseCondWriteControlVal( op, &lberBervCtlValue, &((*control)->value.condWriteCtrlVal), lr); if (retVal != LDAP_SUCCESS) { BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "ParseRequestControls: _ParseConditionalWriteControlVal failed."); } op->pCondWriteCtrl = *control; } if (VmDirStringCompareA( (*control)->type, LDAP_APPEND_ENTRIES_CONTROL, TRUE ) == 0) { retVal = _ParseAppendEntriesControlVal( op, &lberBervCtlValue, &((*control)->value.appendEntriesCtrlVal), lr); if (retVal != LDAP_SUCCESS) { BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "ParseRequestControls: _ParseAppendEntriesControlVal failed."); } op->appendEntriesCtrl = *control; } if (VmDirStringCompareA( (*control)->type, LDAP_REQUEST_VOTE_CONTROL, TRUE ) == 0) { retVal = _ParseRequestVoteControlVal( op, &lberBervCtlValue, &((*control)->value.requestVoteCtrlVal), lr); if (retVal != LDAP_SUCCESS) { BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "ParseRequestControls: _ParseRequestVoteControlVal failed."); } op->requestVoteCtrl = *control; } if (VmDirStringCompareA( (*control)->type, VMDIR_LDAP_CONTROL_TXN_SPEC, TRUE ) == 0) { retVal = VmDirAllocateMemory(lberBervCtlValue.bv_len+1, (PVOID*)&((*control)->value.txnSpecCtrlVal).pszTxnId); BAIL_ON_VMDIR_ERROR(retVal); VmDirStringNCpyA(((*control)->value.txnSpecCtrlVal).pszTxnId, lberBervCtlValue.bv_len+1, lberBervCtlValue.bv_val, lberBervCtlValue.bv_len); op->txnSpecCtrl = *control; op->pBECtx->pszTxnId = (op->txnSpecCtrl->value.txnSpecCtrlVal).pszTxnId; } if ( ber_scanf( op->ber, "}") == LBER_ERROR ) // end of control { lr->errCode = LDAP_PROTOCOL_ERROR; retVal = LDAP_NOTICE_OF_DISCONNECT; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "ParseRequestControls: ber_scanf failed while parsing the end of control"); } control = &((*control)->next); } retVal = LDAP_SUCCESS; } cleanup: VMDIR_LOG_DEBUG( LDAP_DEBUG_TRACE, "ParseRequestControls: End." ); VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg); return retVal; error: DeleteControls(&(op->reqControls)); if (pszLocalErrorMsg) { VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, pszLocalErrorMsg); VMDIR_APPEND_ERROR_MSG(lr->pszErrMsg, pszLocalErrorMsg); } goto cleanup; }
static int ParseSyncRequestControlVal( VDIR_OPERATION * op, BerValue * controlValue, // Input: control value encoded as ber SyncRequestControlValue * syncReqCtrlVal, // Output VDIR_LDAP_RESULT * lr // Output ) { int retVal = LDAP_SUCCESS; ber_tag_t tag = LBER_ERROR; ber_len_t len = 0; UptoDateVectorEntry * utdVectorEntry = NULL; BerElementBuffer berbuf; BerElement * ber = (BerElement *)&berbuf; PSTR pszLocalErrorMsg = NULL; VDIR_BACKEND_CTX backendCtx = {0}; USN maxPartnerVisibleUSN = 0; VMDIR_LOG_DEBUG( LDAP_DEBUG_TRACE, "ParseSyncRequestControlVal: Begin." ); ber_init2( ber, controlValue, LBER_USE_DER ); /* http://www.rfc-editor.org/rfc/rfc4533.txt * * syncCookie ::= OCTET STRING * * syncRequestValue ::= SEQUENCE { * mode ENUMERATED { * -- 0 unused * refreshOnly (1), * -- 2 reserved * refreshAndPersist (3) * }, * cookie syncCookie OPTIONAL, * reloadHint BOOLEAN DEFAULT FALSE * } */ if (ber_scanf( ber, "{i", &(syncReqCtrlVal->mode) ) == LBER_ERROR) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "ParseSyncRequestControlVal: ber_scanf failed while parsing the sync request " "control mode" ); lr->errCode = LDAP_PROTOCOL_ERROR; retVal = LDAP_NOTICE_OF_DISCONNECT; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Error in reading sync request control mode from PDU."); } syncReqCtrlVal->bvLastLocalUsnProcessed.lberbv.bv_val = ""; syncReqCtrlVal->intLastLocalUsnProcessed = 0; if (VmDirAllocateMemory( sizeof( VDIR_LDAP_CONTROL ), (PVOID *)&op->syncDoneCtrl) != 0) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "ParseSyncRequestControlVal: VmDirAllocateMemory failed " ); lr->errCode = retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "ParseSyncRequestControlVal: VmDirAllocateMemory failed."); } op->syncDoneCtrl->type = LDAP_CONTROL_SYNC_DONE; if (LwRtlCreateHashTable( &op->syncDoneCtrl->value.syncDoneCtrlVal.htUtdVector, UtdVectorEntryGetKey, LwRtlHashDigestPstr, LwRtlHashEqualPstr, NULL, VMDIR_UTD_VECTOR_HASH_TABLE_SIZE ) != 0) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "UpdateSyncDoneUtdVectorEntry: LwRtlCreateHashTable failed" ); lr->errCode = retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "UpdateSyncDoneUtdVectorEntry: LwRtlCreateHashTable failed"); } tag = ber_peek_tag( ber, &len ); if (tag == LBER_SEQUENCE) { // syncCookie /* syncCookie ::= SEQUENCE { * reqServerId LDAPString, * lastLocalUsnProcessed INTEGER (0 .. maxInt), * utdVector UptoDateVectorEntryList } * * UptoDateVectorEntryList ::= SEQUENCE OF uptoDateVectorEntry UptoDateVectorEntry * * UptoDateVectorEntry ::= SEQUENCE { * serverId LDAPString, * lastOrigUsnProcessed INTEGER (0 .. maxInt) } */ // {lastLocalUsnProcessed{{<serverid1><lastOrigUsnProcessed1>}{<serverid2><lastOrigUsnProcessed2>}...}} if (ber_scanf( ber, "{mmm}", &syncReqCtrlVal->reqInvocationId.lberbv, &syncReqCtrlVal->bvLastLocalUsnProcessed.lberbv, &syncReqCtrlVal->bvUtdVector.lberbv ) == LBER_ERROR ) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "ParseSyncRequestControlVal: ber_scanf failed while parsing " "lastLocalUsnProcessed in the sync request control value" ); lr->errCode = LDAP_PROTOCOL_ERROR; retVal = LDAP_NOTICE_OF_DISCONNECT; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Error in reading lastLocalUsnProcessed in the sync request control value"); } VMDIR_LOG_DEBUG( LDAP_DEBUG_REPL, "ParseSyncRequestControlVal: ServerId: %s, lastLocalUsnProcessed: %s, utdVector: %s", syncReqCtrlVal->reqInvocationId.lberbv.bv_val, syncReqCtrlVal->bvLastLocalUsnProcessed.lberbv.bv_val, syncReqCtrlVal->bvUtdVector.lberbv.bv_val ); syncReqCtrlVal->intLastLocalUsnProcessed = op->syncDoneCtrl->value.syncDoneCtrlVal.intLastLocalUsnProcessed = VmDirStringToLA( syncReqCtrlVal->bvLastLocalUsnProcessed.lberbv.bv_val, NULL, 10 ); { char * nextServerIdStr = NULL; char * nextOrigUsnStr = NULL; nextServerIdStr = syncReqCtrlVal->bvUtdVector.lberbv.bv_val; while( nextServerIdStr != NULL && nextServerIdStr[0] != '\0') { PLW_HASHTABLE_NODE pNode = NULL; if (VmDirAllocateMemory( sizeof(UptoDateVectorEntry), (PVOID *)&utdVectorEntry ) != 0) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "ParseSyncRequestControlVal: VmDirAllocateMemory failed " ); lr->errCode = retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "ParseSyncRequestControlVal: VmDirAllocateMemory failed"); } nextOrigUsnStr = VmDirStringChrA( nextServerIdStr, ':'); *nextOrigUsnStr = '\0'; nextOrigUsnStr++; utdVectorEntry->invocationId.lberbv.bv_val = nextServerIdStr; utdVectorEntry->invocationId.lberbv.bv_len = VmDirStringLenA( nextServerIdStr ); nextServerIdStr = VmDirStringChrA( nextOrigUsnStr, ','); *nextServerIdStr = '\0'; nextServerIdStr++; utdVectorEntry->currMaxOrigUsnProcessed = utdVectorEntry->reqLastOrigUsnProcessed = atol( nextOrigUsnStr ); LwRtlHashTableResizeAndInsert( op->syncDoneCtrl->value.syncDoneCtrlVal.htUtdVector, &utdVectorEntry->Node, &pNode); assert( pNode == NULL ); // assert the key of added node is unique. } } tag = ber_peek_tag( ber, &len ); } if (tag == LBER_BOOLEAN) { ber_int_t reloadHint; if (ber_scanf( ber, "b", &reloadHint) == LBER_ERROR) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "ParseSyncRequestControlVal: Error in reading reloadHint from the PDU" ); lr->errCode = LDAP_PROTOCOL_ERROR; retVal = LDAP_NOTICE_OF_DISCONNECT; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Error in reading reloadHint from the PDU."); } if (reloadHint) { syncReqCtrlVal->reloadHint = TRUE; } } if ( ber_scanf( ber, "}") == LBER_ERROR ) // End of control value { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "ParseSyncRequestControlVal: ber_scanf failed while parsing the end of " "sync request control value." ); lr->errCode = LDAP_PROTOCOL_ERROR; retVal = LDAP_NOTICE_OF_DISCONNECT; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Decoding error while parsing the end of sync request control value."); } backendCtx.pBE = VmDirBackendSelect(""); maxPartnerVisibleUSN = backendCtx.pBE->pfnBEGetLeastOutstandingUSN( &backendCtx, FALSE ) - 1; if (syncReqCtrlVal->intLastLocalUsnProcessed > maxPartnerVisibleUSN) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "ParseSyncRequestControlVal: ServerId %s has processed my USN (%u), my max USN is (%u).", syncReqCtrlVal->reqInvocationId.lberbv.bv_val, syncReqCtrlVal->intLastLocalUsnProcessed, maxPartnerVisibleUSN ); lr->errCode = LDAP_UNWILLING_TO_PERFORM; retVal = LDAP_NOTICE_OF_DISCONNECT; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Partner is ahead of my changes."); } cleanup: // Even in the error case, syncDoneCtrl should be freed during operation delete. VMDIR_LOG_DEBUG( LDAP_DEBUG_TRACE, "ParseSyncRequestControlVal: End." ); VmDirBackendCtxContentFree( &backendCtx ); VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg); return retVal; error: VMDIR_APPEND_ERROR_MSG(lr->pszErrMsg, pszLocalErrorMsg); goto cleanup; }
static int _ParseRequestVoteControlVal( VDIR_OPERATION * pOp, BerValue * pControlBer, // Input: control value encoded as ber PVDIR_REQUEST_VOTE_CONTROL_VALUE pCtrlVal, // Output VDIR_LDAP_RESULT * pLdapResult // Output ) { int retVal = LDAP_SUCCESS; BerElementBuffer berbuf = {0}; BerElement * ber = (BerElement *)&berbuf; PSTR pszLocalErrorMsg = NULL; ber_int_t term = 0; BerValue candidateId = {0}; BerValue lastLogIndex = {0}; ber_int_t lastLogTerm = 0; if (!pOp || !pControlBer ) { retVal = LDAP_PROTOCOL_ERROR; BAIL_ON_VMDIR_ERROR( retVal ); } if (!pCtrlVal || !pLdapResult) { retVal = ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR( retVal ); } ber_init2( ber, pControlBer, LBER_USE_DER ); /* * The RequestVoteControl the BER-encoded version of the following SEQUENCE: * * ControlValue ::= SEQUENCE { * term Integer * candidateId OCTET STRING * lastLogIndex OCTET STRING * lastLogTerm Integer * } */ if (ber_scanf(ber, "{immi}", &term, &candidateId, &lastLogIndex, &lastLogTerm) == LBER_ERROR) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s: ber_scanf failed while parsing filter value", __FUNCTION__); pLdapResult->errCode = LDAP_PROTOCOL_ERROR; retVal = LDAP_NOTICE_OF_DISCONNECT; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Error in reading cluster state control filter"); } pCtrlVal->term = term; retVal = VmDirAllocateStringA(candidateId.bv_val, &(pCtrlVal->candidateId)); BAIL_ON_VMDIR_ERROR(retVal); pCtrlVal->lastLogIndex = VmDirStringToLA(lastLogIndex.bv_val, NULL, 10); BAIL_ON_VMDIR_ERROR(retVal); pCtrlVal->lastLogTerm = lastLogTerm; cleanup: VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg); return retVal; error: if (pszLocalErrorMsg && pLdapResult->pszErrMsg) { VMDIR_APPEND_ERROR_MSG(pLdapResult->pszErrMsg, pszLocalErrorMsg); } VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "%s Error: %d", __func__, retVal); goto cleanup; }
static int _ParseAppendEntriesControlVal( VDIR_OPERATION * pOp, BerValue * pControlBer, // Input: control value encoded as ber PVDIR_APPEND_ENTRIES_CONTROL_VALUE pCtrlVal, // Output VDIR_LDAP_RESULT * pLdapResult // Output ) { int retVal = LDAP_SUCCESS; BerElementBuffer berbuf = {0}; BerElement * ber = (BerElement *)&berbuf; PSTR pszLocalErrorMsg = NULL; ber_int_t term = 0; BerValue leader = {0}; BerValue preLogIndex= {0}; ber_int_t preLogTerm = 0; BerValue leaderCommit = {0}; BerValue entries = {0}; if (!pOp || !pControlBer) { retVal = LDAP_PROTOCOL_ERROR; BAIL_ON_VMDIR_ERROR( retVal ); } if (!pCtrlVal || !pLdapResult) { retVal = ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR( retVal ); } ber_init2( ber, pControlBer, LBER_USE_DER ); /* * The AppendEntriesControl the BER-encoded version of the following SEQUENCE: * * ControlValue ::= SEQUENCE { * term Integer * leader OCTET STRING * preLogIndex OCTET STRING * prevLogTerm Integer * leaderCommit OCTET STRING * entries OCTET STRING * } */ if (ber_scanf(ber, "{immimm}", &term, &leader, &preLogIndex, &preLogTerm, &leaderCommit, &entries) == LBER_ERROR) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s: ber_scanf failed while parsing filter value", __FUNCTION__); pLdapResult->errCode = LDAP_PROTOCOL_ERROR; retVal = LDAP_NOTICE_OF_DISCONNECT; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Error in reading cluster state control filter"); } pCtrlVal->term = term; retVal = VmDirAllocateStringA(leader.bv_val, &(pCtrlVal->leader)); BAIL_ON_VMDIR_ERROR(retVal); pCtrlVal->preLogIndex = VmDirStringToLA(preLogIndex.bv_val, NULL, 10); BAIL_ON_VMDIR_ERROR(retVal); pCtrlVal->preLogTerm = preLogTerm; pCtrlVal->leaderCommit = VmDirStringToLA(leaderCommit.bv_val, NULL, 10); BAIL_ON_VMDIR_ERROR(retVal); retVal = VmDirAllocateAndCopyMemory(entries.bv_val, entries.bv_len, (PVOID*)&(pCtrlVal->entries.lberbv_val)); BAIL_ON_VMDIR_ERROR(retVal); pCtrlVal->entries.lberbv_len = entries.bv_len; cleanup: VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg); return retVal; error: if (pszLocalErrorMsg && pLdapResult->pszErrMsg) { VMDIR_APPEND_ERROR_MSG(pLdapResult->pszErrMsg, pszLocalErrorMsg); } VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "%s Error: %d", __func__, retVal); goto cleanup; }
int VmDirPerformSearch( PVDIR_OPERATION pOperation ) { ber_len_t size = 0; SearchReq * sr = &(pOperation->request.searchReq); int retVal = LDAP_SUCCESS; BerValue* pLberBerv = NULL; PSTR pszLocalErrorMsg = NULL; BOOLEAN bResultAlreadySent = FALSE; PVDIR_LDAP_RESULT pResult = &(pOperation->ldapResult); // Parse base object, scope, deref alias, sizeLimit, timeLimit and typesOnly search parameters. if ( ber_scanf( pOperation->ber, "{miiiib", &(pOperation->reqDn.lberbv), &sr->scope, &sr->derefAlias, &sr->sizeLimit, &sr->timeLimit, &sr->attrsOnly ) == LBER_ERROR ) { VMDIR_LOG_ERROR( LDAP_DEBUG_ARGS, "PerformSearch: Decoding baseDN, ... attrsOnly error." ); pResult->errCode = LDAP_PROTOCOL_ERROR; retVal = LDAP_NOTICE_OF_DISCONNECT; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Decoding error while parsing baseDN, ... attrsOnly."); } VMDIR_LOG_VERBOSE( LDAP_DEBUG_ARGS, "Search Request: base: \"%s\", scope: %d, deref: %d, sizeLimit: %d, timeLimit: %d," "attrsOnly: %d", pOperation->reqDn.lberbv.bv_val, sr->scope, sr->derefAlias, sr->sizeLimit, sr->timeLimit, sr->attrsOnly); if (sr->scope != LDAP_SCOPE_BASE && sr->scope != LDAP_SCOPE_ONELEVEL && sr->scope != LDAP_SCOPE_SUBTREE) { pResult->errCode = retVal = LDAP_PROTOCOL_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Invalid scope" ); } if (sr->sizeLimit < 0 || sr->sizeLimit > LDAP_MAXINT) { pResult->errCode = retVal = LDAP_PROTOCOL_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Invalid size limit: %d", sr->sizeLimit ); } if (sr->timeLimit < 0 || sr->timeLimit > LDAP_MAXINT) { pResult->errCode = retVal = LDAP_PROTOCOL_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Invalid time limit: %d", sr->timeLimit ); } if (sr->derefAlias != LDAP_DEREF_NEVER && sr->derefAlias != LDAP_DEREF_SEARCHING && sr->derefAlias != LDAP_DEREF_FINDING && sr->derefAlias != LDAP_DEREF_ALWAYS) { pResult->errCode = retVal = LDAP_PROTOCOL_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Invalid dereference alias parameter"); } // Parse filter retVal = ParseFilter( pOperation, &sr->filter, pResult ); BAIL_ON_VMDIR_ERROR(retVal); // Log String filter, if desired. if (VmDirLogGetLevel() >= VMDIR_LOG_VERBOSE && VmDirLogGetMask() & LDAP_DEBUG_ARGS) { VDIR_BERVALUE strFilter = VDIR_BERVALUE_INIT; FilterToStrFilter( sr->filter, &strFilter ); VMDIR_LOG_VERBOSE( LDAP_DEBUG_ARGS, " Filter: %s", strFilter.lberbv.bv_val ); VmDirFreeBervalContent(&strFilter); } // Parse attributes. 'M' => attribute names point within (in-place) the ber. size = sizeof( BerValue ); // Size of the structure is passed-in, and number of attributes are returned back in // the same parameter. if ( ber_scanf( pOperation->ber, "{M}}", &pLberBerv, &size, 0 ) == LBER_ERROR ) { pResult->errCode = LDAP_PROTOCOL_ERROR; retVal = LDAP_NOTICE_OF_DISCONNECT; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Decoding error while parsing required attributes."); } // copy pLberBerv content into sr->attrs if (pLberBerv && size > 0) { int iCnt = 0; if (VmDirAllocateMemory(sizeof(VDIR_BERVALUE) * (size+1), (PVOID*)&sr->attrs) != 0) { pResult->errCode = retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "no memory"); } for (iCnt = 0; iCnt < size; iCnt++) { sr->attrs[iCnt].lberbv.bv_val = pLberBerv[iCnt].bv_val; sr->attrs[iCnt].lberbv.bv_len = pLberBerv[iCnt].bv_len; } } // Log list of the required attributes, if desired. if (( VmDirLogGetMask() & LDAP_DEBUG_ARGS) && size > 0) { if (VmDirLogSearchRequest(sr, size) != 0) { pResult->errCode = retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, (pszLocalErrorMsg), "Error while logging search request"); } } // Parse LDAP controls present (if any) in the request. retVal = ParseRequestControls(pOperation, pResult); // ldapResult.errCode set inside BAIL_ON_VMDIR_ERROR( retVal ); retVal = pResult->errCode = VmDirMLSearch( pOperation ); bResultAlreadySent = TRUE; BAIL_ON_VMDIR_ERROR(retVal); cleanup: VMDIR_SAFE_FREE_MEMORY(pLberBerv); VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg); return retVal; error: VMDIR_APPEND_ERROR_MSG(pResult->pszErrMsg, pszLocalErrorMsg); if (retVal != LDAP_NOTICE_OF_DISCONNECT && bResultAlreadySent == FALSE) { VmDirSendLdapResult( pOperation ); } goto cleanup; }