Esempio n. 1
0
static
DWORD
_VmDirRidSyncThr(
    PVOID    pArg
    )
{
    DWORD               dwError = 0;
    BOOLEAN             bInLock = FALSE;
    PVDIR_THREAD_INFO   pThrInfo = (PVDIR_THREAD_INFO)pArg;
    PVMDIR_SID_GEN_STACK_NODE pSidGenStackNode = NULL;

    VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL, "_VmDirRidSyc thr started" );

    while (1)
    {
        if (VmDirdState() == VMDIRD_STATE_SHUTDOWN)
        {
            goto cleanup;
        }

        VMDIR_SAFE_FREE_MEMORY(pSidGenStackNode);
        while (VmDirPopTSStack(gSidGenState.pStack, (PVOID*)&pSidGenStackNode) == 0 &&
               pSidGenStackNode != NULL)
        {
            (VOID)VmDirSyncRIDSeqToDB(
                    pSidGenStackNode->pszDomainDn,
                    pSidGenStackNode->dwDomainRidSequence);

            if (VmDirdState() == VMDIRD_STATE_SHUTDOWN)
            {
                //
                // Any pending updates will be performed by VmDirVmAclShutdown.
                //
                goto cleanup;
            }

            VMDIR_SAFE_FREE_MEMORY(pSidGenStackNode);
        }

        VMDIR_LOCK_MUTEX(bInLock, pThrInfo->mutexUsed);

        VmDirConditionTimedWait(
            pThrInfo->conditionUsed,
            pThrInfo->mutexUsed,
            3 * 1000);          // time wait 3 seconds
        // ignore error

        VMDIR_UNLOCK_MUTEX(bInLock, pThrInfo->mutexUsed);
    }

cleanup:

    VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL, "_VmDirRidSyc thr stopped (%d)", dwError );

    VMDIR_SAFE_FREE_MEMORY(pSidGenStackNode);

    return dwError;
}
Esempio n. 2
0
DWORD
VmDirIndexCfgMap(
    PLW_HASHMAP*    ppIndexCfgMap
    )
{
    DWORD   dwError = 0;
    VDIR_SERVER_STATE   vmdirState = VmDirdState();

    if (!ppIndexCfgMap)
    {
        dwError = VMDIR_ERROR_INVALID_PARAMETER;
        BAIL_ON_VMDIR_ERROR(dwError);
    }

    if (vmdirState != VMDIRD_STATE_STARTUP)
    {
        dwError = VMDIR_ERROR_UNWILLING_TO_PERFORM;
        BAIL_ON_VMDIR_ERROR(dwError);
    }

    *ppIndexCfgMap = gVdirIndexGlobals.pIndexCfgMap;

error:
    return dwError;
}
Esempio n. 3
0
/*
 * Waits until there's data from the worker thread to read (or until the
 * server's shutdown).
 */
static
DWORD
_VmDirPagedSearchCacheWaitAndRead_inlock(
    PVDIR_PAGED_SEARCH_RECORD pSearchRecord,
    PVDIR_PAGED_SEARCH_ENTRY_LIST *ppEntryList
    )
{
    DWORD dwError = 0;
    PVDIR_PAGED_SEARCH_ENTRY_LIST pEntryList = NULL;

    while (TRUE)
    {
        dwError = dequePopLeft(pSearchRecord->pQueue, (PVOID*)&pEntryList);
        if (dwError == 0)
        {
            break;
        }
        else if (pSearchRecord->bProcessingCompleted)
        {
            //
            // Nothing in the queue and processing's complete so we must have
            // read all the data.
            //
            pSearchRecord->bSearchCompleted = TRUE;
            dwError = 0;
            break;
        }
        else
        {
            (VOID)VmDirConditionTimedWait(
                    pSearchRecord->pDataAvailable,
                    pSearchRecord->mutex,
                    VMDIR_PSCACHE_READ_TIMEOUT);
        }

        if (VmDirdState() == VMDIRD_STATE_SHUTDOWN)
        {
            BAIL_WITH_VMDIR_ERROR(dwError, VMDIR_ERROR_UNAVAILABLE);
        }
    }

    *ppEntryList = pEntryList;

    pSearchRecord->tLastClientRead = time(NULL);

cleanup:
    return dwError;
error:
    goto cleanup;
}
Esempio n. 4
0
/*
 * Thread to handle db checkpoint and log file aging.
 * 1.  it sleep for x (configurable) minutes.
 * 2.  check how long ago was lost check point
 * 2.1   if longer than y (configurable) minutes then check point
 *
 */
static
DWORD
VmDirBdbCheckpointThrFun(
    PVOID   pArg
    )
{
    DWORD   dwError = 0;
    int     iCFGChkpointIntervalinMIN = 0;
    int     iCFGCheckpointSizeinKB = 0;
    int     iCFGLogAgingIntervalInMIN = 0;

    time_t  tLastLogAge = time(NULL);
    PVDIR_THREAD_INFO   pThrInfo = (PVDIR_THREAD_INFO)pArg;

    //TODO, make this configurable (or even changeable during online)
    iCFGChkpointIntervalinMIN = 3;
    iCFGCheckpointSizeinKB = 100;
    iCFGLogAgingIntervalInMIN = 360;

    while (1)
    {
        struct timespec ts = {0};
        BOOLEAN bInLock = FALSE;

        ts.tv_sec = time(NULL) + (iCFGChkpointIntervalinMIN * 60);
        ts.tv_nsec = 0;

        VMDIR_LOCK_MUTEX(bInLock, pThrInfo->mutexUsed);

        dwError = VmDirConditionTimedWait(
                pThrInfo->conditionUsed,
                pThrInfo->mutexUsed,
                (iCFGChkpointIntervalinMIN * 60)*1000);

        VMDIR_UNLOCK_MUTEX(bInLock, pThrInfo->mutexUsed);

        if (VmDirdState() == VMDIR_SHUTDOWN)
        {
            break;
        }

        // ignore dwError == ETIMEOUT check as rare case and benign checkpoint

        dwError = gVdirBdbGlobals.bdbEnv->txn_checkpoint(
                gVdirBdbGlobals.bdbEnv,
                iCFGCheckpointSizeinKB,
                iCFGChkpointIntervalinMIN ,
                0);
        BAIL_ON_VMDIR_ERROR(dwError);
        VmDirLog( LDAP_DEBUG_TRACE, "Bdb: checkpoint" );

        if (ts.tv_sec - tLastLogAge > (iCFGLogAgingIntervalInMIN * 60))
        {
            dwError = bdbLogfileAging();
            BAIL_ON_VMDIR_ERROR(dwError);

            tLastLogAge = ts.tv_sec;
        }
    }

cleanup:

    // TODO: return dwError ?
    return 0;

error:

    raise(SIGTERM);

    goto cleanup;
}
Esempio n. 5
0
static
DWORD
vmdirConnAccept(
    Sockbuf_IO*         pSockbuf_IO,
    DWORD               dwPort,
    BOOLEAN             bIsLdaps
    )
{
    ber_socket_t         newsockfd = -1;
    int                  retVal = LDAP_SUCCESS;
    ber_socket_t         ip4_fd = -1;
    ber_socket_t         ip6_fd = -1;
    ber_socket_t         max_fd = -1;
    VMDIR_THREAD         threadId;
    BOOLEAN              bInLock = FALSE;
    int                  iLocalLogMask = 0;
    PVDIR_CONNECTION_CTX pConnCtx = NULL;
    fd_set               event_fd_set;
    fd_set               poll_fd_set;
    struct timeval       timeout = {0};

    // Wait for ***1st*** replication cycle to be over.
    if (gVmdirServerGlobals.serverId == 0) // instance has not been initialized
    {
        VMDIR_LOG_WARNING( VMDIR_LOG_MASK_ALL, "Connection accept thread: Have NOT yet started listening on LDAP port (%u),"
                  " waiting for the 1st replication cycle to be over.", dwPort);

        VMDIR_LOCK_MUTEX(bInLock, gVmdirGlobals.replCycleDoneMutex);
        // wait till 1st replication cycle is over
        if (VmDirConditionWait( gVmdirGlobals.replCycleDoneCondition, gVmdirGlobals.replCycleDoneMutex ) != 0)
        {
            VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "Connection accept thread: VmDirConditionWait failed." );
            retVal = LDAP_OPERATIONS_ERROR;
            goto cleanup;
        }
        // also wake up the other (normal LDAP port/SSL LDAP port listner) LDAP connection accept thread,
        // waiting on 1st replication cycle to be over
        // BUGBUG Does not handle spurious wake up
        VmDirConditionSignal(gVmdirGlobals.replCycleDoneCondition);
        VMDIR_UNLOCK_MUTEX(bInLock, gVmdirGlobals.replCycleDoneMutex);

        if (VmDirdState() == VMDIRD_STATE_SHUTDOWN) // Asked to shutdown before we started accepting
        {
            goto cleanup;
        }

        VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "Connection accept thread: listening on LDAP port (%u).", dwPort);
    }

    iLocalLogMask = VmDirLogGetMask();
    ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &iLocalLogMask);

    SetupLdapPort(dwPort, &ip4_fd, &ip6_fd);
    if (ip4_fd < 0 && ip6_fd < 0)
    {
        VmDirSleep(1000);
        goto cleanup;
    }

    FD_ZERO(&event_fd_set);
    if (ip4_fd >= 0)
    {
        FD_SET (ip4_fd, &event_fd_set);
        if (ip4_fd > max_fd)
        {
            max_fd = ip4_fd;
        }
    }

    if (ip6_fd >= 0)
    {
        FD_SET (ip6_fd, &event_fd_set);
        if (ip6_fd > max_fd)
        {
            max_fd = ip6_fd;
        }
    }

    retVal = VmDirSyncCounterIncrement(gVmdirGlobals.pPortListenSyncCounter);
    if (retVal != 0 )
    {
        VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "%s: VmDirSyncCounterIncrement(gVmdirGlobals.pPortListenSyncCounter) returned error", __func__);
        BAIL_ON_VMDIR_ERROR(retVal);
    }

    while (TRUE)
    {
        if (VmDirdState() == VMDIRD_STATE_SHUTDOWN)
        {
            goto cleanup;
        }

        poll_fd_set = event_fd_set;
        timeout.tv_sec = 3;
        timeout.tv_usec = 0;
        retVal = select ((int)max_fd+1, &poll_fd_set, NULL, NULL, &timeout);
        if (retVal < 0 )
        {
#ifdef _WIN32
            errno = WSAGetLastError();
#endif
            VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s: select() (port %d) call failed: %d.", __func__, dwPort, errno);
            VmDirSleep( 1000 );
            continue;
        } else if (retVal == 0)
        {
            //VMDIR_LOG_INFO( LDAP_DEBUG_CONNS, "%s: select() timeout (port %d)", __func__, dwPort);
            continue;
        }

        if (ip4_fd >= 0 && FD_ISSET(ip4_fd, &poll_fd_set))
        {
            newsockfd = accept(ip4_fd, (struct sockaddr *) NULL, NULL);
        } else if (ip6_fd >= 0 && FD_ISSET(ip6_fd, &poll_fd_set))
        {
            newsockfd = accept(ip6_fd, (struct sockaddr *) NULL, NULL);
        } else
        {
            VMDIR_LOG_INFO( LDAP_DEBUG_CONNS, "%s: select() returned with no data (port %d), return: %d",
                            __func__, dwPort, retVal);
            continue;
        }

        if (newsockfd < 0)
        {
#ifdef _WIN32
            errno = WSAGetLastError();
#endif
            if (errno != EAGAIN && errno != EWOULDBLOCK )
            {
                VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s: accept() (port %d) failed with errno: %d.",
                                 __func__, dwPort, errno );
            }
            continue;
        }

        if ( _VmDirFlowCtrlThrEnter() == TRUE )
        {
            tcp_close(newsockfd);
            newsockfd = -1;
            VMDIR_LOG_WARNING( VMDIR_LOG_MASK_ALL, "Maxmimum number of concurrent LDAP threads reached. Blocking new connection" );

            continue;
        }

        retVal = VmDirAllocateMemory(
                sizeof(VDIR_CONNECTION_CTX),
                (PVOID*)&pConnCtx);
        BAIL_ON_VMDIR_ERROR(retVal);

        pConnCtx->sockFd  = newsockfd;
        newsockfd = -1;
        pConnCtx->pSockbuf_IO = pSockbuf_IO;

        retVal = VmDirCreateThread(&threadId, TRUE, ProcessAConnection, (PVOID)pConnCtx);
        if (retVal != 0)
        {
            VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s: VmDirCreateThread() (port) failed with errno: %d",
                             __func__, dwPort, errno );

            tcp_close(pConnCtx->sockFd);
            _VmDirFlowCtrlThrExit();
            VMDIR_SAFE_FREE_MEMORY(pConnCtx);
            continue;
        }
        else
        {
            pConnCtx = NULL; //thread take ownership on pConnCtx
            VmDirFreeVmDirThread(&threadId);
        }
    }

