usp10: Simplify the offset calculation by always using ETO_PDY.
[wine] / dlls / dnsapi / record.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 <stdio.h>
27 #include <string.h>
28 #include <sys/types.h>
29
30 #ifdef HAVE_NETINET_IN_H
31 # include <netinet/in.h>
32 #endif
33 #ifdef HAVE_ARPA_NAMESER_H
34 # include <arpa/nameser.h>
35 #endif
36 #ifdef HAVE_RESOLV_H
37 # include <resolv.h>
38 #endif
39
40 #include "windef.h"
41 #include "winbase.h"
42 #include "winnls.h"
43 #include "windns.h"
44
45 #include "dnsapi.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(dnsapi);
48
49 const char *dns_type_to_str( unsigned short type )
50 {
51     switch (type)
52     {
53 #define X(x)    case (x): return #x;
54     X(DNS_TYPE_ZERO)
55     X(DNS_TYPE_A)
56     X(DNS_TYPE_NS)
57     X(DNS_TYPE_MD)
58     X(DNS_TYPE_MF)
59     X(DNS_TYPE_CNAME)
60     X(DNS_TYPE_SOA)
61     X(DNS_TYPE_MB)
62     X(DNS_TYPE_MG)
63     X(DNS_TYPE_MR)
64     X(DNS_TYPE_NULL)
65     X(DNS_TYPE_WKS)
66     X(DNS_TYPE_PTR)
67     X(DNS_TYPE_HINFO)
68     X(DNS_TYPE_MINFO)
69     X(DNS_TYPE_MX)
70     X(DNS_TYPE_TEXT)
71     X(DNS_TYPE_RP)
72     X(DNS_TYPE_AFSDB)
73     X(DNS_TYPE_X25)
74     X(DNS_TYPE_ISDN)
75     X(DNS_TYPE_RT)
76     X(DNS_TYPE_NSAP)
77     X(DNS_TYPE_NSAPPTR)
78     X(DNS_TYPE_SIG)
79     X(DNS_TYPE_KEY)
80     X(DNS_TYPE_PX)
81     X(DNS_TYPE_GPOS)
82     X(DNS_TYPE_AAAA)
83     X(DNS_TYPE_LOC)
84     X(DNS_TYPE_NXT)
85     X(DNS_TYPE_EID)
86     X(DNS_TYPE_NIMLOC)
87     X(DNS_TYPE_SRV)
88     X(DNS_TYPE_ATMA)
89     X(DNS_TYPE_NAPTR)
90     X(DNS_TYPE_KX)
91     X(DNS_TYPE_CERT)
92     X(DNS_TYPE_A6)
93     X(DNS_TYPE_DNAME)
94     X(DNS_TYPE_SINK)
95     X(DNS_TYPE_OPT)
96     X(DNS_TYPE_UINFO)
97     X(DNS_TYPE_UID)
98     X(DNS_TYPE_GID)
99     X(DNS_TYPE_UNSPEC)
100     X(DNS_TYPE_ADDRS)
101     X(DNS_TYPE_TKEY)
102     X(DNS_TYPE_TSIG)
103     X(DNS_TYPE_IXFR)
104     X(DNS_TYPE_AXFR)
105     X(DNS_TYPE_MAILB)
106     X(DNS_TYPE_MAILA)
107     X(DNS_TYPE_ANY)
108     X(DNS_TYPE_WINS)
109     X(DNS_TYPE_WINSR)
110 #undef X
111     default: { static char tmp[7]; sprintf( tmp, "0x%04x", type ); return tmp; }
112     }
113 }
114
115 static int dns_strcmpX( LPCVOID str1, LPCVOID str2, BOOL wide )
116 {
117     if (wide)
118         return lstrcmpiW( str1, str2 );
119     else
120         return lstrcmpiA( str1, str2 );
121 }
122
123 /******************************************************************************
124  * DnsRecordCompare                        [DNSAPI.@]
125  *
126  */
127 BOOL WINAPI DnsRecordCompare( PDNS_RECORD r1, PDNS_RECORD r2 )
128 {
129     BOOL wide;
130     unsigned int i;
131
132     TRACE( "(%p,%p)\n", r1, r2 );
133
134     if (r1->wType       != r2->wType       ||
135         r1->wDataLength != r2->wDataLength ||
136         r1->Flags.DW    != r2->Flags.DW    ||
137         r1->dwReserved  != r2->dwReserved) return FALSE;
138
139     wide = r1->Flags.S.CharSet == DnsCharSetUnicode;
140     if (dns_strcmpX( r1->pName, r2->pName, wide )) return FALSE;
141
142     switch (r1->wType)
143     {
144     case DNS_TYPE_A:
145     {
146         if (r1->Data.A.IpAddress != r2->Data.A.IpAddress) return FALSE;
147         break;
148     }
149     case DNS_TYPE_SOA:
150     {
151         if (r1->Data.SOA.dwSerialNo   != r2->Data.SOA.dwSerialNo ||
152             r1->Data.SOA.dwRefresh    != r2->Data.SOA.dwRefresh  ||
153             r1->Data.SOA.dwRetry      != r2->Data.SOA.dwRetry    ||
154             r1->Data.SOA.dwExpire     != r2->Data.SOA.dwExpire   ||
155             r1->Data.SOA.dwDefaultTtl != r2->Data.SOA.dwDefaultTtl)
156             return FALSE;
157         if (dns_strcmpX( r1->Data.SOA.pNamePrimaryServer,
158                          r2->Data.SOA.pNamePrimaryServer, wide ) ||
159             dns_strcmpX( r1->Data.SOA.pNameAdministrator,
160                          r2->Data.SOA.pNameAdministrator, wide ))
161             return FALSE;
162         break;
163     }
164     case DNS_TYPE_PTR:
165     case DNS_TYPE_NS:
166     case DNS_TYPE_CNAME:
167     case DNS_TYPE_MB:
168     case DNS_TYPE_MD:
169     case DNS_TYPE_MF:
170     case DNS_TYPE_MG:
171     case DNS_TYPE_MR:
172     {
173         if (dns_strcmpX( r1->Data.PTR.pNameHost,
174                          r2->Data.PTR.pNameHost, wide )) return FALSE;
175         break;
176     }
177     case DNS_TYPE_MINFO:
178     case DNS_TYPE_RP:
179     {
180         if (dns_strcmpX( r1->Data.MINFO.pNameMailbox,
181                          r2->Data.MINFO.pNameMailbox, wide ) ||
182             dns_strcmpX( r1->Data.MINFO.pNameErrorsMailbox,
183                          r2->Data.MINFO.pNameErrorsMailbox, wide ))
184             return FALSE;
185         break;
186     }
187     case DNS_TYPE_MX:
188     case DNS_TYPE_AFSDB:
189     case DNS_TYPE_RT:
190     {
191         if (r1->Data.MX.wPreference != r2->Data.MX.wPreference)
192             return FALSE;
193         if (dns_strcmpX( r1->Data.MX.pNameExchange,
194                          r2->Data.MX.pNameExchange, wide ))
195             return FALSE;
196         break;
197     }
198     case DNS_TYPE_HINFO:
199     case DNS_TYPE_ISDN:
200     case DNS_TYPE_TEXT:
201     case DNS_TYPE_X25:
202     {
203         if (r1->Data.TXT.dwStringCount != r2->Data.TXT.dwStringCount)
204             return FALSE;
205         for (i = 0; i < r1->Data.TXT.dwStringCount; i++)
206         {
207             if (dns_strcmpX( r1->Data.TXT.pStringArray[i],
208                              r2->Data.TXT.pStringArray[i], wide ))
209                 return FALSE;
210         }
211         break;
212     }
213     case DNS_TYPE_NULL:
214     {
215         if (r1->Data.Null.dwByteCount != r2->Data.Null.dwByteCount)
216             return FALSE;
217         if (memcmp( r1->Data.Null.Data,
218                     r2->Data.Null.Data, r1->Data.Null.dwByteCount ))
219             return FALSE;
220         break;
221     }
222     case DNS_TYPE_AAAA:
223     {
224         for (i = 0; i < sizeof(IP6_ADDRESS)/sizeof(DWORD); i++)
225         {
226             if (r1->Data.AAAA.Ip6Address.IP6Dword[i] !=
227                 r2->Data.AAAA.Ip6Address.IP6Dword[i]) return FALSE;
228         }
229         break;
230     }
231     case DNS_TYPE_KEY:
232     {
233         if (r1->Data.KEY.wFlags      != r2->Data.KEY.wFlags      ||
234             r1->Data.KEY.chProtocol  != r2->Data.KEY.chProtocol  ||
235             r1->Data.KEY.chAlgorithm != r2->Data.KEY.chAlgorithm)
236             return FALSE;
237         if (memcmp( r1->Data.KEY.Key, r2->Data.KEY.Key,
238                     r1->wDataLength - sizeof(DNS_KEY_DATA) + 1 ))
239             return FALSE;
240         break;
241     }
242     case DNS_TYPE_SIG:
243     {
244         if (dns_strcmpX( r1->Data.SIG.pNameSigner,
245                          r2->Data.SIG.pNameSigner, wide ))
246             return FALSE;
247         if (r1->Data.SIG.wTypeCovered  != r2->Data.SIG.wTypeCovered  ||
248             r1->Data.SIG.chAlgorithm   != r2->Data.SIG.chAlgorithm   ||
249             r1->Data.SIG.chLabelCount  != r2->Data.SIG.chLabelCount  ||
250             r1->Data.SIG.dwOriginalTtl != r2->Data.SIG.dwOriginalTtl ||
251             r1->Data.SIG.dwExpiration  != r2->Data.SIG.dwExpiration  ||
252             r1->Data.SIG.dwTimeSigned  != r2->Data.SIG.dwTimeSigned  ||
253             r1->Data.SIG.wKeyTag       != r2->Data.SIG.wKeyTag)
254             return FALSE;
255         if (memcmp( r1->Data.SIG.Signature, r2->Data.SIG.Signature,
256                     r1->wDataLength - sizeof(DNS_SIG_DATAA) + 1 ))
257             return FALSE;
258         break;
259     }
260     case DNS_TYPE_ATMA:
261     {
262         if (r1->Data.ATMA.AddressType != r2->Data.ATMA.AddressType)
263             return FALSE;
264         for (i = 0; i < DNS_ATMA_MAX_ADDR_LENGTH; i++)
265         {
266             if (r1->Data.ATMA.Address[i] != r2->Data.ATMA.Address[i])
267                 return FALSE;
268         }
269         break;
270     }
271     case DNS_TYPE_NXT:
272     {
273         if (dns_strcmpX( r1->Data.NXT.pNameNext,
274                          r2->Data.NXT.pNameNext, wide )) return FALSE;
275         if (r1->Data.NXT.wNumTypes != r2->Data.NXT.wNumTypes) return FALSE;
276         if (memcmp( r1->Data.NXT.wTypes, r2->Data.NXT.wTypes,
277                     r1->wDataLength - sizeof(DNS_NXT_DATAA) + sizeof(WORD) ))
278             return FALSE;
279         break;
280     }
281     case DNS_TYPE_SRV:
282     {
283         if (dns_strcmpX( r1->Data.SRV.pNameTarget,
284                          r2->Data.SRV.pNameTarget, wide )) return FALSE;
285         if (r1->Data.SRV.wPriority != r2->Data.SRV.wPriority ||
286             r1->Data.SRV.wWeight   != r2->Data.SRV.wWeight   ||
287             r1->Data.SRV.wPort     != r2->Data.SRV.wPort)
288             return FALSE;
289         break;
290     }
291     case DNS_TYPE_TKEY:
292     {
293         if (dns_strcmpX( r1->Data.TKEY.pNameAlgorithm,
294                          r2->Data.TKEY.pNameAlgorithm, wide ))
295             return FALSE;
296         if (r1->Data.TKEY.dwCreateTime    != r2->Data.TKEY.dwCreateTime     ||
297             r1->Data.TKEY.dwExpireTime    != r2->Data.TKEY.dwExpireTime     ||
298             r1->Data.TKEY.wMode           != r2->Data.TKEY.wMode            ||
299             r1->Data.TKEY.wError          != r2->Data.TKEY.wError           ||
300             r1->Data.TKEY.wKeyLength      != r2->Data.TKEY.wKeyLength       ||
301             r1->Data.TKEY.wOtherLength    != r2->Data.TKEY.wOtherLength     ||
302             r1->Data.TKEY.cAlgNameLength  != r2->Data.TKEY.cAlgNameLength   ||
303             r1->Data.TKEY.bPacketPointers != r2->Data.TKEY.bPacketPointers)
304             return FALSE;
305
306         /* FIXME: ignoring pAlgorithmPacket field */
307         if (memcmp( r1->Data.TKEY.pKey, r2->Data.TKEY.pKey,
308                     r1->Data.TKEY.wKeyLength ) ||
309             memcmp( r1->Data.TKEY.pOtherData, r2->Data.TKEY.pOtherData,
310                     r1->Data.TKEY.wOtherLength )) return FALSE;
311         break;
312     }
313     case DNS_TYPE_TSIG:
314     {
315         if (dns_strcmpX( r1->Data.TSIG.pNameAlgorithm,
316                          r2->Data.TSIG.pNameAlgorithm, wide ))
317             return FALSE;
318         if (r1->Data.TSIG.i64CreateTime   != r2->Data.TSIG.i64CreateTime    ||
319             r1->Data.TSIG.wFudgeTime      != r2->Data.TSIG.wFudgeTime       ||
320             r1->Data.TSIG.wOriginalXid    != r2->Data.TSIG.wOriginalXid     ||
321             r1->Data.TSIG.wError          != r2->Data.TSIG.wError           ||
322             r1->Data.TSIG.wSigLength      != r2->Data.TSIG.wSigLength       ||
323             r1->Data.TSIG.wOtherLength    != r2->Data.TSIG.wOtherLength     ||
324             r1->Data.TSIG.cAlgNameLength  != r2->Data.TSIG.cAlgNameLength   ||
325             r1->Data.TSIG.bPacketPointers != r2->Data.TSIG.bPacketPointers)
326             return FALSE;
327
328         /* FIXME: ignoring pAlgorithmPacket field */
329         if (memcmp( r1->Data.TSIG.pSignature, r2->Data.TSIG.pSignature,
330                     r1->Data.TSIG.wSigLength ) ||
331             memcmp( r1->Data.TSIG.pOtherData, r2->Data.TSIG.pOtherData,
332                     r1->Data.TSIG.wOtherLength )) return FALSE;
333         break;
334     }
335     case DNS_TYPE_WINS:
336     {
337         if (r1->Data.WINS.dwMappingFlag    != r2->Data.WINS.dwMappingFlag   ||
338             r1->Data.WINS.dwLookupTimeout  != r2->Data.WINS.dwLookupTimeout ||
339             r1->Data.WINS.dwCacheTimeout   != r2->Data.WINS.dwCacheTimeout  ||
340             r1->Data.WINS.cWinsServerCount != r2->Data.WINS.cWinsServerCount)
341             return FALSE;
342         if (memcmp( r1->Data.WINS.WinsServers, r2->Data.WINS.WinsServers,
343                     r1->wDataLength - sizeof(DNS_WINS_DATA) + sizeof(IP4_ADDRESS) ))
344             return FALSE;
345         break;
346     }
347     case DNS_TYPE_WINSR:
348     {
349         if (r1->Data.WINSR.dwMappingFlag   != r2->Data.WINSR.dwMappingFlag   ||
350             r1->Data.WINSR.dwLookupTimeout != r2->Data.WINSR.dwLookupTimeout ||
351             r1->Data.WINSR.dwCacheTimeout  != r2->Data.WINSR.dwCacheTimeout)
352             return FALSE;
353         if (dns_strcmpX( r1->Data.WINSR.pNameResultDomain,
354                          r2->Data.WINSR.pNameResultDomain, wide ))
355             return FALSE;
356         break;
357     }
358     default:
359         FIXME( "unknown type: %s\n", dns_type_to_str( r1->wType ) );
360         return FALSE;
361     }
362     return TRUE;
363 }
364
365 static LPVOID dns_strcpyX( LPCVOID src, DNS_CHARSET in, DNS_CHARSET out )
366 {
367     switch (in)
368     {
369     case DnsCharSetUnicode:
370     {
371         switch (out)
372         {
373         case DnsCharSetUnicode: return dns_strdup_w( src );
374         case DnsCharSetUtf8:    return dns_strdup_wu( src );
375         case DnsCharSetAnsi:    return dns_strdup_wa( src );
376         default:
377             WARN( "unhandled target charset: %d\n", out );
378             break;
379         }
380         break;
381     }
382     case DnsCharSetUtf8:
383         switch (out)
384         {
385         case DnsCharSetUnicode: return dns_strdup_uw( src );
386         case DnsCharSetUtf8:    return dns_strdup_u( src );
387         case DnsCharSetAnsi:    return dns_strdup_ua( src );
388         default:
389             WARN( "unhandled target charset: %d\n", out );
390             break;
391         }
392         break;
393     case DnsCharSetAnsi:
394         switch (out)
395         {
396         case DnsCharSetUnicode: return dns_strdup_aw( src );
397         case DnsCharSetUtf8:    return dns_strdup_au( src );
398         case DnsCharSetAnsi:    return dns_strdup_a( src );
399         default:
400             WARN( "unhandled target charset: %d\n", out );
401             break;
402         }
403         break;
404     default:
405         WARN( "unhandled source charset: %d\n", in );
406         break;
407     }
408     return NULL;
409 }
410
411 /******************************************************************************
412  * DnsRecordCopyEx                         [DNSAPI.@]
413  *
414  */
415 PDNS_RECORD WINAPI DnsRecordCopyEx( PDNS_RECORD src, DNS_CHARSET in, DNS_CHARSET out )
416 {
417     DNS_RECORD *dst;
418     unsigned int i, size;
419
420     TRACE( "(%p,%d,%d)\n", src, in, out );
421
422     size = FIELD_OFFSET(DNS_RECORD, Data) + src->wDataLength;
423     dst = heap_alloc_zero( size );
424     if (!dst) return NULL;
425
426     memcpy( dst, src, size );
427
428     if (src->Flags.S.CharSet == DnsCharSetUtf8 ||
429         src->Flags.S.CharSet == DnsCharSetAnsi ||
430         src->Flags.S.CharSet == DnsCharSetUnicode) in = src->Flags.S.CharSet;
431
432     dst->Flags.S.CharSet = out;
433     dst->pName = dns_strcpyX( src->pName, in, out );
434     if (!dst->pName) goto error;
435
436     switch (src->wType)
437     {
438     case DNS_TYPE_HINFO:
439     case DNS_TYPE_ISDN:
440     case DNS_TYPE_TEXT:
441     case DNS_TYPE_X25:
442     {
443         for (i = 0; i < src->Data.TXT.dwStringCount; i++)
444         {
445             dst->Data.TXT.pStringArray[i] =
446                 dns_strcpyX( src->Data.TXT.pStringArray[i], in, out );
447
448             if (!dst->Data.TXT.pStringArray[i])
449             {
450                 while (i > 0) heap_free( dst->Data.TXT.pStringArray[--i] );
451                 goto error;
452             }
453         }
454         break;
455     }
456     case DNS_TYPE_MINFO:
457     case DNS_TYPE_RP:
458     {
459         dst->Data.MINFO.pNameMailbox =
460             dns_strcpyX( src->Data.MINFO.pNameMailbox, in, out );
461         if (!dst->Data.MINFO.pNameMailbox) goto error;
462
463         dst->Data.MINFO.pNameErrorsMailbox =
464             dns_strcpyX( src->Data.MINFO.pNameErrorsMailbox, in, out );
465         if (!dst->Data.MINFO.pNameErrorsMailbox)
466         {
467             heap_free( dst->Data.MINFO.pNameMailbox );
468             goto error;
469         }
470         break;
471     }
472     case DNS_TYPE_AFSDB:
473     case DNS_TYPE_RT:
474     case DNS_TYPE_MX:
475     {
476         dst->Data.MX.pNameExchange =
477             dns_strcpyX( src->Data.MX.pNameExchange, in, out );
478         if (!dst->Data.MX.pNameExchange) goto error;
479         break;
480     }
481     case DNS_TYPE_NXT:
482     {
483         dst->Data.NXT.pNameNext =
484             dns_strcpyX( src->Data.NXT.pNameNext, in, out );
485         if (!dst->Data.NXT.pNameNext) goto error;
486         break;
487     }
488     case DNS_TYPE_CNAME:
489     case DNS_TYPE_MB:
490     case DNS_TYPE_MD:
491     case DNS_TYPE_MF:
492     case DNS_TYPE_MG:
493     case DNS_TYPE_MR:
494     case DNS_TYPE_NS:
495     case DNS_TYPE_PTR:
496     {
497         dst->Data.PTR.pNameHost =
498             dns_strcpyX( src->Data.PTR.pNameHost, in, out );
499         if (!dst->Data.PTR.pNameHost) goto error;
500         break;
501     }
502     case DNS_TYPE_SIG:
503     {
504         dst->Data.SIG.pNameSigner =
505             dns_strcpyX( src->Data.SIG.pNameSigner, in, out );
506         if (!dst->Data.SIG.pNameSigner) goto error;
507         break;
508     }
509     case DNS_TYPE_SOA:
510     {
511         dst->Data.SOA.pNamePrimaryServer =
512             dns_strcpyX( src->Data.SOA.pNamePrimaryServer, in, out );
513         if (!dst->Data.SOA.pNamePrimaryServer) goto error;
514
515         dst->Data.SOA.pNameAdministrator =
516             dns_strcpyX( src->Data.SOA.pNameAdministrator, in, out );
517         if (!dst->Data.SOA.pNameAdministrator)
518         {
519             heap_free( dst->Data.SOA.pNamePrimaryServer );
520             goto error;
521         }
522         break;
523     }
524     case DNS_TYPE_SRV:
525     {
526         dst->Data.SRV.pNameTarget =
527             dns_strcpyX( src->Data.SRV.pNameTarget, in, out );
528         if (!dst->Data.SRV.pNameTarget) goto error;
529         break;
530     }
531     default:
532         break;
533     }
534     return dst;
535
536 error:
537     heap_free( dst->pName );
538     heap_free( dst );
539     return NULL;
540 }
541
542 /******************************************************************************
543  * DnsRecordListFree                       [DNSAPI.@]
544  *
545  */
546 VOID WINAPI DnsRecordListFree( PDNS_RECORD list, DNS_FREE_TYPE type )
547 {
548     DNS_RECORD *r, *next;
549     unsigned int i;
550
551     TRACE( "(%p,%d)\n", list, type );
552
553     if (!list) return;
554
555     switch (type)
556     {
557     case DnsFreeRecordList:
558     {
559         for (r = list; (list = r); r = next)
560         {
561             heap_free( r->pName );
562
563             switch (r->wType)
564             {
565             case DNS_TYPE_HINFO:
566             case DNS_TYPE_ISDN:
567             case DNS_TYPE_TEXT:
568             case DNS_TYPE_X25:
569             {
570                 for (i = 0; i < r->Data.TXT.dwStringCount; i++)
571                     heap_free( r->Data.TXT.pStringArray[i] );
572
573                 break;
574             }
575             case DNS_TYPE_MINFO:
576             case DNS_TYPE_RP:
577             {
578                 heap_free( r->Data.MINFO.pNameMailbox );
579                 heap_free( r->Data.MINFO.pNameErrorsMailbox );
580                 break;
581             }
582             case DNS_TYPE_AFSDB:
583             case DNS_TYPE_RT:
584             case DNS_TYPE_MX:
585             {
586                 heap_free( r->Data.MX.pNameExchange );
587                 break;
588             }
589             case DNS_TYPE_NXT:
590             {
591                 heap_free( r->Data.NXT.pNameNext );
592                 break;
593             }
594             case DNS_TYPE_CNAME:
595             case DNS_TYPE_MB:
596             case DNS_TYPE_MD:
597             case DNS_TYPE_MF:
598             case DNS_TYPE_MG:
599             case DNS_TYPE_MR:
600             case DNS_TYPE_NS:
601             case DNS_TYPE_PTR:
602             {
603                 heap_free( r->Data.PTR.pNameHost );
604                 break;
605             }
606             case DNS_TYPE_SIG:
607             {
608                 heap_free( r->Data.SIG.pNameSigner );
609                 break;
610             }
611             case DNS_TYPE_SOA:
612             {
613                 heap_free( r->Data.SOA.pNamePrimaryServer );
614                 heap_free( r->Data.SOA.pNameAdministrator );
615                 break;
616             }
617             case DNS_TYPE_SRV:
618             {
619                 heap_free( r->Data.SRV.pNameTarget );
620                 break;
621             }
622             default:
623                 break;
624             }
625
626             next = r->pNext;
627             heap_free( r );
628         }
629         break;
630     }
631     case DnsFreeFlat:
632     case DnsFreeParsedMessageFields:
633     {
634         FIXME( "unhandled free type: %d\n", type );
635         break;
636     }
637     default:
638         WARN( "unknown free type: %d\n", type );
639         break;
640     }
641 }
642
643 /******************************************************************************
644  * DnsFree                     [DNSAPI.@]
645  *
646  */
647 void WINAPI DnsFree( PVOID data, DNS_FREE_TYPE type )
648 {
649     DnsRecordListFree( data, type );
650 }
651
652 /******************************************************************************
653  * DnsRecordSetCompare                     [DNSAPI.@]
654  *
655  */
656 BOOL WINAPI DnsRecordSetCompare( PDNS_RECORD set1, PDNS_RECORD set2,
657                                  PDNS_RECORD *diff1, PDNS_RECORD *diff2 )
658 {
659     BOOL ret = TRUE;
660     DNS_RECORD *r, *t, *u;
661     DNS_RRSET rr1, rr2;
662
663     TRACE( "(%p,%p,%p,%p)\n", set1, set2, diff1, diff2 );
664
665     if (!set1 && !set2) return FALSE;
666
667     if (diff1) *diff1 = NULL;
668     if (diff2) *diff2 = NULL;
669
670     if (set1 && !set2)
671     {
672         if (diff1) *diff1 = DnsRecordSetCopyEx( set1, 0, set1->Flags.S.CharSet );
673         return FALSE;
674     }
675     if (!set1 && set2)
676     {
677         if (diff2) *diff2 = DnsRecordSetCopyEx( set2, 0, set2->Flags.S.CharSet );
678         return FALSE;
679     }
680
681     DNS_RRSET_INIT( rr1 );
682     DNS_RRSET_INIT( rr2 );
683
684     for (r = set1; r; r = r->pNext)
685     {
686         for (t = set2; t; t = t->pNext)
687         {
688             u = DnsRecordCopyEx( r, r->Flags.S.CharSet, t->Flags.S.CharSet );
689             if (!u) goto error;
690
691             if (!DnsRecordCompare( t, u ))
692             {
693                 DNS_RRSET_ADD( rr1, u );
694                 ret = FALSE;
695             }
696             else DnsRecordListFree( u, DnsFreeRecordList );
697         }
698     }
699
700     for (t = set2; t; t = t->pNext)
701     {
702         for (r = set1; r; r = r->pNext)
703         {
704             u = DnsRecordCopyEx( t, t->Flags.S.CharSet, r->Flags.S.CharSet );
705             if (!u) goto error;
706
707             if (!DnsRecordCompare( r, u ))
708             {
709                 DNS_RRSET_ADD( rr2, u );
710                 ret = FALSE;
711             }
712             else DnsRecordListFree( u, DnsFreeRecordList );
713         }
714     }
715
716     DNS_RRSET_TERMINATE( rr1 );
717     DNS_RRSET_TERMINATE( rr2 );
718     
719     if (diff1) *diff1 = rr1.pFirstRR;
720     else DnsRecordListFree( rr1.pFirstRR, DnsFreeRecordList );
721
722     if (diff2) *diff2 = rr2.pFirstRR;
723     else DnsRecordListFree( rr2.pFirstRR, DnsFreeRecordList );
724
725     return ret;
726
727 error:
728     DNS_RRSET_TERMINATE( rr1 );
729     DNS_RRSET_TERMINATE( rr2 );
730
731     DnsRecordListFree( rr1.pFirstRR, DnsFreeRecordList );
732     DnsRecordListFree( rr2.pFirstRR, DnsFreeRecordList );
733     
734     return FALSE;
735 }
736
737 /******************************************************************************
738  * DnsRecordSetCopyEx                      [DNSAPI.@]
739  *
740  */
741 PDNS_RECORD WINAPI DnsRecordSetCopyEx( PDNS_RECORD src_set, DNS_CHARSET in, DNS_CHARSET out )
742 {
743     DNS_RRSET dst_set;
744     DNS_RECORD *src, *dst;
745
746     TRACE( "(%p,%d,%d)\n", src_set, in, out );
747
748     DNS_RRSET_INIT( dst_set );
749
750     for (src = src_set; (src_set = src); src = src_set->pNext)
751     {
752         dst = DnsRecordCopyEx( src, in, out );
753         if (!dst)
754         {
755             DNS_RRSET_TERMINATE( dst_set );
756             DnsRecordListFree( dst_set.pFirstRR, DnsFreeRecordList );
757             return NULL;
758         }
759         DNS_RRSET_ADD( dst_set, dst );
760     }
761
762     DNS_RRSET_TERMINATE( dst_set );
763     return dst_set.pFirstRR;
764 }
765
766 /******************************************************************************
767  * DnsRecordSetDetach                      [DNSAPI.@]
768  *
769  */
770 PDNS_RECORD WINAPI DnsRecordSetDetach( PDNS_RECORD set )
771 {
772     DNS_RECORD *r, *s;
773
774     TRACE( "(%p)\n", set );
775
776     for (r = set; (set = r); r = set->pNext)
777     {
778         if (r->pNext && !r->pNext->pNext)
779         {
780             s = r->pNext;
781             r->pNext = NULL;
782             return s;
783         }
784     }
785     return NULL;
786 }