diff --git a/dlls/netapi32/Makefile.in b/dlls/netapi32/Makefile.in index 23da4838f9c..13065578efe 100644 --- a/dlls/netapi32/Makefile.in +++ b/dlls/netapi32/Makefile.in @@ -1,7 +1,7 @@ EXTRADEFS = -D_SVRAPI_ MODULE = netapi32.dll IMPORTLIB = netapi32 -IMPORTS = rpcrt4 iphlpapi ws2_32 advapi32 +IMPORTS = rpcrt4 iphlpapi ws2_32 advapi32 dnsapi C_SRCS = \ nbcmdqueue.c \ diff --git a/dlls/netapi32/nbt.c b/dlls/netapi32/nbt.c index 48166303346..9c2a731a94c 100644 --- a/dlls/netapi32/nbt.c +++ b/dlls/netapi32/nbt.c @@ -1437,12 +1437,15 @@ static const WCHAR Config_NetworkW[] = { 'S','o','f','t','w','a','r','e','\\', /* Initializes global variables and registers the NetBT transport */ void NetBTInit(void) { + WSADATA wsa_data; HKEY hKey; NetBIOSTransport transport; LONG ret; TRACE("\n"); + WSAStartup(MAKEWORD(2, 2), &wsa_data); + gEnableDNS = TRUE; gBCastQueries = BCAST_QUERIES; gBCastQueryTimeout = BCAST_QUERY_TIMEOUT; diff --git a/dlls/netapi32/netapi32.c b/dlls/netapi32/netapi32.c index d6554aa676c..f86e033c211 100644 --- a/dlls/netapi32/netapi32.c +++ b/dlls/netapi32/netapi32.c @@ -4,6 +4,7 @@ * Copyright 2005,2006 Paul Vriens * Copyright 2006 Robert Reif * Copyright 2013 Hans Leidekker for CodeWeavers + * Copyright 2020 Dmitry Timoshkov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -37,6 +38,9 @@ #define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" +#include "winsock2.h" +#include "ws2ipdef.h" +#include "windns.h" #include "lm.h" #include "lmaccess.h" #include "atsvc.h" @@ -56,9 +60,12 @@ #include "wine/library.h" #include "wine/list.h" #include "wine/unicode.h" +#include "initguid.h" WINE_DEFAULT_DEBUG_CHANNEL(netapi32); +DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); + static char *strdup_unixcp( const WCHAR *str ) { char *ret; @@ -3033,14 +3040,142 @@ NET_API_STATUS WINAPI I_BrowserQueryEmulatedDomains( return ERROR_NOT_SUPPORTED; } -DWORD WINAPI DsGetDcNameW(LPCWSTR ComputerName, LPCWSTR AvoidDCName, - GUID* DomainGuid, LPCWSTR SiteName, ULONG Flags, - PDOMAIN_CONTROLLER_INFOW *DomainControllerInfo) +#define NS_MAXDNAME 1025 + +static DWORD get_dc_info(const WCHAR *domain, WCHAR *dc, WCHAR *ip) { - FIXME("(%s, %s, %s, %s, %08x, %p): stub\n", debugstr_w(ComputerName), - debugstr_w(AvoidDCName), debugstr_guid(DomainGuid), - debugstr_w(SiteName), Flags, DomainControllerInfo); - return ERROR_CALL_NOT_IMPLEMENTED; + static const WCHAR pfx[] = {'_','l','d','a','p','.','_','t','c','p','.','d','c','.','_','m','s','d','c','s','.',0}; + WCHAR name[NS_MAXDNAME]; + DWORD ret, size; + DNS_RECORDW *rec; + + lstrcpyW(name, pfx); + lstrcatW(name, domain); + + ret = DnsQuery_W(name, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &rec, NULL); + TRACE("DnsQuery_W(%s) => %d\n", wine_dbgstr_w(domain), ret); + if (ret == ERROR_SUCCESS) + { + TRACE("target %s, port %d\n", wine_dbgstr_w(rec->Data.Srv.pNameTarget), rec->Data.Srv.wPort); + + lstrcpynW(dc, rec->Data.Srv.pNameTarget, NS_MAXDNAME); + DnsRecordListFree(rec, DnsFreeRecordList); + + /* IPv4 */ + ret = DnsQuery_W(dc, DNS_TYPE_A, DNS_QUERY_STANDARD, NULL, &rec, NULL); + TRACE("DnsQuery_W(%s) => %d\n", wine_dbgstr_w(dc), ret); + if (ret == ERROR_SUCCESS) + { + SOCKADDR_IN addr; + + addr.sin_family = AF_INET; + addr.sin_port = 0; + addr.sin_addr.s_addr = rec->Data.A.IpAddress; + size = IP6_ADDRESS_STRING_LENGTH; + ret = WSAAddressToStringW((SOCKADDR *)&addr, sizeof(addr), NULL, ip, &size); + if (!ret) + TRACE("WSAAddressToStringW => %d, %s\n", ret, wine_dbgstr_w(ip)); + + DnsRecordListFree(rec, DnsFreeRecordList); + + return ret; + } + + /* IPv6 */ + ret = DnsQuery_W(dc, DNS_TYPE_AAAA, DNS_QUERY_STANDARD, NULL, &rec, NULL); + TRACE("DnsQuery_W(%s) => %d\n", wine_dbgstr_w(dc), ret); + if (ret == ERROR_SUCCESS) + { + SOCKADDR_IN6 addr; + + addr.sin6_family = AF_INET6; + addr.sin6_port = 0; + addr.sin6_scope_id = 0; + memcpy(addr.sin6_addr.s6_addr, &rec->Data.AAAA.Ip6Address, sizeof(rec->Data.AAAA.Ip6Address)); + size = IP6_ADDRESS_STRING_LENGTH; + ret = WSAAddressToStringW((SOCKADDR *)&addr, sizeof(addr), NULL, ip, &size); + if (!ret) + TRACE("WSAAddressToStringW => %d, %s\n", ret, wine_dbgstr_w(ip)); + + DnsRecordListFree(rec, DnsFreeRecordList); + } + } + + return ret; +} + +DWORD WINAPI DsGetDcNameW(LPCWSTR computer, LPCWSTR domain, GUID *domain_guid, + LPCWSTR site, ULONG flags, PDOMAIN_CONTROLLER_INFOW *dc_info) +{ + static const WCHAR pfxW[] = {'\\','\\'}; + static const WCHAR default_site_nameW[] = {'D','e','f','a','u','l','t','-','F','i','r','s','t','-','S','i','t','e','-','N','a','m','e',0}; + NTSTATUS status; + POLICY_DNS_DOMAIN_INFO *dns_domain_info = NULL; + DOMAIN_CONTROLLER_INFOW *info; + WCHAR dc[NS_MAXDNAME], ip[IP6_ADDRESS_STRING_LENGTH]; + DWORD size; + + FIXME("(%s, %s, %s, %s, %08x, %p): semi-stub\n", debugstr_w(computer), + debugstr_w(domain), debugstr_guid(domain_guid), debugstr_w(site), flags, dc_info); + + if (!dc_info) return ERROR_INVALID_PARAMETER; + + if (!domain) + { + LSA_OBJECT_ATTRIBUTES attrs; + LSA_HANDLE lsa; + + memset(&attrs, 0, sizeof(attrs)); + attrs.Length = sizeof(attrs); + status = LsaOpenPolicy(NULL, &attrs, POLICY_VIEW_LOCAL_INFORMATION, &lsa); + if (status) + return LsaNtStatusToWinError(status); + + status = LsaQueryInformationPolicy(lsa, PolicyDnsDomainInformation, (void **)&dns_domain_info); + LsaClose(lsa); + if (status) + return LsaNtStatusToWinError(status); + + domain = dns_domain_info->DnsDomainName.Buffer; + } + + status = get_dc_info(domain, dc, ip); + if (status) return status; + + size = sizeof(DOMAIN_CONTROLLER_INFOW) + lstrlenW(domain) * sizeof(WCHAR) + + sizeof(pfxW) * 2 + (lstrlenW(dc) + 1 + lstrlenW(ip) + 1) * sizeof(WCHAR) + + lstrlenW(domain) * sizeof(WCHAR) /* assume forest == domain */ + + sizeof(default_site_nameW) * 2; + status = NetApiBufferAllocate(size, (void **)&info); + if (status != NERR_Success) + { + LsaFreeMemory(dns_domain_info); + return ERROR_NOT_ENOUGH_MEMORY; + } + + info->DomainControllerName = (WCHAR *)(info + 1); + memcpy(info->DomainControllerName, pfxW, sizeof(pfxW)); + lstrcpyW(info->DomainControllerName + 2, dc); + info->DomainControllerAddress = (WCHAR *)((char *)info->DomainControllerName + (strlenW(info->DomainControllerName) + 1) * sizeof(WCHAR)); + memcpy(info->DomainControllerAddress, pfxW, sizeof(pfxW)); + lstrcpyW(info->DomainControllerAddress + 2, ip); + info->DomainControllerAddressType = DS_INET_ADDRESS; + info->DomainGuid = dns_domain_info ? dns_domain_info->DomainGuid : GUID_NULL /* FIXME */; + info->DomainName = (WCHAR *)((char *)info->DomainControllerAddress + (strlenW(info->DomainControllerAddress) + 1) * sizeof(WCHAR)); + lstrcpyW(info->DomainName, domain); + info->DnsForestName = (WCHAR *)((char *)info->DomainName + (lstrlenW(info->DomainName) + 1) * sizeof(WCHAR)); + lstrcpyW(info->DnsForestName, domain); + info->DcSiteName = (WCHAR *)((char *)info->DnsForestName + (lstrlenW(info->DnsForestName) + 1) * sizeof(WCHAR)); + lstrcpyW(info->DcSiteName, default_site_nameW); + info->ClientSiteName = (WCHAR *)((char *)info->DcSiteName + sizeof(default_site_nameW)); + lstrcpyW(info->ClientSiteName, default_site_nameW); + info->Flags = DS_DNS_DOMAIN_FLAG | DS_DNS_FOREST_FLAG; + + LsaFreeMemory(dns_domain_info); + + *dc_info = info; + + return ERROR_SUCCESS; } DWORD WINAPI DsGetDcNameA(LPCSTR ComputerName, LPCSTR AvoidDCName, diff --git a/include/dsgetdc.h b/include/dsgetdc.h index c53fcc299a7..856912212fa 100644 --- a/include/dsgetdc.h +++ b/include/dsgetdc.h @@ -23,6 +23,13 @@ extern "C" { #endif +#define DS_INET_ADDRESS 1 +#define DS_NETBIOS_ADDRESS 2 + +#define DS_DNS_CONTROLLER_FLAG 0x20000000 +#define DS_DNS_DOMAIN_FLAG 0x40000000 +#define DS_DNS_FOREST_FLAG 0x80000000 + #define DS_FORCE_REDISCOVERY 0x00000001 #define DS_DIRECTORY_SERVICE_REQUIRED 0x00000010 #define DS_DIRECTORY_SERVICE_PREFERRED 0x00000020