xref: /reactos/dll/win32/dnsapi/query.c (revision d6eebaa4)
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS system libraries
4  * FILE:        lib/dnsapi/dnsapi/query.c
5  * PURPOSE:     DNSAPI functions built on the ADNS library.
6  * PROGRAMER:   Art Yerkes
7  * UPDATE HISTORY:
8  *              12/15/03 -- Created
9  */
10 
11 #include "precomp.h"
12 #include <winreg.h>
13 #include <iphlpapi.h>
14 #include <strsafe.h>
15 
16 #define NDEBUG
17 #include <debug.h>
18 
19 static
20 BOOL
21 ParseIpv4Address(
22     _In_ PCWSTR AddressString,
23     _Out_ PIN_ADDR pAddress)
24 {
25     PCWSTR pTerminator = NULL;
26     NTSTATUS Status;
27 
28     Status = RtlIpv4StringToAddressW(AddressString,
29                                      TRUE,
30                                      &pTerminator,
31                                      pAddress);
32     if (NT_SUCCESS(Status) && pTerminator != NULL && *pTerminator == L'\0')
33         return TRUE;
34 
35     return FALSE;
36 }
37 
38 
39 static
40 BOOL
41 ParseIpv6Address(
42     _In_ PCWSTR AddressString,
43     _Out_ PIN6_ADDR pAddress)
44 {
45     PCWSTR pTerminator = NULL;
46     NTSTATUS Status;
47 
48     Status = RtlIpv6StringToAddressW(AddressString,
49                                      &pTerminator,
50                                      pAddress);
51     if (NT_SUCCESS(Status) && pTerminator != NULL && *pTerminator == L'\0')
52         return TRUE;
53 
54     return FALSE;
55 }
56 
57 
58 static
59 PDNS_RECORDW
60 CreateRecordForIpAddress(
61     _In_ PCWSTR Name,
62     _In_ WORD Type)
63 {
64     IN_ADDR Ip4Address;
65     IN6_ADDR Ip6Address;
66     PDNS_RECORDW pRecord = NULL;
67 
68     if (Type == DNS_TYPE_A)
69     {
70         if (ParseIpv4Address(Name, &Ip4Address))
71         {
72             pRecord = RtlAllocateHeap(RtlGetProcessHeap(),
73                                       HEAP_ZERO_MEMORY,
74                                       sizeof(DNS_RECORDW));
75             if (pRecord == NULL)
76                 return NULL;
77 
78             pRecord->pName = RtlAllocateHeap(RtlGetProcessHeap(),
79                                              0,
80                                              (wcslen(Name) + 1) * sizeof(WCHAR));
81             if (pRecord == NULL)
82             {
83                 RtlFreeHeap(RtlGetProcessHeap(), 0, pRecord);
84                 return NULL;
85             }
86 
87             wcscpy(pRecord->pName, Name);
88             pRecord->wType = DNS_TYPE_A;
89             pRecord->wDataLength = sizeof(DNS_A_DATA);
90             pRecord->Flags.S.Section = DnsSectionQuestion;
91             pRecord->Flags.S.CharSet = DnsCharSetUnicode;
92             pRecord->dwTtl = 7 * 24 * 60 * 60;
93 
94             pRecord->Data.A.IpAddress = Ip4Address.S_un.S_addr;
95 
96             return pRecord;
97         }
98     }
99     else if (Type == DNS_TYPE_AAAA)
100     {
101         if (ParseIpv6Address(Name, &Ip6Address))
102         {
103             pRecord = RtlAllocateHeap(RtlGetProcessHeap(),
104                                       HEAP_ZERO_MEMORY,
105                                       sizeof(DNS_RECORDW));
106             if (pRecord == NULL)
107                 return NULL;
108 
109             pRecord->pName = RtlAllocateHeap(RtlGetProcessHeap(),
110                                              0,
111                                              (wcslen(Name) + 1) * sizeof(WCHAR));
112             if (pRecord == NULL)
113             {
114                 RtlFreeHeap(RtlGetProcessHeap(), 0, pRecord);
115                 return NULL;
116             }
117 
118             wcscpy(pRecord->pName, Name);
119             pRecord->wType = DNS_TYPE_AAAA;
120             pRecord->wDataLength = sizeof(DNS_AAAA_DATA);
121             pRecord->Flags.S.Section = DnsSectionQuestion;
122             pRecord->Flags.S.CharSet = DnsCharSetUnicode;
123             pRecord->dwTtl = 7 * 24 * 60 * 60;
124 
125             CopyMemory(&pRecord->Data.AAAA.Ip6Address,
126                        &Ip6Address.u.Byte,
127                        sizeof(IN6_ADDR));
128 
129             return pRecord;
130         }
131     }
132 
133     return NULL;
134 }
135 
136 
137 /* DnsQuery ****************************
138  * Begin a DNS query, and allow the result to be placed in the application
139  * supplied result pointer.  The result can be manipulated with the record
140  * functions.
141  *
142  * Name                 -- The DNS object to be queried.
143  * Type                 -- The type of records to be returned.  These are
144  *                          listed in windns.h
145  * Options              -- Query options.  DNS_QUERY_STANDARD is the base
146  *                          state, and every other option takes precedence.
147  *                          multiple options can be combined.  Listed in
148  *                          windns.h
149  * Servers              -- List of alternate servers (optional)
150  * QueryResultSet       -- Pointer to the result pointer that will be filled
151  *                          when the response is available.
152  * Reserved             -- Response as it appears on the wire.  Optional.
153  */
154 
155 static PCHAR
156 DnsWToC(const WCHAR *WideString)
157 {
158     PCHAR AnsiString;
159     int AnsiLen = WideCharToMultiByte(CP_ACP,
160                                       0,
161                                       WideString,
162                                       -1,
163                                       NULL,
164                                       0,
165                                       NULL,
166                                       0);
167     if (AnsiLen == 0)
168         return NULL;
169     AnsiString = RtlAllocateHeap(RtlGetProcessHeap(), 0, AnsiLen);
170     if (AnsiString == NULL)
171     {
172         return NULL;
173     }
174     WideCharToMultiByte(CP_ACP,
175                         0,
176                         WideString,
177                         -1,
178                         AnsiString,
179                         AnsiLen,
180                         NULL,
181                         0);
182 
183     return AnsiString;
184 }
185 
186 static PWCHAR
187 DnsCToW(const CHAR *NarrowString)
188 {
189     PWCHAR WideString;
190     int WideLen = MultiByteToWideChar(CP_ACP,
191                                       0,
192                                       NarrowString,
193                                       -1,
194                                       NULL,
195                                       0);
196     if (WideLen == 0)
197         return NULL;
198     WideString = RtlAllocateHeap(RtlGetProcessHeap(), 0, WideLen * sizeof(WCHAR));
199     if (WideString == NULL)
200     {
201         return NULL;
202     }
203     MultiByteToWideChar(CP_ACP,
204                         0,
205                         NarrowString,
206                         -1,
207                         WideString,
208                         WideLen);
209 
210     return WideString;
211 }
212 
213 static PCHAR
214 DnsWToUTF8(const WCHAR *WideString)
215 {
216     PCHAR AnsiString;
217     int AnsiLen = WideCharToMultiByte(CP_UTF8,
218                                       0,
219                                       WideString,
220                                       -1,
221                                       NULL,
222                                       0,
223                                       NULL,
224                                       0);
225     if (AnsiLen == 0)
226         return NULL;
227     AnsiString = RtlAllocateHeap(RtlGetProcessHeap(), 0, AnsiLen);
228     if (AnsiString == NULL)
229     {
230         return NULL;
231     }
232     WideCharToMultiByte(CP_UTF8,
233                         0,
234                         WideString,
235                         -1,
236                         AnsiString,
237                         AnsiLen,
238                         NULL,
239                         0);
240 
241     return AnsiString;
242 }
243 
244 static PWCHAR
245 DnsUTF8ToW(const CHAR *NarrowString)
246 {
247     PWCHAR WideString;
248     int WideLen = MultiByteToWideChar(CP_UTF8,
249                                       0,
250                                       NarrowString,
251                                       -1,
252                                       NULL,
253                                       0);
254     if (WideLen == 0)
255         return NULL;
256     WideString = RtlAllocateHeap(RtlGetProcessHeap(), 0, WideLen * sizeof(WCHAR));
257     if (WideString == NULL)
258     {
259         return NULL;
260     }
261     MultiByteToWideChar(CP_UTF8,
262                         0,
263                         NarrowString,
264                         -1,
265                         WideString,
266                         WideLen);
267 
268     return WideString;
269 }
270 
271 DNS_STATUS WINAPI
272 DnsQuery_CodePage(UINT CodePage,
273            LPCSTR Name,
274            WORD Type,
275            DWORD Options,
276            PVOID Extra,
277            PDNS_RECORD *QueryResultSet,
278            PVOID *Reserved)
279 {
280     UINT i;
281     PWCHAR Buffer;
282     DNS_STATUS Status;
283     PDNS_RECORD QueryResultWide;
284     PDNS_RECORD ConvertedRecord = 0, LastRecord = 0;
285 
286     if (Name == NULL)
287         return ERROR_INVALID_PARAMETER;
288     if (QueryResultSet == NULL)
289         return ERROR_INVALID_PARAMETER;
290 
291     switch (CodePage)
292     {
293     case CP_ACP:
294         Buffer = DnsCToW(Name);
295         break;
296 
297     case CP_UTF8:
298         Buffer = DnsUTF8ToW(Name);
299         break;
300 
301     default:
302         return ERROR_INVALID_PARAMETER;
303     }
304 
305     Status = DnsQuery_W(Buffer, Type, Options, Extra, &QueryResultWide, Reserved);
306 
307     while (Status == ERROR_SUCCESS && QueryResultWide)
308     {
309         switch (QueryResultWide->wType)
310         {
311         case DNS_TYPE_A:
312         case DNS_TYPE_WKS:
313         case DNS_TYPE_CNAME:
314         case DNS_TYPE_PTR:
315         case DNS_TYPE_NS:
316         case DNS_TYPE_MB:
317         case DNS_TYPE_MD:
318         case DNS_TYPE_MF:
319         case DNS_TYPE_MG:
320         case DNS_TYPE_MR:
321             ConvertedRecord = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD));
322             break;
323 
324         case DNS_TYPE_MINFO:
325             ConvertedRecord = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_TXT_DATA) + QueryResultWide->Data.TXT.dwStringCount);
326             break;
327 
328         case DNS_TYPE_NULL:
329             ConvertedRecord = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_NULL_DATA) + QueryResultWide->Data.Null.dwByteCount);
330             break;
331         }
332         if (ConvertedRecord == NULL)
333         {
334             /* The name */
335             RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
336             /* The result*/
337             DnsIntFreeRecordList(QueryResultWide);
338             QueryResultSet = NULL;
339             return ERROR_OUTOFMEMORY;
340         }
341 
342         if (CodePage == CP_ACP)
343         {
344             ConvertedRecord->pName = DnsWToC((PWCHAR)QueryResultWide->pName);
345             ConvertedRecord->Flags.S.CharSet = DnsCharSetAnsi;
346         }
347         else
348         {
349             ConvertedRecord->pName = DnsWToUTF8((PWCHAR)QueryResultWide->pName);
350             ConvertedRecord->Flags.S.CharSet = DnsCharSetUtf8;
351         }
352 
353         ConvertedRecord->wType = QueryResultWide->wType;
354 
355         switch (QueryResultWide->wType)
356         {
357         case DNS_TYPE_A:
358         case DNS_TYPE_WKS:
359             ConvertedRecord->wDataLength = QueryResultWide->wDataLength;
360             memcpy(&ConvertedRecord->Data, &QueryResultWide->Data, QueryResultWide->wDataLength);
361             break;
362 
363         case DNS_TYPE_CNAME:
364         case DNS_TYPE_PTR:
365         case DNS_TYPE_NS:
366         case DNS_TYPE_MB:
367         case DNS_TYPE_MD:
368         case DNS_TYPE_MF:
369         case DNS_TYPE_MG:
370         case DNS_TYPE_MR:
371             ConvertedRecord->wDataLength = sizeof(DNS_PTR_DATA);
372             if (CodePage == CP_ACP)
373                 ConvertedRecord->Data.PTR.pNameHost = DnsWToC((PWCHAR)QueryResultWide->Data.PTR.pNameHost);
374             else
375                 ConvertedRecord->Data.PTR.pNameHost = DnsWToUTF8((PWCHAR)QueryResultWide->Data.PTR.pNameHost);
376             break;
377 
378         case DNS_TYPE_MINFO:
379             ConvertedRecord->wDataLength = sizeof(DNS_MINFO_DATA);
380             if (CodePage == CP_ACP)
381             {
382                 ConvertedRecord->Data.MINFO.pNameMailbox = DnsWToC((PWCHAR)QueryResultWide->Data.MINFO.pNameMailbox);
383                 ConvertedRecord->Data.MINFO.pNameErrorsMailbox = DnsWToC((PWCHAR)QueryResultWide->Data.MINFO.pNameErrorsMailbox);
384             }
385             else
386             {
387                 ConvertedRecord->Data.MINFO.pNameMailbox = DnsWToUTF8((PWCHAR)QueryResultWide->Data.MINFO.pNameMailbox);
388                 ConvertedRecord->Data.MINFO.pNameErrorsMailbox = DnsWToUTF8((PWCHAR)QueryResultWide->Data.MINFO.pNameErrorsMailbox);
389             }
390             break;
391 
392         case DNS_TYPE_MX:
393             ConvertedRecord->wDataLength = sizeof(DNS_MX_DATA);
394             if (CodePage == CP_ACP)
395                 ConvertedRecord->Data.MX.pNameExchange = DnsWToC((PWCHAR)QueryResultWide->Data.MX.pNameExchange);
396             else
397                 ConvertedRecord->Data.MX.pNameExchange = DnsWToUTF8((PWCHAR)QueryResultWide->Data.MX.pNameExchange);
398             ConvertedRecord->Data.MX.wPreference = QueryResultWide->Data.MX.wPreference;
399             break;
400 
401         case DNS_TYPE_HINFO:
402             ConvertedRecord->wDataLength = sizeof(DNS_TXT_DATA) + (sizeof(PCHAR) * QueryResultWide->Data.TXT.dwStringCount);
403             ConvertedRecord->Data.TXT.dwStringCount = QueryResultWide->Data.TXT.dwStringCount;
404 
405             if (CodePage == CP_ACP)
406                 for (i = 0; i < ConvertedRecord->Data.TXT.dwStringCount; i++)
407                     ConvertedRecord->Data.TXT.pStringArray[i] = DnsWToC((PWCHAR)QueryResultWide->Data.TXT.pStringArray[i]);
408             else
409                 for (i = 0; i < ConvertedRecord->Data.TXT.dwStringCount; i++)
410                     ConvertedRecord->Data.TXT.pStringArray[i] = DnsWToUTF8((PWCHAR)QueryResultWide->Data.TXT.pStringArray[i]);
411 
412             break;
413 
414         case DNS_TYPE_NULL:
415             ConvertedRecord->wDataLength = sizeof(DNS_NULL_DATA) + QueryResultWide->Data.Null.dwByteCount;
416             ConvertedRecord->Data.Null.dwByteCount = QueryResultWide->Data.Null.dwByteCount;
417             memcpy(&ConvertedRecord->Data.Null.Data, &QueryResultWide->Data.Null.Data, QueryResultWide->Data.Null.dwByteCount);
418             break;
419         }
420 
421         if (LastRecord)
422         {
423             LastRecord->pNext = ConvertedRecord;
424             LastRecord = LastRecord->pNext;
425         }
426         else
427         {
428             LastRecord = *QueryResultSet = ConvertedRecord;
429         }
430 
431         QueryResultWide = QueryResultWide->pNext;
432     }
433 
434     if (LastRecord)
435         LastRecord->pNext = 0;
436 
437     /* The name */
438     RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
439     /* The result*/
440     if (QueryResultWide) DnsIntFreeRecordList(QueryResultWide);
441 
442     return Status;
443 }
444 
445 DNS_STATUS WINAPI
446 DnsQuery_A(LPCSTR Name,
447            WORD Type,
448            DWORD Options,
449            PVOID Extra,
450            PDNS_RECORD *QueryResultSet,
451            PVOID *Reserved)
452 {
453     return DnsQuery_CodePage(CP_ACP, Name, Type, Options, Extra, QueryResultSet, Reserved);
454 }
455 
456 DNS_STATUS WINAPI
457 DnsQuery_UTF8(LPCSTR Name,
458               WORD Type,
459               DWORD Options,
460               PVOID Extra,
461               PDNS_RECORD *QueryResultSet,
462               PVOID *Reserved)
463 {
464     return DnsQuery_CodePage(CP_UTF8, Name, Type, Options, Extra, QueryResultSet, Reserved);
465 }
466 
467 DNS_STATUS
468 WINAPI
469 DnsQuery_W(LPCWSTR Name,
470            WORD Type,
471            DWORD Options,
472            PVOID Extra,
473            PDNS_RECORD *QueryResultSet,
474            PVOID *Reserved)
475 {
476     DWORD dwRecords = 0;
477     PDNS_RECORDW pRecord = NULL;
478     size_t NameLen, i;
479     DNS_STATUS Status = ERROR_SUCCESS;
480 
481     DPRINT("DnsQuery_W()\n");
482 
483     if ((Name == NULL) ||
484         (QueryResultSet == NULL))
485         return ERROR_INVALID_PARAMETER;
486 
487     *QueryResultSet = NULL;
488 
489     /* Create an A or AAAA record for an IP4 or IP6 address */
490     pRecord = CreateRecordForIpAddress(Name,
491                                        Type);
492     if (pRecord != NULL)
493     {
494         *QueryResultSet = (PDNS_RECORD)pRecord;
495         return ERROR_SUCCESS;
496     }
497 
498     /*
499      * Check allowed characters
500      * According to RFC a-z,A-Z,0-9,-,_, but can't start or end with - or _
501      */
502     NameLen = wcslen(Name);
503     if (Name[0] == L'-' || Name[0] == L'_' || Name[NameLen - 1] == L'-' ||
504         Name[NameLen - 1] == L'_' || wcsstr(Name, L"..") != NULL)
505     {
506         return ERROR_INVALID_NAME;
507     }
508 
509     i = 0;
510     while (i < NameLen)
511     {
512         if (!((Name[i] >= L'a' && Name[i] <= L'z') ||
513               (Name[i] >= L'A' && Name[i] <= L'Z') ||
514               (Name[i] >= L'0' && Name[i] <= L'9') ||
515               Name[i] == L'-' || Name[i] == L'_' || Name[i] == L'.'))
516         {
517             return DNS_ERROR_INVALID_NAME_CHAR;
518         }
519 
520         i++;
521     }
522 
523     RpcTryExcept
524     {
525         Status = R_ResolverQuery(NULL,
526                                  Name,
527                                  Type,
528                                  Options,
529                                  &dwRecords,
530                                  (DNS_RECORDW **)QueryResultSet);
531         DPRINT("R_ResolverQuery() returned %lu\n", Status);
532     }
533     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
534     {
535         Status = RpcExceptionCode();
536         DPRINT("Exception returned %lu\n", Status);
537     }
538     RpcEndExcept;
539 
540     return Status;
541 }
542 
543 WCHAR
544 *xstrsave(const WCHAR *str)
545 {
546     WCHAR *p;
547     size_t len = 0;
548 
549     /* FIXME: how much instead of MAX_PATH? */
550     StringCbLengthW(str, MAX_PATH, &len);
551     len+=sizeof(WCHAR);
552 
553     p = RtlAllocateHeap(RtlGetProcessHeap(), 0, len);
554 
555     if (p)
556         StringCbCopyW(p, len, str);
557 
558     return p;
559 }
560 
561 CHAR
562 *xstrsaveA(const CHAR *str)
563 {
564     CHAR *p;
565     size_t len = 0;
566 
567     /* FIXME: how much instead of MAX_PATH? */
568     StringCbLengthA(str, MAX_PATH, &len);
569     len++;
570 
571     p = RtlAllocateHeap(RtlGetProcessHeap(), 0, len);
572 
573     if (p)
574         StringCbCopyA(p, len, str);
575 
576     return p;
577 }
578 
579 
580 /* This function is far from perfect but it works enough */
581 IP4_ADDRESS
582 CheckForCurrentHostname(CONST CHAR * Name, PFIXED_INFO network_info)
583 {
584     PCHAR TempName;
585     DWORD AdapterAddressesSize, Status;
586     IP4_ADDRESS ret = 0, Address;
587     PIP_ADAPTER_ADDRESSES Addresses = NULL, pip;
588     BOOL Found = FALSE;
589 
590     if (network_info->DomainName[0])
591     {
592         size_t StringLength;
593         size_t TempSize = 2;
594         StringCchLengthA(network_info->HostName, sizeof(network_info->HostName), &StringLength);
595         TempSize += StringLength;
596         StringCchLengthA(network_info->DomainName, sizeof(network_info->DomainName), &StringLength);
597         TempSize += StringLength;
598         TempName = RtlAllocateHeap(RtlGetProcessHeap(), 0, TempSize);
599         StringCchCopyA(TempName, TempSize, network_info->HostName);
600         StringCchCatA(TempName, TempSize, ".");
601         StringCchCatA(TempName, TempSize, network_info->DomainName);
602     }
603     else
604     {
605         TempName = RtlAllocateHeap(RtlGetProcessHeap(), 0, 1);
606         TempName[0] = 0;
607     }
608     Found = !_stricmp(Name, network_info->HostName) || !_stricmp(Name, TempName);
609     RtlFreeHeap(RtlGetProcessHeap(), 0, TempName);
610     if (!Found)
611     {
612         return 0;
613     }
614     /* get adapter info */
615     AdapterAddressesSize = 0;
616     GetAdaptersAddresses(AF_INET,
617                          GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_SKIP_DNS_SERVER |
618                          GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST,
619                          NULL,
620                          Addresses,
621                          &AdapterAddressesSize);
622     if (!AdapterAddressesSize)
623     {
624         return 0;
625     }
626     Addresses = RtlAllocateHeap(RtlGetProcessHeap(), 0, AdapterAddressesSize);
627     Status = GetAdaptersAddresses(AF_INET,
628                                   GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_SKIP_DNS_SERVER |
629                                   GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST,
630                                   NULL,
631                                   Addresses,
632                                   &AdapterAddressesSize);
633     if (Status)
634     {
635         RtlFreeHeap(RtlGetProcessHeap(), 0, Addresses);
636         return 0;
637     }
638     for (pip = Addresses; pip != NULL; pip = pip->Next) {
639         Address = ((LPSOCKADDR_IN)pip->FirstUnicastAddress->Address.lpSockaddr)->sin_addr.S_un.S_addr;
640         if (Address != ntohl(INADDR_LOOPBACK))
641             break;
642     }
643     if (Address && Address != ntohl(INADDR_LOOPBACK))
644     {
645         ret = Address;
646     }
647     RtlFreeHeap(RtlGetProcessHeap(), 0, Addresses);
648     return ret;
649 }
650 
651 
652 DNS_STATUS
653 WINAPI
654 Query_Main(LPCWSTR Name,
655            WORD Type,
656            DWORD Options,
657            PDNS_RECORD *QueryResultSet)
658 {
659     adns_state astate;
660     int quflags = (Options & DNS_QUERY_NO_RECURSION) == 0 ? adns_qf_search : 0;
661     int adns_error;
662     adns_answer *answer;
663     LPSTR CurrentName;
664     unsigned CNameLoop;
665     PFIXED_INFO network_info;
666     ULONG network_info_blen = 0;
667     DWORD network_info_result;
668     PIP_ADDR_STRING pip;
669     IP4_ADDRESS Address;
670     struct in_addr addr;
671     PCHAR HostWithDomainName;
672     PCHAR AnsiName;
673     size_t NameLen = 0;
674 
675     if (Name == NULL)
676         return ERROR_INVALID_PARAMETER;
677     if (QueryResultSet == NULL)
678         return ERROR_INVALID_PARAMETER;
679 
680     *QueryResultSet = NULL;
681 
682     switch (Type)
683     {
684     case DNS_TYPE_A:
685         /* FIXME: how much instead of MAX_PATH? */
686         NameLen = WideCharToMultiByte(CP_ACP,
687                                       0,
688                                       Name,
689                                       -1,
690                                       NULL,
691                                       0,
692                                       NULL,
693                                       0);
694         AnsiName = RtlAllocateHeap(RtlGetProcessHeap(), 0, NameLen);
695         if (NULL == AnsiName)
696         {
697             return ERROR_OUTOFMEMORY;
698         }
699         WideCharToMultiByte(CP_ACP,
700                             0,
701                             Name,
702                             -1,
703                             AnsiName,
704                             NameLen,
705                             NULL,
706                             0);
707         NameLen--;
708 
709         network_info_result = GetNetworkParams(NULL, &network_info_blen);
710         network_info = (PFIXED_INFO)RtlAllocateHeap(RtlGetProcessHeap(), 0, (size_t)network_info_blen);
711         if (NULL == network_info)
712         {
713             return ERROR_OUTOFMEMORY;
714         }
715 
716         network_info_result = GetNetworkParams(network_info, &network_info_blen);
717         if (network_info_result != ERROR_SUCCESS)
718         {
719             RtlFreeHeap(RtlGetProcessHeap(), 0, network_info);
720             return network_info_result;
721         }
722 
723         if ((Address = CheckForCurrentHostname(NameLen != 0 ? AnsiName : network_info->HostName, network_info)) != 0)
724         {
725             size_t TempLen = 2, StringLength = 0;
726             RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
727             StringCchLengthA(network_info->HostName, sizeof(network_info->HostName), &StringLength);
728             TempLen += StringLength;
729             StringCchLengthA(network_info->DomainName, sizeof(network_info->DomainName), &StringLength);
730             TempLen += StringLength;
731             HostWithDomainName = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(), 0, TempLen);
732             StringCchCopyA(HostWithDomainName, TempLen, network_info->HostName);
733             if (network_info->DomainName[0])
734             {
735                 StringCchCatA(HostWithDomainName, TempLen, ".");
736                 StringCchCatA(HostWithDomainName, TempLen, network_info->DomainName);
737             }
738             RtlFreeHeap(RtlGetProcessHeap(), 0, network_info);
739             *QueryResultSet = (PDNS_RECORD)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD));
740 
741             if (NULL == *QueryResultSet)
742             {
743                 RtlFreeHeap(RtlGetProcessHeap(), 0, HostWithDomainName);
744                 return ERROR_OUTOFMEMORY;
745             }
746 
747             (*QueryResultSet)->pNext = NULL;
748             (*QueryResultSet)->wType = Type;
749             (*QueryResultSet)->wDataLength = sizeof(DNS_A_DATA);
750             (*QueryResultSet)->Flags.S.Section = DnsSectionAnswer;
751             (*QueryResultSet)->Flags.S.CharSet = DnsCharSetUnicode;
752             (*QueryResultSet)->Data.A.IpAddress = Address;
753 
754             (*QueryResultSet)->pName = (LPSTR)DnsCToW(HostWithDomainName);
755 
756             RtlFreeHeap(RtlGetProcessHeap(), 0, HostWithDomainName);
757             return (*QueryResultSet)->pName ? ERROR_SUCCESS : ERROR_OUTOFMEMORY;
758         }
759 
760         if ((Options & DNS_QUERY_NO_WIRE_QUERY) != 0)
761         {
762             RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
763             RtlFreeHeap(RtlGetProcessHeap(), 0, network_info);
764             return ERROR_FILE_NOT_FOUND;
765         }
766 
767         adns_error = adns_init(&astate, adns_if_noenv | adns_if_noerrprint | adns_if_noserverwarn, 0);
768         if (adns_error != adns_s_ok)
769         {
770             RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
771             RtlFreeHeap(RtlGetProcessHeap(), 0, network_info);
772             return DnsIntTranslateAdnsToDNS_STATUS(adns_error);
773         }
774         for (pip = &(network_info->DnsServerList); pip; pip = pip->Next)
775         {
776             addr.s_addr = inet_addr(pip->IpAddress.String);
777             if ((addr.s_addr != INADDR_ANY) && (addr.s_addr != INADDR_NONE))
778                 adns_addserver(astate, addr);
779         }
780         if (network_info->DomainName[0])
781         {
782             adns_ccf_search(astate, "LOCALDOMAIN", -1, network_info->DomainName);
783         }
784         RtlFreeHeap(RtlGetProcessHeap(), 0, network_info);
785 
786         if (!adns_numservers(astate))
787         {
788             /* There are no servers to query so bail out */
789             adns_finish(astate);
790             RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
791             return ERROR_FILE_NOT_FOUND;
792         }
793 
794         /*
795         * adns doesn't resolve chained CNAME records (a CNAME which points to
796         * another CNAME pointing to another... pointing to an A record), according
797         * to a mailing list thread the authors believe that chained CNAME records
798         * are invalid and the DNS entries should be fixed. That's a nice academic
799         * standpoint, but there certainly are chained CNAME records out there,
800         * even some fairly major ones (at the time of this writing
801         * download.mozilla.org is a chained CNAME). Everyone else seems to resolve
802         * these fine, so we should too. So we loop here to try to resolve CNAME
803         * chains ourselves. Of course, there must be a limit to protect against
804         * CNAME loops.
805         */
806 
807 #define CNAME_LOOP_MAX 16
808 
809         CurrentName = AnsiName;
810 
811         for (CNameLoop = 0; CNameLoop < CNAME_LOOP_MAX; CNameLoop++)
812         {
813             adns_error = adns_synchronous(astate, CurrentName, adns_r_addr, quflags, &answer);
814 
815             if (adns_error != adns_s_ok)
816             {
817                 adns_finish(astate);
818 
819                 if (CurrentName != AnsiName)
820                     RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName);
821 
822                 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
823                 return DnsIntTranslateAdnsToDNS_STATUS(adns_error);
824             }
825 
826             if (answer && answer->rrs.addr)
827             {
828                 if (CurrentName != AnsiName)
829                     RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName);
830 
831                 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
832                 *QueryResultSet = (PDNS_RECORD)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD));
833 
834                 if (NULL == *QueryResultSet)
835                 {
836                     adns_finish(astate);
837                     return ERROR_OUTOFMEMORY;
838                 }
839 
840                 (*QueryResultSet)->pNext = NULL;
841                 (*QueryResultSet)->wType = Type;
842                 (*QueryResultSet)->wDataLength = sizeof(DNS_A_DATA);
843                 (*QueryResultSet)->Flags.S.Section = DnsSectionAnswer;
844                 (*QueryResultSet)->Flags.S.CharSet = DnsCharSetUnicode;
845                 (*QueryResultSet)->Data.A.IpAddress = answer->rrs.addr->addr.inet.sin_addr.s_addr;
846 
847                 adns_finish(astate);
848 
849                 (*QueryResultSet)->pName = (LPSTR)xstrsave(Name);
850 
851                 return (*QueryResultSet)->pName ? ERROR_SUCCESS : ERROR_OUTOFMEMORY;
852             }
853 
854             if (NULL == answer || adns_s_prohibitedcname != answer->status || NULL == answer->cname)
855             {
856                 adns_finish(astate);
857 
858                 if (CurrentName != AnsiName)
859                     RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName);
860 
861                 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
862                 return ERROR_FILE_NOT_FOUND;
863             }
864 
865             if (CurrentName != AnsiName)
866                 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName);
867 
868             CurrentName = (LPSTR)xstrsaveA(answer->cname);
869 
870             if (!CurrentName)
871             {
872                 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
873                 adns_finish(astate);
874                 return ERROR_OUTOFMEMORY;
875             }
876         }
877 
878         adns_finish(astate);
879         RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
880         RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName);
881         return ERROR_FILE_NOT_FOUND;
882 
883     default:
884         return ERROR_OUTOFMEMORY; /* XXX arty: find a better error code. */
885     }
886 }
887 
888 void
889 DnsIntFreeRecordList(PDNS_RECORD ToDelete)
890 {
891     UINT i;
892     PDNS_RECORD next = 0;
893 
894     while(ToDelete)
895     {
896         if(ToDelete->pName)
897             RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete->pName);
898 
899         switch(ToDelete->wType)
900         {
901             case DNS_TYPE_CNAME:
902             case DNS_TYPE_PTR:
903             case DNS_TYPE_NS:
904             case DNS_TYPE_MB:
905             case DNS_TYPE_MD:
906             case DNS_TYPE_MF:
907             case DNS_TYPE_MG:
908             case DNS_TYPE_MR:
909                 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete->Data.PTR.pNameHost);
910                 break;
911 
912             case DNS_TYPE_MINFO:
913             case DNS_TYPE_MX:
914                 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete->Data.MX.pNameExchange);
915                 break;
916 
917             case DNS_TYPE_HINFO:
918                 for(i = 0; i < ToDelete->Data.TXT.dwStringCount; i++)
919                     RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete->Data.TXT.pStringArray[i]);
920 
921                 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete->Data.TXT.pStringArray);
922                 break;
923         }
924 
925         next = ToDelete->pNext;
926         RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete);
927         ToDelete = next;
928     }
929 }
930 
931 BOOL
932 WINAPI
933 DnsFlushResolverCache(VOID)
934 {
935     DNS_STATUS Status = ERROR_SUCCESS;
936 
937     DPRINT("DnsFlushResolverCache()\n");
938 
939     RpcTryExcept
940     {
941         Status = R_ResolverFlushCache(NULL);
942         DPRINT("R_ResolverFlushCache() returned %lu\n", Status);
943     }
944     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
945     {
946         Status = RpcExceptionCode();
947         DPRINT("Exception returned %lu\n", Status);
948     }
949     RpcEndExcept;
950 
951     return (Status == ERROR_SUCCESS);
952 }
953 
954 
955 BOOL
956 WINAPI
957 DnsFlushResolverCacheEntry_A(
958     _In_ LPCSTR pszEntry)
959 {
960     DNS_STATUS Status = ERROR_SUCCESS;
961     LPWSTR pszUnicodeEntry;
962 
963     DPRINT1("DnsFlushResolverCacheEntry_A(%s)\n", pszEntry);
964 
965     if (pszEntry == NULL)
966         return FALSE;
967 
968     pszUnicodeEntry = DnsCToW(pszEntry);
969     if (pszUnicodeEntry == NULL)
970         return FALSE;
971 
972     RpcTryExcept
973     {
974         Status = R_ResolverFlushCacheEntry(NULL, pszUnicodeEntry, DNS_TYPE_ANY);
975         DPRINT("R_ResolverFlushCacheEntry() returned %lu\n", Status);
976     }
977     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
978     {
979         Status = RpcExceptionCode();
980         DPRINT("Exception returned %lu\n", Status);
981     }
982     RpcEndExcept;
983 
984     RtlFreeHeap(RtlGetProcessHeap(), 0, pszUnicodeEntry);
985 
986     return (Status == ERROR_SUCCESS);
987 }
988 
989 
990 BOOL
991 WINAPI
992 DnsFlushResolverCacheEntry_UTF8(
993     _In_ LPCSTR pszEntry)
994 {
995     DNS_STATUS Status = ERROR_SUCCESS;
996     LPWSTR pszUnicodeEntry;
997 
998     DPRINT1("DnsFlushResolverCacheEntry_UTF8(%s)\n", pszEntry);
999 
1000     if (pszEntry == NULL)
1001         return FALSE;
1002 
1003     pszUnicodeEntry = DnsCToW(pszEntry);
1004     if (pszUnicodeEntry == NULL)
1005         return FALSE;
1006 
1007     RpcTryExcept
1008     {
1009         Status = R_ResolverFlushCacheEntry(NULL, pszUnicodeEntry, DNS_TYPE_ANY);
1010         DPRINT("R_ResolverFlushCacheEntry() returned %lu\n", Status);
1011     }
1012     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1013     {
1014         Status = RpcExceptionCode();
1015         DPRINT("Exception returned %lu\n", Status);
1016     }
1017     RpcEndExcept;
1018 
1019     RtlFreeHeap(RtlGetProcessHeap(), 0, pszUnicodeEntry);
1020 
1021     return (Status == ERROR_SUCCESS);
1022 }
1023 
1024 
1025 BOOL
1026 WINAPI
1027 DnsFlushResolverCacheEntry_W(
1028     _In_ LPCWSTR pszEntry)
1029 {
1030     DNS_STATUS Status = ERROR_SUCCESS;
1031 
1032     DPRINT1("DnsFlushResolverCacheEntry_W(%S)\n", pszEntry);
1033 
1034     if (pszEntry == NULL)
1035         return FALSE;
1036 
1037     RpcTryExcept
1038     {
1039         Status = R_ResolverFlushCacheEntry(NULL, pszEntry, DNS_TYPE_ANY);
1040         DPRINT("R_ResolverFlushCacheEntry() returned %lu\n", Status);
1041     }
1042     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1043     {
1044         Status = RpcExceptionCode();
1045         DPRINT("Exception returned %lu\n", Status);
1046     }
1047     RpcEndExcept;
1048 
1049     return (Status == ERROR_SUCCESS);
1050 }
1051 
1052 
1053 BOOL
1054 WINAPI
1055 DnsGetCacheDataTable(
1056     _Out_ PDNS_CACHE_ENTRY *DnsCache)
1057 {
1058     DNS_STATUS Status = ERROR_SUCCESS;
1059     PDNS_CACHE_ENTRY CacheEntries = NULL;
1060 
1061     if (DnsCache == NULL)
1062         return FALSE;
1063 
1064     RpcTryExcept
1065     {
1066         Status = CRrReadCache(NULL,
1067                               &CacheEntries);
1068         DPRINT("CRrReadCache() returned %lu\n", Status);
1069     }
1070     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1071     {
1072         Status = RpcExceptionCode();
1073         DPRINT1("Exception returned %lu\n", Status);
1074     }
1075     RpcEndExcept;
1076 
1077     if (Status != ERROR_SUCCESS)
1078         return FALSE;
1079 
1080     if (CacheEntries == NULL)
1081         return FALSE;
1082 
1083     *DnsCache = CacheEntries;
1084 
1085     return TRUE;
1086 }
1087 
1088 DWORD
1089 WINAPI
1090 GetCurrentTimeInSeconds(VOID)
1091 {
1092     FILETIME Time;
1093     FILETIME Adjustment;
1094     ULARGE_INTEGER lTime, lAdj;
1095     SYSTEMTIME st = {1970, 1, 0, 1, 0, 0, 0};
1096 
1097     SystemTimeToFileTime(&st, &Adjustment);
1098     memcpy(&lAdj, &Adjustment, sizeof(lAdj));
1099     GetSystemTimeAsFileTime(&Time);
1100     memcpy(&lTime, &Time, sizeof(lTime));
1101     lTime.QuadPart -= lAdj.QuadPart;
1102     return (DWORD)(lTime.QuadPart/10000000ULL);
1103 }
1104