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