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