comctl32: Constify some variables.
[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     status = ERROR_SUCCESS;
537
538 exit:
539     DNS_RRSET_TERMINATE( rrset );
540
541     if (status != ERROR_SUCCESS)
542         DnsRecordListFree( rrset.pFirstRR, DnsFreeRecordList );
543     else
544         *recp = (DNS_RECORDA *)rrset.pFirstRR;
545
546     return status;
547 }
548
549 /*  The resolver lock must be held and res_init() must have been
550  *  called before calling these three functions.
551  */
552 static DNS_STATUS dns_set_serverlist( PIP4_ARRAY addrs )
553 {
554     unsigned int i;
555
556     if (addrs->AddrCount > MAXNS) 
557     {
558         WARN( "too many servers: %d only using the first: %d\n",
559               addrs->AddrCount, MAXNS );
560         _res.nscount = MAXNS;
561     }
562     else _res.nscount = addrs->AddrCount;
563
564     for (i = 0; i < _res.nscount; i++)
565         _res.nsaddr_list[i].sin_addr.s_addr = addrs->AddrArray[i];
566
567     return ERROR_SUCCESS;
568 }
569
570 static DNS_STATUS dns_get_serverlist( PIP4_ARRAY addrs, PDWORD len )
571 {
572     unsigned int i, size;
573
574     size = sizeof(IP4_ARRAY) + sizeof(IP4_ADDRESS) * (_res.nscount - 1);
575     if (!addrs || *len < size)
576     {
577         *len = size;
578         return ERROR_INSUFFICIENT_BUFFER;
579     }
580
581     addrs->AddrCount = _res.nscount;
582
583     for (i = 0; i < _res.nscount; i++)
584         addrs->AddrArray[i] = _res.nsaddr_list[i].sin_addr.s_addr;
585
586     return ERROR_SUCCESS;
587 }
588
589 static DNS_STATUS dns_do_query( PCSTR name, WORD type, DWORD options,
590                                 PDNS_RECORDA *result )
591 {
592     DNS_STATUS ret = DNS_ERROR_RCODE_NOT_IMPLEMENTED;
593
594     unsigned int i, num;
595     unsigned char answer[NS_PACKETSZ];
596     ns_sect sections[] = { ns_s_an, ns_s_ar };
597     ns_msg msg;
598
599     DNS_RECORDA *record = NULL;
600     DNS_RRSET rrset;
601     int len;
602
603     DNS_RRSET_INIT( rrset );
604
605     len = res_query( name, ns_c_in, type, answer, sizeof(answer) );
606     if (len < 0)
607     {
608         ret = dns_map_h_errno( h_errno );
609         goto exit;
610     }
611
612     if (dns_ns_initparse( answer, len, &msg ) < 0)
613     {
614         ret = DNS_ERROR_BAD_PACKET;
615         goto exit;
616     }
617
618 #define RCODE_MASK 0x0f
619     if ((msg._flags & RCODE_MASK) != ns_r_noerror)
620     {
621         ret = dns_map_error( msg._flags & RCODE_MASK );
622         goto exit;
623     }
624
625     for (i = 0; i < sizeof(sections)/sizeof(sections[0]); i++)
626     {
627         for (num = 0; num < ns_msg_count( msg, sections[i] ); num++)
628         {
629             ret = dns_copy_record( msg, sections[i], num, &record );
630             if (ret != ERROR_SUCCESS) goto exit;
631
632             DNS_RRSET_ADD( rrset, (DNS_RECORD *)record );
633         }
634     }
635
636 exit:
637     DNS_RRSET_TERMINATE( rrset );
638
639     if (ret != ERROR_SUCCESS)
640         DnsRecordListFree( rrset.pFirstRR, DnsFreeRecordList );
641     else
642         *result = (DNS_RECORDA *)rrset.pFirstRR;
643
644     return ret;
645 }
646
647 #endif /* HAVE_RESOLV */
648
649 /******************************************************************************
650  * DnsQuery_A           [DNSAPI.@]
651  *
652  */
653 DNS_STATUS WINAPI DnsQuery_A( PCSTR name, WORD type, DWORD options, PIP4_ARRAY servers,
654                               PDNS_RECORDA *result, PVOID *reserved )
655 {
656     WCHAR *nameW;
657     DNS_RECORDW *resultW;
658     DNS_STATUS status;
659
660     TRACE( "(%s,%s,0x%08x,%p,%p,%p)\n", debugstr_a(name), dns_type_to_str( type ),
661            options, servers, result, reserved );
662
663     if (!name || !result)
664         return ERROR_INVALID_PARAMETER;
665
666     nameW = dns_strdup_aw( name );
667     if (!nameW) return ERROR_NOT_ENOUGH_MEMORY;
668
669     status = DnsQuery_W( nameW, type, options, servers, &resultW, reserved ); 
670
671     if (status == ERROR_SUCCESS)
672     {
673         *result = (DNS_RECORDA *)DnsRecordSetCopyEx(
674              (DNS_RECORD *)resultW, DnsCharSetUnicode, DnsCharSetAnsi );
675
676         if (!*result) status = ERROR_NOT_ENOUGH_MEMORY;
677         DnsRecordListFree( (DNS_RECORD *)resultW, DnsFreeRecordList );
678     }
679
680     dns_free( nameW );
681     return status;
682 }
683
684 /******************************************************************************
685  * DnsQuery_UTF8              [DNSAPI.@]
686  *
687  */
688 DNS_STATUS WINAPI DnsQuery_UTF8( PCSTR name, WORD type, DWORD options, PIP4_ARRAY servers,
689                                  PDNS_RECORDA *result, PVOID *reserved )
690 {
691     DNS_STATUS ret = DNS_ERROR_RCODE_NOT_IMPLEMENTED;
692 #ifdef HAVE_RESOLV
693
694     TRACE( "(%s,%s,0x%08x,%p,%p,%p)\n", debugstr_a(name), dns_type_to_str( type ),
695            options, servers, result, reserved );
696
697     if (!name || !result)
698         return ERROR_INVALID_PARAMETER;
699
700     LOCK_RESOLVER();
701
702     res_init();
703     _res.options |= dns_map_options( options );
704
705     if (servers && (ret = dns_set_serverlist( servers )))
706     {
707         UNLOCK_RESOLVER();
708         return ret;
709     }
710
711     ret = dns_do_query( name, type, options, result );
712
713     if (ret == DNS_ERROR_RCODE_NAME_ERROR && type == DNS_TYPE_A &&
714         !(options & DNS_QUERY_NO_NETBT))
715     {
716         TRACE( "dns lookup failed, trying netbios query\n" );
717         ret = dns_do_query_netbios( name, result );
718     }
719
720     UNLOCK_RESOLVER();
721
722 #endif
723     return ret;
724 }
725
726 /******************************************************************************
727  * DnsQuery_W              [DNSAPI.@]
728  *
729  */
730 DNS_STATUS WINAPI DnsQuery_W( PCWSTR name, WORD type, DWORD options, PIP4_ARRAY servers,
731                               PDNS_RECORDW *result, PVOID *reserved )
732 {
733     char *nameU;
734     DNS_RECORDA *resultA;
735     DNS_STATUS status;
736
737     TRACE( "(%s,%s,0x%08x,%p,%p,%p)\n", debugstr_w(name), dns_type_to_str( type ),
738            options, servers, result, reserved );
739
740     if (!name || !result)
741         return ERROR_INVALID_PARAMETER;
742
743     nameU = dns_strdup_wu( name );
744     if (!nameU) return ERROR_NOT_ENOUGH_MEMORY;
745
746     status = DnsQuery_UTF8( nameU, type, options, servers, &resultA, reserved ); 
747
748     if (status == ERROR_SUCCESS)
749     {
750         *result = (DNS_RECORDW *)DnsRecordSetCopyEx(
751             (DNS_RECORD *)resultA, DnsCharSetUtf8, DnsCharSetUnicode );
752
753         if (!*result) status = ERROR_NOT_ENOUGH_MEMORY;
754         DnsRecordListFree( (DNS_RECORD *)resultA, DnsFreeRecordList );
755     }
756
757     dns_free( nameU );
758     return status;
759 }
760
761 static DNS_STATUS dns_get_hostname_a( COMPUTER_NAME_FORMAT format,
762                                       LPSTR buffer, PDWORD len )
763 {
764     char name[256];
765     DWORD size = sizeof(name);
766
767     if (!GetComputerNameExA( format, name, &size ))
768         return DNS_ERROR_NAME_DOES_NOT_EXIST;
769
770     if (!buffer || (size = lstrlenA( name ) + 1) > *len)
771     {
772         *len = size;
773         return ERROR_INSUFFICIENT_BUFFER;
774     }
775
776     lstrcpyA( buffer, name );
777     return ERROR_SUCCESS;
778 }
779
780 static DNS_STATUS dns_get_hostname_w( COMPUTER_NAME_FORMAT format,
781                                       LPWSTR buffer, PDWORD len )
782 {
783     WCHAR name[256];
784     DWORD size = sizeof(name);
785
786     if (!GetComputerNameExW( format, name, &size ))
787         return DNS_ERROR_NAME_DOES_NOT_EXIST;
788
789     if (!buffer || (size = lstrlenW( name ) + 1) > *len)
790     {
791         *len = size;
792         return ERROR_INSUFFICIENT_BUFFER;
793     }
794
795     lstrcpyW( buffer, name );
796     return ERROR_SUCCESS;
797 }
798
799 /******************************************************************************
800  * DnsQueryConfig          [DNSAPI.@]
801  *
802  */
803 DNS_STATUS WINAPI DnsQueryConfig( DNS_CONFIG_TYPE config, DWORD flag, PWSTR adapter,
804                                   PVOID reserved, PVOID buffer, PDWORD len )
805 {
806     DNS_STATUS ret = ERROR_INVALID_PARAMETER;
807
808     TRACE( "(%d,0x%08x,%s,%p,%p,%p)\n", config, flag, debugstr_w(adapter),
809            reserved, buffer, len );
810
811     if (!len) return ERROR_INVALID_PARAMETER;
812
813     switch (config)
814     {
815     case DnsConfigDnsServerList:
816     {
817 #ifdef HAVE_RESOLV
818         LOCK_RESOLVER();
819
820         res_init();
821         ret = dns_get_serverlist( buffer, len );
822
823         UNLOCK_RESOLVER();
824         break;
825 #else
826         WARN( "compiled without resolver support\n" );
827         break;
828 #endif
829     }
830     case DnsConfigHostName_A:
831     case DnsConfigHostName_UTF8:
832         return dns_get_hostname_a( ComputerNameDnsHostname, buffer, len );
833
834     case DnsConfigFullHostName_A:
835     case DnsConfigFullHostName_UTF8:
836         return dns_get_hostname_a( ComputerNameDnsFullyQualified, buffer, len );
837
838     case DnsConfigPrimaryDomainName_A:
839     case DnsConfigPrimaryDomainName_UTF8:
840         return dns_get_hostname_a( ComputerNameDnsDomain, buffer, len );
841
842     case DnsConfigHostName_W:
843         return dns_get_hostname_w( ComputerNameDnsHostname, buffer, len );
844
845     case DnsConfigFullHostName_W:
846         return dns_get_hostname_w( ComputerNameDnsFullyQualified, buffer, len );
847
848     case DnsConfigPrimaryDomainName_W:
849         return dns_get_hostname_w( ComputerNameDnsDomain, buffer, len );
850
851     case DnsConfigAdapterDomainName_A:
852     case DnsConfigAdapterDomainName_W:
853     case DnsConfigAdapterDomainName_UTF8:
854     case DnsConfigSearchList:
855     case DnsConfigAdapterInfo:
856     case DnsConfigPrimaryHostNameRegistrationEnabled:
857     case DnsConfigAdapterHostNameRegistrationEnabled:
858     case DnsConfigAddressRegistrationMaxCount:
859         FIXME( "unimplemented config type %d\n", config );
860         break;
861
862     default:
863         WARN( "unknown config type: %d\n", config );
864         break;
865     }
866     return ret;
867 }