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; }
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; }
int VmDirPerformDelete( PVDIR_OPERATION pOperation ) { int retVal = LDAP_SUCCESS; DeleteReq * dr = &(pOperation->request.deleteReq); BOOLEAN bResultAlreadySent = FALSE; // Get entry DN. 'm' => pOperation->reqDn.lberbv.bv_val points to DN within (in-place) ber if ( ber_scanf( pOperation->ber, "m", &(pOperation->reqDn.lberbv) ) == LBER_ERROR ) { VMDIR_LOG_ERROR( LDAP_DEBUG_ARGS, "PerformDelete: ber_scanf failed" ); retVal = LDAP_NOTICE_OF_DISCONNECT; BAIL_ON_VMDIR_ERROR( retVal ); } VMDIR_LOG_INFO( LDAP_DEBUG_ARGS, "Delete Request: dn (%s)", pOperation->reqDn.lberbv.bv_val ); memset( dr, 0, sizeof( DeleteReq )); // NOTE: pOperation->reqDn.lberbv.bv_val is NULL terminated (TODO, verify this) dr->dn.lberbv.bv_val = pOperation->reqDn.lberbv.bv_val; dr->dn.lberbv.bv_len = pOperation->reqDn.lberbv.bv_len; retVal = VmDirMLDelete( pOperation ); bResultAlreadySent = TRUE; BAIL_ON_VMDIR_ERROR(retVal); cleanup: return retVal; error: if (retVal != LDAP_NOTICE_OF_DISCONNECT && bResultAlreadySent == FALSE) { VmDirSendLdapResult( pOperation ); } 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; }
int VmDirPerformBind( PVDIR_OPERATION pOperation ) { BindReq * pBindReq = &(pOperation->request.bindReq); int retVal = LDAP_SUCCESS; ber_len_t berLen = 0; ber_tag_t berTag = 0; BOOLEAN bResultAlreadySent = FALSE; memset( pBindReq, 0, sizeof( BindReq )); if (ber_scanf( pOperation->ber, "{imt", &pOperation->protocol, &(pOperation->reqDn.lberbv), &pBindReq->method ) == LBER_ERROR ) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "PerformBind: ber_scanf failed" ); BAIL_ON_STATIC_LDAP_ERROR( retVal, LDAP_PROTOCOL_ERROR, (pOperation->ldapResult.pszErrMsg), "Decoding error while parsing protocol version, bind DN, bind method."); } VMDIR_LOG_VERBOSE( LDAP_DEBUG_ARGS, "Bind Request (%s): Protocol version: %d, Bind DN: \"%s\", Method: %ld", pOperation->conn->szClientIP, pOperation->protocol, pOperation->reqDn.lberbv.bv_val, pBindReq->method ); if (pOperation->protocol != LDAP_VERSION3) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "PerformBind: Non-ldap-v3 version." ); BAIL_ON_STATIC_LDAP_ERROR( retVal, LDAP_PROTOCOL_ERROR, (pOperation->ldapResult.pszErrMsg), "Currently, only LDAP V3 is supported."); } switch (pBindReq->method) { case LDAP_AUTH_SIMPLE: if ( ber_scanf( pOperation->ber, "m}", &(pBindReq->cred.lberbv) ) == LBER_ERROR ) { VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "PerformBind: ber_scanf failed" ); BAIL_ON_STATIC_LDAP_ERROR( retVal, LDAP_PROTOCOL_ERROR, (pOperation->ldapResult.pszErrMsg), "Decoding error while parsing simple credentials."); } break; case LDAP_AUTH_SASL: if ( ber_scanf( pOperation->ber, "{m" /*}*/, &(pBindReq->bvMechanism.lberbv) ) == LBER_ERROR) { BAIL_ON_STATIC_LDAP_ERROR( retVal, LDAP_PROTOCOL_ERROR, (pOperation->ldapResult.pszErrMsg), "Decoding error while parsing sasl mechanism."); } berTag = ber_peek_tag( pOperation->ber, &berLen ); if ( berTag == LDAP_TAG_LDAPCRED ) { if ( ber_scanf( pOperation->ber, "m", &(pBindReq->cred.lberbv)) == LBER_ERROR ) { BAIL_ON_STATIC_LDAP_ERROR( retVal, LDAP_PROTOCOL_ERROR, (pOperation->ldapResult.pszErrMsg), "Decoding error while parsing sasl creds."); } } if ( ber_scanf( pOperation->ber, /*{{*/ "}}" ) == LBER_ERROR ) { BAIL_ON_STATIC_LDAP_ERROR( retVal, LDAP_PROTOCOL_ERROR, (pOperation->ldapResult.pszErrMsg), "Decoding error."); } break; default: BAIL_ON_STATIC_LDAP_ERROR( retVal, LDAP_UNWILLING_TO_PERFORM, (pOperation->ldapResult.pszErrMsg), "bind method not supported."); } retVal = VmDirMLBind( pOperation ); bResultAlreadySent = TRUE; if (retVal && retVal != LDAP_SASL_BIND_IN_PROGRESS) { VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "Bind Request Failed (%s) error %u: Protocol version: %d, Bind DN: \"%s\", Method: %ld", pOperation->conn->szClientIP, retVal, pOperation->protocol, VDIR_SAFE_STRING(pOperation->reqDn.lberbv.bv_val), pBindReq->method ); } BAIL_ON_SIMPLE_LDAP_ERROR(retVal); cleanup: return retVal; ldaperror: pOperation->ldapResult.errCode = retVal; if (retVal != LDAP_NOTICE_OF_DISCONNECT && bResultAlreadySent == FALSE) { VmDirSendLdapResult( pOperation ); } goto cleanup; }
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; }
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; }
int VmDirPerformDelete( PVDIR_OPERATION pOperation ) { int retVal = LDAP_SUCCESS; DeleteReq * dr = &(pOperation->request.deleteReq); BOOLEAN bRefSent = FALSE; PSTR pszRefStr = NULL; PSTR pszLocalErrMsg = NULL; // Get entry DN. 'm' => pOperation->reqDn.lberbv.bv_val points to DN within (in-place) ber if ( ber_scanf( pOperation->ber, "m", &(pOperation->reqDn.lberbv) ) == LBER_ERROR ) { VMDIR_LOG_ERROR( LDAP_DEBUG_ARGS, "PerformDelete: ber_scanf failed" ); retVal = LDAP_NOTICE_OF_DISCONNECT; BAIL_ON_VMDIR_ERROR( retVal ); } VMDIR_LOG_INFO( LDAP_DEBUG_ARGS, "Delete Request: dn (%s)", pOperation->reqDn.lberbv.bv_val ); memset( dr, 0, sizeof( DeleteReq )); // NOTE: pOperation->reqDn.lberbv.bv_val is NULL terminated (TODO, verify this) dr->dn.lberbv.bv_val = pOperation->reqDn.lberbv.bv_val; dr->dn.lberbv.bv_len = pOperation->reqDn.lberbv.bv_len; retVal = ParseRequestControls(pOperation, &pOperation->ldapResult); BAIL_ON_VMDIR_ERROR(retVal); if (pOperation->manageDsaITCtrl == NULL && (gVmdirGlobals.dwEnableRaftReferral & VMDIR_RAFT_ENABLE_UPDATE_REFERRAL) && VmDirRaftNeedReferral(pOperation->reqDn.lberbv.bv_val)) { retVal = VmDirAllocateStringPrintf(&pszRefStr, "%s", pOperation->reqDn.lberbv.bv_len > 0 ? pOperation->reqDn.lberbv.bv_val:""); BAIL_ON_VMDIR_ERROR(retVal); VmDirSendLdapReferralResult(pOperation, pszRefStr, &bRefSent); if (bRefSent) { goto cleanup; } // Referral is not sent because the raft state might have changed. Go throughput normal procedure. } retVal = VmDirMLDelete( pOperation ); BAIL_ON_VMDIR_ERROR(retVal); cleanup: if (retVal != LDAP_NOTICE_OF_DISCONNECT && bRefSent == FALSE) { VmDirSendLdapResult( pOperation ); } VMDIR_SAFE_FREE_MEMORY(pszRefStr); VMDIR_SAFE_FREE_MEMORY(pszLocalErrMsg); return retVal; error: VMDIR_SET_LDAP_RESULT_ERROR(&pOperation->ldapResult, retVal, pszLocalErrMsg); goto cleanup; }