예제 #1
0
static
DWORD
LWNetSrvGetDCNameDiscoverInternal(
    IN PCSTR pszDnsDomainName,
    IN OPTIONAL PCSTR pszSiteName,
    IN OPTIONAL PCSTR pszPrimaryDomain,
    IN DWORD dwDsFlags,
    IN DWORD dwBlackListCount,
    IN OPTIONAL PSTR* ppszAddressBlackList,
    IN PLWNET_DC_LIST_QUERY_METHOD pfnDCListQuery,
    OUT PLWNET_DC_INFO* ppDcInfo,
    OUT OPTIONAL PDNS_SERVER_INFO* ppServerArray,
    OUT OPTIONAL PDWORD pdwServerCount,
    OUT PBOOLEAN pbFailedFindWritable
)
//
// Algorithm:
//
//    - DNS query for desired site & required DC type (pdc, kdc, gc).
//      - note that if no site is specified, use "un-sited" lookup.
//    - If no site specified:
//      - CLDAP to one DC to get actual site
//      - use new site info that to do DNS query for updated DC list
//    - CLDAP to DCs in parallel to find the first responder
//      (meeting any additional criteria -- writable, etc)
//
{
    DWORD dwError = 0;
    PLWNET_DC_INFO pDcInfo = NULL;
    PDNS_SERVER_INFO pServerArray = NULL;
    PDNS_SERVER_INFO pServersInPrimaryDomain = NULL;
    DWORD dwServersInPrimaryDomainCount = 0;
    DWORD dwServerCount = 0;
    PLWNET_DC_INFO pSiteDcInfo = NULL;
    PDNS_SERVER_INFO pSiteServerArray = NULL;
    DWORD dwSiteServerCount = 0;
    BOOLEAN bFailedFindWritable = FALSE;

    // Get server list
    dwError = pfnDCListQuery(pszDnsDomainName,
                             pszSiteName,
                             dwDsFlags,
                             &pServerArray,
                             &dwServerCount);
    BAIL_ON_LWNET_ERROR(dwError);

    LWNetFilterFromBlackList(
        dwBlackListCount,
        ppszAddressBlackList,
        &dwServerCount,
        pServerArray);

    if (!dwServerCount)
    {
        dwError = ERROR_DOMAIN_BLACKLISTED;
        BAIL_ON_LWNET_ERROR(dwError);
    }

    if (pszPrimaryDomain)
    {
        dwError = LWNetFindServersInDomain(
                      pServerArray,
                      dwServerCount,
                      pszPrimaryDomain,
                      &pServersInPrimaryDomain,
                      &dwServersInPrimaryDomainCount);
        BAIL_ON_LWNET_ERROR(dwError);

        LWNetFilterFromBlackList(
            dwBlackListCount,
            ppszAddressBlackList,
            &dwServersInPrimaryDomainCount,
            pServersInPrimaryDomain);

        if (dwServersInPrimaryDomainCount > 0)
        {
            dwError = LWNetSrvPingCLdapArray(pszDnsDomainName,
                                             dwDsFlags,
                                             pServersInPrimaryDomain,
                                             dwServersInPrimaryDomainCount,
                                             0, &pDcInfo, &bFailedFindWritable);
        }

        if (dwServersInPrimaryDomainCount == 0 ||
                dwError == NERR_DCNotFound)
        {
            dwError = LWNetSrvPingCLdapArray(pszDnsDomainName,
                                             dwDsFlags,
                                             pServerArray, dwServerCount,
                                             0, &pDcInfo, &bFailedFindWritable);
            BAIL_ON_LWNET_ERROR(dwError);
        }
    }
    else
    {
        // Do CLDAP
        dwError = LWNetSrvPingCLdapArray(pszDnsDomainName,
                                         dwDsFlags,
                                         pServerArray, dwServerCount,
                                         0, &pDcInfo, &bFailedFindWritable);
        BAIL_ON_LWNET_ERROR(dwError);
    }

    // If there is no client site, then we are done (though we do not
    // expect this to ever happen).
    if (IsNullOrEmptyString(pDcInfo->pszClientSiteName))
    {
        LWNET_LOG_ALWAYS("Missing client site name from "
                         "DC response from %s (%s)",
                         LWNET_SAFE_LOG_STRING(pDcInfo->pszDomainControllerName),
                         LWNET_SAFE_LOG_STRING(pDcInfo->pszDomainControllerAddress));
        goto cleanup;
    }

    // If a site was passed in, there is nothing more to do.
    if (!IsNullOrEmptyString(pszSiteName))
    {
        goto cleanup;
    }

    // There was no site passed in, so we need to look at the
    // CLDAP response to get the client site.

    // If we got the correct site already, we are done.
    if (LWNetSrvIsInSameSite(pDcInfo))
    {
        if (LWNetIsUpdateKrb5AffinityEnabled(dwDsFlags, pszSiteName, pDcInfo) &&
                !pszSiteName &&
                pDcInfo->pszClientSiteName)
        {
            dwError = pfnDCListQuery(
                          pszDnsDomainName,
                          pDcInfo->pszClientSiteName,
                          dwDsFlags,
                          &pSiteServerArray,
                          &dwSiteServerCount);
            if (dwError == 0)
            {
                // Use the site-specific DC.
                LWNET_SAFE_FREE_MEMORY(pServerArray);
                dwServerCount = 0;

                LWNetFilterFromBlackList(
                    dwBlackListCount,
                    ppszAddressBlackList,
                    &dwSiteServerCount,
                    pSiteServerArray);
                if (!dwSiteServerCount)
                {
                    dwError = DNS_ERROR_BAD_PACKET;
                    BAIL_ON_LWNET_ERROR(dwError);
                }

                pServerArray = pSiteServerArray;
                dwServerCount = dwSiteServerCount;

                pSiteServerArray = NULL;
                dwSiteServerCount = 0;
            }
        }

        dwError = 0;
        goto cleanup;
    }

    // Now we need to use the client site to find a site-specific DC.
    dwError = LWNetSrvGetDCNameDiscover(pszDnsDomainName,
                                        pDcInfo->pszClientSiteName,
                                        pszPrimaryDomain,
                                        dwDsFlags,
                                        dwBlackListCount,
                                        ppszAddressBlackList,
                                        &pSiteDcInfo,
                                        &pSiteServerArray, &dwSiteServerCount,
                                        &bFailedFindWritable);
    if (NERR_DCNotFound == dwError)
    {
        if (bFailedFindWritable)
        {
            LWNET_LOG_WARNING("No writable DC in client site '%s' for domain '%s'",
                              pDcInfo->pszClientSiteName,
                              pszDnsDomainName);
        }
        // Count not find site-specific DC, so use the original DC.
        dwError = 0;
        goto cleanup;
    }
    BAIL_ON_LWNET_ERROR(dwError);

    // Use the site-specific DC.
    LWNET_SAFE_FREE_DC_INFO(pDcInfo);
    LWNET_SAFE_FREE_MEMORY(pServerArray);
    dwServerCount = 0;

    pDcInfo = pSiteDcInfo;
    pServerArray = pSiteServerArray;
    dwServerCount = dwSiteServerCount;

    pSiteDcInfo = NULL;
    pSiteServerArray = NULL;
    dwSiteServerCount = 0;

error:
cleanup:
    LWNET_SAFE_FREE_DC_INFO(pSiteDcInfo);
    LWNET_SAFE_FREE_MEMORY(pSiteServerArray);
    LWNET_SAFE_FREE_MEMORY(pServersInPrimaryDomain);
    dwSiteServerCount = 0;

    if (dwError)
    {
        LWNET_SAFE_FREE_DC_INFO(pDcInfo);
        LWNET_SAFE_FREE_MEMORY(pServerArray);
        dwServerCount = 0;
    }

    *ppDcInfo = pDcInfo;
    if (ppServerArray)
    {
        *ppServerArray = pServerArray;
        *pdwServerCount = dwServerCount;
    }
    else
    {
        LWNET_SAFE_FREE_MEMORY(pServerArray);
    }
    *pbFailedFindWritable = bFailedFindWritable;

    return dwError;
}
예제 #2
0
DWORD
LWNetSrvPingCLdapArray(
    IN PCSTR pszDnsDomainName,
    IN DWORD dwDsFlags,
    IN PDNS_SERVER_INFO pServerArray,
    IN DWORD dwServerCount,
    IN OPTIONAL DWORD dwTimeoutSeconds,
    OUT PLWNET_DC_INFO* ppDcInfo,
    OUT PBOOLEAN pbFailedFindWritable
)
{
    DWORD dwError = 0;
    DWORD dwMaxConnCount = 0;
    DWORD dwIncrementalConnCount = 0;
    DWORD dwActualTimeoutSeconds = 0;
    DWORD dwSingleConnTimeoutSeconds = 0;
    DWORD dwSingleConnTimeoutMilliseconds = 0;
    DWORD dwTimeoutMilliseconds = 0;
    LWNET_UNIX_MS_TIME_T StopTime = 0;
    LWNET_UNIX_MS_TIME_T CurrentTime = 0;
    PLWNET_DC_INFO pDcInfo = NULL;
    BOOLEAN bFailedFindWritable = FALSE;
    PLWNET_CLDAP_CONNECTION_CONTEXT pConnections = NULL;
    DWORD dwActualConnCount = 0;
    DWORD dwUsedServers = 0;
    DWORD dwIndexConn = 0;
    struct pollfd *Readfds = NULL;

    // The basic scheme is a big loop over:
    //
    //     1. starting some CLDAP searches
    //     2. polling for responses
    //     3. processing responses
    //
    // When starting CLDAP searches, a portion of the
    // available connections will be started followed
    // by a short poll until the maximum number of
    // connections has been used.  Once the maximum
    // number of connections are in use, the polling
    // timeout will be the single search timeout for
    // the oldest connection.  This will start the
    // maximum number of connections reasonably fast
    // yet prevent excess network traffic if a server
    // responds quickly.
    //
    // Active connections will be tracked in a list
    // that is ordered by start time.  If several
    // servers respond at the same time, the one
    // nearest the end of the list will be the one
    // that responded the fastest.

    dwMaxConnCount = CT_MIN(LWNetConfigGetCLdapMaximumConnections(), dwServerCount);
    dwIncrementalConnCount = CT_MAX(dwMaxConnCount / 5, LWNET_CLDAP_MINIMUM_INCREMENTAL_CONNECTIONS);

    if (dwTimeoutSeconds > 0)
    {
        dwActualTimeoutSeconds = dwTimeoutSeconds;
    }
    else
    {
        dwActualTimeoutSeconds = LWNetConfigGetCLdapSearchTimeoutSeconds();
    }

    dwSingleConnTimeoutSeconds = CT_MIN(LWNetConfigGetCLdapSingleConnectionTimeoutSeconds(), dwActualTimeoutSeconds);
    dwSingleConnTimeoutMilliseconds = dwSingleConnTimeoutSeconds * 1000;

    dwError = LWNetAllocateMemory(
                  dwMaxConnCount * sizeof(*pConnections),
                  OUT_PPVOID(&pConnections));
    BAIL_ON_LWNET_ERROR(dwError);

    dwError = LWNetAllocateMemory(
                  dwMaxConnCount * sizeof(*Readfds),
                  OUT_PPVOID(&Readfds));
    BAIL_ON_LWNET_ERROR(dwError);

    dwError = LWNetGetSystemTimeInMs(&CurrentTime);
    BAIL_ON_LWNET_ERROR(dwError);

    StopTime = CurrentTime + (dwActualTimeoutSeconds * 1000);

    for (;;)
    {
        LWNetSrvPingCLdapNewConnections(
            pszDnsDomainName,
            dwSingleConnTimeoutMilliseconds,
            dwMaxConnCount,
            dwServerCount,
            dwIncrementalConnCount,
            pServerArray,
            pConnections,
            Readfds,
            &dwActualConnCount,
            &dwUsedServers);

        if (dwActualConnCount == 0)
        {
            dwError = NERR_DCNotFound;
            BAIL_ON_LWNET_ERROR(dwError);
        }

        dwError = LWNetGetSystemTimeInMs(&CurrentTime);
        BAIL_ON_LWNET_ERROR(dwError);

        if (CurrentTime > StopTime)
        {
            dwError = NERR_DCNotFound;
            BAIL_ON_LWNET_ERROR(dwError);
        }

        if (dwActualConnCount < dwMaxConnCount &&
                dwUsedServers < dwServerCount)
        {
            // If there are more connections available,
            // use a short timeout
            dwTimeoutMilliseconds = LWNET_CLDAP_SHORT_POLL_TIMEOUT_MILLISECONDS;
        }
        else
        {
            if (pConnections[0].StartTime +
                    dwSingleConnTimeoutMilliseconds > CurrentTime)
            {
                // Use the remaining time for the oldest connection
                dwTimeoutMilliseconds = pConnections[0].StartTime +
                                        dwSingleConnTimeoutMilliseconds -
                                        CurrentTime;
                dwTimeoutMilliseconds = CT_MIN(dwSingleConnTimeoutMilliseconds, StopTime - CurrentTime);
            }
            else
            {
                // The oldest connection has exceeded its limit so
                // use the shortest possible timeout to check which
                // connections have responded now.
                dwTimeoutMilliseconds = 1;
            }
        }

        dwError = LWNetSrvPingCLdapPoll(
                      dwTimeoutMilliseconds,
                      dwActualConnCount,
                      Readfds);
        BAIL_ON_LWNET_ERROR(dwError);

        dwError = LWNetGetSystemTimeInMs(&CurrentTime);
        BAIL_ON_LWNET_ERROR(dwError);

        LWNetSrvPingCLdapProcessConnections(
            dwDsFlags,
            CurrentTime,
            dwSingleConnTimeoutMilliseconds,
            dwActualConnCount,
            Readfds,
            pConnections,
            &pDcInfo,
            &bFailedFindWritable);

        if (pDcInfo)
        {
            break;
        }

        dwActualConnCount = LWNetSrvPingCLdapPackArrays(
                                dwActualConnCount,
                                pConnections,
                                Readfds);
    }

error:
    if (pConnections)
    {
        for (dwIndexConn = 0 ; dwIndexConn < dwActualConnCount ; dwIndexConn++)
        {
            LWNetSrvPingCLdapEnd(&pConnections[dwIndexConn]);
        }
        LW_SAFE_FREE_MEMORY(pConnections);
    }
    LW_SAFE_FREE_MEMORY(Readfds);
    if (dwError)
    {
        LWNET_SAFE_FREE_DC_INFO(pDcInfo);
    }
    *ppDcInfo = pDcInfo;
    *pbFailedFindWritable = pDcInfo ? FALSE : bFailedFindWritable;
    return dwError;
}
예제 #3
0
DWORD
LWNetBuildDCInfo(
    IN PBYTE pBuffer,
    IN DWORD dwBufferSize,
    OUT PLWNET_DC_INFO* ppDCInfo
)
{
    DWORD dwError = 0;
    PLWNET_DC_INFO pDCInfo = NULL;
    PACKED_ARRAY netLogon = { 0 };

    dwError = LWNetAllocateMemory(sizeof(LWNET_DC_INFO), (PVOID*)&pDCInfo);
    BAIL_ON_LWNET_ERROR(dwError);

    netLogon.pStart = pBuffer;
    netLogon.pCur = pBuffer;
    netLogon.totalSize = dwBufferSize;

    dwError = LWNetReadLEDword(&pDCInfo->dwDomainControllerAddressType, &netLogon);
    BAIL_ON_LWNET_ERROR(dwError);

    dwError = LWNetReadLEDword(&pDCInfo->dwFlags, &netLogon);
    BAIL_ON_LWNET_ERROR(dwError);

    dwError = LWNetReadGUID((PBYTE)&pDCInfo->pucDomainGUID[0], &netLogon);
    BAIL_ON_LWNET_ERROR(dwError);

    dwError = LWNetReadString(&pDCInfo->pszDnsForestName, &netLogon);
    BAIL_ON_LWNET_ERROR(dwError);

    dwError = LWNetReadString(&pDCInfo->pszFullyQualifiedDomainName, &netLogon);
    BAIL_ON_LWNET_ERROR(dwError);

    dwError = LWNetReadString(&pDCInfo->pszDomainControllerName, &netLogon);
    BAIL_ON_LWNET_ERROR(dwError);

    dwError = LWNetReadString(&pDCInfo->pszNetBIOSDomainName, &netLogon);
    BAIL_ON_LWNET_ERROR(dwError);

    dwError = LWNetReadString(&pDCInfo->pszNetBIOSHostName, &netLogon);
    BAIL_ON_LWNET_ERROR(dwError);

    dwError = LWNetReadString(&pDCInfo->pszUserName, &netLogon);
    BAIL_ON_LWNET_ERROR(dwError);

    dwError = LWNetReadString(&pDCInfo->pszDCSiteName, &netLogon);
    BAIL_ON_LWNET_ERROR(dwError);

    dwError = LWNetReadString(&pDCInfo->pszClientSiteName, &netLogon);
    BAIL_ON_LWNET_ERROR(dwError);

    dwError = LWNetReadLEDword(&pDCInfo->dwVersion, &netLogon);
    BAIL_ON_LWNET_ERROR(dwError);

    dwError = LWNetReadLEWord(&pDCInfo->wLMToken, &netLogon);
    BAIL_ON_LWNET_ERROR(dwError);

    dwError = LWNetReadLEWord(&pDCInfo->wNTToken, &netLogon);
    BAIL_ON_LWNET_ERROR(dwError);

error:
    if (dwError)
    {
        LWNET_SAFE_FREE_DC_INFO(pDCInfo);
    }

    *ppDCInfo = pDCInfo;

    return dwError;
}
예제 #4
0
static
DWORD
LWNetSrvPingCLdapProcess(
    IN PLWNET_CLDAP_CONNECTION_CONTEXT pContext,
    IN DWORD dwDsFlags,
    IN LWNET_UNIX_MS_TIME_T StopTime,
    OUT PLWNET_DC_INFO* ppDcInfo,
    OUT PBOOLEAN pbFailedFindWritable
)
{
    DWORD dwError = 0;
    DWORD dwResultType = 0;
    LDAPMessage* pMessage = NULL;
    PBYTE pNetlogonAttributeValue = NULL;
    DWORD dwNetlogonAttributeSize = 0;
    PLWNET_DC_INFO pDcInfo = NULL;
    BOOLEAN bFailedFindWritable = FALSE;
    struct timeval timeout = {0};
    LDAP *ld = NULL;

    ld = LwLdapGetSession(pContext->hDirectory);

    dwResultType =  ldap_result(
                        ld,
                        pContext->msgid,
                        0,
                        &timeout,
                        &pMessage);
    if (dwResultType == 0)
    {
        // timed out
        goto error;
    }
    else if (dwResultType == -1)
    {
        // -1 = problem
        dwError = LDAP_NO_SUCH_OBJECT;
        LWNET_LOG_VERBOSE("Caught LDAP_NO_SUCH_OBJECT Error on ldap search");
    }
    else
    {
        // returns result type
        if (dwResultType != LDAP_RES_SEARCH_ENTRY)
        {
            dwError = LDAP_NO_SUCH_OBJECT;
            LWNET_LOG_DEBUG("Caught incorrect result type on ldap search: %d", dwError);
        }
    }
    dwError = LwMapLdapErrorToLwError(dwError);
    BAIL_ON_LWNET_ERROR(dwError);

    dwError = LwLdapGetBytes(
                  pContext->hDirectory,
                  pMessage,
                  NETLOGON_LDAP_ATTRIBUTE_NAME,
                  &pNetlogonAttributeValue,
                  &dwNetlogonAttributeSize);
    BAIL_ON_LWNET_ERROR(dwError);

    dwError = LWNetBuildDCInfo(pNetlogonAttributeValue,
                               dwNetlogonAttributeSize,
                               &pDcInfo);
    BAIL_ON_LWNET_ERROR(dwError);

    dwError = LWNetAllocateString(pContext->pServerInfo->pszAddress, &pDcInfo->pszDomainControllerAddress);
    BAIL_ON_LWNET_ERROR(dwError);

    pDcInfo->dwPingTime = (DWORD)(StopTime - pContext->StartTime);
    if (StopTime < pContext->StartTime)
    {
        LWNET_LOG_ERROR("Stop time is earlier than start time");
    }

    if (!LWNetSrvIsMatchingDcInfo(pDcInfo, dwDsFlags))
    {
        dwError = LW_ERROR_NO_SUCH_OBJECT;

        if (LWNetSrvIsMatchingDcInfo(pDcInfo, dwDsFlags & ~DS_WRITABLE_REQUIRED))
        {
            // We found something, but it failed only because it did
            // not satisfy writability.
            bFailedFindWritable = TRUE;
        }
    }

error:
    if (pMessage)
    {
        ldap_msgfree(pMessage);
    }

    LWNET_SAFE_FREE_MEMORY(pNetlogonAttributeValue);

    if (dwError)
    {
        LWNET_SAFE_FREE_DC_INFO(pDcInfo);

        LWNetSrvPingCLdapEnd(pContext);
    }

    *ppDcInfo = pDcInfo;
    *pbFailedFindWritable = bFailedFindWritable;

    return dwError;
}
예제 #5
0
int
main(
    int argc,
    char* argv[]
    )
{
    DWORD dwError = 0;

    PSTR pszTargetFQDN = NULL;
    PSTR pszSiteName = NULL;
    PSTR pszPrimaryDomain = NULL;
    PLWNET_DC_INFO pDCInfo = NULL;
    DWORD dwFlags = 0;
    CHAR szErrorBuf[1024];
    
    INT i = 0;
    
    dwError = ParseArgs(
                argc,
                argv,
                &pszTargetFQDN,
                &pszSiteName,
                &pszPrimaryDomain,
                &dwFlags
                );
    BAIL_ON_LWNET_ERROR(dwError);

    lwnet_init_logging_to_file(LWNET_LOG_LEVEL_VERBOSE, TRUE, "");

    dwError = LWNetGetDCNameExt(
                NULL,
                pszTargetFQDN,
                pszSiteName,
                pszPrimaryDomain,
                dwFlags,
                0,
                NULL,
                &pDCInfo
                );
    BAIL_ON_LWNET_ERROR(dwError); 

    printf("Printing LWNET_DC_INFO fields:\n");
    printf("===============================\n");
    if(pDCInfo == NULL)
    {
        printf("<NULL>");
    }
    else
    {
        printf("dwDomainControllerAddressType = %u\n", pDCInfo->dwDomainControllerAddressType); 
        printf("dwFlags = %u\n", pDCInfo->dwFlags); 
        printf("dwVersion = %u\n", pDCInfo->dwVersion);       
        printf("wLMToken = %u\n", pDCInfo->wLMToken);  
        printf("wNTToken = %u\n", pDCInfo->wNTToken);
        
        safePrintString("pszDomainControllerName", pDCInfo->pszDomainControllerName);
        safePrintString("pszDomainControllerAddress", pDCInfo->pszDomainControllerAddress);
        
        printf("pucDomainGUID(hex) = ");
        for(i = 0; i < LWNET_GUID_SIZE; i++)
        {
            printf("%.2X ", pDCInfo->pucDomainGUID[i]);
        }
        printf("\n");
        
        safePrintString("pszNetBIOSDomainName", pDCInfo->pszNetBIOSDomainName);    
        safePrintString("pszFullyQualifiedDomainName", pDCInfo->pszFullyQualifiedDomainName);     
        safePrintString("pszDnsForestName", pDCInfo->pszDnsForestName);       
        safePrintString("pszDCSiteName", pDCInfo->pszDCSiteName);      
        safePrintString("pszClientSiteName", pDCInfo->pszClientSiteName); 
        safePrintString("pszNetBIOSHostName", pDCInfo->pszNetBIOSHostName);   
        safePrintString("pszUserName", pDCInfo->pszUserName);     
        
    }

error:
    if (dwError)
    {
        DWORD dwLen = LwGetErrorString(dwError, szErrorBuf, 1024);

        if (dwLen)
        {
            fprintf(
                 stderr,
                 "Failed communication with the LWNET Agent.  Error code %u (%s).\n%s\n",
                 dwError,
                 LW_PRINTF_STRING(LwWin32ExtErrorToName(dwError)),
                 szErrorBuf);
        }
        else
        {
            fprintf(
                 stderr,
                 "Failed communication with the LWNET Agent.  Error code %u (%s).\n",
                 dwError,
                 LW_PRINTF_STRING(LwWin32ExtErrorToName(dwError)));
        }
    }

    LWNET_SAFE_FREE_DC_INFO(pDCInfo);
    LWNET_SAFE_FREE_STRING(pszTargetFQDN);
    LWNET_SAFE_FREE_STRING(pszSiteName);
    return dwError;
}