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; }
/* * 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; }
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; }
static int _VmDirInternalPagedSearch( VDIR_OPERATION * pOperation ) { int retVal = LDAP_SUCCESS; PSTR pszLocalErrMsg = NULL; // should never happen - there are asserts in calling function if (pOperation == NULL) { BAIL_WITH_VMDIR_ERROR(retVal, VMDIR_ERROR_INVALID_PARAMETER); } /* * New page search * TODO: Iterator logic and ranking algorithm will be added in next tasks */ if (pOperation->showPagedResultsCtrl != NULL && IsNullOrEmptyString(pOperation->showPagedResultsCtrl->value.pagedResultCtrlVal.cookie)) { retVal = BuildCandidateList(pOperation, pOperation->request.searchReq.filter, 0); 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 = VmDirProcessPagedSearch(pOperation); BAIL_ON_VMDIR_ERROR(retVal); cleanup: VMDIR_SAFE_FREE_MEMORY(pszLocalErrMsg); return retVal; error: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s failed, error(%d)", __FUNCTION__, retVal); 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; }
VOID VdcadminReplNow( VOID ) { DWORD dwError = 0; char pszServerName[SIZE_256]; PSTR pszLocalErrorMsg = NULL; VmDirReadString( " Enter hostname to start replication cycle: ", pszServerName, SIZE_256, FALSE); dwError = VmDirReplNow( pszServerName ); BAIL_ON_VMDIR_ERROR_WITH_MSG( dwError, (pszLocalErrorMsg), "VdcadminReplNow: VmDirReplNow() call failed with error: %d", dwError ); printf( "VmDirReplNow passed\n"); cleanup: VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg); return; error: printf( "%s\n", pszLocalErrorMsg ? pszLocalErrorMsg : "Hmmm ... no local error message." ); goto cleanup; }
int VmDirMLDelete( PVDIR_OPERATION pOperation ) { DWORD dwError = 0; PSTR pszLocalErrMsg = NULL; pOperation->pBECtx->pBE = VmDirBackendSelect(pOperation->reqDn.lberbv.bv_val); assert(pOperation->pBECtx->pBE); // AnonymousBind Or in case of a failed bind, do not grant delete access if (pOperation->conn->bIsAnonymousBind || VmDirIsFailedAccessInfo(&pOperation->conn->AccessInfo)) { dwError = LDAP_INSUFFICIENT_ACCESS; BAIL_ON_VMDIR_ERROR_WITH_MSG( dwError, pszLocalErrMsg, "Not bind/authenticate yet" ); } dwError = VmDirInternalDeleteEntry( pOperation ); BAIL_ON_VMDIR_ERROR( dwError ); cleanup: VmDirSendLdapResult( pOperation ); VMDIR_SAFE_FREE_MEMORY( pszLocalErrMsg ); return pOperation->ldapResult.errCode; error: VMDIR_SET_LDAP_RESULT_ERROR( &(pOperation->ldapResult), dwError, pszLocalErrMsg); goto cleanup; }
static DWORD _VmDirSchemaCheckNameform( PVDIR_SCHEMA_CTX pCtx, PVDIR_ENTRY pEntry, PVDIR_SCHEMA_OC_DESC pStructOCDesc ) { DWORD dwError = 0; PSTR pszLocalErrorMsg = NULL; if ( !pCtx || !pStructOCDesc || !pEntry || !pEntry->dn.bvnorm_val ) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } #if 0 // should NOT enable this until we have all namform and structure rule defined if ( pStructOCDesc->usNumMustRDNs > 0 ) { // not yet support multi RDNs case. only check the first MUST RDN for now. size_t iLen = VmDirStringLenA(pStructOCDesc->ppszMustRDNs[0]); if ( VmDirStringNCompareA( pEntry->dn.bvnorm_val, pStructOCDesc->ppszMustRDNs[0], iLen, FALSE ) != 0 || pEntry->dn.bvnorm_val[iLen] != '=' ) { dwError = ERROR_INVALID_ENTRY; BAIL_ON_VMDIR_ERROR_WITH_MSG( dwError, pszLocalErrorMsg, "_VmDirSchemaCheckNameform: rdn must be (%s). (%d)", VDIR_SAFE_STRING( pStructOCDesc->ppszMustRDNs[0] ), dwError ); } } #endif cleanup: VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg); return dwError; error: if ( !pCtx->pszErrorMsg ) { pCtx->pszErrorMsg = pszLocalErrorMsg; pszLocalErrorMsg = NULL; pCtx->dwErrorCode = dwError; } goto cleanup; }
static 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; }
int VmDirMLModify( PVDIR_OPERATION pOperation ) { DWORD dwError = 0; PSTR pszLocalErrMsg = NULL; pOperation->pBECtx->pBE = VmDirBackendSelect(pOperation->request.modifyReq.dn.lberbv.bv_val); assert(pOperation->pBECtx->pBE); // AnonymousBind Or in case of a failed bind, do not grant modify access if (pOperation->conn->bIsAnonymousBind || VmDirIsFailedAccessInfo(&pOperation->conn->AccessInfo)) { dwError = LDAP_INSUFFICIENT_ACCESS; BAIL_ON_VMDIR_ERROR_WITH_MSG( dwError, pszLocalErrMsg, "Not bind/authenticate yet"); } if (!VmDirValidTxnState(pOperation->pBECtx, pOperation->reqCode)) { dwError = LDAP_UNWILLING_TO_PERFORM; BAIL_ON_VMDIR_ERROR_WITH_MSG(dwError, pszLocalErrMsg, "%s: invaid request for transaction state", __func__); } // Mod request sanity check dwError = _VmDirExternalModsSanityCheck(pOperation, pOperation->request.modifyReq.mods); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirInternalModifyEntry(pOperation); BAIL_ON_VMDIR_ERROR(dwError); cleanup: VMDIR_SAFE_FREE_MEMORY(pszLocalErrMsg); return pOperation->ldapResult.errCode; error: VMDIR_SET_LDAP_RESULT_ERROR(&(pOperation->ldapResult), dwError, pszLocalErrMsg); goto cleanup; }
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; }
// 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; }
/* * 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 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; }
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; }
int VmDirMLDelete( PVDIR_OPERATION pOperation ) { DWORD dwError = 0; PSTR pszLocalErrMsg = NULL; pOperation->pBECtx->pBE = VmDirBackendSelect(pOperation->reqDn.lberbv.bv_val); assert(pOperation->pBECtx->pBE); // AnonymousBind Or in case of a failed bind, do not grant delete access if (pOperation->conn->bIsAnonymousBind || VmDirIsFailedAccessInfo(&pOperation->conn->AccessInfo)) { dwError = LDAP_INSUFFICIENT_ACCESS; BAIL_ON_VMDIR_ERROR_WITH_MSG( dwError, pszLocalErrMsg, "Not bind/authenticate yet" ); } if (VmDirRaftDisallowUpdates("Delete")) { dwError = VMDIR_ERROR_UNWILLING_TO_PERFORM; BAIL_ON_VMDIR_ERROR( dwError ); } dwError = VmDirInternalDeleteEntry( pOperation ); BAIL_ON_VMDIR_ERROR( dwError ); if (pOperation->opType == VDIR_OPERATION_TYPE_EXTERNAL) { pOperation->pBEIF->pfnBESetMaxOriginatingUSN(pOperation->pBECtx, pOperation->pBECtx->wTxnUSN); } cleanup: VMDIR_SAFE_FREE_MEMORY( pszLocalErrMsg ); return pOperation->ldapResult.errCode; error: VMDIR_SET_LDAP_RESULT_ERROR( &(pOperation->ldapResult), dwError, pszLocalErrMsg); goto cleanup; }
int VmDirMLSearch( PVDIR_OPERATION pOperation ) { int retVal = 0; PSTR pszLocalErrMsg = NULL; pOperation->pBEIF = VmDirBackendSelect(pOperation->reqDn.lberbv.bv_val); assert(pOperation->pBEIF); if (pOperation->conn->bIsAnonymousBind && !VmDirIsSearchForDseRootEntry( pOperation )) { retVal = LDAP_INSUFFICIENT_ACCESS; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "Not bind/authenticate yet" ); } // AnonymousBind is handled when retrieving search candidate result // DSE_ROOT_DN and PERSISTED_DSE_ROOT_DN, SCHEMA_NAMING_CONTEXT_DN // SUB_SCHEMA_SUB_ENTRY_DN should allow anonymous bind READ retVal = VmDirInternalSearch( pOperation); BAIL_ON_VMDIR_ERROR(retVal); cleanup: VmDirSendLdapResult( pOperation ); VMDIR_SAFE_FREE_MEMORY(pszLocalErrMsg); return pOperation->ldapResult.errCode; error: VMDIR_SET_LDAP_RESULT_ERROR( &(pOperation->ldapResult), retVal, pszLocalErrMsg); goto cleanup; }
/* * Before modify schema cache, make sure new schema is valid. * 1. schema of pEntry must be live one * 2. create new schema instance via pEntry * 3. check active and new schema compatibility * NOT compatible - reject this operation * Compatible but NO semantic chnage - update schema entry * Compatible and has semantic chnage - update schema entry and cache * 4. make new instance pending in gVdirSchemaGlobals */ DWORD VmDirSchemaCacheModifyPrepare( PVDIR_OPERATION pOperation, VDIR_MODIFICATION* pMods, PVDIR_ENTRY pSchemaEntry ) { DWORD dwError = 0; BOOLEAN bInLock = FALSE; PSTR pszLocalErrMsg = NULL; BOOLEAN bOwnNewInstance = FALSE; BOOLEAN bCompatible = FALSE; // schema compatible BOOLEAN bNeedCachePatch = FALSE; // schema semantic/cache change PVDIR_SCHEMA_INSTANCE pNewInstance = NULL; // DO NOT free, pEntry should take over it. PVDIR_SCHEMA_INSTANCE pEntryOrgSchemaInstance = NULL; if ( !pMods || !pSchemaEntry || !pOperation ) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } { PVDIR_MODIFICATION pLocalMods = NULL; PCSTR immutableList[] = VDIR_IMMUTABLE_SCHEMA_ELEMENT_INITIALIZER; int iImmutableSize = sizeof(immutableList)/sizeof(immutableList[0]); for (pLocalMods = pMods; pLocalMods; pLocalMods = pLocalMods->next) { BOOLEAN bImmutableElement = _VmDirIsNameInCaseIgnoreList( pLocalMods->attr.pATDesc->pszName, immutableList, iImmutableSize); if ( bImmutableElement ) { dwError = ERROR_OPERATION_NOT_PERMITTED; BAIL_ON_VMDIR_ERROR_WITH_MSG(dwError, pszLocalErrMsg, "modify (%s) not allowed", pLocalMods->attr.pATDesc->pszName); } } } // make sure pEntry uses live schema if (! vdirIsLiveSchema(pSchemaEntry->pSchemaCtx->pSchema)) { dwError = LDAP_UNWILLING_TO_PERFORM; BAIL_ON_VMDIR_ERROR_WITH_MSG(dwError, pszLocalErrMsg, "Out dated schema"); } pEntryOrgSchemaInstance = pSchemaEntry->pSchemaCtx->pSchema; // instantiate a schema cache - pNewInstance // If this call succeed, do NOT free pNewInstance. pEntry->pSchemaCtx takes it over. dwError = VdirSchemaInstanceInitViaEntry( pSchemaEntry, &pNewInstance); if ( dwError != 0 && pSchemaEntry->pSchemaCtx->pSchema != pNewInstance ) { // we still own pNewInstance and need to free it. bOwnNewInstance = TRUE; } BAIL_ON_VMDIR_ERROR_WITH_MSG(dwError, pszLocalErrMsg, "Entry to schema instance failed (%d)", dwError); // check if two instances are compatible and if schema patching is needed dwError = VmDirSchemaInstancePatchCheck( pEntryOrgSchemaInstance, pNewInstance, &bCompatible, &bNeedCachePatch); BAIL_ON_VMDIR_ERROR_WITH_MSG(dwError, pszLocalErrMsg, "VmDirSchemaInstancePatch (%d)", dwError); if ( !bCompatible ) { dwError = LDAP_UNWILLING_TO_PERFORM; BAIL_ON_VMDIR_ERROR_WITH_MSG(dwError, pszLocalErrMsg, "Schema NOT compatible (%d)", dwError); } if ( !bNeedCachePatch ) { // no semantic change, just update schema entry VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "Prepare schema entry update"); } else { // need schema entry and cache update VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "Prepare schema entry and instance update (%p)", pNewInstance); } VMDIR_LOCK_MUTEX(bInLock, gVdirSchemaGlobals.mutex); if ( bNeedCachePatch ) { gVdirSchemaGlobals.bHasPendingChange = TRUE; } VMDIR_UNLOCK_MUTEX(bInLock, gVdirSchemaGlobals.mutex); cleanup: VMDIR_UNLOCK_MUTEX(bInLock, gVdirSchemaGlobals.mutex); VMDIR_SAFE_FREE_MEMORY(pszLocalErrMsg); return dwError; error: if ( bOwnNewInstance ) { VdirSchemaInstanceFree( pNewInstance ); } VMDIR_SET_LDAP_RESULT_ERROR( &pOperation->ldapResult, dwError, pszLocalErrMsg ); goto cleanup; }
static int NewConnection( ber_socket_t sfd, VDIR_CONNECTION **ppConnection, Sockbuf_IO *pSockbuf_IO ) { int retVal = LDAP_SUCCESS; ber_len_t max = SOCK_BUF_MAX_INCOMING; PVDIR_CONNECTION pConn; PSTR pszLocalErrMsg = NULL; if (VmDirAllocateMemory(sizeof(VDIR_CONNECTION), (PVOID *)&pConn) != 0) { retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, pszLocalErrMsg, "NewConnection: VmDirAllocateMemory call failed"); } pConn->bIsAnonymousBind = TRUE; // default to anonymous bind pConn->sd = sfd; retVal = VmDirGetNetworkInfoFromSocket(pConn->sd, pConn->szClientIP, sizeof(pConn->szClientIP), &pConn->dwClientPort, true); BAIL_ON_VMDIR_ERROR(retVal); retVal = VmDirGetNetworkInfoFromSocket(pConn->sd, pConn->szServerIP, sizeof(pConn->szServerIP), &pConn->dwServerPort, false); BAIL_ON_VMDIR_ERROR(retVal); VMDIR_LOG_DEBUG(VMDIR_LOG_MASK_ALL, "New connection (%s)", pConn->szClientIP); if ((pConn->sb = ber_sockbuf_alloc()) == NULL) { retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, pszLocalErrMsg, "New Connection (%s): ber_sockbuf_alloc() call failed with errno: %d", pConn->szClientIP, errno); } if (ber_sockbuf_ctrl(pConn->sb, LBER_SB_OPT_SET_MAX_INCOMING, &max) < 0) { retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, pszLocalErrMsg, "NewConnection (%s): ber_sockbuf_ctrl() failed while setting MAX_INCOMING", pConn->szClientIP); } if (ber_sockbuf_add_io(pConn->sb, pSockbuf_IO, LBER_SBIOD_LEVEL_PROVIDER, (void *)&sfd) != 0) { retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, pszLocalErrMsg, "NewConnection (%s): ber_sockbuf_addd_io() failed while setting LEVEL_PROVIDER", pConn->szClientIP); } //This is to disable NONBLOCK mode (when NULL passed in) if (ber_sockbuf_ctrl(pConn->sb, LBER_SB_OPT_SET_NONBLOCK, NULL) < 0) { retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, pszLocalErrMsg, "NewConnection (%s): ber_sockbuf_ctrl failed while setting NONBLOCK", pConn->szClientIP); } *ppConnection = pConn; cleanup: VMDIR_SAFE_FREE_MEMORY(pszLocalErrMsg); return retVal; error: VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "NewConnection failing with error %d", retVal); goto cleanup; }
/* InternalSearch: Interface that can be used "internally" by the server code. One of the main differences between * this function and MLSearch is that this function does not send back an LDAP result to the client. * * Return: VmDir level error code. Also, pOperation->ldapResult content is set. */ int VmDirInternalSearch( PVDIR_OPERATION pOperation ) { int retVal = LDAP_SUCCESS; DWORD dwEntryCount = 0; BOOLEAN bHasTxn = FALSE; PSTR pszLocalErrMsg = NULL; ENTRYID eId = 0; ENTRYID* pValidatedEntries = NULL; PVDIR_LDAP_RESULT pResult = &(pOperation->ldapResult); PVDIR_OPERATION_ML_METRIC pMLMetrics = NULL; assert(pOperation && pOperation->pBEIF); pMLMetrics = &pOperation->MLMetrics; VMDIR_COLLECT_TIME(pMLMetrics->iMLStartTime); // compute required access for this search ComputeRequiredAccess(&pOperation->request.searchReq); // Normalize (base) DN retVal = VmDirNormalizeDN( &(pOperation->reqDn), pOperation->pSchemaCtx ); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "DN normalization failed - (%u)(%s)", retVal, VDIR_SAFE_STRING(VmDirSchemaCtxGetErrorMsg(pOperation->pSchemaCtx)) ); if (VmDirHandleSpecialSearch( pOperation, pResult )) // TODO, add &pszLocalErrMsg { retVal = pResult->errCode ? pResult->errCode : pResult->vmdirErrCode; BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, pszLocalErrMsg, "Special search failed - (%u)", retVal); goto cleanup; // done special search } if (pOperation->dbCopyCtrl) { retVal = VmDirExecDbCopyCtrl(pOperation); BAIL_ON_VMDIR_ERROR(retVal); } if (pOperation->syncReqCtrl != NULL) // Replication { pOperation->opType = VDIR_OPERATION_TYPE_REPL; } if (pOperation->pReplAgrDisableCtrl) { retVal = VmDirExecReplAgrEnableDisableCtrl(BERVAL_NORM_VAL(pOperation->reqDn), FALSE); BAIL_ON_VMDIR_ERROR(retVal); } else if (pOperation->pReplAgrEnableCtrl) { retVal = VmDirExecReplAgrEnableDisableCtrl(BERVAL_NORM_VAL(pOperation->reqDn), TRUE); BAIL_ON_VMDIR_ERROR(retVal); } // If base is not ROOT, read lock the base object (DnToEntryId index entry) to make sure it exists, and it does // not get deleted during this search processing. if (pOperation->reqDn.lberbv.bv_len != 0) { VMDIR_COLLECT_TIME(pMLMetrics->iBETxnBeginStartTime); retVal = pOperation->pBEIF->pfnBETxnBegin( pOperation->pBECtx, VDIR_BACKEND_TXN_READ ); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "txn begin (%u)(%s)", retVal, VDIR_SAFE_STRING(pOperation->pBEErrorMsg)); bHasTxn = TRUE; VMDIR_COLLECT_TIME(pMLMetrics->iBETxnBeginEndTime); // Lookup in the DN index. retVal = pOperation->pBEIF->pfnBEDNToEntryId( pOperation->pBECtx, &(pOperation->reqDn), &eId ); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "DNToEID (%u)(%s)", retVal, VDIR_SAFE_STRING(pOperation->pBEErrorMsg)); } // start txn if not has one already. if (! pOperation->pBECtx->pBEPrivate) { retVal = pOperation->pBEIF->pfnBETxnBegin( pOperation->pBECtx, VDIR_BACKEND_TXN_READ ); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "txn begin (%u)(%s)", retVal, VDIR_SAFE_STRING(pOperation->pBEErrorMsg)); bHasTxn = TRUE; } retVal = AppendDNFilter( pOperation ); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "Appending DN filter failed."); /* * TODO cleanup During background thread implementation of page search */ if (gVmdirGlobals.bPagedSearchReadAhead) { if (pOperation->showPagedResultsCtrl != NULL && !IsNullOrEmptyString(pOperation->showPagedResultsCtrl->value.pagedResultCtrlVal.cookie)) { retVal = VmDirPagedSearchCacheRead( pOperation->showPagedResultsCtrl->value.pagedResultCtrlVal.cookie, &pValidatedEntries, &dwEntryCount); BAIL_ON_VMDIR_ERROR(retVal); } } if (pOperation->showPagedResultsCtrl == NULL) { retVal = _VmDirInternalNormalSearch(pOperation); BAIL_ON_VMDIR_ERROR(retVal); } else { retVal = _VmDirInternalPagedSearch(pOperation); BAIL_ON_VMDIR_ERROR(retVal); } /* * TODO cleanup During background thread implementation of page search */ if (pValidatedEntries != NULL) { retVal = ProcessPreValidatedEntries( pOperation, dwEntryCount, pValidatedEntries); BAIL_ON_VMDIR_ERROR(retVal); } VMDIR_COLLECT_TIME(pMLMetrics->iBETxnCommitStartTime); retVal = pOperation->pBEIF->pfnBETxnCommit( pOperation->pBECtx); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "txn commit (%u)(%s)", retVal, VDIR_SAFE_STRING(pOperation->pBEErrorMsg)); bHasTxn = FALSE; VMDIR_COLLECT_TIME(pMLMetrics->iBETxnCommitEndTime); cleanup: // collect metrics VMDIR_COLLECT_TIME(pMLMetrics->iMLEndTime); VmDirInternalMetricsUpdate(pOperation); VmDirInternalMetricsLogInefficientOp(pOperation); VMDIR_SAFE_FREE_MEMORY(pValidatedEntries); VMDIR_SAFE_FREE_MEMORY(pszLocalErrMsg); return retVal; error: if (bHasTxn) { pOperation->pBEIF->pfnBETxnAbort(pOperation->pBECtx); } VMDIR_SET_LDAP_RESULT_ERROR(&pOperation->ldapResult, retVal, pszLocalErrMsg); goto cleanup; }
/* * Test whether the origUsn is in scope so that attribute, attr-meta-data or * attr-value-meta-data be sent back to the replicaiton consumer based on whether * the origUsn for that invocationId has been processed already by the consumer * TODO: Needed Refractoring */ DWORD VmDirIsUsnInScope( PVDIR_OPERATION pOperation, PCSTR pAttrName, PCSTR pszOrigInvocationId, USN origUsn, USN localUSN, USN priorSentUSNCreated, PBOOLEAN pbIsUsnInScope ) { DWORD dwError = 0; PLW_HASHTABLE_NODE pNode = NULL; PSTR pszLocalErrorMsg = NULL; UptoDateVectorEntry *pUtdVectorEntry = NULL; UptoDateVectorEntry *pNewUtdVectorEntry = NULL; int retVal = 0; if (!pOperation || !pszOrigInvocationId || !pbIsUsnInScope || !pOperation->syncReqCtrl || !pOperation->syncDoneCtrl) { BAIL_WITH_VMDIR_ERROR(dwError, VMDIR_ERROR_INVALID_PARAMETER); } *pbIsUsnInScope = FALSE; //Originating server for the current state is same as the requesting server if (VmDirStringCompareA( pszOrigInvocationId, pOperation->syncReqCtrl->value.syncReqCtrlVal.reqInvocationId.lberbv.bv_val, TRUE) == 0) { *pbIsUsnInScope = FALSE; goto cleanup; } retVal = LwRtlHashTableFindKey( pOperation->syncDoneCtrl->value.syncDoneCtrlVal.htUtdVector, &pNode, pszOrigInvocationId); retVal = LwNtStatusToWin32Error(retVal); if (retVal != 0 && retVal != ERROR_NOT_FOUND) { VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL, "%s: LwRtlHashTableFindKey failed for origInvocationId: %s", __FUNCTION__, pszOrigInvocationId); dwError = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG(dwError, (pszLocalErrorMsg), "LwRtlHashTableFindKey failed."); } if (pNode == NULL) { VDIR_BERVALUE bvServerId = VDIR_BERVALUE_INIT; dwError = VmDirAllocateMemory(sizeof(UptoDateVectorEntry), (PVOID *)&pNewUtdVectorEntry); BAIL_ON_VMDIR_ERROR(dwError); bvServerId.lberbv.bv_val = (PSTR)pszOrigInvocationId; bvServerId.lberbv.bv_len = VmDirStringLenA(pszOrigInvocationId); dwError = VmDirBervalContentDup(&bvServerId, &pNewUtdVectorEntry->invocationId); BAIL_ON_VMDIR_ERROR(dwError); pNewUtdVectorEntry->currMaxOrigUsnProcessed = origUsn; LwRtlHashTableResizeAndInsert( pOperation->syncDoneCtrl->value.syncDoneCtrlVal.htUtdVector, &pNewUtdVectorEntry->Node, &pNode); // assert the key of added node is unique assert(pNode == NULL); pNewUtdVectorEntry = NULL; *pbIsUsnInScope = TRUE; goto cleanup; } pUtdVectorEntry = (UptoDateVectorEntry *)LW_STRUCT_FROM_FIELD(pNode, UptoDateVectorEntry, Node); if (origUsn > pUtdVectorEntry->reqLastOrigUsnProcessed ) { // attribute or the valueMetaData item in scope if origUsn valueMetaData is > the current highest if (origUsn > pUtdVectorEntry->currMaxOrigUsnProcessed ) { pUtdVectorEntry->currMaxOrigUsnProcessed = origUsn; } // Note, this handles ADD->MODIFY case but not multiple MODIFYs scenario. // However, it is fine as consumer should be able to handle redundant feed from supplier. // The key point here is to NOT send ATTR_USN_CREATED, so we can derive correct sync_state in WriteSyncStateControl. if (localUSN > priorSentUSNCreated) { *pbIsUsnInScope = TRUE; if (priorSentUSNCreated > 0) { VMDIR_LOG_INFO( LDAP_DEBUG_REPL, "%s new usn %llu after prior usncreated %llu attr %s", __FUNCTION__, origUsn, priorSentUSNCreated, VDIR_SAFE_STRING(pAttrName)); } } else { VMDIR_LOG_INFO( LDAP_DEBUG_REPL, "%s (add->modify) race condition avoided. skip prior usncreated %llu attr %s", __FUNCTION__, priorSentUSNCreated, VDIR_SAFE_STRING(pAttrName)); } goto cleanup; } VMDIR_LOG_INFO( LDAP_DEBUG_REPL, "%s: (not in scope) attr name: %s orig invo: %s utdUsn: %"PRId64" usn: %"PRId64, __FUNCTION__, VDIR_SAFE_STRING(pAttrName), VDIR_SAFE_STRING(pszOrigInvocationId), pUtdVectorEntry->reqLastOrigUsnProcessed, origUsn); cleanup: VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg); return dwError; error: VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "failed, error (%d)", dwError); if (pNewUtdVectorEntry) { VmDirFreeBervalContent(&pNewUtdVectorEntry->invocationId); } VMDIR_SAFE_FREE_MEMORY(pNewUtdVectorEntry); goto cleanup; }
static int BindListenOnPort( #ifndef _WIN32 sa_family_t addr_type, size_t addr_size, #else short addr_type, int addr_size, #endif void *pServ_addr, ber_socket_t *pSockfd ) { #define LDAP_PORT_LISTEN_BACKLOG 128 int optname = 0; int retVal = LDAP_SUCCESS; int retValBind = 0; PSTR pszLocalErrMsg = NULL; int on = 1; #ifdef _WIN32 DWORD sTimeout = 0; int reTries = 0; #else struct timeval sTimeout = {0}; #endif *pSockfd = -1; *pSockfd = socket(addr_type, SOCK_STREAM, 0); if (*pSockfd < 0) { #ifdef _WIN32 errno = WSAGetLastError(); #endif retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "%s: socket() call failed with errno: %d", __func__, errno ); } #ifdef _WIN32 optname = SO_EXCLUSIVEADDRUSE; #else optname = SO_REUSEADDR; #endif if (setsockopt(*pSockfd, SOL_SOCKET, optname, (const char *)(&on), sizeof(on)) < 0) { #ifdef _WIN32 errno = WSAGetLastError(); #endif retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "%s: setsockopt() call failed with errno: %d", __func__, errno ); } on = 1; // turn on TCP_NODELAY below if (setsockopt(*pSockfd, IPPROTO_TCP, TCP_NODELAY, (const char *)(&on), sizeof(on) ) < 0) { #ifdef _WIN32 errno = WSAGetLastError(); #endif retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "%s: setsockopt() TCP_NODELAY call failed with errno: %d", __func__, errno ); } if (addr_type == AF_INET6) { #ifdef _WIN32 if (setsockopt(*pSockfd, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)(&on), sizeof(on) ) < 0) { errno = WSAGetLastError(); #else if (setsockopt(*pSockfd, SOL_IPV6, IPV6_V6ONLY, (const char *)(&on), sizeof(on) ) < 0) { #endif retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "%s: setsockopt() IPV6_V6ONLY call failed with errno: %d", __func__, errno ); } } if (gVmdirGlobals.dwLdapRecvTimeoutSec > 0) { #ifdef _WIN32 sTimeout = gVmdirGlobals.dwLdapRecvTimeoutSec*1000; #else sTimeout.tv_sec = gVmdirGlobals.dwLdapRecvTimeoutSec; sTimeout.tv_usec = 0; #endif if (setsockopt(*pSockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*) &sTimeout, sizeof(sTimeout)) < 0) { #ifdef _WIN32 errno = WSAGetLastError(); #endif retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "%s: setsockopt() SO_RCVTIMEO failed, errno: %d", __func__, errno ); } } retValBind = bind(*pSockfd, (struct sockaddr *) pServ_addr, addr_size); #ifdef _WIN32 // Add retry logic per PR 1347783 reTries = 0; while (retValBind != 0 && reTries < MAX_NUM_OF_BIND_PORT_RETRIES) { errno = WSAGetLastError(); if (errno != WSAEADDRINUSE) { break; } reTries++; VMDIR_LOG_WARNING( VMDIR_LOG_MASK_ALL, "%s: bind() call failed with errno: %d, re-trying (%d)", __func__, errno, reTries); VmDirSleep(1000); retValBind = bind(*pSockfd, (struct sockaddr *) pServ_addr, addr_size); } #endif if (retValBind != 0) { retVal = LDAP_OPERATIONS_ERROR; //need to free socket ... BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "%s: bind() call failed with errno: %d", __func__, errno ); } if (listen(*pSockfd, LDAP_PORT_LISTEN_BACKLOG) != 0) { #ifdef _WIN32 errno = WSAGetLastError(); #endif retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "%s: listen() call failed with errno: %d", __func__, errno ); } cleanup: VMDIR_SAFE_FREE_MEMORY(pszLocalErrMsg); return retVal; error: if (*pSockfd >= 0) { tcp_close(*pSockfd); *pSockfd = -1; } VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, VDIR_SAFE_STRING(pszLocalErrMsg)); goto cleanup; } /* * We own pConnection and delete it when done. */ static DWORD ProcessAConnection( PVOID pArg ) { VDIR_CONNECTION *pConn = NULL; int retVal = LDAP_SUCCESS; ber_tag_t tag = LBER_ERROR; ber_len_t len = 0; BerElement * ber = NULL; ber_int_t msgid = -1; PVDIR_OPERATION pOperation = NULL; int reTries = 0; BOOLEAN bDownOpThrCount = FALSE; PVDIR_CONNECTION_CTX pConnCtx = NULL; // increment operation thread counter retVal = VmDirSyncCounterIncrement(gVmdirGlobals.pOperationThrSyncCounter); BAIL_ON_VMDIR_ERROR(retVal); bDownOpThrCount = TRUE; pConnCtx = (PVDIR_CONNECTION_CTX)pArg; assert(pConnCtx); retVal = NewConnection(pConnCtx->sockFd, &pConn, pConnCtx->pSockbuf_IO); if (retVal != LDAP_SUCCESS) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s: NewConnection [%d] failed with error: %d", __func__, pConnCtx->sockFd, retVal); goto error; } while (TRUE) { if (VmDirdState() == VMDIRD_STATE_SHUTDOWN) { goto cleanup; } ber = ber_alloc(); assert( ber != NULL); /* An LDAP request message looks like: * LDAPMessage ::= SEQUENCE { * messageID MessageID, * protocolOp CHOICE { * bindRequest BindRequest, * unbindRequest UnbindRequest, * searchRequest SearchRequest, * ... }, * controls [0] Controls OPTIONAL } */ // reset retry count reTries = 0; // Read complete LDAP request message (tag, length, and real message). while( reTries < MAX_NUM_OF_SOCK_READ_RETRIES ) { if ((tag = ber_get_next( pConn->sb, &len, ber )) == LDAP_TAG_MESSAGE ) { break; } #ifdef _WIN32 // in ber_get_next (liblber) call, sock_errset() call WSASetLastError() errno = WSAGetLastError(); if ( errno == EWOULDBLOCK || errno == EAGAIN || errno == WSAETIMEDOUT) #else if ( errno == EWOULDBLOCK || errno == EAGAIN) #endif { if (gVmdirGlobals.dwLdapRecvTimeoutSec > 0 && ber->ber_len == 0) { VMDIR_LOG_INFO( LDAP_DEBUG_CONNS, "%s: disconnecting peer (%s), idle > %d seconds", __func__, pConn->szClientIP, gVmdirGlobals.dwLdapRecvTimeoutSec); retVal = LDAP_NOTICE_OF_DISCONNECT; BAIL_ON_VMDIR_ERROR( retVal ); } //This may occur when not all data have recieved - set to EAGAIN/EWOULDBLOCK by ber_get_next, // and in such case ber->ber_len > 0; if (reTries > 0 && reTries % 5 == 0) { VMDIR_LOG_WARNING( VMDIR_LOG_MASK_ALL, "%s: ber_get_next() failed with errno = %d, peer (%s), re-trying (%d)", __func__, errno , pConn->szClientIP, reTries); } VmDirSleep(200); reTries++; continue; } // Unexpected error case. if (errno == 0) { VMDIR_LOG_INFO( LDAP_DEBUG_CONNS, "%s: ber_get_next() peer (%s) disconnected", __func__, pConn->szClientIP); } else { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s: ber_get_next() call failed with errno = %d peer (%s)", __func__, errno, pConn->szClientIP); } retVal = LDAP_NOTICE_OF_DISCONNECT; BAIL_ON_VMDIR_ERROR( retVal ); } // Read LDAP request messageID (tag, length (not returned since it is implicit/integer), and messageID value) if ( (tag = ber_get_int( ber, &msgid )) != LDAP_TAG_MSGID ) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "ProcessAConnection: ber_get_int() call failed." ); retVal = LDAP_NOTICE_OF_DISCONNECT; BAIL_ON_VMDIR_ERROR( retVal ); } // Read protocolOp (tag) and length of the LDAP operation message, and leave the pointer at the beginning // of the LDAP operation message (to be parsed by PerformXYZ methods). if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "ProcessAConnection: ber_peek_tag() call failed." ); retVal = LDAP_NOTICE_OF_DISCONNECT; BAIL_ON_VMDIR_ERROR( retVal ); } retVal = VmDirNewOperation(ber, msgid, tag, pConn, &pOperation); if (retVal) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "ProcessAConnection: NewOperation() call failed." ); retVal = LDAP_OPERATIONS_ERROR; } BAIL_ON_VMDIR_ERROR( retVal ); // // If this is a multi-stage operation don't overwrite the start time if it's already set. // pConn->SuperLogRec.iStartTime = pConn->SuperLogRec.iStartTime ? pConn->SuperLogRec.iStartTime : VmDirGetTimeInMilliSec(); switch (tag) { case LDAP_REQ_BIND: retVal = VmDirPerformBind(pOperation); if (retVal != LDAP_SASL_BIND_IN_PROGRESS) { _VmDirCollectBindSuperLog(pConn, pOperation); // ignore error } break; case LDAP_REQ_ADD: retVal = VmDirPerformAdd(pOperation); break; case LDAP_REQ_SEARCH: retVal = VmDirPerformSearch(pOperation); break; case LDAP_REQ_UNBIND: retVal = VmDirPerformUnbind(pOperation); break; case LDAP_REQ_MODIFY: retVal = VmDirPerformModify(pOperation); break; case LDAP_REQ_DELETE: retVal = VmDirPerformDelete(pOperation); break; case LDAP_REQ_MODDN: case LDAP_REQ_COMPARE: case LDAP_REQ_ABANDON: case LDAP_REQ_EXTENDED: VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "ProcessAConnection: Operation is not yet implemented.." ); pOperation->ldapResult.errCode = retVal = LDAP_UNWILLING_TO_PERFORM; // ignore following VmDirAllocateStringA error. VmDirAllocateStringA( "Operation is not yet implemented.", &pOperation->ldapResult.pszErrMsg); VmDirSendLdapResult( pOperation ); break; default: pOperation->ldapResult.errCode = LDAP_PROTOCOL_ERROR; retVal = LDAP_NOTICE_OF_DISCONNECT; break; } pConn->SuperLogRec.iEndTime = VmDirGetTimeInMilliSec(); VmDirOPStatisticUpdate(tag, pConn->SuperLogRec.iEndTime - pConn->SuperLogRec.iStartTime); if (tag != LDAP_REQ_BIND) { VmDirLogOperation(gVmdirGlobals.pLogger, tag, pConn, pOperation->ldapResult.errCode); _VmDirScrubSuperLogContent(tag, &pConn->SuperLogRec); } VmDirFreeOperation(pOperation); pOperation = NULL; ber_free( ber, 1); ber = NULL; if (retVal == LDAP_NOTICE_OF_DISCONNECT) // returned as a result of protocol parsing error. { // RFC 4511, section 4.1.1: If the server receives an LDAPMessage from the client in which the LDAPMessage // SEQUENCE tag cannot be recognized, the messageID cannot be parsed, the tag of the protocolOp is not // recognized as a request, or the encoding structures or lengths of data fields are found to be incorrect, // then the server **SHOULD** return the Notice of Disconnection, with the resultCode // set to protocolError, and **MUST** immediately terminate the LDAP session as described in Section 5.3. goto cleanup; } } cleanup: if (retVal == LDAP_NOTICE_OF_DISCONNECT) { // Optionally send Notice of Disconnection with rs->err. } if (ber != NULL) { ber_free( ber, 1 ); } VmDirDeleteConnection(&pConn); VMDIR_SAFE_FREE_MEMORY(pConnCtx); VmDirFreeOperation(pOperation); if (bDownOpThrCount) { VmDirSyncCounterDecrement(gVmdirGlobals.pOperationThrSyncCounter); } _VmDirFlowCtrlThrExit(); // TODO: should we return dwError ? return 0; error: goto cleanup; }
static DWORD VmDirSrvModifyPersistedDSERoot( PVDIR_SCHEMA_CTX pSchemaCtx, PSTR pszRootNamingContextDN, PSTR pszConfigNamingContextDN, PSTR pszSchemaNamingContextDN, PSTR pszSubSchemaSubEntryDN, PSTR pszServerDN, PSTR pszDefaultAdminDN, PSTR pszDCAccountDN, PSTR pszDCAccountUPN, PSTR pszDelObjsContainerDN, PSTR pszSiteName ) { DWORD dwError = 0; PSTR ppszPersistedDSERootAttrs[] = { ATTR_ROOT_DOMAIN_NAMING_CONTEXT, pszRootNamingContextDN, ATTR_DEFAULT_NAMING_CONTEXT, pszRootNamingContextDN, ATTR_CONFIG_NAMING_CONTEXT, pszConfigNamingContextDN, ATTR_SCHEMA_NAMING_CONTEXT, pszSchemaNamingContextDN, ATTR_SUB_SCHEMA_SUB_ENTRY, pszSubSchemaSubEntryDN, ATTR_NAMING_CONTEXTS, pszRootNamingContextDN, ATTR_NAMING_CONTEXTS, pszConfigNamingContextDN, ATTR_NAMING_CONTEXTS, pszSchemaNamingContextDN, ATTR_SERVER_NAME, pszServerDN, ATTR_DEFAULT_ADMIN_DN, pszDefaultAdminDN, ATTR_DC_ACCOUNT_DN, pszDCAccountDN, ATTR_DC_ACCOUNT_UPN, pszDCAccountUPN, ATTR_DEL_OBJS_CONTAINER, pszDelObjsContainerDN, ATTR_SITE_NAME, pszSiteName, NULL }; VDIR_OPERATION op = {0}; PSTR pszLocalErrMsg = NULL; VDIR_BERVALUE bvDSERootDN = VDIR_BERVALUE_INIT; int i = 0; dwError = VmDirInitStackOperation( &op, VDIR_OPERATION_TYPE_INTERNAL, LDAP_REQ_MODIFY, NULL ); BAIL_ON_VMDIR_ERROR_WITH_MSG( dwError, pszLocalErrMsg, "VmDirSrvModifyPersistedDSERoot: VmDirInitStackOperation failed with error code: %d.", dwError ); // Setup target DN bvDSERootDN.lberbv.bv_val = PERSISTED_DSE_ROOT_DN; bvDSERootDN.lberbv.bv_len = VmDirStringLenA( bvDSERootDN.lberbv.bv_val ); dwError = VmDirNormalizeDN( &bvDSERootDN, op.pSchemaCtx); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirBervalContentDup( &bvDSERootDN, &op.reqDn ); BAIL_ON_VMDIR_ERROR_WITH_MSG( dwError, pszLocalErrMsg, "VmDirSrvModifyPersistedDSERoot: BervalContentDup failed with error code: %d.", dwError ); op.pBEIF = VmDirBackendSelect(op.reqDn.lberbv.bv_val); assert(op.pBEIF); dwError = VmDirBervalContentDup( &op.reqDn, &op.request.modifyReq.dn ); BAIL_ON_VMDIR_ERROR_WITH_MSG( dwError, pszLocalErrMsg, "VmDirSrvModifyPersistedDSERoot: BervalContentDup failed with error code: %d.", dwError ); // Setup mods for (i = 0; ppszPersistedDSERootAttrs[i] != NULL; i += 2 ) { dwError = VmDirAppendAMod( &op, MOD_OP_REPLACE, ppszPersistedDSERootAttrs[i], (int) VmDirStringLenA(ppszPersistedDSERootAttrs[i]), ppszPersistedDSERootAttrs[i + 1], VmDirStringLenA(ppszPersistedDSERootAttrs[i + 1]) ); BAIL_ON_VMDIR_ERROR_WITH_MSG( dwError, pszLocalErrMsg, "VmDirSrvModifyPersistedDSERoot: VmDirAppendAMod failed with error code: %d.", dwError ); } dwError = VmDirAppendAMod( &op, MOD_OP_DELETE, ATTR_INVOCATION_ID, ATTR_INVOCATION_ID_LEN, gVmdirServerGlobals.invocationId.lberbv.bv_val, gVmdirServerGlobals.invocationId.lberbv.bv_len ); BAIL_ON_VMDIR_ERROR_WITH_MSG( dwError, pszLocalErrMsg, "VmDirSrvModifyPersistedDSERoot: VmDirAppendAMod failed with error code: %d.", dwError ); // Modify dwError = VmDirInternalModifyEntry( &op ); BAIL_ON_VMDIR_ERROR_WITH_MSG( dwError, pszLocalErrMsg, "VmDirSrvModifyPersistedDSERoot: InternalModifyEntry failed. DN: %s, Error code: %d, Error string: %s", op.reqDn.lberbv.bv_val, dwError, VDIR_SAFE_STRING( op.ldapResult.pszErrMsg ) ); cleanup: VmDirFreeBervalContent(&bvDSERootDN); VmDirFreeOperationContent(&op); VMDIR_SAFE_FREE_MEMORY(pszLocalErrMsg); return dwError; error: VmDirLog(LDAP_DEBUG_ANY, VDIR_SAFE_STRING(pszLocalErrMsg) ); goto cleanup; }
static int WriteAttributes( VDIR_OPERATION * op, PVDIR_ENTRY pEntry, uint32_t iSearchReqSpecialChars, BerElement * ber, PSTR* ppszErrorMsg ) { int retVal = LDAP_SUCCESS; unsigned int i = 0; SearchReq * sr = &(op->request.searchReq); BOOLEAN mapFSPDN = FALSE; PVDIR_ATTRIBUTE pAttr = NULL; PVDIR_ATTRIBUTE pRetAttrs[3] = {pEntry->attrs, pEntry->pComputedAttrs, NULL}; DWORD dwCnt = 0; PSTR pszLocalErrorMsg = NULL; // loop through both normal and computed attributes for ( dwCnt = 0, pAttr = pRetAttrs[dwCnt]; pAttr != NULL; ++dwCnt, pAttr = pRetAttrs[dwCnt]) { for ( ; pAttr != NULL; pAttr = pAttr->next ) { BOOLEAN bSendAttribute = FALSE; if (op->syncReqCtrl != NULL) // Replication, { // Filter attributes based on the input utdVector, and attribute's meta-data retVal = IsAttrInReplScope( op, pAttr->type.lberbv.bv_val, pAttr->metaData, &bSendAttribute, &pszLocalErrorMsg ); BAIL_ON_VMDIR_ERROR( retVal ); } else { // WEI: the correct way to handle this is to have attribute level 'ACL' check // For instance, the 'userPassword' attribute ACL defines: // Deny 'READ' access to everyone including administrator/admins/SELF // Possibly only allow 'backup Operators' 'READ' access // Allow 'administrator/admins' WRITE (set password) // Allow 'SELF' WRITE (reset password) // For now, do not send 'userPassword' attribute for everyone when implicitly/explicitly requested // normal ldap client search request // check if we need to return this attribute if (VmDirStringCompareA(pAttr->type.lberbv.bv_val, ATTR_USER_PASSWORD, FALSE) == 0) { if ((iSearchReqSpecialChars & LDAP_SEARCH_REQUEST_CHAR_PASSWD) != 0) { // vmdir specific - return password only if special char '-' is requested bSendAttribute = TRUE; } } else if (VmDirStringCompareA(pAttr->type.lberbv.bv_val, ATTR_KRB_MASTER_KEY, FALSE) == 0) { //only return master key if all of following conditions are satisfied if (op->showMasterKeyCtrl && // server control must be present op->conn->bIsLdaps && // must be ldaps op->conn->AccessInfo.pszNormBindedDn && // can't be anonymous VmDirStringCompareA(op->reqDn.bvnorm_val, gVmdirServerGlobals.systemDomainDN.bvnorm_val, FALSE) == 0 && // must query system domain object op->request.searchReq.scope == LDAP_SCOPE_BASE && // scope must be base op->request.searchReq.attrs != NULL && // attribute must be krbMKey only VmDirStringCompareA(op->request.searchReq.attrs[0].lberbv.bv_val, ATTR_KRB_MASTER_KEY, FALSE) == 0 && op->request.searchReq.attrs[1].lberbv.bv_val == NULL) { retVal = VmDirSrvAccessCheckIsAdminRole( //must be administrator op, op->conn->AccessInfo.pszNormBindedDn, &op->conn->AccessInfo, &bSendAttribute); BAIL_ON_VMDIR_ERROR( retVal ); } } else if ( (VmDirStringCompareA(pAttr->type.lberbv.bv_val, ATTR_VMW_STS_PASSWORD, FALSE) == 0) || (VmDirStringCompareA(pAttr->type.lberbv.bv_val, ATTR_VMW_STS_TENANT_KEY, FALSE) == 0) ) { //only admin users can read ATTR_VMW_STS_PASSWORD, ATTR_VMW_STS_TENANT_KEY attribute { retVal = VmDirSrvAccessCheckIsAdminRole( //must be administrator op, op->conn->AccessInfo.pszNormBindedDn, &op->conn->AccessInfo, &bSendAttribute); BAIL_ON_VMDIR_ERROR( retVal ); } } else if (((iSearchReqSpecialChars & LDAP_SEARCH_REQUEST_CHAR_USER) != 0) && pAttr->pATDesc->usage == VDIR_ATTRIBUTETYPE_USER_APPLICATIONS) { bSendAttribute = TRUE; // return all user attributes - "*" } else if (((iSearchReqSpecialChars & LDAP_SEARCH_REQUEST_CHAR_OP) != 0) && (pAttr->pATDesc->usage == VDIR_ATTRIBUTETYPE_DIRECTORY_OPERATION || pAttr->pATDesc->usage == VDIR_ATTRIBUTETYPE_DSA_OPERATION || pAttr->pATDesc->usage == VDIR_ATTRIBUTETYPE_DISTRIBUTED_OPERATION)) { bSendAttribute = TRUE; // return all operational attributes - "+" } else { for (i = 0; sr->attrs && sr->attrs[i].lberbv.bv_val != NULL; i++) { if (VmDirStringCompareA( sr->attrs[i].lberbv.bv_val, pAttr->type.lberbv.bv_val, FALSE) == 0) { bSendAttribute = TRUE; break; } } } } if (bSendAttribute) { if (ber_printf( ber, "{O[", &(pAttr->type) ) == -1 ) { VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL, "WriteAttributes: ber_printf (to print attribute name ...) failed" ); retVal = LDAP_OTHER; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Encoding attribute type failed."); } // Non-replication/normal search request, and the attribute is FSP enabled (SJ-TBD, for now ATTR_MEMBER) if (op->syncReqCtrl == NULL && VmDirStringCompareA(pAttr->type.lberbv.bv_val, ATTR_MEMBER, FALSE) == 0) { mapFSPDN = TRUE; } else { mapFSPDN = FALSE; } if ( VmDirStringCompareA( pAttr->type.lberbv_val, ATTR_OBJECT_CLASS, FALSE ) == 0 ) { if ( op->syncReqCtrl == NULL ) // Not replication { BerValue bvOCTop = {OC_TOP_LEN, OC_TOP}; // explicitly send TOP as we don't store it in Entry/DB if (ber_printf( ber, "O", &bvOCTop ) == -1 ) { VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL, "WriteAttributes: ber_printf (to print an attribute value ...) failed." ); retVal = LDAP_OTHER; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Encoding an attribute value failed."); } } // ADSI wants structure objetclass at the end to display correctly. for ( i = pAttr->numVals ; i > 0; i-- ) { if (ber_printf( ber, "O", &(pAttr->vals[i-1]) ) == -1 ) { VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL, "WriteAttributes: ber_printf (to print an attribute value ...) failed." ); retVal = LDAP_OTHER; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Encoding an attribute value failed."); } } } else { for ( i = 0; i< pAttr->numVals; i++ ) { // SJ-TBD: A better/bit-more-expensive way is to Normalize the value, do GetParentDN, check if the 1st // RDN is FSP container RDN ... if (mapFSPDN && VmDirStringStrA(pAttr->vals[i].lberbv.bv_val, FSP_CONTAINER_RDN_ATTR_VALUE) != NULL) { char * tmpPos = VmDirStringChrA(pAttr->vals[i].lberbv.bv_val, ','); assert( tmpPos != NULL); *tmpPos = '\0'; pAttr->vals[i].lberbv.bv_len = tmpPos - pAttr->vals[i].lberbv.bv_val; } if (ber_printf( ber, "O", &(pAttr->vals[i]) ) == -1 ) { VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL, "WriteAttributes: ber_printf (to print an attribute value ...) failed." ); retVal = LDAP_OTHER; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Encoding an attribute value failed."); } } } if ( ber_printf( ber, "]N}" ) == -1 ) { VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL, "WriteAttributes: ber_printf (to terminate an attribute's values ...) failed" ); retVal = LDAP_OTHER; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Encoding terminating an attribute type failed."); } } } } cleanup: if (ppszErrorMsg) { *ppszErrorMsg = pszLocalErrorMsg; } else { VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg); } return( retVal ); error: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "WriteAttributes failed (%u)(%s)", retVal, VDIR_SAFE_STRING(pszLocalErrorMsg) ); goto cleanup; }
static int WriteMetaDataAttribute( VDIR_OPERATION * op, VDIR_ATTRIBUTE * pAttr, int numAttrMetaData, PATTRIBUTE_META_DATA_NODE pAttrMetaData, BerElement * ber, BOOLEAN * nonTrivialAttrsInReplScope, PSTR* ppszErrorMsg ) { int retVal = LDAP_SUCCESS; VDIR_BERVALUE attrMetaData = { {ATTR_ATTR_META_DATA_LEN, ATTR_ATTR_META_DATA}, 0, 0, NULL }; int i = 0; VDIR_BERVALUE berVal = VDIR_BERVALUE_INIT; char attrMetaDataVal[256 + VMDIR_MAX_ATTR_META_DATA_LEN]; PSTR pszLocalErrorMsg = NULL; *nonTrivialAttrsInReplScope = FALSE; if (ber_printf( ber, "{O[", &(attrMetaData) ) == -1 ) { VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL, "WriteMetaDataAttribute: ber_printf (to print attribute name ...) failed" ); retVal = LDAP_OTHER; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Encoding attribute type failed."); } for ( ; pAttr != NULL; pAttr = pAttr->next) { // By this time, we have already filtered out attributes that should be send back to replication consumer // in prior WriteAttributes -> IsAttrInReplScope call. They contain proper pAttr->metaData value. if (pAttr->metaData[0] != '\0') { VmDirStringPrintFA( attrMetaDataVal, sizeof(attrMetaDataVal), "%.256s:%s", pAttr->type.lberbv.bv_val, pAttr->metaData); berVal.lberbv.bv_val = attrMetaDataVal; berVal.lberbv.bv_len = VmDirStringLenA( attrMetaDataVal ); if (VmDirStringCompareA( pAttr->type.lberbv.bv_val, ATTR_MODIFYTIMESTAMP, FALSE ) != 0 && VmDirStringCompareA( pAttr->type.lberbv.bv_val, ATTR_USN_CHANGED, FALSE ) != 0) { // To prevent endless replication ping pong, supplier should send result only if there are changes // to attribute other than ATTR_USN_CHANGED and ATTR_MODIFYTIMESTAMP. *nonTrivialAttrsInReplScope = TRUE; } if (ber_printf( ber, "O", &berVal ) == -1 ) { VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL, "WriteMetaDataAttribute: ber_printf (to print an attribute value ...) failed." ); retVal = LDAP_OTHER; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Encoding an attribute value failed."); } } } // include attrMetaData for the deleted attributes for (i = 0; i<numAttrMetaData; i++) { if (pAttrMetaData[i].metaData[0] != '\0') { BOOLEAN bSendAttrMetaData = TRUE; PVDIR_SCHEMA_AT_DESC pATDesc = NULL; if (op->syncReqCtrl != NULL) // Replication { retVal = IsAttrInReplScope( op, NULL, pAttrMetaData[i].metaData, &bSendAttrMetaData, &pszLocalErrorMsg ); BAIL_ON_VMDIR_ERROR( retVal ); } else { bSendAttrMetaData = TRUE; } if (bSendAttrMetaData) { if ((pATDesc = VmDirSchemaAttrIdToDesc(op->pSchemaCtx, pAttrMetaData[i].attrID)) == NULL) { VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL, "WriteMetaDataAttribute: VmDirSchemaAttrIdToDesc failed for attribute id: %d.", pAttrMetaData[i].attrID ); retVal = LDAP_OTHER; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "WriteMetaDataAttribute: VmDirSchemaAttrIdToDesc failed."); } VmDirStringPrintFA( attrMetaDataVal, sizeof(attrMetaDataVal), "%.256s:%s", pATDesc->pszName, pAttrMetaData[i].metaData); berVal.lberbv.bv_val = attrMetaDataVal; berVal.lberbv.bv_len = VmDirStringLenA( attrMetaDataVal ); *nonTrivialAttrsInReplScope = TRUE; if (ber_printf( ber, "O", &berVal ) == -1 ) { VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL, "WriteMetaDataAttribute: ber_printf (to print an attribute value ...) failed." ); retVal = LDAP_OTHER; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Encoding an attribute value failed."); } } } } if ( ber_printf( ber, "]N}" ) == -1 ) { VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL, "WriteMetaDataAttribute: ber_printf (to terminate an attribute's values ...) failed" ); retVal = LDAP_OTHER; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Encoding terminating an attribute type failed."); } cleanup: if (ppszErrorMsg) { *ppszErrorMsg = pszLocalErrorMsg; } else { VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg); } return( retVal ); error: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "WriteMetaDataAttribute failed (%u)(%s)", retVal, VDIR_SAFE_STRING(pszLocalErrorMsg) ); goto cleanup; }
static int IsAttrInReplScope( VDIR_OPERATION * op, char * attrType, char * attrMetaData, BOOLEAN * inScope, PSTR* ppszErrorMsg ) { int retVal = LDAP_SUCCESS; PLW_HASHTABLE_NODE pNode = NULL; char origInvocationId[VMDIR_GUID_STR_LEN]; USN origUsn = VmDirStringToLA( VmDirStringRChrA( attrMetaData, ':' ) + 1, NULL, 10 ); int rc = 0; PSTR pszLocalErrorMsg = NULL; *inScope = FALSE; // attrMetaData format is: <local USN>:<version no>:<originating server ID>:<originating time>:<originating USN> VmDirStringNCpyA( origInvocationId, VMDIR_GUID_STR_LEN, VmDirStringChrA( VmDirStringChrA( attrMetaData, ':' ) + 1, ':') + 1, VMDIR_GUID_STR_LEN - 1); origInvocationId[VMDIR_GUID_STR_LEN - 1] = '\0'; // Skip the attribute: // - if the originating server for the current state is same as the requesting server or if it is one of those // attributes that have "local" scope only. E.g. sending ATTR_LAST_LOCAL_USN_PROCESSED and // ATTR_UP_TO_DATE_VECTOR, causes continuous back-forth replication of Replication Agreements and Server // entries between various servers. assert( op->syncReqCtrl != NULL ); if ((attrType != NULL && (VmDirStringCompareA( attrType, ATTR_LAST_LOCAL_USN_PROCESSED, FALSE) == 0 || VmDirStringCompareA( attrType, ATTR_UP_TO_DATE_VECTOR, FALSE) == 0 || VmDirStringCompareA( attrType, VDIR_ATTRIBUTE_SEQUENCE_RID, FALSE) == 0))) { // Reset metaData value so that we don't send local only attribute back. attrMetaData[0] = '\0'; *inScope = FALSE; goto cleanup; } else if ( attrType != NULL && (VmDirStringCompareA( attrType, ATTR_USN_CHANGED, FALSE) == 0)) { ; // always send uSNChanged. (PR 1573117) } else if (VmDirStringCompareA( origInvocationId, op->syncReqCtrl->value.syncReqCtrlVal.reqInvocationId.lberbv.bv_val,TRUE ) == 0) { // Change is originated from the requesting server. // Reset metaData value so that we don't send metaData as well as this attribute back. attrMetaData[0] = '\0'; *inScope = FALSE; goto cleanup; } else { rc = LwRtlHashTableFindKey( op->syncDoneCtrl->value.syncDoneCtrlVal.htUtdVector, &pNode, origInvocationId ); rc = LwNtStatusToWin32Error(rc); if (rc != 0 && rc != ERROR_NOT_FOUND) { VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL, "IsAttrInReplScope: LwRtlHashTableFindKey failed for origInvocationId: %s", origInvocationId ); retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "LwRtlHashTableFindKey failed."); } if (pNode == NULL) // Attribute is to be sent in the result entry. { UptoDateVectorEntry * utdVectorEntry = NULL; VDIR_BERVALUE bvServerId = VDIR_BERVALUE_INIT; if (VmDirAllocateMemory( sizeof( UptoDateVectorEntry ), (PVOID *)&utdVectorEntry) != 0) { retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "IsAttrInReplScope: BervalContentDup failed."); } bvServerId.lberbv.bv_val = origInvocationId; bvServerId.lberbv.bv_len = VmDirStringLenA( origInvocationId ); if (VmDirBervalContentDup( &bvServerId, &utdVectorEntry->invocationId ) != 0) { retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "IsAttrInReplScope: BervalContentDup failed."); } utdVectorEntry->currMaxOrigUsnProcessed = origUsn; LwRtlHashTableResizeAndInsert( op->syncDoneCtrl->value.syncDoneCtrlVal.htUtdVector, &utdVectorEntry->Node, &pNode); assert( pNode == NULL ); // assert the key of added node is unique } else { UptoDateVectorEntry * utdVectorEntry = NULL; utdVectorEntry = (UptoDateVectorEntry *)LW_STRUCT_FROM_FIELD(pNode, UptoDateVectorEntry, Node); if (origUsn > utdVectorEntry->reqLastOrigUsnProcessed ) { // Attribute is to be sent in the result entry. // Update if origUsn of this attribute is > the current highest if (origUsn > utdVectorEntry->currMaxOrigUsnProcessed ) { utdVectorEntry->currMaxOrigUsnProcessed = origUsn; } } else { VMDIR_LOG_VERBOSE( LDAP_DEBUG_REPL_ATTR, "IsAttrInReplScope: Attribute: %s, metaData: %s, replication scope = FALSE", attrType, attrMetaData ); // Reset metaData value so that we don't send metaData for this attribute back. attrMetaData[0] = '\0'; *inScope = FALSE; goto cleanup; } } } VMDIR_LOG_INFO( LDAP_DEBUG_REPL_ATTR, "IsAttrInReplScope: Attribute: %s, metaData: %s, replication scope = TRUE", attrType, attrMetaData ); *inScope = TRUE; cleanup: if (ppszErrorMsg) { *ppszErrorMsg = pszLocalErrorMsg; } else { VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg); } return( retVal ); error: goto cleanup; }
int VmDirSendSearchEntry( PVDIR_OPERATION pOperation, PVDIR_ENTRY pSrEntry ) { int retVal = LDAP_SUCCESS; BerElementBuffer berbuf; BerElement * ber = (BerElement *) &berbuf; BOOLEAN bFreeBer = FALSE; ber_len_t iBlobSize = 0; BerValue lberBervEntryBlob = {0}; int nAttrs = 0; int nVals = 0; BOOLEAN attrMetaDataReqd = FALSE; SearchReq * sr = &(pOperation->request.searchReq); int i = 0; BOOLEAN nonTrivialAttrsInReplScope = FALSE; uint32_t iSearchReqSpecialChars = 0; PATTRIBUTE_META_DATA_NODE pAttrMetaData = NULL; int numAttrMetaData = 0; PVDIR_ATTRIBUTE pAttr = NULL; USN usnChanged = 0; PSTR pszLocalErrorMsg = NULL; if ( !pOperation || !pSrEntry ) { retVal = ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(retVal); } pSrEntry->bSearchEntrySent = FALSE; // see if client request has "*" and/or "+" ("-" for userpassword internal to vmdir) // WEI TODO: when we have attribute level ACL check, this information will be useful // return result will depend on ACL each on each attribute client is asking before // generating a final result to send back SetSpecialReturnChar(&pOperation->request.searchReq, &iSearchReqSpecialChars); if ( pSrEntry->eId == DSE_ROOT_ENTRY_ID && pOperation->request.searchReq.attrs == NULL ) { // For ADSI, if no specific attributes requested of DSE ROOT search, // return ALL (include operational) attributes. iSearchReqSpecialChars |= LDAP_SEARCH_REQUEST_CHAR_OP; } // ACL check before processing/sending the current srEntry back retVal = VmDirSrvAccessCheck( pOperation, &pOperation->conn->AccessInfo, pSrEntry, VMDIR_RIGHT_DS_READ_PROP ); BAIL_ON_VMDIR_ERROR( retVal ); if ( pOperation->opType == VDIR_OPERATION_TYPE_INTERNAL ) { ; // no op in INTERNAL case } else { // If not replication, and showDeletedObjectsCtrl not present, => don't send back Deleted objects (tombstones). if (pOperation->syncReqCtrl == NULL && pOperation->showDeletedObjectsCtrl == NULL) { pAttr = VmDirEntryFindAttribute(ATTR_IS_DELETED, pSrEntry); if (pAttr) { if (VmDirStringCompareA((PSTR)pAttr->vals[0].lberbv.bv_val, VMDIR_IS_DELETED_TRUE_STR, FALSE) == 0) { goto cleanup; // Don't send this entry } } } // In case of replication request, skip certain updates if (pOperation->syncReqCtrl != NULL) { PVDIR_ATTRIBUTE pAttrUsnCreated = NULL; USN usnCreated = 0; USN limitUsn = 0; VMDIR_REPLICATION_AGREEMENT * replAgr = NULL; pAttr = VmDirEntryFindAttribute(ATTR_USN_CHANGED, pSrEntry); assert( pAttr != NULL ); usnChanged = VmDirStringToLA( pAttr->vals[0].lberbv.bv_val, NULL, 10); // Check if usnChanged is beyond successful replication update state limitUsn = VmDirdGetLimitLocalUsnToBeSupplied(); if (limitUsn != 0 && usnChanged >= limitUsn) { VMDIR_LOG_INFO(VMDIR_LOG_MASK_ALL, "SendSearchEntry: bug# 863244 RACE CONDITION encountered., " "usnChanged = %ld, limitLocalUsnToBeSupplied = %ld, skipping entry: %s", usnChanged, limitUsn, pSrEntry->dn.lberbv.bv_val ); goto cleanup; // Don't send this entry } // Check if usnChanged is beyond lowestPendingUncommittedUsn recorded at the beginning of replication search if (pOperation->lowestPendingUncommittedUsn != 0 && usnChanged >= pOperation->lowestPendingUncommittedUsn) { VMDIR_LOG_INFO( LDAP_DEBUG_REPL, "SendSearchEntry: usnChanged = %ld, lowestPendingUncommittedUsn = %ld, " "skipping entry: %s", usnChanged, pOperation->lowestPendingUncommittedUsn, pSrEntry->dn.lberbv.bv_val ); goto cleanup; // Don't send this entry } // Don't send (skip) modifications to my server object, and my RAs pAttrUsnCreated = VmDirEntryFindAttribute(ATTR_USN_CREATED, pSrEntry); assert( pAttrUsnCreated != NULL ); usnCreated = VmDirStringToLA( pAttrUsnCreated->vals[0].lberbv.bv_val, NULL, 10); // Only send back creation of certain objects, and not their modifications. // Check if consumer has already seen the creation. If yes, we are dealing with mods, which should be skipped // for my server object, and my RAs // Note: Skipping mods for RAs and Server Objects will cause inconsistencies with replicas. But these // two types only have local scope regarding functional effects. But if we are looking up / processing // information for these two types of objects on a replica, we need to watch out for potential // inconsistencies against the original source. if (pOperation->syncReqCtrl->value.syncReqCtrlVal.intLastLocalUsnProcessed > usnCreated) { if (strcmp(pSrEntry->dn.bvnorm_val, gVmdirServerGlobals.serverObjDN.bvnorm_val) == 0) { VMDIR_LOG_INFO( LDAP_DEBUG_REPL, "SendSearchEntry: Not sending modifications to my server object, DN: %s", gVmdirServerGlobals.serverObjDN.lberbv.bv_val ); goto cleanup; // Don't send this entry } for (replAgr = gVmdirReplAgrs; replAgr != NULL; replAgr = replAgr->next ) { if (strcmp(pSrEntry->dn.bvnorm_val, replAgr->dn.bvnorm_val) == 0) { VMDIR_LOG_INFO( LDAP_DEBUG_REPL, "SendSearchEntry: Not sending modifications to my RA object, DN: %s", replAgr->dn.bvnorm_val ); goto cleanup; // Don't send this entry } } } // do not replicate DSE Root entry, because it is a "local" entry. if (pSrEntry->eId == DSE_ROOT_ENTRY_ID) { VMDIR_LOG_INFO( LDAP_DEBUG_REPL, "SendSearchEntry: Not sending modifications to DSE Root entry, DN: %s", pSrEntry->dn.bvnorm_val ); goto cleanup; // Don't send this entry } } // Approximate calculation for the required ber size, because apart from lengths and strings, ber also includes // tags. if ( VmDirComputeEncodedEntrySize(pSrEntry, &nAttrs, &nVals, &iBlobSize) != 0 || VmDirAllocateMemory(iBlobSize, (PVOID*)&lberBervEntryBlob.bv_val) != 0 ) { retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "no memory"); } lberBervEntryBlob.bv_len = iBlobSize; ber_init2( ber, &lberBervEntryBlob, LBER_USE_DER ); // ber takes over lberBervEntryBlob.lberbv.bv_val ownership bFreeBer = TRUE; if ( ber_printf( ber, "{it{O{", pOperation->msgId, LDAP_RES_SEARCH_ENTRY, &pSrEntry->dn ) == -1) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "SendSearchEntry: ber_printf (to print msgId ...) failed" ); retVal = LDAP_OTHER; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Encoding msgId, RES_SEARCH_ENTRY, DN failed"); } // Determine if we need to send back the attribute metaData if ( pOperation->syncReqCtrl != NULL ) // Replication { attrMetaDataReqd = TRUE; } else // check if attrMetaData attribute has been requested explicitly. { if (sr->attrs != NULL) { for (i = 0; sr->attrs[i].lberbv.bv_val != NULL; i++) { if (VmDirStringCompareA( sr->attrs[i].lberbv.bv_val, ATTR_ATTR_META_DATA, FALSE) == 0) { attrMetaDataReqd = TRUE; break; } } } } if (attrMetaDataReqd) { if ((pOperation->pBEIF->pfnBEGetAllAttrsMetaData( pOperation->pBECtx, pSrEntry->eId, &pAttrMetaData, &numAttrMetaData )) != 0) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "SendSearchEntry: pfnBEGetAllAttrsMetaData failed for entryId: %ld", pSrEntry->eId); retVal = LDAP_OPERATIONS_ERROR; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "pfnBEGetAllAttrsMetaData failed."); } // SJ-TBD: Following double for loop to be optimized // Copy attrMetaData to corresponding attributes for (i=0; i<numAttrMetaData; i++) { for ( pAttr = pSrEntry->attrs; pAttr != NULL; pAttr = pAttr->next) { if (pAttr->pATDesc->usAttrID == pAttrMetaData[i].attrID) { VmDirStringCpyA( pAttr->metaData, VMDIR_MAX_ATTR_META_DATA_LEN, pAttrMetaData[i].metaData ); pAttrMetaData[i].metaData[0] = '\0'; } } } } retVal = WriteAttributes( pOperation, pSrEntry, iSearchReqSpecialChars , ber, &pszLocalErrorMsg ); BAIL_ON_VMDIR_ERROR( retVal ); if (attrMetaDataReqd) { retVal = WriteMetaDataAttribute( pOperation, pSrEntry->attrs, numAttrMetaData, pAttrMetaData, ber, &nonTrivialAttrsInReplScope, &pszLocalErrorMsg ); BAIL_ON_VMDIR_ERROR( retVal ); } if (ber_printf( ber, "N}N}" ) == -1) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "ber_printf (to terminate the entry and the complete search result entry message ...) failed" ); retVal = LDAP_OTHER; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Encoding terminating the entry failed."); } if ( pOperation->syncReqCtrl != NULL ) // Replication, => write Sync State Control { retVal = WriteSyncStateControl( pOperation, pSrEntry->attrs, ber, &pszLocalErrorMsg ); BAIL_ON_VMDIR_ERROR( retVal ); } if (ber_printf( ber, "N}" ) == -1) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "ber_printf (to terminate the entry and the complete search result entry message ...) failed" );; retVal = LDAP_OTHER; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg), "Encoding terminating the entry failed."); } if ((pOperation->syncReqCtrl == NULL) || (pOperation->syncReqCtrl != NULL && nonTrivialAttrsInReplScope )) { if (WriteBerOnSocket( pOperation->conn, ber ) != 0) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "SendSearchEntry: WriteBerOnSocket failed." ); retVal = LDAP_UNAVAILABLE; BAIL_ON_VMDIR_ERROR( retVal ); } pSrEntry->bSearchEntrySent = TRUE; sr->iNumEntrySent++; VMDIR_LOG_INFO( LDAP_DEBUG_REPL, "SendSearchEntry: Send entry: %s", pSrEntry->dn.lberbv.bv_val); } else { VMDIR_LOG_INFO( LDAP_DEBUG_REPL, "SendSearchEntry: NOT Sending entry: %s %p %d", pSrEntry->dn.lberbv.bv_val, pOperation->syncReqCtrl, nonTrivialAttrsInReplScope); } // record max local usnChanged in syncControlDone if (pOperation->syncReqCtrl != NULL) { if (usnChanged > pOperation->syncDoneCtrl->value.syncDoneCtrlVal.intLastLocalUsnProcessed) { pOperation->syncDoneCtrl->value.syncDoneCtrlVal.intLastLocalUsnProcessed = usnChanged; } } retVal = LDAP_SUCCESS; } cleanup: if (bFreeBer) { ber_free_buf( ber ); } VMDIR_SAFE_FREE_MEMORY( pAttrMetaData ); VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg); return( retVal ); error: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "SendSearchEntry failed DN=(%s), (%u)(%s)", (pSrEntry && pSrEntry->dn.lberbv.bv_val) ? pSrEntry->dn.lberbv.bv_val : "", retVal, VDIR_SAFE_STRING( pszLocalErrorMsg)); if ( !pOperation->ldapResult.pszErrMsg && pszLocalErrorMsg ) { pOperation->ldapResult.pszErrMsg = pszLocalErrorMsg; pszLocalErrorMsg = NULL; } goto cleanup; }
/* * Add a ModifyRequest to pOperation with- * 1. modOp * 2. create attribute with values from pBerValue * * i.e. this function call is equivalent of a modify section in LDIF file * changetype: modify * add/delete/replace: attributeXYZ <<<<<<<<<<<<<<<< modOp * attributeXYZ: value1 <<<<<<<<<<<<<<<<<<<<<<<<<<<<< pBervalue * attributeXYZ: valueN <<<<<<<<<<<<<<<<<<<<<<<<<<<<< iBerValueSize */ DWORD VmDirOperationAddModReq( PVDIR_OPERATION pOperation, int modOp, char * pszAttrName, PVDIR_BERVALUE pBerValue, size_t iBerValueSize ) { DWORD dwError = 0; PSTR pszLocalErrMsg = NULL; VDIR_MODIFICATION * pMod = NULL; ModifyReq * pModReq = &(pOperation->request.modifyReq); size_t iCnt = 0; if ( !pOperation || !pszAttrName || !pBerValue ) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } dwError = VmDirAllocateMemory( sizeof( *pMod ), (PVOID *)&(pMod) ); BAIL_ON_VMDIR_ERROR( dwError ); pMod->operation = modOp; pMod->attr.next = NULL; pMod->attr.pATDesc = VmDirSchemaAttrNameToDesc( pOperation->pSchemaCtx, pszAttrName); if ( !pMod->attr.pATDesc ) { dwError = ERROR_NO_SUCH_ATTRIBUTE; BAIL_ON_VMDIR_ERROR_WITH_MSG( dwError, pszLocalErrMsg, "attibute (%s) not defined", pszAttrName ); } // attribute.type.lberbv use (schema cache) inplace memory (we don't fee it). pMod->attr.type.lberbv.bv_val = pMod->attr.pATDesc->pszName; pMod->attr.type.lberbv.bv_len = VmDirStringLenA(pMod->attr.pATDesc->pszName); dwError = VmDirAllocateMemory( sizeof( VDIR_BERVALUE ) * (iBerValueSize + 1 ), (PVOID *)&(pMod->attr.vals) ); BAIL_ON_VMDIR_ERROR( dwError ); for (iCnt = 0; iCnt < iBerValueSize; iCnt++) { dwError = VmDirAllocateAndCopyMemory( pBerValue[iCnt].lberbv_val, pBerValue[iCnt].lberbv_len, (PVOID *)&(pMod->attr.vals[iCnt].lberbv.bv_val)); BAIL_ON_VMDIR_ERROR( dwError ); pMod->attr.vals[iCnt].lberbv.bv_len = pBerValue[iCnt].lberbv_len; pMod->attr.vals[iCnt].bOwnBvVal = TRUE; pMod->attr.numVals++; } pMod->next = pModReq->mods; pModReq->mods = pMod; // pOpeartion->request.modifyRequest takes over pMod pModReq->numMods++; cleanup: VMDIR_SAFE_FREE_MEMORY(pszLocalErrMsg); return dwError; error: if (pMod) { VmDirModificationFree( pMod ); } VMDIR_SET_LDAP_RESULT_ERROR( &(pOperation->ldapResult), dwError, pszLocalErrMsg ); goto cleanup; }
/* * Set vmwPasswordNeverExpires (if it doesn't have a value) to TRUE * on the domain administrator's account. */ DWORD VmDirSetAdministratorPasswordNeverExpires( VOID ) { DWORD dwError = 0; PCSTR pszDomainDn = NULL; const CHAR szAdministrator[] = "cn=Administrator,cn=Users"; const CHAR szTrue[] = "TRUE"; PSTR pszAdministratorDn = NULL; VDIR_OPERATION op = {0}; PSTR pszLocalErrMsg = NULL; VDIR_ENTRY_ARRAY entryArray = {0}; PVDIR_ENTRY pEntry = NULL; VDIR_BERVALUE bervBlob = VDIR_BERVALUE_INIT; pszDomainDn = gVmdirServerGlobals.systemDomainDN.lberbv.bv_val; if (pszDomainDn == NULL) { dwError = ERROR_INVALID_STATE; BAIL_ON_VMDIR_ERROR(dwError); } dwError = VmDirAllocateStringPrintf(&pszAdministratorDn, "%s,%s", szAdministrator, pszDomainDn); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirSimpleEqualFilterInternalSearch( pszDomainDn, LDAP_SCOPE_SUBTREE, ATTR_DN, pszAdministratorDn, &entryArray); BAIL_ON_VMDIR_ERROR(dwError); if (entryArray.iSize != 1) { dwError = VMDIR_ERROR_DATA_CONSTRAINT_VIOLATION; BAIL_ON_VMDIR_ERROR(dwError); } pEntry = &(entryArray.pEntry[0]); if (pEntry->allocType == ENTRY_STORAGE_FORMAT_PACK) { dwError = VmDirEntryUnpack( pEntry ); BAIL_ON_VMDIR_ERROR(dwError); } dwError = VmDirInitStackOperation( &op, VDIR_OPERATION_TYPE_INTERNAL, LDAP_REQ_MODIFY, NULL); BAIL_ON_VMDIR_ERROR_WITH_MSG(dwError, pszLocalErrMsg, "VmDirSetAdministratorPasswordNeverExpire: VmDirInitStackOperation failed: %u", dwError); op.pBEIF = VmDirBackendSelect(NULL); assert(op.pBEIF); op.reqDn.lberbv.bv_val = pEntry->dn.lberbv.bv_val; op.reqDn.lberbv.bv_len = pEntry->dn.lberbv.bv_len; op.request.modifyReq.dn.lberbv = op.reqDn.lberbv; bervBlob.lberbv.bv_val = (PSTR) szTrue; bervBlob.lberbv.bv_len = strlen(szTrue); dwError = VmDirAppendAMod( &op, MOD_OP_REPLACE, ATTR_PASSWORD_NEVER_EXPIRES, ATTR_PASSWORD_NEVER_EXPIRES_LEN, bervBlob.lberbv_val, bervBlob.lberbv_len); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirInternalModifyEntry(&op); BAIL_ON_VMDIR_ERROR(dwError); cleanup: VmDirFreeEntryArrayContent(&entryArray); VmDirFreeOperationContent(&op); VMDIR_SAFE_FREE_STRINGA(pszAdministratorDn); return dwError; error: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "VmDirSetAdministratorPasswordNeverExpires failed, (%u)", dwError); goto cleanup; }
/* * Set SRP Identifier's secret on existing entry with Password set */ DWORD VmDirSRPSetIdentityData( PCSTR pszUPN, PCSTR pszClearTextPassword ) { DWORD dwError = 0; VDIR_OPERATION op = {0}; PSTR pszLocalErrMsg = NULL; VDIR_ENTRY_ARRAY entryArray = {0}; PVDIR_ENTRY pEntry = NULL; PVDIR_ATTRIBUTE pAttrSecret = NULL; VDIR_BERVALUE bvUPN = VDIR_BERVALUE_INIT; VDIR_BERVALUE bvClearTextPassword = VDIR_BERVALUE_INIT; VDIR_BERVALUE bervSecretBlob = VDIR_BERVALUE_INIT; if ( IsNullOrEmptyString(pszUPN) || IsNullOrEmptyString(pszClearTextPassword) ) { dwError = VMDIR_ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } bvUPN.lberbv_val = (PSTR)pszUPN; bvUPN.lberbv_len = VmDirStringLenA(pszUPN); bvClearTextPassword.lberbv_val = (PSTR)pszClearTextPassword; bvClearTextPassword.lberbv_len = VmDirStringLenA(pszClearTextPassword); dwError = VmDirSimpleEqualFilterInternalSearch( "", LDAP_SCOPE_SUBTREE, ATTR_KRB_UPN, pszUPN, &entryArray); BAIL_ON_VMDIR_ERROR(dwError); if (entryArray.iSize == 1) { pAttrSecret = VmDirFindAttrByName(&(entryArray.pEntry[0]), ATTR_SRP_SECRET); if (pAttrSecret) { dwError = VMDIR_ERROR_ENTRY_ALREADY_EXIST; BAIL_ON_VMDIR_ERROR(dwError); } } else { dwError = VMDIR_ERROR_DATA_CONSTRAINT_VIOLATION; BAIL_ON_VMDIR_ERROR(dwError); } pEntry = &(entryArray.pEntry[0]); dwError = VdirPasswordCheck(&bvClearTextPassword, pEntry); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirSRPCreateSecret(&bvUPN, &bvClearTextPassword, &bervSecretBlob); BAIL_ON_VMDIR_ERROR(dwError); if (pEntry->allocType == ENTRY_STORAGE_FORMAT_PACK) { dwError = VmDirEntryUnpack( pEntry ); BAIL_ON_VMDIR_ERROR(dwError); } dwError = VmDirInitStackOperation( &op, VDIR_OPERATION_TYPE_INTERNAL, LDAP_REQ_MODIFY, NULL); BAIL_ON_VMDIR_ERROR_WITH_MSG(dwError, pszLocalErrMsg, "VmDirSRPSetIdentityData: VmDirInitStackOperation failed: %u", dwError); op.pBEIF = VmDirBackendSelect(NULL); assert(op.pBEIF); op.reqDn.lberbv.bv_val = pEntry->dn.lberbv.bv_val; op.reqDn.lberbv.bv_len = pEntry->dn.lberbv.bv_len; op.request.modifyReq.dn.lberbv = op.reqDn.lberbv; dwError = VmDirAppendAMod( &op, MOD_OP_ADD, ATTR_SRP_SECRET, ATTR_SRP_SECRET_LEN, bervSecretBlob.lberbv_val, bervSecretBlob.lberbv_len); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirInternalModifyEntry(&op); BAIL_ON_VMDIR_ERROR(dwError); cleanup: VmDirFreeBervalContent(&bervSecretBlob); VmDirFreeEntryArrayContent(&entryArray); VmDirFreeOperationContent(&op); return dwError; error: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "VmDirSRPSetIdentityData (%s) failed, (%u)", VDIR_SAFE_STRING(pszUPN), dwError); goto cleanup; }