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