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