Получить имя контроллера домена

Резюме: я хочу получить имя контроллера домена, используя только WinAPI, компьютер не находится в сети, что может привести к сбою моего кода с "NERR_DCNotFound"?

Я пытаюсь получить имя контроллера домена, частью которого будет сетевой компьютер.

Компьютер, с которым я экспериментирую, — это просто персональный компьютер, я никогда не устанавливаю контроллер домена или что-то, что может затруднить тестирование? На данный момент он находится внутри VirtualBox, изолированного от Интернета.

Когда я запускаю это из командной строки, я получаю следующий вывод, который, по-видимому, содержит доменное имя:

C:\Users\lone>gpresult /Z

Microsoft (R) Windows (R) Operating System Group Policy Result tool v2.0
© 2016 Microsoft Corporation. All rights reserved.

Created on 31/01/2018 at 12:24:12


RSOP data for DESKTOP-I53IU6C\lone on DESKTOP-I53IU6C : Logging Mode
---------------------------------------------------------------------

OS Configuration:            Standalone Workstation
OS Version:                  10.0.10586
Site Name:                   N/A
Roaming Profile:             N/A
Local Profile:               C:\Users\lone
Connected over a slow link?: No


USER SETTINGS
--------------

    Last time Group Policy was applied: 31/01/2018 at 10:30:38
    Group Policy was applied from:      N/A
    Group Policy slow link threshold:   500 kbps
    Domain Name:                        DESKTOP-I53IU6C
    Domain Type:                        <Local Computer>

    Applied Group Policy Objects
    -----------------------------
        N/A

    The following GPOs were not applied because they were filtered out
    -------------------------------------------------------------------
        Local Group Policy
            Filtering:  Not Applied (Empty)

    The user is a part of the following security groups
    ---------------------------------------------------
        None
        Everyone
        Local account and member of Administrators group
        HelpLibraryUpdaters
        BUILTIN\Administrators
        BUILTIN\Users
        NT AUTHORITY\INTERACTIVE
        CONSOLE LOGON
        NT AUTHORITY\Authenticated Users
        This Organization
        Local account
        LOCAL
        NTLM Authentication
        High Mandatory Level

    The user has the following security privileges
    ----------------------------------------------


    Resultant Set Of Policies for User
    -----------------------------------

        Software Installations
        ----------------------
            N/A

        Logon Scripts
        -------------
            N/A

        Logoff Scripts
        --------------
            N/A

        Public Key Policies
        -------------------
            N/A

        Administrative Templates
        ------------------------
            N/A

        Folder Redirection
        ------------------
            N/A

        Internet Explorer Browser User Interface
        ----------------------------------------
            N/A

        Internet Explorer Connection
        ----------------------------
            N/A

        Internet Explorer URLs
        ----------------------
            N/A

        Internet Explorer Security
        --------------------------
            N/A

        Internet Explorer Programs
        --------------------------
            N/A

Я получаю это из приведенного выше вывода:

Имя домена: DESKTOP-I53IU6C

Может быть, я путаю доменное имя с именем контроллера домена?

Я копирую и вставляю код из MSDN учебник:

#ifndef UNICODE
#define UNICODE
#endif

#include <stdio.h>
#include <stdlib.h>  // for _wtoi function
#include <assert.h>
#include <windows.h>
#include <lm.h>

// Need to link with netapi32.lib
#pragma comment(lib, "netapi32.lib")