cleanup:

    VMDIR_UNLOCK_MUTEX(bInLock, gVmdirGlobals.replCycleDoneMutex);

    if (ip4_fd >= 0)
    {
        tcp_close(ip4_fd);
    }
    if (ip6_fd >= 0)
    {
        tcp_close(ip6_fd);
    }
    if (newsockfd >= 0)
    {
        tcp_close(newsockfd);
    }
#ifndef _WIN32
    raise(SIGTERM);
#endif

    VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "%s: Connection accept thread: stop (port %d)", __func__, dwPort);

    return retVal;

error:
    goto cleanup;
}
Esempio n. 6
0
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;
}
Esempio n. 7
0
static
int
VmDirProcessCandidateList(
    VDIR_OPERATION * pOperation
    )
{
    int               retVal = LDAP_SUCCESS;
    int               i = 0;
    VDIR_CANDIDATES * cl = pOperation->request.searchReq.filter->candidates;
    VDIR_ENTRY        srEntry = {0};
    VDIR_ENTRY *      pSrEntry = NULL;
    int               numSentEntries = 0;
    BOOLEAN           bExternalSearch = FALSE;
    BOOLEAN           bInternalSearch = FALSE;
    BOOLEAN           bStoreRsltInMem = FALSE;
    BOOLEAN           bPageResultsCtrl = FALSE;
    DWORD             dwPageSize = 0;
    ENTRYID           lastEID = 0;

    /*
     * If the page size is greater than or equal to the sizeLimit value,
     * the server should ignore the control as the request can be satisfied in a single page.
     */
    if (pOperation->showPagedResultsCtrl && (pOperation->request.searchReq.sizeLimit == 0 ||
        pOperation->showPagedResultsCtrl->value.pagedResultCtrlVal.pageSize < (DWORD)pOperation->request.searchReq.sizeLimit))
    {
        VmDirLog( LDAP_DEBUG_TRACE, "showPagedResultsCtrl applies to this query." );

        bPageResultsCtrl = TRUE;
        dwPageSize = pOperation->showPagedResultsCtrl->value.pagedResultCtrlVal.pageSize;
        lastEID = atoll(pOperation->showPagedResultsCtrl->value.pagedResultCtrlVal.cookie);
        pOperation->showPagedResultsCtrl->value.pagedResultCtrlVal.cookie[0] = '\0';

        VmDirSortCandidateList(cl);  // sort candidate list if not yet sorted
    }

    bExternalSearch = pOperation->opType == VDIR_OPERATION_TYPE_EXTERNAL;
    bInternalSearch = pOperation->opType == VDIR_OPERATION_TYPE_INTERNAL;
    bStoreRsltInMem = pOperation->request.searchReq.bStoreRsltInMem;

    if (cl && cl->size > 0)
    {
        if (bInternalSearch || bStoreRsltInMem)
        {   //TODO, we should have a hard limit on the cl->size we handle
            VmDirFreeEntryArrayContent(&pOperation->internalSearchEntryArray);
            retVal = VmDirAllocateMemory(   sizeof(VDIR_ENTRY) * cl->size,
                                            (PVOID*)&pOperation->internalSearchEntryArray.pEntry);
            BAIL_ON_VMDIR_ERROR(retVal);
        }

        for (i = 0, numSentEntries = 0;
             (i < cl->size) &&
             (pOperation->request.searchReq.sizeLimit == 0 /* unlimited */ ||
              numSentEntries < pOperation->request.searchReq.sizeLimit);
             i++)
        {
            if (bExternalSearch &&
                VmDirdState() == VMDIRD_STATE_SHUTDOWN &&
                pOperation->syncReqCtrl == NULL)
            {
                retVal = LDAP_UNAVAILABLE; // stop all external search ops, except replication pull
                goto cleanup;
            }

            if (!gVmdirGlobals.bPagedSearchReadAhead)
            {
                //skip entries we sent before in sorted cl->eIds.
                if (bPageResultsCtrl && cl->eIds[i] <= lastEID)
                {
                    continue;
                }
            }

            pSrEntry = bInternalSearch || bStoreRsltInMem ?
                        (pOperation->internalSearchEntryArray.pEntry + pOperation->internalSearchEntryArray.iSize) : &srEntry;

            retVal = pOperation->pBEIF->pfnBEIdToEntry(
                        pOperation->pBECtx,
                        pOperation->pSchemaCtx,
                        cl->eIds[i],
                        pSrEntry,
                        VDIR_BACKEND_ENTRY_LOCK_READ);

            if (retVal)
            {
                // Ignore BdbEIdToEntry errors.
                VMDIR_LOG_WARNING( VMDIR_LOG_MASK_ALL,
                        "ProcessCandiateList BEIdToEntry EID(%u), error (%u)",
                        cl->eIds[i], retVal);

                continue;
            }

            if (CheckIfEntryPassesFilter(pOperation, pSrEntry, pOperation->request.searchReq.filter) == FILTER_RES_TRUE)
            {
                BOOLEAN bSendEntry = TRUE;
                CHAR    sha1Digest[SHA_DIGEST_LENGTH] = {0};

                retVal = VmDirBuildComputedAttribute( pOperation, pSrEntry );
                BAIL_ON_VMDIR_ERROR( retVal );

                if (pOperation->digestCtrl)
                {
                    retVal = VmDirEntrySHA1Digest(pSrEntry, sha1Digest);
                    BAIL_ON_VMDIR_ERROR(retVal);

                    if (memcmp(sha1Digest, pOperation->digestCtrl->value.digestCtrlVal.sha1Digest, SHA_DIGEST_LENGTH) == 0)
                    {
                        bSendEntry = FALSE;
                        VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL,"%s digest match %s",
                                           __FUNCTION__, pSrEntry->dn.lberbv.bv_val);
                    }
                    else
                    {
                        VMDIR_LOG_VERBOSE( VMDIR_LOG_MASK_ALL,"%s digest mismatch %s",
                                           __FUNCTION__, pSrEntry->dn.lberbv.bv_val);
                    }
                }

                if (bSendEntry)
                {
                    retVal = VmDirSendSearchEntry(pOperation, pSrEntry);
                    if (retVal == VMDIR_ERROR_INSUFFICIENT_ACCESS)
                    {
                        VMDIR_LOG_WARNING( VMDIR_LOG_MASK_ALL,
                                "Access deny on search entry result [%s,%d] (bindedDN-%s) (targetDn-%s)\n",
                                __FILE__,
                                __LINE__,
                                pOperation->conn->AccessInfo.pszBindedDn,
                                pSrEntry->dn.lberbv.bv_val);
                        // make sure search continues
                        retVal = 0;
                    }
                    BAIL_ON_VMDIR_ERROR( retVal );

                    if (pSrEntry->bSearchEntrySent)
                    {
                        numSentEntries++;
                        if (bInternalSearch || bStoreRsltInMem)
                        {
                            pOperation->internalSearchEntryArray.iSize++;
                            pSrEntry = NULL;    // EntryArray takes over *pSrEntry content

                            if (pOperation->internalSearchEntryArray.iSize > gVmdirServerGlobals.dwMaxInternalSearchLimit)
                            {
                                BAIL_WITH_VMDIR_ERROR(retVal, VMDIR_ERROR_INTERNAL_SEARCH_LIMIT);
                            }
                        }
                    }
                }
            }

            //We have sent one page size of entries, so we can break here
            if (bPageResultsCtrl && numSentEntries == dwPageSize)
            {
                retVal = SetPagedSearchCookie(pOperation, cl->eIds[i], i);
                BAIL_ON_VMDIR_ERROR(retVal);
                break;
            }

            VmDirFreeEntryContent( pSrEntry );
            pSrEntry = NULL; // Reset to NULL so that DeleteEntry is no-op.
        }

        VMDIR_LOG_VERBOSE( LDAP_DEBUG_FILTER, "(%d) candiates processed and (%d) entries sent", cl->size, numSentEntries);
    }

    if ( pOperation->request.searchReq.sizeLimit && numSentEntries < pOperation->request.searchReq.sizeLimit &&
         pOperation->pBECtx->iPartialCandidates)
    {
        retVal = LDAP_UNWILLING_TO_PERFORM;
        VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "ProcessCandiateList may return none or paritial requested entries with sizelimit %d",
                        pOperation->request.searchReq.sizeLimit);
    }

