ntdll: Avoid inter-process APCs when called for the process itself.
[wine/multimedia.git] / dlls / dnsapi / query.c
blob38f8801b295dccbfaeed064b612bdd808fdddd95
1 /*
2 * DNS support
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.
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.
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
21 #include "config.h"
22 #include "wine/port.h"
23 #include "wine/debug.h"
25 #include <stdarg.h>
26 #include <string.h>
27 #include <sys/types.h>
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
42 #include "windef.h"
43 #include "winbase.h"
44 #include "winerror.h"
45 #include "winnls.h"
46 #include "windns.h"
47 #include "nb30.h"
49 #include "dnsapi.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(dnsapi);
53 #ifdef HAVE_RESOLV
55 static CRITICAL_SECTION resolver_cs;
56 static CRITICAL_SECTION_DEBUG resolver_cs_debug =
58 0, 0, &resolver_cs,
59 { &resolver_cs_debug.ProcessLocksList,
60 &resolver_cs_debug.ProcessLocksList },
61 0, 0, { (DWORD_PTR)(__FILE__ ": resolver_cs") }
63 static CRITICAL_SECTION resolver_cs = { &resolver_cs_debug, -1, 0, 0, 0, 0 };
65 #define LOCK_RESOLVER() do { EnterCriticalSection( &resolver_cs ); } while (0)
66 #define UNLOCK_RESOLVER() do { LeaveCriticalSection( &resolver_cs ); } while (0)
69 static const char *dns_section_to_str( ns_sect section )
71 switch (section)
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:
79 static char tmp[5];
80 FIXME( "unknown section: 0x%02x\n", section );
81 sprintf( tmp, "0x%02x", section );
82 return tmp;
87 static unsigned long dns_map_options( DWORD options )
89 unsigned long ret = 0;
91 if (options == DNS_QUERY_STANDARD)
92 return RES_DEFAULT;
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;
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" );
120 if (options & DNS_QUERY_NO_NETBT)
121 TRACE( "netbios query disabled\n" );
123 return ret;
126 static DNS_STATUS dns_map_error( int error )
128 switch (error)
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;
147 static DNS_STATUS dns_map_h_errno( int error )
149 switch (error)
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;
162 static char *dns_dname_from_msg( ns_msg msg, const unsigned char *pos )
164 int len;
165 char *str, dname[NS_MAXDNAME] = ".";
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) );
171 len = strlen( dname );
172 str = dns_alloc( len + 1 );
173 if (str) strcpy( str, dname );
174 return str;
177 static char *dns_str_from_rdata( const unsigned char *rdata )
179 char *str;
180 unsigned int len = rdata[0];
182 str = dns_alloc( len + 1 );
183 if (str)
185 memcpy( str, ++rdata, len );
186 str[len] = '\0';
188 return str;
191 static unsigned int dns_get_record_size( ns_rr *rr )
193 const unsigned char *pos = rr->rdata;
194 unsigned int num = 0, size = sizeof(DNS_RECORDA);
196 switch (rr->type)
198 case ns_t_key:
200 pos += sizeof(WORD) + sizeof(BYTE) + sizeof(BYTE);
201 size += rr->rdata + rr->rdlength - pos - 1;
202 break;
204 case ns_t_sig:
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;
211 case ns_t_hinfo:
212 case ns_t_isdn:
213 case ns_t_txt:
214 case ns_t_x25:
216 while (pos[0] && pos < rr->rdata + rr->rdlength)
218 num++;
219 pos += pos[0] + 1;
221 size += (num - 1) * sizeof(PCHAR);
222 break;
224 case ns_t_null:
226 size += rr->rdlength - 1;
227 break;
229 case ns_t_nxt:
230 case ns_t_wks:
231 case 0xff01: /* WINS */
233 FIXME( "unhandled type: %s\n", dns_type_to_str( rr->type ) );
234 break;
236 default:
237 break;
239 return size;
242 static DNS_STATUS dns_copy_rdata( ns_msg msg, ns_rr *rr, DNS_RECORDA *r, WORD *dlen )
244 DNS_STATUS ret = ERROR_SUCCESS;
245 const unsigned char *pos = rr->rdata;
246 unsigned int i, size;
248 switch (rr->type)
250 case ns_t_a:
252 r->Data.A.IpAddress = *(const DWORD *)pos;
253 *dlen = sizeof(DNS_A_DATA);
254 break;
256 case ns_t_aaaa:
258 for (i = 0; i < sizeof(IP6_ADDRESS)/sizeof(DWORD); i++)
260 r->Data.AAAA.Ip6Address.IP6Dword[i] = *(const DWORD *)pos;
261 pos += sizeof(DWORD);
264 *dlen = sizeof(DNS_AAAA_DATA);
265 break;
267 case ns_t_key:
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++;
274 size = rr->rdata + rr->rdlength - pos;
276 for (i = 0; i < size; i++)
277 r->Data.KEY.Key[i] = *(const BYTE *)pos++;
279 *dlen = sizeof(DNS_KEY_DATA) + (size - 1) * sizeof(BYTE);
280 break;
282 case ns_t_rp:
283 case ns_t_minfo:
285 r->Data.MINFO.pNameMailbox = dns_dname_from_msg( msg, pos );
286 if (!r->Data.MINFO.pNameMailbox) return ERROR_NOT_ENOUGH_MEMORY;
288 if (dns_ns_name_skip( &pos, ns_msg_end( msg ) ) < 0)
289 return DNS_ERROR_BAD_PACKET;
291 r->Data.MINFO.pNameErrorsMailbox = dns_dname_from_msg( msg, pos );
292 if (!r->Data.MINFO.pNameErrorsMailbox)
294 dns_free( r->Data.MINFO.pNameMailbox );
295 return ERROR_NOT_ENOUGH_MEMORY;
298 *dlen = sizeof(DNS_MINFO_DATAA);
299 break;
301 case ns_t_afsdb:
302 case ns_t_rt:
303 case ns_t_mx:
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;
309 *dlen = sizeof(DNS_MX_DATAA);
310 break;
312 case ns_t_null:
314 r->Data.Null.dwByteCount = rr->rdlength;
315 memcpy( r->Data.Null.Data, rr->rdata, rr->rdlength );
317 *dlen = sizeof(DNS_NULL_DATA) + rr->rdlength - 1;
318 break;
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:
329 r->Data.PTR.pNameHost = dns_dname_from_msg( msg, pos );
330 if (!r->Data.PTR.pNameHost) return ERROR_NOT_ENOUGH_MEMORY;
332 *dlen = sizeof(DNS_PTR_DATAA);
333 break;
335 case ns_t_sig:
337 r->Data.SIG.pNameSigner = dns_dname_from_msg( msg, pos );
338 if (!r->Data.SIG.pNameSigner) return ERROR_NOT_ENOUGH_MEMORY;
340 if (dns_ns_name_skip( &pos, ns_msg_end( msg ) ) < 0)
341 return DNS_ERROR_BAD_PACKET;
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;
352 size = rr->rdata + rr->rdlength - pos;
354 for (i = 0; i < size; i++)
355 r->Data.SIG.Signature[i] = *(const BYTE *)pos++;
357 *dlen = sizeof(DNS_SIG_DATAA) + (size - 1) * sizeof(BYTE);
358 break;
360 case ns_t_soa:
362 r->Data.SOA.pNamePrimaryServer = dns_dname_from_msg( msg, pos );
363 if (!r->Data.SOA.pNamePrimaryServer) return ERROR_NOT_ENOUGH_MEMORY;
365 if (dns_ns_name_skip( &pos, ns_msg_end( msg ) ) < 0)
366 return DNS_ERROR_BAD_PACKET;
368 r->Data.SOA.pNameAdministrator = dns_dname_from_msg( msg, pos );
369 if (!r->Data.SOA.pNameAdministrator)
371 dns_free( r->Data.SOA.pNamePrimaryServer );
372 return ERROR_NOT_ENOUGH_MEMORY;
375 if (dns_ns_name_skip( &pos, ns_msg_end( msg ) ) < 0)
376 return DNS_ERROR_BAD_PACKET;
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);
384 *dlen = sizeof(DNS_SOA_DATAA);
385 break;
387 case ns_t_srv:
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);
393 r->Data.SRV.pNameTarget = dns_dname_from_msg( msg, pos );
394 if (!r->Data.SRV.pNameTarget) return ERROR_NOT_ENOUGH_MEMORY;
396 *dlen = sizeof(DNS_SRV_DATAA);
397 break;
399 case ns_t_hinfo:
400 case ns_t_isdn:
401 case ns_t_x25:
402 case ns_t_txt:
404 i = 0;
405 while (pos[0] && pos < rr->rdata + rr->rdlength)
407 r->Data.TXT.pStringArray[i] = dns_str_from_rdata( pos );
408 if (!r->Data.TXT.pStringArray[i])
410 for (--i; i >= 0; i--)
411 dns_free( r->Data.TXT.pStringArray[i] );
412 return ERROR_NOT_ENOUGH_MEMORY;
414 i++;
415 pos += pos[0] + 1;
417 r->Data.TXT.dwStringCount = i;
418 *dlen = sizeof(DNS_TXT_DATAA) + (i - 1) * sizeof(PCHAR);
419 break;
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;
434 return ret;
437 static DNS_STATUS dns_copy_record( ns_msg msg, ns_sect section,
438 unsigned short num, DNS_RECORDA **recp )
440 DNS_STATUS ret;
441 DNS_RECORDA *record;
442 WORD dlen;
443 ns_rr rr;
445 if (dns_ns_parserr( &msg, section, num, &rr ) < 0)
446 return DNS_ERROR_BAD_PACKET;
448 if (!(record = dns_zero_alloc( dns_get_record_size( &rr ) )))
449 return ERROR_NOT_ENOUGH_MEMORY;
451 record->pName = dns_strdup_u( rr.name );
452 if (!record->pName)
454 dns_free( record );
455 return ERROR_NOT_ENOUGH_MEMORY;
458 record->wType = rr.type;
459 record->Flags.S.Section = section;
460 record->Flags.S.CharSet = DnsCharSetUtf8;
461 record->dwTtl = rr.ttl;
463 if ((ret = dns_copy_rdata( msg, &rr, record, &dlen )))
465 dns_free( record->pName );
466 dns_free( record );
467 return ret;
469 record->wDataLength = dlen;
470 *recp = record;
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;
477 #define DEFAULT_TTL 1200
479 static DNS_STATUS dns_do_query_netbios( PCSTR name, DNS_RECORDA **recp )
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;
490 len = strlen( name );
491 if (len >= NCBNAMSZ) return DNS_ERROR_RCODE_NAME_ERROR;
493 DNS_RRSET_INIT( rrset );
495 memset( &ncb, 0, sizeof(ncb) );
496 ncb.ncb_command = NCBFINDNAME;
498 memset( ncb.ncb_callname, ' ', sizeof(ncb.ncb_callname) );
499 memcpy( ncb.ncb_callname, name, len );
500 ncb.ncb_callname[NCBNAMSZ - 1] = '\0';
502 ret = Netbios( &ncb );
503 if (ret != NRC_GOODRET) return ERROR_INVALID_NAME;
505 header = (FIND_NAME_HEADER *)ncb.ncb_buffer;
506 buffer = (FIND_NAME_BUFFER *)((char *)header + sizeof(FIND_NAME_HEADER));
508 for (i = 0; i < header->node_count; i++)
510 record = dns_zero_alloc( sizeof(DNS_RECORDA) );
511 if (!record)
513 status = ERROR_NOT_ENOUGH_MEMORY;
514 goto exit;
516 else
518 record->pName = dns_strdup_u( name );
519 if (!record->pName)
521 status = ERROR_NOT_ENOUGH_MEMORY;
522 goto exit;
525 record->wType = DNS_TYPE_A;
526 record->Flags.S.Section = DnsSectionAnswer;
527 record->Flags.S.CharSet = DnsCharSetUtf8;
528 record->dwTtl = DEFAULT_TTL;
530 /* FIXME: network byte order? */
531 record->Data.A.IpAddress = *(DWORD *)((char *)buffer[i].destination_addr + 2);
533 DNS_RRSET_ADD( rrset, (DNS_RECORD *)record );
536 status = ERROR_SUCCESS;
538 exit:
539 DNS_RRSET_TERMINATE( rrset );
541 if (status != ERROR_SUCCESS)
542 DnsRecordListFree( rrset.pFirstRR, DnsFreeRecordList );
543 else
544 *recp = (DNS_RECORDA *)rrset.pFirstRR;
546 return status;
549 /* The resolver lock must be held and res_init() must have been
550 * called before calling these three functions.
552 static DNS_STATUS dns_set_serverlist( PIP4_ARRAY addrs )
554 unsigned int i;
556 if (addrs->AddrCount > MAXNS)
558 WARN( "too many servers: %d only using the first: %d\n",
559 addrs->AddrCount, MAXNS );
560 _res.nscount = MAXNS;
562 else _res.nscount = addrs->AddrCount;
564 for (i = 0; i < _res.nscount; i++)
565 _res.nsaddr_list[i].sin_addr.s_addr = addrs->AddrArray[i];
567 return ERROR_SUCCESS;
570 static DNS_STATUS dns_get_serverlist( PIP4_ARRAY addrs, PDWORD len )
572 unsigned int i, size;
574 size = sizeof(IP4_ARRAY) + sizeof(IP4_ADDRESS) * (_res.nscount - 1);
575 if (!addrs || *len < size)
577 *len = size;
578 return ERROR_INSUFFICIENT_BUFFER;
581 addrs->AddrCount = _res.nscount;
583 for (i = 0; i < _res.nscount; i++)
584 addrs->AddrArray[i] = _res.nsaddr_list[i].sin_addr.s_addr;
586 return ERROR_SUCCESS;
589 static DNS_STATUS dns_do_query( PCSTR name, WORD type, DWORD options,
590 PDNS_RECORDA *result )
592 DNS_STATUS ret = DNS_ERROR_RCODE_NOT_IMPLEMENTED;
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;
599 DNS_RECORDA *record = NULL;
600 DNS_RRSET rrset;
601 int len;
603 DNS_RRSET_INIT( rrset );
605 len = res_query( name, ns_c_in, type, answer, sizeof(answer) );
606 if (len < 0)
608 ret = dns_map_h_errno( h_errno );
609 goto exit;
612 if (dns_ns_initparse( answer, len, &msg ) < 0)
614 ret = DNS_ERROR_BAD_PACKET;
615 goto exit;
618 #define RCODE_MASK 0x0f
619 if ((msg._flags & RCODE_MASK) != ns_r_noerror)
621 ret = dns_map_error( msg._flags & RCODE_MASK );
622 goto exit;
625 for (i = 0; i < sizeof(sections)/sizeof(sections[0]); i++)
627 for (num = 0; num < ns_msg_count( msg, sections[i] ); num++)
629 ret = dns_copy_record( msg, sections[i], num, &record );
630 if (ret != ERROR_SUCCESS) goto exit;
632 DNS_RRSET_ADD( rrset, (DNS_RECORD *)record );
636 exit:
637 DNS_RRSET_TERMINATE( rrset );
639 if (ret != ERROR_SUCCESS)
640 DnsRecordListFree( rrset.pFirstRR, DnsFreeRecordList );
641 else
642 *result = (DNS_RECORDA *)rrset.pFirstRR;
644 return ret;
647 #endif /* HAVE_RESOLV */
649 /******************************************************************************
650 * DnsQuery_A [DNSAPI.@]
653 DNS_STATUS WINAPI DnsQuery_A( PCSTR name, WORD type, DWORD options, PIP4_ARRAY servers,
654 PDNS_RECORDA *result, PVOID *reserved )
656 WCHAR *nameW;
657 DNS_RECORDW *resultW;
658 DNS_STATUS status;
660 TRACE( "(%s,%s,0x%08x,%p,%p,%p)\n", debugstr_a(name), dns_type_to_str( type ),
661 options, servers, result, reserved );
663 if (!name || !result)
664 return ERROR_INVALID_PARAMETER;
666 nameW = dns_strdup_aw( name );
667 if (!nameW) return ERROR_NOT_ENOUGH_MEMORY;
669 status = DnsQuery_W( nameW, type, options, servers, &resultW, reserved );
671 if (status == ERROR_SUCCESS)
673 *result = (DNS_RECORDA *)DnsRecordSetCopyEx(
674 (DNS_RECORD *)resultW, DnsCharSetUnicode, DnsCharSetAnsi );
676 if (!*result) status = ERROR_NOT_ENOUGH_MEMORY;
677 DnsRecordListFree( (DNS_RECORD *)resultW, DnsFreeRecordList );
680 dns_free( nameW );
681 return status;
684 /******************************************************************************
685 * DnsQuery_UTF8 [DNSAPI.@]
688 DNS_STATUS WINAPI DnsQuery_UTF8( PCSTR name, WORD type, DWORD options, PIP4_ARRAY servers,
689 PDNS_RECORDA *result, PVOID *reserved )
691 DNS_STATUS ret = DNS_ERROR_RCODE_NOT_IMPLEMENTED;
692 #ifdef HAVE_RESOLV
694 TRACE( "(%s,%s,0x%08x,%p,%p,%p)\n", debugstr_a(name), dns_type_to_str( type ),
695 options, servers, result, reserved );
697 if (!name || !result)
698 return ERROR_INVALID_PARAMETER;
700 LOCK_RESOLVER();
702 res_init();
703 _res.options |= dns_map_options( options );
705 if (servers && (ret = dns_set_serverlist( servers )))
707 UNLOCK_RESOLVER();
708 return ret;
711 ret = dns_do_query( name, type, options, result );
713 if (ret == DNS_ERROR_RCODE_NAME_ERROR && type == DNS_TYPE_A &&
714 !(options & DNS_QUERY_NO_NETBT))
716 TRACE( "dns lookup failed, trying netbios query\n" );
717 ret = dns_do_query_netbios( name, result );
720 UNLOCK_RESOLVER();
722 #endif
723 return ret;
726 /******************************************************************************
727 * DnsQuery_W [DNSAPI.@]
730 DNS_STATUS WINAPI DnsQuery_W( PCWSTR name, WORD type, DWORD options, PIP4_ARRAY servers,
731 PDNS_RECORDW *result, PVOID *reserved )
733 char *nameU;
734 DNS_RECORDA *resultA;
735 DNS_STATUS status;
737 TRACE( "(%s,%s,0x%08x,%p,%p,%p)\n", debugstr_w(name), dns_type_to_str( type ),
738 options, servers, result, reserved );
740 if (!name || !result)
741 return ERROR_INVALID_PARAMETER;
743 nameU = dns_strdup_wu( name );
744 if (!nameU) return ERROR_NOT_ENOUGH_MEMORY;
746 status = DnsQuery_UTF8( nameU, type, options, servers, &resultA, reserved );
748 if (status == ERROR_SUCCESS)
750 *result = (DNS_RECORDW *)DnsRecordSetCopyEx(
751 (DNS_RECORD *)resultA, DnsCharSetUtf8, DnsCharSetUnicode );
753 if (!*result) status = ERROR_NOT_ENOUGH_MEMORY;
754 DnsRecordListFree( (DNS_RECORD *)resultA, DnsFreeRecordList );
757 dns_free( nameU );
758 return status;
761 static DNS_STATUS dns_get_hostname_a( COMPUTER_NAME_FORMAT format,
762 LPSTR buffer, PDWORD len )
764 char name[256];
765 DWORD size = sizeof(name);
767 if (!GetComputerNameExA( format, name, &size ))
768 return DNS_ERROR_NAME_DOES_NOT_EXIST;
770 if (!buffer || (size = lstrlenA( name ) + 1) > *len)
772 *len = size;
773 return ERROR_INSUFFICIENT_BUFFER;
776 lstrcpyA( buffer, name );
777 return ERROR_SUCCESS;
780 static DNS_STATUS dns_get_hostname_w( COMPUTER_NAME_FORMAT format,
781 LPWSTR buffer, PDWORD len )
783 WCHAR name[256];
784 DWORD size = sizeof(name);
786 if (!GetComputerNameExW( format, name, &size ))
787 return DNS_ERROR_NAME_DOES_NOT_EXIST;
789 if (!buffer || (size = lstrlenW( name ) + 1) > *len)
791 *len = size;
792 return ERROR_INSUFFICIENT_BUFFER;
795 lstrcpyW( buffer, name );
796 return ERROR_SUCCESS;
799 /******************************************************************************
800 * DnsQueryConfig [DNSAPI.@]
803 DNS_STATUS WINAPI DnsQueryConfig( DNS_CONFIG_TYPE config, DWORD flag, PWSTR adapter,
804 PVOID reserved, PVOID buffer, PDWORD len )
806 DNS_STATUS ret = ERROR_INVALID_PARAMETER;
808 TRACE( "(%d,0x%08x,%s,%p,%p,%p)\n", config, flag, debugstr_w(adapter),
809 reserved, buffer, len );
811 if (!len) return ERROR_INVALID_PARAMETER;
813 switch (config)
815 case DnsConfigDnsServerList:
817 #ifdef HAVE_RESOLV
818 LOCK_RESOLVER();
820 res_init();
821 ret = dns_get_serverlist( buffer, len );
823 UNLOCK_RESOLVER();
824 break;
825 #else
826 WARN( "compiled without resolver support\n" );
827 break;
828 #endif
830 case DnsConfigHostName_A:
831 case DnsConfigHostName_UTF8:
832 return dns_get_hostname_a( ComputerNameDnsHostname, buffer, len );
834 case DnsConfigFullHostName_A:
835 case DnsConfigFullHostName_UTF8:
836 return dns_get_hostname_a( ComputerNameDnsFullyQualified, buffer, len );
838 case DnsConfigPrimaryDomainName_A:
839 case DnsConfigPrimaryDomainName_UTF8:
840 return dns_get_hostname_a( ComputerNameDnsDomain, buffer, len );
842 case DnsConfigHostName_W:
843 return dns_get_hostname_w( ComputerNameDnsHostname, buffer, len );
845 case DnsConfigFullHostName_W:
846 return dns_get_hostname_w( ComputerNameDnsFullyQualified, buffer, len );
848 case DnsConfigPrimaryDomainName_W:
849 return dns_get_hostname_w( ComputerNameDnsDomain, buffer, len );
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;
862 default:
863 WARN( "unknown config type: %d\n", config );
864 break;
866 return ret;