int wmain(int argc, wchar_t * argv[])
{

    NET_API_STATUS nStatus;

    LPCWSTR lpServer = NULL;
    LPCWSTR lpDomain = NULL;

    LPCWSTR lpDcName = NULL;

    if (argc != 3 ) {
        wprintf(L"Usage: %ws <ServerName> <DomainName>\n",
                argv[0]);
        wprintf(L"     %ws Myserver Domain\n", argv[0]);
        exit(1);
    }

    // lpServer = argv[1];
    // lpDomain = argv[2];

    wprintf(L"Calling NetGetDCName with parameters\n");
    wprintf(L"    lpServer = %ws\n", lpServer);
    wprintf(L"    lpDomain = %ws\n", lpDomain);

    //
    // Call the NetGetDCName function
    //
    nStatus = NetGetDCName(lpServer, lpDomain, (LPBYTE *) &lpDcName);
    //
    // If the call succeeds,
    //
    if (nStatus == NERR_Success) {
        wprintf(L"NetGetDCName was successful\n", nStatus);
        wprintf(L"DC Name = %ws\n", lpDcName);
        // Need to free the returned buffer
        nStatus = NetApiBufferFree( (LPVOID) lpDcName);
        if (nStatus != NERR_Success)
            wprintf(L"NetApiBufferFree failed with error: %lu (0x%lx)\n",
                nStatus, nStatus);
    } else {
        wprintf(L"NetGetDCName failed with error: %lu (0x%lx)\n", nStatus,
                nStatus);
        wprintf(L"   Error = ");
        switch (nStatus) {
        case ERROR_INVALID_PARAMETER:
            wprintf(L"ERROR_INVALID_PARAMETER\n");
            break;
        case ERROR_NO_SUCH_DOMAIN:
            wprintf(L"ERROR_NO_SUCH_DOMAIN\n");
            break;
        case ERROR_NOT_SUPPORTED:
            wprintf(L"ERROR_NOT_SUPPORTED\n");
            break;
        case ERROR_BAD_NETPATH:
            wprintf(L"ERROR_BAD_NETPATH\n");
            break;
        case ERROR_INVALID_COMPUTERNAME:
            wprintf(L"ERROR_INVALID_COMPUTERNAME\n");
            break;
        case DNS_ERROR_INVALID_NAME_CHAR:
            wprintf(L"DNS_ERROR_INVALID_NAME_CHAR\n");
            break;
        case DNS_ERROR_NON_RFC_NAME:
            wprintf(L"DNS_ERROR_NON_RFC_NAME\n");
            break;
        case ERROR_INVALID_NAME:
            wprintf(L"ERROR_INVALID_NAME\n");
            break;
        case NERR_DCNotFound:
            wprintf(L"NERR_DCNotFound\n");
            break;
        case NERR_WkstaNotStarted:
            wprintf(L"NERR_WkstaNotStarted\n");
            break;
        case RPC_S_SERVER_UNAVAILABLE:
            wprintf(L"RPC_S_SERVER_UNAVAILABLE\n");
            break;
        case RPC_E_REMOTE_DISABLED:
            wprintf(L"RPC_E_REMOTE_DISABLED\n");
            break;
        default:
            wprintf(L"Other error, see Winerror.h or lmerr.h)\n");
            break;
        }
    }

    return nStatus;
}

Я только закомментировал аргументы командной строки, чтобы оставить их как NULL:

    // lpServer = argv[1];
    // lpDomain = argv[2];

Указатель на постоянную строку, указывающую имя DNS или NetBIOS удаленного сервера, на котором должна выполняться функция. Если этот параметр имеет значение NULL, используется локальный компьютер.

Указатель на константную строку, указывающую имя домена. Имя домена должно быть доменным именем NetBIOS (например, Microsoft). NetGetDCName не поддерживает имена в стиле DNS (например, microsoft.com). Если этот параметр имеет значение NULL, функция возвращает имя контроллера домена для основного домена.

Я получаю сообщение об ошибке:

NERR_DCNotFound

Почему аргумент командной строки дал мне доменное имя, но WinAPI не работает, или это две разные вещи с похожим именем?

Спасибо!


