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