#ifndef REPLICATION_V2
    retVal = VmDirUpdateSyncDoneCtl(
            pOperation,
            numSentEntries);
    BAIL_ON_VMDIR_ERROR(retVal);
#endif

cleanup:
    pOperation->dwSentEntries = numSentEntries;
    VmDirFreeEntryContent(pSrEntry);
    return retVal;

error:
    VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "ProcessCandiateList failed. (%u)", retVal);
    goto cleanup;
}
Esempio n. 8
0
DWORD
VmDirIndexingThreadFun(
    PVOID   pArg
    )
{
    DWORD   dwError = 0;
    BOOLEAN bInLock = FALSE;
    BOOLEAN bResume = FALSE;
    VDIR_SERVER_STATE   vmdirState = VMDIRD_STATE_UNDEFINED;
    PVDIR_INDEXING_TASK pTask = NULL;

    VmDirDropThreadPriority(DEFAULT_THREAD_PRIORITY_DELTA);

resume:
    while (1)
    {
        vmdirState = VmDirdState();
        if (vmdirState == VMDIRD_STATE_SHUTDOWN)
        {
            break;
        }
        else if (vmdirState != VMDIRD_STATE_NORMAL)
        {
            VmDirSleep(1000);
            continue;
        }

        VMDIR_LOCK_MUTEX(bInLock, gVdirIndexGlobals.mutex);

        if (!bResume)
        {
            PVDIR_INDEX_UPD pIndexUpd = gVdirIndexGlobals.pIndexUpd;

            // record current progress
            dwError = VmDirIndexingTaskRecordProgress(pTask, pIndexUpd);
            BAIL_ON_VMDIR_ERROR(dwError);

            // apply index updates
            dwError = VmDirIndexUpdApply(pIndexUpd);
            BAIL_ON_VMDIR_ERROR(dwError);

            VmDirIndexUpdFree(pIndexUpd);
            gVdirIndexGlobals.pIndexUpd = NULL;

            // compute new task
            VmDirFreeIndexingTask(pTask);
            dwError = VmDirIndexingTaskCompute(&pTask);
            BAIL_ON_VMDIR_ERROR(dwError);
        }

        if (VmDirIndexingTaskIsNoop(pTask))
        {
            dwError = VmDirConditionWait(
                    gVdirIndexGlobals.cond,
                    gVdirIndexGlobals.mutex);
            BAIL_ON_VMDIR_ERROR(dwError);

            continue;
        }

        VMDIR_UNLOCK_MUTEX(bInLock, gVdirIndexGlobals.mutex);

        dwError = VmDirIndexingTaskPopulateIndices(pTask);
        BAIL_ON_VMDIR_ERROR(dwError);

        dwError = VmDirIndexingTaskValidateScopes(pTask);
        BAIL_ON_VMDIR_ERROR(dwError);

        dwError = VmDirIndexingTaskDeleteIndices(pTask);
        BAIL_ON_VMDIR_ERROR(dwError);
        bResume = FALSE;
    }

cleanup:
    VMDIR_UNLOCK_MUTEX(bInLock, gVdirIndexGlobals.mutex);
    VmDirFreeIndexingTask(pTask);
    return dwError;

error:
    if (dwError == ERROR_INVALID_STATE)
    {
        bResume = TRUE;
        goto resume;
    }
    else
    {
        VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL,
                "%s failed, error (%d)", __FUNCTION__, dwError );
    }
    goto cleanup;
}
Esempio n. 9
0
/*
 * This thread waits on gVdirAttrIndexGlobals.condition and spawns worker thread
 * to perform indexing in the back ground.
 */