person securityauditor    schedule 31.01.2018    source источник
comment
Близко только на подковы и ручные гранаты.   -  person stark    schedule 31.01.2018
comment
Для автономного компьютера доменным именем является имя компьютера. Нет контроллера домена, так как у вас нет реального домена.   -  person Richard Critten    schedule 31.01.2018
comment
Почему этот вопрос помечен c++?   -  person Eljay    schedule 31.01.2018
comment
@Eljay Хотя я предпочитаю C, я рад решению на C++.   -  person securityauditor    schedule 31.01.2018
comment
@RichardCritten Хорошо, но почему эта командная строка возвращает что-то под названием Доменное имя: ?? Это что-то другое? Кроме того, если доменное имя является именем компьютера, почему опубликованный мной код не работает?   -  person securityauditor    schedule 31.01.2018
comment
@stark Я знаю, что это значит, но мне нужен код WinAPI для работы, мне не разрешено использовать командную строку (с системой () или чем-то еще), извините.   -  person securityauditor    schedule 31.01.2018
comment
Ваш код запрашивает контроллер домена. У вас его нет. Так что это не удается. Ваша командная строка дает вам доменное имя, а не имя контроллера домена (которого у вас нет).   -  person Mat    schedule 31.01.2018
comment
вам нужно имя домена учетной записи? (DESKTOP-I53IU6C в вашем случае это именно так). Домен учетной записи - это нужно?   -  person RbMm    schedule 31.01.2018
comment
@RbMm Я думаю, мне нужен домен учетной записи, как я могу получить его с помощью WinAPI, поскольку использование командной строки не разрешено?   -  person securityauditor    schedule 31.01.2018
comment
@ user5623335 - я уже вставляю ответ   -  person RbMm    schedule 31.01.2018
comment
@RbMm Вы собираетесь убить меня, но не могли бы вы сделать это на C, а не на C++, извините? Ваш исходный код был очень и очень полезным.   -  person securityauditor    schedule 31.01.2018
comment
@ user5623335 - извините - я не понимаю ваш последний комментарий   -  person RbMm    schedule 31.01.2018
comment
@RbMm Код, который вы опубликовали, написан на C++, а не на C?   -  person securityauditor    schedule 31.01.2018
comment
что отличается ? я всегда компилирую код как c++. для меня это код С++.   -  person RbMm    schedule 31.01.2018
comment
@RbMm Можно ли получить это в коде C, пожалуйста, я недостаточно знаю C ++, чтобы понять это. Я компилирую как C, а не C++.   -  person securityauditor    schedule 31.01.2018
comment
но это почти совместимо с кодом c - я не использую никаких функций С++ (за исключением того, как объявлена ​​​​переменная). в какой проблеме скомпилировать его как c ?   -  person RbMm    schedule 31.01.2018
comment
ошибка C2223: слева от '->DnsDomainName' должен указывать на структуру/объединение. Я получаю эту ошибку для DomainName, Name, Sid...   -  person securityauditor    schedule 31.01.2018
comment
но это уже ваша задача написать окончательный код и скомпилировать его. вам в любом случае нужно что-то изменить. я описываю, какой API и как нужно вызывать для получения информации   -  person RbMm    schedule 31.01.2018


Ответы (1)


вы можете использовать call LsaQueryInformationPolicy сначала с PolicyDnsDomainInformation или PolicyPrimaryDomainInformation для получения компьютера основной домен.

если член Sid POLICY_DNS_DOMAIN_INFO или POLICY_PRIMARY_DOMAIN_INFO (SID основного домена) равен 0 — это означает, что в системе нет основного домена. в этом случае нам нужен запрос домен аккаунта:

В системе, которая не является частью сети и поэтому не имеет основного домена, домен учетной записи используется для размещения всех учетных записей, обеспечивающих доступ к компьютеру.

для этого нам нужно вызвать LsaQueryInformationPolicy< /a> с PolicyAccountDomainInformation и получил POLICY_ACCOUNT_DOMAIN_INFO

#include <Ntsecapi.h>

NTSTATUS PrintDomainName()
{
    LSA_HANDLE PolicyHandle;

    static LSA_OBJECT_ATTRIBUTES oa = { sizeof(oa) };

    NTSTATUS status = LsaOpenPolicy(0, &oa, POLICY_VIEW_LOCAL_INFORMATION, &PolicyHandle);

    if (LSA_SUCCESS(status))
    {
        union {
            PPOLICY_DNS_DOMAIN_INFO ppddi;
            PPOLICY_ACCOUNT_DOMAIN_INFO ppadi;
        };

        if (LSA_SUCCESS(status = LsaQueryInformationPolicy(PolicyHandle, PolicyDnsDomainInformation, (void**)&ppddi)))
        {
            if (ppddi->Sid)
            {
                DbgPrint("DnsDomainName: %wZ\n", &ppddi->DnsDomainName);
            }
            else
            {
                DbgPrint("%wZ: not domain controller !!\n", &ppddi->Name);
                status = -1;
            }

            LsaFreeMemory(ppddi);

            if (0 > status)
            {
                if (LSA_SUCCESS(status = LsaQueryInformationPolicy(PolicyHandle, PolicyAccountDomainInformation, (void**)&ppadi)))
                {
                    DbgPrint("DomainName: %wZ\n", &ppadi->DomainName);
                    LsaFreeMemory(ppadi);
                }
            }
        }

        LsaClose(PolicyHandle);
    }

    return status;
}

я получил следующий вывод:

WORKGROUP: not domain controller !!
DomainName: DESKTOP-2N5ODLB
person RbMm    schedule 31.01.2018