wininet: Fix buffer size query for InternetQueryOption(INTERNET_OPTION_PROXY).
[wine] / dlls / dnsapi / query.c
1 /*
2  * DNS support
3  *
4  * Copyright (C) 2006 Hans Leidekker
5  * 
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23 #include "wine/debug.h"
24
25 #include <stdarg.h>
26 #include <string.h>
27 #include <sys/types.h>
28
29 #ifdef HAVE_NETINET_IN_H
30 # include <netinet/in.h>
31 #endif
32 #ifdef HAVE_ARPA_NAMESER_H
33 # include <arpa/nameser.h>
34 #endif
35 #ifdef HAVE_RESOLV_H
36 # include <resolv.h>
37 #endif
38 #ifdef HAVE_NETDB_H
39 # include <netdb.h>
40 #endif
41
42 #include "windef.h"
43 #include "winbase.h"
44 #include "winerror.h"
45 #include "winnls.h"
46 #include "windns.h"
47 #include "nb30.h"
48
49 #include "dnsapi.h"
50
51 WINE_DEFAULT_DEBUG_CHANNEL(dnsapi);
52
53 #ifdef HAVE_RESOLV
54
55 static CRITICAL_SECTION resolver_cs;
56 static CRITICAL_SECTION_DEBUG resolver_cs_debug =
57 {
58     0, 0, &resolver_cs,
59     { &resolver_cs_debug.ProcessLocksList,
60       &resolver_cs_debug.ProcessLocksList },
61       0, 0, { (DWORD_PTR)(__FILE__ ": resolver_cs") }
62 };
63 static CRITICAL_SECTION resolver_cs = { &resolver_cs_debug, -1, 0, 0, 0, 0 };
64
65 #define LOCK_RESOLVER()     do { EnterCriticalSection( &resolver_cs ); } while (0)
66 #define UNLOCK_RESOLVER()   do { LeaveCriticalSection( &resolver_cs ); } while (0)
67
68 static int resolver_initialised;
69
70 /* call res_init() just once because of a bug in Mac OS X 10.4 */
71 static void initialise_resolver( void )
72 {
73     if (!resolver_initialised)
74     {
75         res_init();
76         resolver_initialised = 1;
77     }
78 }
79
80 static const char *dns_section_to_str( ns_sect section )
81 {
82     switch (section)
83     {
84     case ns_s_qd:   return "Question";
85     case ns_s_an:   return "Answer";
86     case ns_s_ns:   return "Authority";
87     case ns_s_ar:   return "Additional";
88     default:
89     {
90         static char tmp[5];
91         FIXME( "unknown section: 0x%02x\n", section );
92         sprintf( tmp, "0x%02x", section );
93         return tmp;
94     }
95     }
96 }
97
98 static unsigned long dns_map_options( DWORD options )
99 {
100     unsigned long ret = 0;
101             
102     if (options == DNS_QUERY_STANDARD)
103         return RES_DEFAULT;
104
105     if (options & DNS_QUERY_ACCEPT_TRUNCATED_RESPONSE)
106         ret |= RES_IGNTC;
107     if (options & DNS_QUERY_USE_TCP_ONLY)
108         ret |= RES_USEVC;
109     if (options & DNS_QUERY_NO_RECURSION)
110         ret &= ~RES_RECURSE;
111     if (options & DNS_QUERY_NO_LOCAL_NAME)
112         ret &= ~RES_DNSRCH;
113     if (options & DNS_QUERY_NO_HOSTS_FILE)
114         ret |= RES_NOALIASES;
115     if (options & DNS_QUERY_TREAT_AS_FQDN)
116         ret &= ~RES_DEFNAMES;
117
118     if (options & DNS_QUERY_DONT_RESET_TTL_VALUES)
119         FIXME( "option DNS_QUERY_DONT_RESET_TTL_VALUES not implemented\n" );
120     if (options & DNS_QUERY_RESERVED)
121         FIXME( "option DNS_QUERY_RESERVED not implemented\n" );
122     if (options & DNS_QUERY_WIRE_ONLY)
123         FIXME( "option DNS_QUERY_WIRE_ONLY not implemented\n" );
124     if (options & DNS_QUERY_NO_WIRE_QUERY)
125         FIXME( "option DNS_QUERY_NO_WIRE_QUERY not implemented\n" );
126     if (options & DNS_QUERY_BYPASS_CACHE)
127         FIXME( "option DNS_QUERY_BYPASS_CACHE not implemented\n" );
128     if (options & DNS_QUERY_RETURN_MESSAGE)
129         FIXME( "option DNS_QUERY_RETURN_MESSAGE not implemented\n" );
130
131     if (options & DNS_QUERY_NO_NETBT)
132         TRACE( "netbios query disabled\n" );
133
134     return ret;
135 }
136
137 static DNS_STATUS dns_map_error( int error )
138 {
139     switch (error)
140     {
141     case ns_r_noerror:  return ERROR_SUCCESS;
142     case ns_r_formerr:  return DNS_ERROR_RCODE_FORMAT_ERROR;
143     case ns_r_servfail: return DNS_ERROR_RCODE_SERVER_FAILURE;
144     case ns_r_nxdomain: return DNS_ERROR_RCODE_NAME_ERROR;
145     case ns_r_notimpl:  return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
146     case ns_r_refused:  return DNS_ERROR_RCODE_REFUSED;
147     case ns_r_yxdomain: return DNS_ERROR_RCODE_YXDOMAIN;
148     case ns_r_yxrrset:  return DNS_ERROR_RCODE_YXRRSET;
149     case ns_r_nxrrset:  return DNS_ERROR_RCODE_NXRRSET;
150     case ns_r_notauth:  return DNS_ERROR_RCODE_NOTAUTH;
151     case ns_r_notzone:  return DNS_ERROR_RCODE_NOTZONE;
152     default:
153         FIXME( "unmapped error code: %d\n", error );
154         return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
155     }
156 }
157
158 static DNS_STATUS dns_map_h_errno( int error )
159 {
160     switch (error)
161     {
162     case NO_DATA:
163     case HOST_NOT_FOUND: return DNS_ERROR_RCODE_NAME_ERROR;
164     case TRY_AGAIN:      return DNS_ERROR_RCODE_SERVER_FAILURE;
165     case NO_RECOVERY:    return DNS_ERROR_RCODE_REFUSED;
166     case NETDB_INTERNAL: return DNS_ERROR_RCODE;
167     default:
168         FIXME( "unmapped error code: %d\n", error );
169         return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
170     }
171 }
172
173 static char *dns_dname_from_msg( ns_msg msg, const unsigned char *pos )
174 {
175     int len;
176     char *str, dname[NS_MAXDNAME] = ".";
177
178     /* returns *compressed* length, ignore it */
179     len = dns_ns_name_uncompress( ns_msg_base( msg ), ns_msg_end( msg ),
180                                   pos, dname, sizeof(dname) );
181
182     len = strlen( dname );
183     str = heap_alloc( len + 1 );
184     if (str) strcpy( str, dname );
185     return str;
186 }
187
188 static char *dns_str_from_rdata( const unsigned char *rdata )
189 {
190     char *str;
191     unsigned int len = rdata[0];
192
193     str = heap_alloc( len + 1 );
194     if (str)
195     {
196         memcpy( str, ++rdata, len );
197         str[len] = '\0';
198     }
199     return str;
200 }
201
202 static unsigned int dns_get_record_size( const ns_rr *rr )
203 {
204     const unsigned char *pos = rr->rdata;
205     unsigned int num = 0, size = sizeof(DNS_RECORDA);
206
207     switch (rr->type)
208     {
209     case ns_t_key:
210     {
211         pos += sizeof(WORD) + sizeof(BYTE) + sizeof(BYTE);
212         size += rr->rdata + rr->rdlength - pos - 1;
213         break;
214     }
215     case ns_t_sig:
216     {
217         pos += sizeof(PCHAR) + sizeof(WORD) + 2 * sizeof(BYTE);
218         pos += 3 * sizeof(DWORD) + 2 * sizeof(WORD);
219         size += rr->rdata + rr->rdlength - pos - 1;
220         break;
221     }
222     case ns_t_hinfo:
223     case ns_t_isdn:
224     case ns_t_txt:
225     case ns_t_x25:
226     {
227         while (pos[0] && pos < rr->rdata + rr->rdlength)
228         {
229             num++;
230             pos += pos[0] + 1;
231         }
232         size += (num - 1) * sizeof(PCHAR);
233         break;
234     }
235     case ns_t_null:
236     {
237         size += rr->rdlength - 1;
238         break;
239     }
240     case ns_t_nxt:
241     case ns_t_wks:
242     case 0xff01:  /* WINS */
243     {
244         FIXME( "unhandled type: %s\n", dns_type_to_str( rr->type ) );
245         break;
246     }
247     default:
248         break;
249     }
250     return size;
251 }
252
253 static DNS_STATUS dns_copy_rdata( ns_msg msg, const ns_rr *rr, DNS_RECORDA *r, WORD *dlen )
254 {
255     DNS_STATUS ret = ERROR_SUCCESS;
256     const unsigned char *pos = rr->rdata;
257     unsigned int i, size;
258
259     switch (rr->type)
260     {
261     case ns_t_a:
262     {
263         r->Data.A.IpAddress = *(const DWORD *)pos;
264         *dlen = sizeof(DNS_A_DATA);
265         break; 
266     }
267     case ns_t_aaaa:
268     {
269         for (i = 0; i < sizeof(IP6_ADDRESS)/sizeof(DWORD); i++)
270         {
271             r->Data.AAAA.Ip6Address.IP6Dword[i] = *(const DWORD *)pos;
272             pos += sizeof(DWORD);
273         }
274
275         *dlen = sizeof(DNS_AAAA_DATA);
276         break;
277     }
278     case ns_t_key:
279     {
280         /* FIXME: byte order? */
281         r->Data.KEY.wFlags      = *(const WORD *)pos;   pos += sizeof(WORD);
282         r->Data.KEY.chProtocol  = *pos++;
283         r->Data.KEY.chAlgorithm = *pos++;
284
285         size = rr->rdata + rr->rdlength - pos;
286
287         for (i = 0; i < size; i++)
288             r->Data.KEY.Key[i] = *pos++;
289
290         *dlen = sizeof(DNS_KEY_DATA) + (size - 1) * sizeof(BYTE);
291         break;
292     }
293     case ns_t_rp:
294     case ns_t_minfo:
295     {
296         r->Data.MINFO.pNameMailbox = dns_dname_from_msg( msg, pos );
297         if (!r->Data.MINFO.pNameMailbox) return ERROR_NOT_ENOUGH_MEMORY;
298
299         if (dns_ns_name_skip( &pos, ns_msg_end( msg ) ) < 0)
300             return DNS_ERROR_BAD_PACKET;
301
302         r->Data.MINFO.pNameErrorsMailbox = dns_dname_from_msg( msg, pos );
303         if (!r->Data.MINFO.pNameErrorsMailbox)
304         {
305             heap_free( r->Data.MINFO.pNameMailbox );
306             return ERROR_NOT_ENOUGH_MEMORY;
307         }
308
309         *dlen = sizeof(DNS_MINFO_DATAA);
310         break; 
311     }
312     case ns_t_afsdb:
313     case ns_t_rt:
314     case ns_t_mx:
315     {
316         r->Data.MX.wPreference = ntohs( *(const WORD *)pos );
317         r->Data.MX.pNameExchange = dns_dname_from_msg( msg, pos + sizeof(WORD) );
318         if (!r->Data.MX.pNameExchange) return ERROR_NOT_ENOUGH_MEMORY;
319
320         *dlen = sizeof(DNS_MX_DATAA);
321         break; 
322     }
323     case ns_t_null:
324     {
325         r->Data.Null.dwByteCount = rr->rdlength;
326         memcpy( r->Data.Null.Data, rr->rdata, rr->rdlength );
327
328         *dlen = sizeof(DNS_NULL_DATA) + rr->rdlength - 1;
329         break;
330     }
331     case ns_t_cname:
332     case ns_t_ns:
333     case ns_t_mb:
334     case ns_t_md:
335     case ns_t_mf:
336     case ns_t_mg:
337     case ns_t_mr:
338     case ns_t_ptr:
339     {
340         r->Data.PTR.pNameHost = dns_dname_from_msg( msg, pos );
341         if (!r->Data.PTR.pNameHost) return ERROR_NOT_ENOUGH_MEMORY;
342
343         *dlen = sizeof(DNS_PTR_DATAA);
344         break;
345     }
346     case ns_t_sig:
347     {
348         r->Data.SIG.pNameSigner = dns_dname_from_msg( msg, pos );
349         if (!r->Data.SIG.pNameSigner) return ERROR_NOT_ENOUGH_MEMORY;
350
351         if (dns_ns_name_skip( &pos, ns_msg_end( msg ) ) < 0)
352             return DNS_ERROR_BAD_PACKET;
353
354         /* FIXME: byte order? */
355         r->Data.SIG.wTypeCovered  = *(const WORD *)pos;   pos += sizeof(WORD);
356         r->Data.SIG.chAlgorithm   = *pos++;
357         r->Data.SIG.chLabelCount  = *pos++;
358         r->Data.SIG.dwOriginalTtl = *(const DWORD *)pos;  pos += sizeof(DWORD);
359         r->Data.SIG.dwExpiration  = *(const DWORD *)pos;  pos += sizeof(DWORD);
360         r->Data.SIG.dwTimeSigned  = *(const DWORD *)pos;  pos += sizeof(DWORD);
361         r->Data.SIG.wKeyTag       = *(const WORD *)pos;
362
363         size = rr->rdata + rr->rdlength - pos;
364
365         for (i = 0; i < size; i++)
366             r->Data.SIG.Signature[i] = *pos++;
367
368         *dlen = sizeof(DNS_SIG_DATAA) + (size - 1) * sizeof(BYTE);
369         break; 
370     }
371     case ns_t_soa:
372     {
373         r->Data.SOA.pNamePrimaryServer = dns_dname_from_msg( msg, pos );
374         if (!r->Data.SOA.pNamePrimaryServer) return ERROR_NOT_ENOUGH_MEMORY;
375
376         if (dns_ns_name_skip( &pos, ns_msg_end( msg ) ) < 0)
377             return DNS_ERROR_BAD_PACKET;
378
379         r->Data.SOA.pNameAdministrator = dns_dname_from_msg( msg, pos );
380         if (!r->Data.SOA.pNameAdministrator)
381         {
382             heap_free( r->Data.SOA.pNamePrimaryServer );
383             return ERROR_NOT_ENOUGH_MEMORY;
384         }
385
386         if (dns_ns_name_skip( &pos, ns_msg_end( msg ) ) < 0)
387             return DNS_ERROR_BAD_PACKET;
388
389         r->Data.SOA.dwSerialNo   = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD);
390         r->Data.SOA.dwRefresh    = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD);
391         r->Data.SOA.dwRetry      = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD);
392         r->Data.SOA.dwExpire     = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD);
393         r->Data.SOA.dwDefaultTtl = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD);
394
395         *dlen = sizeof(DNS_SOA_DATAA);
396         break; 
397     }
398     case ns_t_srv:
399     {
400         r->Data.SRV.wPriority = ntohs( *(const WORD *)pos ); pos += sizeof(WORD);
401         r->Data.SRV.wWeight   = ntohs( *(const WORD *)pos ); pos += sizeof(WORD);
402         r->Data.SRV.wPort     = ntohs( *(const WORD *)pos ); pos += sizeof(WORD);
403
404         r->Data.SRV.pNameTarget = dns_dname_from_msg( msg, pos );
405         if (!r->Data.SRV.pNameTarget) return ERROR_NOT_ENOUGH_MEMORY;
406
407         *dlen = sizeof(DNS_SRV_DATAA);
408         break; 
409     }
410     case ns_t_hinfo:
411     case ns_t_isdn:
412     case ns_t_x25:
413     case ns_t_txt:
414     {
415         i = 0;
416         while (pos[0] && pos < rr->rdata + rr->rdlength)
417         {
418             r->Data.TXT.pStringArray[i] = dns_str_from_rdata( pos );
419             if (!r->Data.TXT.pStringArray[i])
420             {
421                 while (i > 0) heap_free( r->Data.TXT.pStringArray[--i] );
422                 return ERROR_NOT_ENOUGH_MEMORY;
423             }
424             i++;
425             pos += pos[0] + 1;
426         }
427         r->Data.TXT.dwStringCount = i;
428         *dlen = sizeof(DNS_TXT_DATAA) + (i - 1) * sizeof(PCHAR);
429         break;
430     }
431     case ns_t_atma:
432     case ns_t_loc:
433     case ns_t_nxt:
434     case ns_t_tsig:
435     case ns_t_wks:
436     case 0x00f9:  /* TKEY */
437     case 0xff01:  /* WINS */
438     case 0xff02:  /* WINSR */
439     default:
440         FIXME( "unhandled type: %s\n", dns_type_to_str( rr->type ) );
441         return DNS_ERROR_RCODE_NOT_IMPLEMENTED;
442     }
443
444     return ret;
445
446
447 static DNS_STATUS dns_copy_record( ns_msg msg, ns_sect section,
448                                    unsigned short num, DNS_RECORDA **recp )
449 {
450     DNS_STATUS ret;
451     DNS_RECORDA *record;
452     WORD dlen;
453     ns_rr rr;
454
455     if (dns_ns_parserr( &msg, section, num, &rr ) < 0)
456         return DNS_ERROR_BAD_PACKET;
457
458     if (!(record = heap_alloc_zero( dns_get_record_size( &rr ) )))
459         return ERROR_NOT_ENOUGH_MEMORY;
460
461     record->pName = dns_strdup_u( rr.name );
462     if (!record->pName)
463     {
464         heap_free( record );
465         return ERROR_NOT_ENOUGH_MEMORY;
466     }
467
468     record->wType = rr.type;
469     record->Flags.S.Section = section;
470     record->Flags.S.CharSet = DnsCharSetUtf8;
471     record->dwTtl = rr.ttl;
472
473     if ((ret = dns_copy_rdata( msg, &rr, record, &dlen )))
474     {
475         heap_free( record->pName );
476         heap_free( record );
477         return ret;
478     }
479     record->wDataLength = dlen;
480     *recp = record;
481
482     TRACE( "found %s record in %s section\n",
483            dns_type_to_str( rr.type ), dns_section_to_str( section ) );
484     return ERROR_SUCCESS;
485 }
486
487 #define DEFAULT_TTL  1200
488
489 static DNS_STATUS dns_do_query_netbios( PCSTR name, DNS_RECORDA **recp )
490 {
491     NCB ncb;
492     UCHAR ret;
493     DNS_RRSET rrset;
494     FIND_NAME_BUFFER *buffer;
495     FIND_NAME_HEADER *header;
496     DNS_RECORDA *record = NULL;
497     unsigned int i, len;
498     DNS_STATUS status = ERROR_INVALID_NAME;
499
500     len = strlen( name );
501     if (len >= NCBNAMSZ) return DNS_ERROR_RCODE_NAME_ERROR;
502
503     DNS_RRSET_INIT( rrset );
504
505     memset( &ncb, 0, sizeof(ncb) );
506     ncb.ncb_command = NCBFINDNAME;
507
508     memset( ncb.ncb_callname, ' ', sizeof(ncb.ncb_callname) );
509     memcpy( ncb.ncb_callname, name, len );
510     ncb.ncb_callname[NCBNAMSZ - 1] = '\0';
511
512     ret = Netbios( &ncb );
513     if (ret != NRC_GOODRET) return ERROR_INVALID_NAME;
514
515     header = (FIND_NAME_HEADER *)ncb.ncb_buffer;
516     buffer = (FIND_NAME_BUFFER *)((char *)header + sizeof(FIND_NAME_HEADER));
517
518     for (i = 0; i < header->node_count; i++) 
519     {
520         record = heap_alloc_zero( sizeof(DNS_RECORDA) );
521         if (!record)
522         {
523             status = ERROR_NOT_ENOUGH_MEMORY;
524             goto exit;
525         }
526         else
527         {
528             record->pName = dns_strdup_u( name );
529             if (!record->pName)
530             {
531                 status = ERROR_NOT_ENOUGH_MEMORY;
532                 goto exit;
533             }
534
535             record->wType = DNS_TYPE_A;
536             record->Flags.S.Section = DnsSectionAnswer;
537             record->Flags.S.CharSet = DnsCharSetUtf8;
538             record->dwTtl = DEFAULT_TTL;
539
540             /* FIXME: network byte order? */
541             record->Data.A.IpAddress = *(DWORD *)((char *)buffer[i].destination_addr + 2);
542
543             DNS_RRSET_ADD( rrset, (DNS_RECORD *)record );
544         }
545     }
546     status = ERROR_SUCCESS;
547
548 exit:
549     DNS_RRSET_TERMINATE( rrset );
550
551     if (status != ERROR_SUCCESS)
552         DnsRecordListFree( rrset.pFirstRR, DnsFreeRecordList );
553     else
554         *recp = (DNS_RECORDA *)rrset.pFirstRR;
555
556     return status;
557 }
558
559 /*  The resolver lock must be held and res_init() must have been
560  *  called before calling these three functions.
561  */
562 static DNS_STATUS dns_set_serverlist( const IP4_ARRAY *addrs )
563 {
564     int i;
565
566     if (addrs->AddrCount > MAXNS) 
567     {
568         WARN( "too many servers: %d only using the first: %d\n",
569               addrs->AddrCount, MAXNS );
570         _res.nscount = MAXNS;
571     }
572     else _res.nscount = addrs->AddrCount;
573
574     for (i = 0; i < _res.nscount; i++)
575         _res.nsaddr_list[i].sin_addr.s_addr = addrs->AddrArray[i];
576
577     return ERROR_SUCCESS;
578 }
579
580 static DNS_STATUS dns_get_serverlist( PIP4_ARRAY addrs, PDWORD len )
581 {
582     unsigned int size;
583     int i;
584
585     size = sizeof(IP4_ARRAY) + sizeof(IP4_ADDRESS) * (_res.nscount - 1);
586     if (!addrs || *len < size)
587     {
588         *len = size;
589         return ERROR_INSUFFICIENT_BUFFER;
590     }
591
592     addrs->AddrCount = _res.nscount;
593
594     for (i = 0; i < _res.nscount; i++)
595         addrs->AddrArray[i] = _res.nsaddr_list[i].sin_addr.s_addr;
596
597     return ERROR_SUCCESS;
598 }
599
600 static DNS_STATUS dns_do_query( PCSTR name, WORD type, DWORD options,
601                                 PDNS_RECORDA *result )
602 {
603     DNS_STATUS ret = DNS_ERROR_RCODE_NOT_IMPLEMENTED;
604
605     unsigned int i, num;
606     unsigned char answer[NS_PACKETSZ];
607     ns_sect sections[] = { ns_s_an, ns_s_ar };
608     ns_msg msg;
609
610     DNS_RECORDA *record = NULL;
611     DNS_RRSET rrset;
612     int len;
613
614     DNS_RRSET_INIT( rrset );
615
616     len = res_query( name, ns_c_in, type, answer, sizeof(answer) );
617     if (len < 0)
618     {
619         ret = dns_map_h_errno( h_errno );
620         goto exit;
621     }
622
623     if (dns_ns_initparse( answer, len, &msg ) < 0)
624     {
625         ret = DNS_ERROR_BAD_PACKET;
626         goto exit;
627     }
628
629 #define RCODE_MASK 0x0f
630     if ((msg._flags & RCODE_MASK) != ns_r_noerror)
631     {
632         ret = dns_map_error( msg._flags & RCODE_MASK );
633         goto exit;
634     }
635
636     for (i = 0; i < sizeof(sections)/sizeof(sections[0]); i++)
637     {
638         for (num = 0; num < ns_msg_count( msg, sections[i] ); num++)
639         {
640             ret = dns_copy_record( msg, sections[i], num, &record );
641             if (ret != ERROR_SUCCESS) goto exit;
642
643             DNS_RRSET_ADD( rrset, (DNS_RECORD *)record );
644         }
645     }
646
647 exit:
648     DNS_RRSET_TERMINATE( rrset );
649
650     if (ret != ERROR_SUCCESS)
651         DnsRecordListFree( rrset.pFirstRR, DnsFreeRecordList );
652     else
653         *result = (DNS_RECORDA *)rrset.pFirstRR;
654
655     return ret;
656 }
657
658 #endif /* HAVE_RESOLV */
659
660 /******************************************************************************
661  * DnsQuery_A           [DNSAPI.@]
662  *
663  */
664 DNS_STATUS WINAPI DnsQuery_A( PCSTR name, WORD type, DWORD options, PVOID servers,
665                               PDNS_RECORDA *result, PVOID *reserved )
666 {
667     WCHAR *nameW;
668     DNS_RECORDW *resultW;
669     DNS_STATUS status;
670
671     TRACE( "(%s,%s,0x%08x,%p,%p,%p)\n", debugstr_a(name), dns_type_to_str( type ),
672            options, servers, result, reserved );
673
674     if (!name || !result)
675         return ERROR_INVALID_PARAMETER;
676
677     nameW = dns_strdup_aw( name );
678     if (!nameW) return ERROR_NOT_ENOUGH_MEMORY;
679
680     status = DnsQuery_W( nameW, type, options, servers, &resultW, reserved ); 
681
682     if (status == ERROR_SUCCESS)
683     {
684         *result = (DNS_RECORDA *)DnsRecordSetCopyEx(
685              (DNS_RECORD *)resultW, DnsCharSetUnicode, DnsCharSetAnsi );
686
687         if (!*result) status = ERROR_NOT_ENOUGH_MEMORY;
688         DnsRecordListFree( (DNS_RECORD *)resultW, DnsFreeRecordList );
689     }
690
691     heap_free( nameW );
692     return status;
693 }
694
695 /******************************************************************************
696  * DnsQuery_UTF8              [DNSAPI.@]
697  *
698  */
699 DNS_STATUS WINAPI DnsQuery_UTF8( PCSTR name, WORD type, DWORD options, PVOID servers,
700                                  PDNS_RECORDA *result, PVOID *reserved )
701 {
702     DNS_STATUS ret = DNS_ERROR_RCODE_NOT_IMPLEMENTED;
703 #ifdef HAVE_RESOLV
704
705     TRACE( "(%s,%s,0x%08x,%p,%p,%p)\n", debugstr_a(name), dns_type_to_str( type ),
706            options, servers, result, reserved );
707
708     if (!name || !result)
709         return ERROR_INVALID_PARAMETER;
710
711     LOCK_RESOLVER();
712
713     initialise_resolver();
714     _res.options |= dns_map_options( options );
715
716     if (servers && (ret = dns_set_serverlist( servers )))
717     {
718         UNLOCK_RESOLVER();
719         return ret;
720     }
721
722     ret = dns_do_query( name, type, options, result );
723
724     if (ret == DNS_ERROR_RCODE_NAME_ERROR && type == DNS_TYPE_A &&
725         !(options & DNS_QUERY_NO_NETBT))
726     {
727         TRACE( "dns lookup failed, trying netbios query\n" );
728         ret = dns_do_query_netbios( name, result );
729     }
730
731     UNLOCK_RESOLVER();
732
733 #endif
734     return ret;
735 }
736
737 /******************************************************************************
738  * DnsQuery_W              [DNSAPI.@]
739  *
740  */
741 DNS_STATUS WINAPI DnsQuery_W( PCWSTR name, WORD type, DWORD options, PVOID servers,
742                               PDNS_RECORDW *result, PVOID *reserved )
743 {
744     char *nameU;
745     DNS_RECORDA *resultA;
746     DNS_STATUS status;
747
748     TRACE( "(%s,%s,0x%08x,%p,%p,%p)\n", debugstr_w(name), dns_type_to_str( type ),
749            options, servers, result, reserved );
750
751     if (!name || !result)
752         return ERROR_INVALID_PARAMETER;
753
754     nameU = dns_strdup_wu( name );
755     if (!nameU) return ERROR_NOT_ENOUGH_MEMORY;
756
757     status = DnsQuery_UTF8( nameU, type, options, servers, &resultA, reserved ); 
758
759     if (status == ERROR_SUCCESS)
760     {
761         *result = (DNS_RECORDW *)DnsRecordSetCopyEx(
762             (DNS_RECORD *)resultA, DnsCharSetUtf8, DnsCharSetUnicode );
763
764         if (!*result) status = ERROR_NOT_ENOUGH_MEMORY;
765         DnsRecordListFree( (DNS_RECORD *)resultA, DnsFreeRecordList );
766     }
767
768     heap_free( nameU );
769     return status;
770 }
771
772 static DNS_STATUS dns_get_hostname_a( COMPUTER_NAME_FORMAT format,
773                                       PSTR buffer, PDWORD len )
774 {
775     char name[256];
776     DWORD size = sizeof(name)/sizeof(name[0]);
777
778     if (!GetComputerNameExA( format, name, &size ))
779         return DNS_ERROR_NAME_DOES_NOT_EXIST;
780
781     if (!buffer || (size = lstrlenA( name ) + 1) > *len)
782     {
783         *len = size;
784         return ERROR_INSUFFICIENT_BUFFER;
785     }
786
787     lstrcpyA( buffer, name );
788     return ERROR_SUCCESS;
789 }
790
791 static DNS_STATUS dns_get_hostname_w( COMPUTER_NAME_FORMAT format,
792                                       PWSTR buffer, PDWORD len )
793 {
794     WCHAR name[256];
795     DWORD size = sizeof(name)/sizeof(name[0]);
796
797     if (!GetComputerNameExW( format, name, &size ))
798         return DNS_ERROR_NAME_DOES_NOT_EXIST;
799
800     if (!buffer || (size = lstrlenW( name ) + 1) > *len)
801     {
802         *len = size;
803         return ERROR_INSUFFICIENT_BUFFER;
804     }
805
806     lstrcpyW( buffer, name );
807     return ERROR_SUCCESS;
808 }
809
810 /******************************************************************************
811  * DnsQueryConfig          [DNSAPI.@]
812  *
813  */
814 DNS_STATUS WINAPI DnsQueryConfig( DNS_CONFIG_TYPE config, DWORD flag, PCWSTR adapter,
815                                   PVOID reserved, PVOID buffer, PDWORD len )
816 {
817     DNS_STATUS ret = ERROR_INVALID_PARAMETER;
818
819     TRACE( "(%d,0x%08x,%s,%p,%p,%p)\n", config, flag, debugstr_w(adapter),
820            reserved, buffer, len );
821
822     if (!len) return ERROR_INVALID_PARAMETER;
823
824     switch (config)
825     {
826     case DnsConfigDnsServerList:
827     {
828 #ifdef HAVE_RESOLV
829         LOCK_RESOLVER();
830
831         initialise_resolver();
832         ret = dns_get_serverlist( buffer, len );
833
834         UNLOCK_RESOLVER();
835         break;
836 #else
837         WARN( "compiled without resolver support\n" );
838         break;
839 #endif
840     }
841     case DnsConfigHostName_A:
842     case DnsConfigHostName_UTF8:
843         return dns_get_hostname_a( ComputerNameDnsHostname, buffer, len );
844
845     case DnsConfigFullHostName_A:
846     case DnsConfigFullHostName_UTF8:
847         return dns_get_hostname_a( ComputerNameDnsFullyQualified, buffer, len );
848
849     case DnsConfigPrimaryDomainName_A:
850     case DnsConfigPrimaryDomainName_UTF8:
851         return dns_get_hostname_a( ComputerNameDnsDomain, buffer, len );
852
853     case DnsConfigHostName_W:
854         return dns_get_hostname_w( ComputerNameDnsHostname, buffer, len );
855
856     case DnsConfigFullHostName_W:
857         return dns_get_hostname_w( ComputerNameDnsFullyQualified, buffer, len );
858
859     case DnsConfigPrimaryDomainName_W:
860         return dns_get_hostname_w( ComputerNameDnsDomain, buffer, len );
861
862     case DnsConfigAdapterDomainName_A:
863     case DnsConfigAdapterDomainName_W:
864     case DnsConfigAdapterDomainName_UTF8:
865     case DnsConfigSearchList:
866     case DnsConfigAdapterInfo:
867     case DnsConfigPrimaryHostNameRegistrationEnabled:
868     case DnsConfigAdapterHostNameRegistrationEnabled:
869     case DnsConfigAddressRegistrationMaxCount:
870         FIXME( "unimplemented config type %d\n", config );
871         break;
872
873     default:
874         WARN( "unknown config type: %d\n", config );
875         break;
876     }
877     return ret;
878 }