static
DWORD
vdirIndexingThrFun(
    PVOID   pArg
)
{
    DWORD   dwError = 0;
    BOOLEAN bInLock = FALSE;
    PVDIR_CFG_ATTR_INDEX_DESC*  ppIndexDesc = NULL;
    PVDIR_THREAD_INFO           pThrInfo = (PVDIR_THREAD_INFO)pArg;

    while (1)
    {
        DWORD   dwCnt = 0;
        DWORD   dwSize = 0;
        VMDIR_THREAD  tid = {0};
        PVDIR_ATTR_INDEX_INSTANCE pCache = NULL;

        memset(&tid, 0, sizeof(tid));

        // wait till new indices are created
        VMDIR_LOCK_MUTEX(bInLock, gVdirAttrIndexGlobals.mutex);

        dwError = VmDirConditionWait(
                      pThrInfo->conditionUsed,
                      pThrInfo->mutexUsed);
        BAIL_ON_VMDIR_ERROR(dwError);

        // get new cache we want to enable
        pCache = gVdirAttrIndexGlobals.pNewCache;

        VMDIR_UNLOCK_MUTEX(bInLock, gVdirAttrIndexGlobals.mutex);

        if (VmDirdState() == VMDIRD_STATE_SHUTDOWN)
        {
            break;
        }

        if (!pCache)
        {
            continue;
        }

        // get number of indices in building status
        for (dwCnt = 0, dwSize = 0; dwCnt < pCache->usNumIndex; dwCnt++)
        {
            if (pCache->pSortName[dwCnt].status == VDIR_CFG_ATTR_INDEX_BUILDING)
            {
                dwSize++;
            }
        }

        if (dwSize == 0)
        {
            continue;
        }

        dwError  = VmDirAllocateMemory(
                       sizeof(PVDIR_CFG_ATTR_INDEX_DESC) * (dwSize + 1),  // +1 for NULL ending
                       (PVOID)&ppIndexDesc);
        BAIL_ON_VMDIR_ERROR(dwError);

        // fill ppIndexDesc with building index
        // NOTE, ppIndexDesc does NOT own them; pCache does.
        for (dwCnt = 0, dwSize = 0; dwCnt < pCache->usNumIndex; dwCnt++)
        {
            if (pCache->pSortName[dwCnt].status == VDIR_CFG_ATTR_INDEX_BUILDING)
            {
                ppIndexDesc[dwSize] = &pCache->pSortName[dwCnt];
                dwSize++;
            }
        }

        // TODO, detach thr now, need to join to safely finish bdb io...
        dwError = VmDirCreateThread(
                      &tid,
                      TRUE,
                      vdirIndexingWorkerThrFun,
                      (PVOID)ppIndexDesc);
        BAIL_ON_VMDIR_ERROR(dwError);
        // worker takes over ppIndexDesc.
        ppIndexDesc = NULL;

        VmDirFreeVmDirThread(&tid);
    }

cleanup:

    VMDIR_UNLOCK_MUTEX(bInLock, gVdirAttrIndexGlobals.mutex);

    // TODO: should be dwError?
    return 0;

error:

    VMDIR_SAFE_FREE_MEMORY(ppIndexDesc);

    //TODO, should we stop vmdird?

    VmDirLog( LDAP_DEBUG_ANY, "VmdirIndexingThr: error stop" );

    goto cleanup;
}
Esempio n. 10
0
/* VmDirInternalDeleteEntry: Interface that can be used "internally" by the server code. One of the main differences between
 * this function and MLDelete 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
VmDirInternalDeleteEntry(
    PVDIR_OPERATION    pOperation
    )
{
    int             retVal = LDAP_SUCCESS;
    int             deadLockRetries = 0;
    VDIR_ENTRY      entry = {0};
    PVDIR_ENTRY     pEntry = NULL;
    BOOLEAN         leafNode = FALSE;
    DeleteReq *     delReq = &(pOperation->request.deleteReq);
    ModifyReq *     modReq = &(pOperation->request.modifyReq);
    BOOLEAN         bIsDomainObject = FALSE;
    BOOLEAN         bHasTxn = FALSE;
    PSTR            pszLocalErrMsg = NULL;

    assert(pOperation && pOperation->pBECtx->pBE);

    if (VmDirdState() == VMDIRD_STATE_READ_ONLY)
    {
        retVal = VMDIR_ERROR_UNWILLING_TO_PERFORM;
        BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "Server in read-only mode" );
    }

    // Normalize DN
    retVal = VmDirNormalizeDN( &(delReq->dn), pOperation->pSchemaCtx );
    BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "DN normalization failed - (%u)(%s)",
                                  retVal, VDIR_SAFE_STRING(VmDirSchemaCtxGetErrorMsg(pOperation->pSchemaCtx)) );

    if (pOperation->opType != VDIR_OPERATION_TYPE_REPL)
    {
        // Execute pre modify apply Delete plugin logic
        retVal = VmDirExecutePreModApplyDeletePlugins(pOperation, NULL, retVal);
        BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "PreModApplyDelete plugin failed - (%u)",  retVal );
    }

    retVal = VmDirNormalizeMods( pOperation->pSchemaCtx, modReq->mods, &pszLocalErrMsg );
    BAIL_ON_VMDIR_ERROR( retVal );

    // make sure VDIR_BACKEND_CTX has usn change number by now
    if ( pOperation->pBECtx->wTxnUSN <= 0 )
    {
        retVal = VMDIR_ERROR_NO_USN;
        BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "BECtx.wTxnUSN not set");
    }

    // BUGBUG, need to protect some system entries such as schema,domain....etc?

    // ************************************************************************************
    // transaction retry loop begin.  make sure all function within are retry agnostic.
    // ************************************************************************************
txnretry:
    if (bHasTxn)
    {
        pOperation->pBEIF->pfnBETxnAbort( pOperation->pBECtx );
        bHasTxn = FALSE;
    }

    deadLockRetries++;
    if (deadLockRetries > MAX_DEADLOCK_RETRIES)
    {
        retVal = VMDIR_ERROR_LOCK_DEADLOCK;
        BAIL_ON_VMDIR_ERROR( retVal );
    }
    else
    {
        if (pEntry)
        {
            VmDirFreeEntryContent(pEntry);
            memset(pEntry, 0, sizeof(VDIR_ENTRY));
            pEntry = NULL;
        }

        retVal = pOperation->pBEIF->pfnBETxnBegin( pOperation->pBECtx, VDIR_BACKEND_TXN_WRITE);
        BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "txn begin (%u)(%s)",
                                      retVal, VDIR_SAFE_STRING(pOperation->pBEErrorMsg));
        bHasTxn = TRUE;

        // Read current entry from DB
        retVal = pOperation->pBEIF->pfnBEDNToEntry(
                                    pOperation->pBECtx,
                                    pOperation->pSchemaCtx,
                                    &(delReq->dn),
                                    &entry,
                                    VDIR_BACKEND_ENTRY_LOCK_WRITE);
        if (retVal != 0)
        {
            switch (retVal)
            {
                case VMDIR_ERROR_BACKEND_DEADLOCK:
                    goto txnretry; // Possible retry.

                default:
                    BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "(%u)(%s)",
                                                  retVal, VDIR_SAFE_STRING(pOperation->pBEErrorMsg));
            }
        }

        pEntry = &entry;

        // Parse Parent DN
        retVal = VmDirGetParentDN( &pEntry->dn, &pEntry->pdn );
        BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "Get ParentDn failed - (%u)",  retVal );

        // get parent entry
        if (pEntry->pdn.lberbv.bv_val)
        {
            PVDIR_ENTRY     pParentEntry = NULL;

            retVal = VmDirAllocateMemory(sizeof(*pEntry), (PVOID)&pParentEntry);
            BAIL_ON_VMDIR_ERROR(retVal);

            retVal = pOperation->pBEIF->pfnBEDNToEntry(
                                        pOperation->pBECtx,
                                        pOperation->pSchemaCtx,
                                        &pEntry->pdn,
                                        pParentEntry,
                                        VDIR_BACKEND_ENTRY_LOCK_READ);
            if (retVal)
            {
                VmDirFreeEntryContent(pParentEntry);
                VMDIR_SAFE_FREE_MEMORY(pParentEntry);

                switch (retVal)
                {
                    case VMDIR_ERROR_BACKEND_DEADLOCK:
                        goto txnretry; // Possible retry.

                    case VMDIR_ERROR_BACKEND_ENTRY_NOTFOUND:
                        BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "parent (%s) not found, (%s)",
                                                      pEntry->pdn.lberbv_val,
                                                      VDIR_SAFE_STRING(pOperation->pBEErrorMsg) );

                    default:
                        BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "parent (%s) lookup failed, (%s)",
                                                      pEntry->pdn.lberbv_val,
                                                      VDIR_SAFE_STRING(pOperation->pBEErrorMsg) );
                }
            }

            pEntry->pParentEntry = pParentEntry;        // pEntry takes over pParentEntry
            pParentEntry = NULL;
        }

        // SJ-TBD: Once ACLs are enabled, following check should go in ACLs logic.
        if (VmDirIsInternalEntry( pEntry ) || VmDirIsProtectedEntry(pEntry))
        {
            retVal = VMDIR_ERROR_UNWILLING_TO_PERFORM;
            BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "An internal entry (%s) can NOT be deleted.",
                                          pEntry->dn.lberbv_val );
        }

        // only when there is parent Entry, ACL check is done
        if (pEntry->pParentEntry)
        {
            retVal = VmDirSrvAccessCheck( pOperation, &pOperation->conn->AccessInfo, pEntry->pParentEntry,
                                          VMDIR_RIGHT_DS_DELETE_CHILD);
            BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "VmDirSrvAccessCheck failed - (%u)(%s)",
                                          retVal, VMDIR_ACCESS_DENIED_ERROR_MSG);
        }

        // Make sure it is a leaf node
        retVal = pOperation->pBEIF->pfnBEChkIsLeafEntry(
                                pOperation->pBECtx,
                                pEntry->eId,
                                &leafNode);
        BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "BEChkIsLeafEntry failed, (%u)(%s)",
                                      retVal, VDIR_SAFE_STRING(pOperation->pBEErrorMsg) );

        if (leafNode == FALSE)
        {
            retVal = VMDIR_ERROR_NOT_ALLOWED_ON_NONLEAF;
            BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "Delete of a non-leaf node is not allowed." );
        }

        // Retrieve to determine whether it is domain object earlier
        // before attribute modifications
        // ('bIsDomainObject' is needed for a domain object deletion)
        retVal = VmDirIsDomainObjectWithEntry(pEntry, &bIsDomainObject);
        BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg,
                                      "VmDirIsDomainObjectWithEntry failed - (%u)", retVal );

        if (pOperation->opType != VDIR_OPERATION_TYPE_REPL)
        {
            // Generate mods to delete attributes that need not be present in a DELETED entry
            // Note: in case of executing the deadlock while loop multiple times, same attribute Delete mod be added
            // multiple times in the modReq, which is expected to work correctly.
            retVal = GenerateDeleteAttrsMods( pOperation, pEntry );
            BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "GenerateDeleteAttrsMods failed - (%u)", retVal);

            // Generate new meta-data for the attributes being updated
            if ((retVal = VmDirGenerateModsNewMetaData( pOperation, modReq->mods, pEntry->eId )) != 0)
            {

                switch (retVal)
                {
                    case VMDIR_ERROR_LOCK_DEADLOCK:
                        goto txnretry; // Possible retry.  BUGBUG, is modReq->mods in above call good for retry?

                    default:
                        BAIL_ON_VMDIR_ERROR( retVal );
                }
            }
        }

        // Normalize attribute values in mods
        retVal = VmDirNormalizeMods( pOperation->pSchemaCtx, modReq->mods, &pszLocalErrMsg );
        BAIL_ON_VMDIR_ERROR( retVal );

        // Apply modify operations to the current entry in the DB.
        retVal = VmDirApplyModsToEntryStruct( pOperation->pSchemaCtx, modReq, pEntry, &pszLocalErrMsg );
        BAIL_ON_VMDIR_ERROR( retVal );

        // Update DBs

        // Update Entry
        retVal = pOperation->pBEIF->pfnBEEntryDelete( pOperation->pBECtx, modReq->mods, pEntry );
        if (retVal != 0)
        {
            switch (retVal)
            {
                case VMDIR_ERROR_BACKEND_DEADLOCK:
                    goto txnretry; // Possible retry.

                default:
                    BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "BEEntryDelete (%u)(%s)",
                                                  retVal, VDIR_SAFE_STRING(pOperation->pBEErrorMsg));
            }
        }

        retVal = DeleteRefAttributesValue(pOperation, &(pEntry->dn));
        if (retVal != 0)
        {
            switch (retVal)
            {
                case VMDIR_ERROR_LOCK_DEADLOCK:
                    goto txnretry; // Possible retry.

                default:
                    BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "BEEntryDelete (%u)(%s)",
                                                  retVal, VDIR_SAFE_STRING(pOperation->pBEErrorMsg));
            }

        }

        // Use normalized DN value
        if (bIsDomainObject)
        {
            retVal = VmDirInternalRemoveOrgConfig(pOperation,
                                                  BERVAL_NORM_VAL(pEntry->dn));
            BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "Update domain list entry failed." );
        }

        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;
    }
    // ************************************************************************************
    // transaction retry loop end.
    // ************************************************************************************

    VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "Delete Entry (%s)", VDIR_SAFE_STRING(pEntry->dn.lberbv_val));

    // Post delete entry
    // TODO, make it into a separate file deletePlugin.c
    // clean lockout cache record if exists
    VdirLockoutCacheRemoveRec(pEntry->dn.bvnorm_val);

cleanup:

    if (pOperation->opType != VDIR_OPERATION_TYPE_REPL)
    {
        if (retVal == LDAP_SUCCESS)
        {
            int iPostCommitPluginRtn  = 0;

            // Execute post Delete commit plugin logic
            iPostCommitPluginRtn = VmDirExecutePostDeleteCommitPlugins(pOperation, pEntry, retVal);
            if ( iPostCommitPluginRtn != LDAP_SUCCESS
                 &&
                 iPostCommitPluginRtn != pOperation->ldapResult.errCode    // pass through
               )
            {
                VmDirLog( LDAP_DEBUG_ANY, "InternalDeleteEntry: VdirExecutePostDeleteCommitPlugins - code(%d)",
                          iPostCommitPluginRtn);
            }
        }

        // In case of replication, modReq is owned by the Replication thread/logic
        DeleteMods ( modReq );
    }
    VmDirFreeEntryContent ( &entry );

    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;
}
Esempio n. 11
0
int
main(
   int     argc,
   char  * argv[])
{
    DWORD        dwError = 0;
    const char * logFileName = NULL;
    const char * pszBootstrapSchemaFile = NULL;
    const char * pszStateDir = VMDIR_DB_DIR VMDIR_PATH_SEP;
    BOOLEAN      bEnableSysLog = FALSE;
    BOOLEAN      bConsoleMode = FALSE;
    int          iLocalLogMask = 0;
    BOOLEAN      bVmDirInit = FALSE;
    BOOLEAN      bShutdownKDCService = FALSE;
    BOOLEAN      bWaitTimeOut = FALSE;

    dwError = VmDirSrvUpdateConfig();
    BAIL_ON_VMDIR_ERROR(dwError);

    dwError = VmDirParseArgs(
                    argc,
                    argv,
                    &pszBootstrapSchemaFile,
                    &iLocalLogMask,
                    &logFileName,
                    &bEnableSysLog,
                    &bConsoleMode);
    if(dwError != ERROR_SUCCESS)
    {
        ShowUsage( argv[0] );
        BAIL_ON_VMDIR_ERROR(dwError);
    }

    dwError = VmDirAllocateStringA(
            pszBootstrapSchemaFile,
            &gVmdirGlobals.pszBootStrapSchemaFile);
    BAIL_ON_VMDIR_ERROR(dwError);

    dwError = VmDirAllocateStringA(pszStateDir, &gVmdirGlobals.pszBDBHome);
    BAIL_ON_VMDIR_ERROR(dwError);

    dwError = VmDirLogInitialize( logFileName, bEnableSysLog, "vmdird", VMDIR_LOG_INFO, iLocalLogMask);
    BAIL_ON_VMDIR_ERROR(dwError);

    VmDirdStateSet(VMDIRD_STATE_STARTUP);
    VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "Lotus Vmdird: starting...");

    VmDirBlockSelectedSignals();

    dwError = VmDirSetEnvironment();
    BAIL_ON_VMDIR_ERROR(dwError);

    dwError = VmDirInit();
    BAIL_ON_VMDIR_ERROR(dwError);
    bVmDirInit = TRUE;

    VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "Lotus Vmkdcd: starting...");


    if (VmDirdGetTargetState() != VMDIRD_STATE_RESTORE)
    {   // Normal server startup route

        dwError = VmKdcServiceStartup();
        BAIL_ON_VMDIR_ERROR(dwError);
        bShutdownKDCService = TRUE;

        VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "Lotus Vmkdcd: running...");

        dwError = VmDirNotifyLikewiseServiceManager();
        BAIL_ON_VMDIR_ERROR(dwError);

        VmDirdStateSet( VmDirdGetTargetState() );
        VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL,
                        "Lotus Vmdird: running... state (%d)",
                        VmDirdState());

        // main thread waits on signals
        dwError = VmDirHandleSignals();
        BAIL_ON_VMDIR_ERROR(dwError);
    }

    VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "Lotus Vmdird: exiting..." );

cleanup:

    if ( bShutdownKDCService )
    {
        VmKdcServiceShutdown();
        VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "Lotus Vmkdcd: stop" );
    }

    if ( bVmDirInit )
    {
        VmDirdStateSet(VMDIRD_STATE_SHUTDOWN);
        VmDirShutdown(&bWaitTimeOut);
        if (bWaitTimeOut)
        {
            VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "Lotus Vmdird: stop" );
            goto done;
        }

        VMDIR_LOG_INFO( VMDIR_LOG_MASK_ALL, "Lotus Vmdird: stop" );
    }

    VmDirLogTerminate();

    VmDirSrvFreeConfig();

done:
    return dwError;

error:
    goto cleanup;
}
Esempio n. 12
0
/* VmDirInternalDeleteEntry: Interface that can be used "internally" by the server code. One of the main differences between
 * this function and MLDelete 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
VmDirInternalDeleteEntry(
    PVDIR_OPERATION    pOperation
    )
{
    int         retVal = LDAP_SUCCESS;
    VDIR_ENTRY  entry = {0};
    PVDIR_ENTRY pEntry = NULL;
    BOOLEAN     leafNode = FALSE;
    DeleteReq*  delReq = &(pOperation->request.deleteReq);
    ModifyReq*  modReq = &(pOperation->request.modifyReq);
    BOOLEAN     bIsDomainObject = FALSE;
    BOOLEAN     bHasTxn = FALSE;
    PSTR        pszLocalErrMsg = NULL;
    PVDIR_OPERATION_ML_METRIC   pMLMetrics = NULL;
    extern DWORD VmDirDeleteRaftPreCommit(PVDIR_SCHEMA_CTX, EntryId, char *, PVDIR_OPERATION);

    assert(pOperation && pOperation->pBECtx->pBE);

    pMLMetrics = &pOperation->MLMetrics;
    VMDIR_COLLECT_TIME(pMLMetrics->iMLStartTime);

    if (VmDirdState() == VMDIRD_STATE_READ_ONLY)
    {
        retVal = VMDIR_ERROR_UNWILLING_TO_PERFORM;
        BAIL_ON_VMDIR_ERROR_WITH_MSG(
                retVal, pszLocalErrMsg,
                "Server in read-only mode");
    }

    // make sure we have minimum DN length
    if (delReq->dn.lberbv_len < 3)
    {
        retVal = VMDIR_ERROR_INVALID_REQUEST;
        BAIL_ON_VMDIR_ERROR_WITH_MSG(
                retVal, pszLocalErrMsg,
                "Invalid DN length - (%u)",
                delReq->dn.lberbv_len);
    }

    // Normalize DN
    retVal = VmDirNormalizeDN(&(delReq->dn), pOperation->pSchemaCtx);
    BAIL_ON_VMDIR_ERROR_WITH_MSG(
            retVal, pszLocalErrMsg,
            "DN normalization failed - (%u)(%s)",
            retVal,
            VDIR_SAFE_STRING(VmDirSchemaCtxGetErrorMsg(pOperation->pSchemaCtx)));

    VMDIR_COLLECT_TIME(pMLMetrics->iBETxnBeginStartTime);

    retVal = pOperation->pBEIF->pfnBETxnBegin(pOperation->pBECtx, VDIR_BACKEND_TXN_WRITE, &bHasTxn);
    BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg,
            "txn begin (%u)(%s)", retVal, VDIR_SAFE_STRING(pOperation->pBEErrorMsg));
    VMDIR_COLLECT_TIME(pMLMetrics->iBETxnBeginEndTime);

    if (bHasTxn)
    {
       retVal = VmDirValidateOp(pOperation, __func__);
       BAIL_ON_VMDIR_ERROR(retVal);
    }

    // Execute pre modify apply Delete plugin logic
    VMDIR_COLLECT_TIME(pMLMetrics->iPrePluginsStartTime);

    retVal = VmDirExecutePreModApplyDeletePlugins(pOperation, NULL, retVal);
    BAIL_ON_VMDIR_ERROR_WITH_MSG(
            retVal, pszLocalErrMsg,
            "PreModApplyDelete plugin failed - (%u)",
            retVal);

    VMDIR_COLLECT_TIME(pMLMetrics->iPrePlugunsEndTim);

    retVal = VmDirNormalizeMods(pOperation->pSchemaCtx, modReq->mods, &pszLocalErrMsg);
    BAIL_ON_VMDIR_ERROR(retVal);

    // BUGBUG, need to protect some system entries such as schema,domain....etc?

    // Read current entry from DB
    retVal = pOperation->pBEIF->pfnBEDNToEntry(
            pOperation->pBECtx,
            pOperation->pSchemaCtx,
            &(delReq->dn),
            &entry,
            VDIR_BACKEND_ENTRY_LOCK_WRITE);
    BAIL_ON_VMDIR_ERROR_WITH_MSG(
            retVal, pszLocalErrMsg,
            "(%u)(%s)",
            retVal,
            VDIR_SAFE_STRING(pOperation->pBEErrorMsg));

    pEntry = &entry;

    // Parse Parent DN
    retVal = VmDirGetParentDN(&pEntry->dn, &pEntry->pdn);
    BAIL_ON_VMDIR_ERROR_WITH_MSG(
            retVal, pszLocalErrMsg,
            "Get ParentDn failed - (%u)",
            retVal);

    // get parent entry
    if (pEntry->pdn.lberbv.bv_val)
    {
        PVDIR_ENTRY     pParentEntry = NULL;

        retVal = VmDirAllocateMemory(sizeof(*pEntry), (PVOID)&pParentEntry);
        BAIL_ON_VMDIR_ERROR(retVal);

        retVal = pOperation->pBEIF->pfnBEDNToEntry(
                pOperation->pBECtx,
                pOperation->pSchemaCtx,
                &pEntry->pdn,
                pParentEntry,
                VDIR_BACKEND_ENTRY_LOCK_READ);
        if (retVal)
        {
            VmDirFreeEntryContent(pParentEntry);
            VMDIR_SAFE_FREE_MEMORY(pParentEntry);

            switch (retVal)
            {
            case VMDIR_ERROR_BACKEND_ENTRY_NOTFOUND:
                BAIL_ON_VMDIR_ERROR_WITH_MSG(
                        retVal, pszLocalErrMsg,
                        "parent (%s) not found, (%s)",
                        pEntry->pdn.lberbv_val,
                        VDIR_SAFE_STRING(pOperation->pBEErrorMsg));

            default:
                BAIL_ON_VMDIR_ERROR_WITH_MSG(
                        retVal, pszLocalErrMsg,
                        "parent (%s) lookup failed, (%s)",
                        pEntry->pdn.lberbv_val,
                        VDIR_SAFE_STRING(pOperation->pBEErrorMsg));
            }
        }

        pEntry->pParentEntry = pParentEntry;    // pEntry takes over pParentEntry
        pParentEntry = NULL;
    }

    //
    // The delete will succeed if the caller either has the explicit right
    // to delete this object or if they have the right to delete children
    // of this object's parent.
    //
    retVal = VmDirSrvAccessCheck(
            pOperation,
            &pOperation->conn->AccessInfo,
            pEntry,
            VMDIR_RIGHT_DS_DELETE_OBJECT);
    if (retVal != ERROR_SUCCESS && pEntry->pParentEntry)
    {
        retVal = VmDirSrvAccessCheck(
                pOperation,
                &pOperation->conn->AccessInfo,
                pEntry->pParentEntry,
                VMDIR_RIGHT_DS_DELETE_CHILD);
    }
    BAIL_ON_VMDIR_ERROR_WITH_MSG(
            retVal, pszLocalErrMsg,
            "VmDirSrvAccessCheck failed - (%u)(%s)",
            retVal,
            VMDIR_ACCESS_DENIED_ERROR_MSG);

    // Make sure it is a leaf node
    retVal = pOperation->pBEIF->pfnBEChkIsLeafEntry(
            pOperation->pBECtx,
            pEntry->eId,
            &leafNode);
    BAIL_ON_VMDIR_ERROR_WITH_MSG(
            retVal, pszLocalErrMsg,
            "BEChkIsLeafEntry failed, (%u)(%s)",
            retVal,
            VDIR_SAFE_STRING(pOperation->pBEErrorMsg));

    if (leafNode == FALSE)
    {
        retVal = VMDIR_ERROR_NOT_ALLOWED_ON_NONLEAF;
        BAIL_ON_VMDIR_ERROR_WITH_MSG(
                retVal, pszLocalErrMsg,
                "Delete of a non-leaf node is not allowed.");
    }

    // Retrieve to determine whether it is domain object earlier
    // before attribute modifications
    // ('bIsDomainObject' is needed for a domain object deletion)
    retVal = VmDirIsDomainObjectWithEntry(pEntry, &bIsDomainObject);
    BAIL_ON_VMDIR_ERROR_WITH_MSG(
            retVal, pszLocalErrMsg,
            "VmDirIsDomainObjectWithEntry failed - (%u)",
            retVal);

    retVal = GenerateDeleteAttrsMods(pOperation, pEntry);
    BAIL_ON_VMDIR_ERROR_WITH_MSG(
            retVal, pszLocalErrMsg,
            "GenerateDeleteAttrsMods failed - (%u)",
            retVal);

    // Normalize attribute values in mods
    retVal = VmDirNormalizeMods(pOperation->pSchemaCtx, modReq->mods, &pszLocalErrMsg);
    BAIL_ON_VMDIR_ERROR(retVal);

    // Apply modify operations to the current entry in the DB.
    retVal = VmDirApplyModsToEntryStruct(pOperation->pSchemaCtx, modReq, pEntry, NULL, &pszLocalErrMsg);
    BAIL_ON_VMDIR_ERROR(retVal);

    // Update Entry
    retVal = pOperation->pBEIF->pfnBEEntryDelete(pOperation->pBECtx, modReq->mods, pEntry);
    BAIL_ON_VMDIR_ERROR_WITH_MSG(
            retVal, pszLocalErrMsg,
            "BEEntryDelete (%u)(%s)",
            retVal,
            VDIR_SAFE_STRING(pOperation->pBEErrorMsg));

    retVal = DeleteRefAttributesValue(pOperation, &(pEntry->dn));
    BAIL_ON_VMDIR_ERROR_WITH_MSG(
            retVal, pszLocalErrMsg,
            "DeleteRefAttributesValue (%u)(%s)",
            retVal,
            VDIR_SAFE_STRING(pOperation->pBEErrorMsg));

    // Use normalized DN value
    if (bIsDomainObject)
    {
        retVal = VmDirInternalRemoveOrgConfig(pOperation, BERVAL_NORM_VAL(pEntry->dn));
        BAIL_ON_VMDIR_ERROR_WITH_MSG(
                retVal, pszLocalErrMsg,
                "Update domain list entry failed.");
    }

    if (pOperation->bNoRaftLog == FALSE)
    {
        retVal = VmDirDeleteRaftPreCommit(
            pOperation->pSchemaCtx, pEntry->eId, BERVAL_NORM_VAL(pEntry->dn), pOperation);
        BAIL_ON_VMDIR_ERROR_WITH_MSG(
            retVal, pszLocalErrMsg,
            "VmDirDeleteRaftPreCommit error (%u)",
            retVal);
    }


    if (bHasTxn)
    {
        VMDIR_COLLECT_TIME(pMLMetrics->iBETxnCommitStartTime);

        retVal = pOperation->pBEIF->pfnBETxnCommit(pOperation->pBECtx);
        bHasTxn = FALSE;
        BAIL_ON_VMDIR_ERROR_WITH_MSG(
             retVal, pszLocalErrMsg,
             "txn commit logIndex %llu (%u)(%s)",
             pOperation->logIndex, retVal,
             VDIR_SAFE_STRING(pOperation->pBEErrorMsg));
        VMDIR_COLLECT_TIME(pMLMetrics->iBETxnCommitEndTime);
    }

    if (!pOperation->bSuppressLogInfo)
    {
        VMDIR_LOG_INFO(
                VMDIR_LOG_MASK_ALL,
                "Delete Entry (%s) logIndex %llu",
                VDIR_SAFE_STRING(pEntry->dn.lberbv_val), pOperation->logIndex);
    }

    // Post delete entry
    // TODO, make it into a separate file deletePlugin.c
    // clean lockout cache record if exists
    VdirLockoutCacheRemoveRec(pEntry->dn.bvnorm_val);

cleanup:

    if (retVal == 0)
    {
        int iPostCommitPluginRtn  = 0;

        VMDIR_COLLECT_TIME(pMLMetrics->iPostPluginsStartTime);

        // Execute post Delete commit plugin logic
        iPostCommitPluginRtn = VmDirExecutePostDeleteCommitPlugins(pOperation, pEntry, retVal);
        if (iPostCommitPluginRtn != LDAP_SUCCESS &&
            iPostCommitPluginRtn != pOperation->ldapResult.errCode) // pass through
        {
            VMDIR_LOG_ERROR(
                    LDAP_DEBUG_ANY,
                    "InternalDeleteEntry: VdirExecutePostDeleteCommitPlugins - code(%d)",
                    iPostCommitPluginRtn);
        }

        VMDIR_COLLECT_TIME(pMLMetrics->iPostPlugunsEndTime);
    }

    // collect metrics
    VMDIR_COLLECT_TIME(pMLMetrics->iMLEndTime);
    VmDirInternalMetricsUpdate(pOperation);
    VmDirInternalMetricsLogInefficientOp(pOperation);

    if (pOperation->opType != VDIR_OPERATION_TYPE_REPL)
    {
        // In case of replication, modReq is owned by the Replication thread/logic
        DeleteMods(modReq);
    }

    VmDirFreeEntryContent(&entry);
    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;
}
Esempio n. 13
0
/* VmDirInternalModifyEntry: Interface that can be used "internally" by the server code, e.g. to modify schema, indices,
 * config etc. entries in the BDB store. One of the main differences between this function and MLModify 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
VmDirInternalModifyEntry(
    PVDIR_OPERATION pOperation
    )
{
    int         retVal = LDAP_SUCCESS;
    VDIR_ENTRY  entry = {0};
    PVDIR_ENTRY pEntry = NULL;
    ModifyReq*  modReq = NULL;
    ENTRYID     entryId = 0;
    BOOLEAN     bHasTxn = FALSE;
    PSTR        pszLocalErrMsg = NULL;
    PVDIR_OPERATION_ML_METRIC   pMLMetrics = NULL;

    assert(pOperation && pOperation->pBEIF);

    pMLMetrics = &pOperation->MLMetrics;
    VMDIR_COLLECT_TIME(pMLMetrics->iMLStartTime);

    if (VmDirdState() == VMDIRD_STATE_READ_ONLY)
    {
        retVal = VMDIR_ERROR_UNWILLING_TO_PERFORM;
        BAIL_ON_VMDIR_ERROR_WITH_MSG(
                retVal, pszLocalErrMsg,
                "Server in read-only mode");
    }

    modReq = &(pOperation->request.modifyReq);

    // make sure we have minimum DN length
    if (modReq->dn.lberbv_len < 3)
    {
        retVal = VMDIR_ERROR_INVALID_REQUEST;
        BAIL_ON_VMDIR_ERROR_WITH_MSG(
                retVal, pszLocalErrMsg,
                "Invalid DN length - (%u)",
                modReq->dn.lberbv_len);
    }

    // Normalize DN
    retVal = VmDirNormalizeDN(&(modReq->dn), pOperation->pSchemaCtx);
    BAIL_ON_VMDIR_ERROR_WITH_MSG(
            retVal, pszLocalErrMsg,
            "DN normalization failed - (%u)(%s)",
            retVal,
            VDIR_SAFE_STRING(VmDirSchemaCtxGetErrorMsg(pOperation->pSchemaCtx)));

    // Acquire schema modification mutex
    retVal = VmDirSchemaModMutexAcquire(pOperation);
    BAIL_ON_VMDIR_ERROR_WITH_MSG(
            retVal, pszLocalErrMsg,
            "Failed to lock schema mod mutex",
            retVal);

    if (pOperation->opType != VDIR_OPERATION_TYPE_REPL)
    {
        // Generate mods based on MODN request
        retVal = VmDirGenerateRenameAttrsMods(pOperation);
        BAIL_ON_VMDIR_ERROR_WITH_MSG(
                retVal, pszLocalErrMsg,
                "GenerateDeleteAttrsMods failed - (%u)",
                retVal);
    }

    VMDIR_COLLECT_TIME(pMLMetrics->iBETxnBeginStartTime);

    retVal = pOperation->pBEIF->pfnBETxnBegin(pOperation->pBECtx, VDIR_BACKEND_TXN_WRITE, &bHasTxn);
    BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "txn begin (%u)(%s)",
            retVal, VDIR_SAFE_STRING(pOperation->pBEErrorMsg));
    VMDIR_COLLECT_TIME(pMLMetrics->iBETxnBeginEndTime);

    if (bHasTxn)
    {
       retVal = VmDirValidateOp(pOperation, __func__);
       BAIL_ON_VMDIR_ERROR(retVal);
    }

    // Execute pre modify plugin logic
    VMDIR_COLLECT_TIME(pMLMetrics->iPrePluginsStartTime);

    retVal = VmDirExecutePreModApplyModifyPlugins(pOperation, NULL, retVal);
    BAIL_ON_VMDIR_ERROR_WITH_MSG(
            retVal, pszLocalErrMsg,
            "PreModApplyModify plugin failed - (%u)",
            retVal);

    VMDIR_COLLECT_TIME(pMLMetrics->iPrePlugunsEndTim);

    // Normalize attribute values in mods
    retVal = VmDirNormalizeMods(pOperation->pSchemaCtx, modReq->mods, &pszLocalErrMsg);
    BAIL_ON_VMDIR_ERROR(retVal);

    // Read current entry from DB
    retVal = pOperation->pBEIF->pfnBEDNToEntryId(pOperation->pBECtx, &(modReq->dn), &entryId);
    BAIL_ON_VMDIR_ERROR_WITH_MSG(
            retVal, pszLocalErrMsg,
            "BEEntryModify (%u)(%s)",
            retVal,
            VDIR_SAFE_STRING(pOperation->pBEErrorMsg));

    pEntry = &entry;

    retVal = VmDirModifyEntryCoreLogic(
            pOperation,
            &pOperation->request.modifyReq,
            entryId,
            pOperation->bNoRaftLog,
            pEntry);
    BAIL_ON_VMDIR_ERROR_WITH_MSG(
            retVal, pszLocalErrMsg,
            "CoreLogicModifyEntry failed. (%u)",
            retVal);

    if (bHasTxn)
    {
        VMDIR_COLLECT_TIME(pMLMetrics->iBETxnCommitStartTime);

        retVal = pOperation->pBEIF->pfnBETxnCommit(pOperation->pBECtx);
        bHasTxn = FALSE;
        BAIL_ON_VMDIR_ERROR_WITH_MSG(
            retVal, pszLocalErrMsg,
            "txn commit logIndex %llu (%u)(%s)",
            pOperation->logIndex, retVal,
            VDIR_SAFE_STRING(pOperation->pBEErrorMsg));

        VMDIR_COLLECT_TIME(pMLMetrics->iBETxnCommitEndTime);
    }

    if (!pOperation->bSuppressLogInfo)
    {
        VMDIR_LOG_INFO(
                VMDIR_LOG_MASK_ALL,
                "Modify Entry (%s) blob size %d logIndex %llu",
                VDIR_SAFE_STRING(pEntry->dn.lberbv_val), pEntry->encodedSize, pOperation->logIndex);
    }

cleanup:

    if (retVal == 0)
    {
        int iPostCommitPluginRtn = 0;

        VMDIR_COLLECT_TIME(pMLMetrics->iPostPluginsStartTime);

        // Execute post modify plugin logic
        iPostCommitPluginRtn = VmDirExecutePostModifyCommitPlugins(pOperation, &entry, retVal);
        if (iPostCommitPluginRtn != LDAP_SUCCESS &&
            iPostCommitPluginRtn != pOperation->ldapResult.errCode) // pass through
        {
            VMDIR_LOG_ERROR(
                    LDAP_DEBUG_ANY,
                    "InternalModifyEntry: VdirExecutePostModifyCommitPlugins - code(%d)",
                    iPostCommitPluginRtn);
        }

        VMDIR_COLLECT_TIME(pMLMetrics->iPostPlugunsEndTime);
    }

    // Release schema modification mutex
    (VOID)VmDirSchemaModMutexRelease(pOperation);

    // collect metrics
    VMDIR_COLLECT_TIME(pMLMetrics->iMLEndTime);
    VmDirInternalMetricsUpdate(pOperation);
    VmDirInternalMetricsLogInefficientOp(pOperation);

    VmDirFreeEntryContent(&entry);
    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;
}
Esempio n. 14
0
static
DWORD
_VmDirDCConnThreadFun(
    PVOID pArg
    )
{
    DWORD dwError = 0;
    DWORD dwSleepTimeSec = 0;
    DWORD dwThrStartTime = time(NULL);
    PVMDIR_DC_CONNECTION pDCConn = (PVMDIR_DC_CONNECTION)pArg;

    pDCConn->connState = DC_CONNECTION_STATE_CONNECTING;

    VMDIR_LOG_VERBOSE(VMDIR_LOG_MASK_ALL,
        "%s user (%s) connecting to (%s) started",
        __FUNCTION__,
        VDIR_SAFE_STRING(pDCConn->creds.pszUPN),
        VDIR_SAFE_STRING(pDCConn->pszRemoteDCHostName));

    while (TRUE)
    {
        if (!_VmDirHasCredInfo(&pDCConn->creds))
        {
            BAIL_WITH_VMDIR_ERROR(dwError, VMDIR_ERROR_USER_INVALID_CREDENTIAL);
        }

        dwError = _VmDirConnectToDC(pDCConn);
        if (dwError == 0)
        {
            VMDIR_LOG_VERBOSE(VMDIR_LOG_MASK_ALL,
                "%s user (%s) connected to (%s) done",
                __FUNCTION__,
                VDIR_SAFE_STRING(pDCConn->creds.pszUPN),
                VDIR_SAFE_STRING(pDCConn->pszRemoteDCHostName));

            // have a live connection, transfer ownership back to owner
            pDCConn->connState = DC_CONNECTION_STATE_CONNECTED;
            goto cleanup;
        }

        if (pDCConn->connType == DC_CONNECTION_TYPE_BASIC)
        {
            goto error;  // no retry, bail
        }

        if (dwError == VMDIR_ERROR_USER_INVALID_CREDENTIAL)
        {
            dwSleepTimeSec = MAX_DC_CONNECT_SLEEP_TIME_SEC;
        }
        else if (dwError == VMDIR_ERROR_SERVER_DOWN || dwError == VMDIR_ERROR_NETWORK_TIMEOUT)
        {
            dwSleepTimeSec = UNIT_DC_CONNECT_SLEEP_TIME_SEC * pDCConn->dwConsecutiveFailAttempt;
        }
        else
        {
            goto error;
        }

        if (dwSleepTimeSec >= MAX_DC_CONNECT_SLEEP_TIME_SEC)
        {
            dwSleepTimeSec = MAX_DC_CONNECT_SLEEP_TIME_SEC;
        }

        VMDIR_LOG_WARNING(VMDIR_LOG_MASK_ALL,
            "%s URGENT %s (%s) connection to (%s) failed (%d) times, last error (%d), sleep (%d)",
            __FUNCTION__,
            _VmDirDCConnType(pDCConn->connType),
            VDIR_SAFE_STRING(pDCConn->creds.pszUPN),
            VDIR_SAFE_STRING(pDCConn->pszRemoteDCHostName),
            pDCConn->dwConsecutiveFailAttempt,
            pDCConn->dwlastFailedError,
            dwSleepTimeSec);

        if (time(NULL) - dwThrStartTime >= MAX_DC_CONNECT_DURATION_TIME_SEC)
        {
            // bail to allow deleted RA cache clean up
            BAIL_WITH_VMDIR_ERROR(dwError, pDCConn->dwlastFailedError);
        }

        while (dwSleepTimeSec)
        {
            VmDirSleep(1000);  // pause 1 second
            dwSleepTimeSec--;

            if (VmDirdState() == VMDIRD_STATE_SHUTDOWN)
            {
                goto cleanup;
            }
        }
    }

cleanup:
    VmDirFreeConnCredContent(&pDCConn->creds);

    return dwError;

error:
    pDCConn->connState = DC_CONNECTION_STATE_FAILED;

    VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL,
        "%s user (%s) connect to (%s) failed (%d), connection state set to failed",
        __FUNCTION__,
        VDIR_SAFE_STRING(pDCConn->creds.pszUPN),
        VDIR_SAFE_STRING(pDCConn->pszRemoteDCHostName),
        dwError);

    goto cleanup;
}
Esempio n. 15
0
static
int
ProcessCandidateList(
    VDIR_OPERATION * pOperation
    )
{
    int               retVal = LDAP_SUCCESS;
    int               i = 0;
    VDIR_CANDIDATES * cl = pOperation->request.searchReq.filter->candidates;
    VDIR_ENTRY        srEntry = {0};
    VDIR_ENTRY *      pSrEntry = NULL;
    int               numSentEntries = 0;
    BOOLEAN           bInternalSearch = FALSE;
    BOOLEAN           bPageResultsCtrl = FALSE;
    DWORD             dwPageSize = 0;
    ENTRYID           lastEID = 0;

    /*
     * If the page size is greater than or equal to the sizeLimit value,
     * the server should ignore the control as the request can be satisfied in a single page.
     */
    if (pOperation->showPagedResultsCtrl && (pOperation->request.searchReq.sizeLimit == 0 ||
            pOperation->showPagedResultsCtrl->value.pagedResultCtrlVal.pageSize < (DWORD)pOperation->request.searchReq.sizeLimit))
    {
        VmDirLog( LDAP_DEBUG_TRACE, "showPagedResultsCtrl applies to this query." );
        bPageResultsCtrl = TRUE;
        dwPageSize = pOperation->showPagedResultsCtrl->value.pagedResultCtrlVal.pageSize;
        lastEID = atoi(pOperation->showPagedResultsCtrl->value.pagedResultCtrlVal.cookie);
        pOperation->showPagedResultsCtrl->value.pagedResultCtrlVal.cookie[0] = '\0';
    }

    if (cl && cl->size > 0)
    {
        if (pOperation->opType == VDIR_OPERATION_TYPE_INTERNAL)
        {   //TODO, we should have a hard limit on the cl->size we handle
            bInternalSearch = TRUE;
            VmDirFreeEntryArrayContent(&pOperation->internalSearchEntryArray);
            retVal = VmDirAllocateMemory(   sizeof(VDIR_ENTRY) * cl->size,
                                            (PVOID*)&pOperation->internalSearchEntryArray.pEntry);
            BAIL_ON_VMDIR_ERROR(retVal);
        }

        for (i = 0, numSentEntries = 0;
             (i < cl->size) && VmDirdState() != VMDIRD_STATE_SHUTDOWN &&
             (pOperation->request.searchReq.sizeLimit == 0 /* unlimited */ ||
              numSentEntries < pOperation->request.searchReq.sizeLimit);
             i++)
        {
            //skip entries we sent before
            if (bPageResultsCtrl && lastEID > 0)
            {
                if (cl->eIds[i] == lastEID)
                {
                    lastEID = 0;
                }
                continue;
            }

            VMDIR_LOG_DEBUG( LDAP_DEBUG_FILTER, "ProcessCandidateList EID(%u)", cl->eIds[i]);

            pSrEntry = bInternalSearch ?
                        (pOperation->internalSearchEntryArray.pEntry + pOperation->internalSearchEntryArray.iSize) : &srEntry;

            retVal = pOperation->pBEIF->pfnBEIdToEntry(
                        pOperation->pBECtx,
                        pOperation->pSchemaCtx,
                        cl->eIds[i],
                        pSrEntry,
                        VDIR_BACKEND_ENTRY_LOCK_READ);

            if (retVal == 0)
            {
                if (CheckIfEntryPassesFilter( pOperation, pSrEntry, pOperation->request.searchReq.filter) == FILTER_RES_TRUE)
                {
                    retVal = VmDirBuildComputedAttribute( pOperation, pSrEntry );
                    BAIL_ON_VMDIR_ERROR( retVal );

                    if (bInternalSearch)
                    {
                        pOperation->internalSearchEntryArray.iSize++;
                        pSrEntry = NULL;    // EntryArray takes over *pSrEntry content
                    }
                    else
                    {
                        retVal = VmDirSendSearchEntry( pOperation, pSrEntry );
                        if (retVal == VMDIR_ERROR_INSUFFICIENT_ACCESS)
                        {
                            VMDIR_LOG_WARNING( VMDIR_LOG_MASK_ALL,
                                               "Access deny on search entry result [%s,%d] (bindedDN-%s) (targetDn-%s)\n",
                                               __FILE__, __LINE__, pOperation->conn->AccessInfo.pszBindedDn, pSrEntry->dn.lberbv.bv_val);
                            // make sure search continues
                            retVal = 0;
                        }
                        BAIL_ON_VMDIR_ERROR( retVal );

                        if (pSrEntry->bSearchEntrySent)
                        {
                            numSentEntries++;
                        }
                    }
                }

                //We have sent one page size of entries, so we can break here
                if (bPageResultsCtrl && numSentEntries == dwPageSize){
                    retVal = VmDirStringPrintFA(
                            pOperation->showPagedResultsCtrl->value.pagedResultCtrlVal.cookie,
                            VMDIR_MAX_I64_ASCII_STR_LEN,
                            "%u",
                            pSrEntry->eId);
                    BAIL_ON_VMDIR_ERROR( retVal );
                    break;
                }

                VmDirFreeEntryContent( pSrEntry );
                pSrEntry = NULL; // Reset to NULL so that DeleteEntry is no-op.
            }
            else
            {
                // Ignore BdbEIdToEntry errors.
                VMDIR_LOG_WARNING( VMDIR_LOG_MASK_ALL, "ProcessCandiateList BEIdToEntry EID(%u), error (%u)",
                                                       cl->eIds[i], retVal);
                retVal = 0;
            }
        }

        VMDIR_LOG_VERBOSE( LDAP_DEBUG_FILTER, "(%d) candiates processed and (%d) entries sent", cl->size, numSentEntries);
    }

    if ( pOperation->request.searchReq.sizeLimit && numSentEntries < pOperation->request.searchReq.sizeLimit &&
         pOperation->pBECtx->iPartialCandidates)
    {
        retVal = LDAP_UNWILLING_TO_PERFORM;
        VMDIR_LOG_ERROR(VMDIR_LOG_MASK_ALL, "ProcessCandiateList may return none or paritial requested entries with sizelimit %d",
                        pOperation->request.searchReq.sizeLimit);
    }

cleanup:

    pOperation->dwSentEntries = numSentEntries;
    VmDirFreeEntryContent( pSrEntry );

    return retVal;

error:

    VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "ProcessCandiateList failed. (%u)", retVal);
    goto cleanup;
}