|  | /* | 
|  | * DNS support | 
|  | * | 
|  | * Copyright (C) 2006 Matthew Kehrer | 
|  | * Copyright (C) 2006 Hans Leidekker | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
|  | */ | 
|  |  | 
|  | #include "config.h" | 
|  | #include "wine/debug.h" | 
|  | #include "wine/unicode.h" | 
|  |  | 
|  | #include <stdarg.h> | 
|  | #include <sys/types.h> | 
|  |  | 
|  | #ifdef HAVE_NETINET_IN_H | 
|  | # include <netinet/in.h> | 
|  | #endif | 
|  | #ifdef HAVE_ARPA_NAMESER_H | 
|  | # include <arpa/nameser.h> | 
|  | # undef NOERROR | 
|  | #endif | 
|  | #ifdef HAVE_RESOLV_H | 
|  | # include <resolv.h> | 
|  | #endif | 
|  |  | 
|  | #include "windef.h" | 
|  | #include "winbase.h" | 
|  | #include "winerror.h" | 
|  | #include "winnls.h" | 
|  | #include "windns.h" | 
|  |  | 
|  | #include "dnsapi.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(dnsapi); | 
|  |  | 
|  | /****************************************************************************** | 
|  | * DnsNameCompare_A               [DNSAPI.@] | 
|  | * | 
|  | */ | 
|  | BOOL WINAPI DnsNameCompare_A( PCSTR name1, PCSTR name2 ) | 
|  | { | 
|  | BOOL ret; | 
|  | PWSTR name1W, name2W; | 
|  |  | 
|  | TRACE( "(%s,%s)\n", debugstr_a(name1), debugstr_a(name2) ); | 
|  |  | 
|  | name1W = dns_strdup_aw( name1 ); | 
|  | name2W = dns_strdup_aw( name2 ); | 
|  |  | 
|  | ret = DnsNameCompare_W( name1W, name2W ); | 
|  |  | 
|  | heap_free( name1W ); | 
|  | heap_free( name2W ); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | * DnsNameCompare_W               [DNSAPI.@] | 
|  | * | 
|  | */ | 
|  | BOOL WINAPI DnsNameCompare_W( PCWSTR name1, PCWSTR name2 ) | 
|  | { | 
|  | PCWSTR p, q; | 
|  |  | 
|  | TRACE( "(%s,%s)\n", debugstr_w(name1), debugstr_w(name2) ); | 
|  |  | 
|  | if (!name1 && !name2) return TRUE; | 
|  | if (!name1 || !name2) return FALSE; | 
|  |  | 
|  | p = name1 + lstrlenW( name1 ) - 1; | 
|  | q = name2 + lstrlenW( name2 ) - 1; | 
|  |  | 
|  | while (*p == '.' && p >= name1) p--; | 
|  | while (*q == '.' && q >= name2) q--; | 
|  |  | 
|  | if (p - name1 != q - name2) return FALSE; | 
|  |  | 
|  | while (name1 <= p) | 
|  | { | 
|  | if (toupperW( *name1 ) != toupperW( *name2 )) | 
|  | return FALSE; | 
|  |  | 
|  | name1++; | 
|  | name2++; | 
|  | } | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | * DnsValidateName_A              [DNSAPI.@] | 
|  | * | 
|  | */ | 
|  | DNS_STATUS WINAPI DnsValidateName_A( PCSTR name, DNS_NAME_FORMAT format ) | 
|  | { | 
|  | PWSTR nameW; | 
|  | DNS_STATUS ret; | 
|  |  | 
|  | TRACE( "(%s, %d)\n", debugstr_a(name), format ); | 
|  |  | 
|  | nameW = dns_strdup_aw( name ); | 
|  | ret = DnsValidateName_W( nameW, format ); | 
|  |  | 
|  | heap_free( nameW ); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | * DnsValidateName_UTF8           [DNSAPI.@] | 
|  | * | 
|  | */ | 
|  | DNS_STATUS WINAPI DnsValidateName_UTF8( PCSTR name, DNS_NAME_FORMAT format ) | 
|  | { | 
|  | PWSTR nameW; | 
|  | DNS_STATUS ret; | 
|  |  | 
|  | TRACE( "(%s, %d)\n", debugstr_a(name), format ); | 
|  |  | 
|  | nameW = dns_strdup_uw( name ); | 
|  | ret = DnsValidateName_W( nameW, format ); | 
|  |  | 
|  | heap_free( nameW ); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | #define HAS_EXTENDED        0x0001 | 
|  | #define HAS_NUMERIC         0x0002 | 
|  | #define HAS_NON_NUMERIC     0x0004 | 
|  | #define HAS_DOT             0x0008 | 
|  | #define HAS_DOT_DOT         0x0010 | 
|  | #define HAS_SPACE           0x0020 | 
|  | #define HAS_INVALID         0x0040 | 
|  | #define HAS_ASTERISK        0x0080 | 
|  | #define HAS_UNDERSCORE      0x0100 | 
|  | #define HAS_LONG_LABEL      0x0200 | 
|  |  | 
|  | /****************************************************************************** | 
|  | * DnsValidateName_W              [DNSAPI.@] | 
|  | * | 
|  | */ | 
|  | DNS_STATUS WINAPI DnsValidateName_W( PCWSTR name, DNS_NAME_FORMAT format ) | 
|  | { | 
|  | PCWSTR p; | 
|  | unsigned int i, j, state = 0; | 
|  | static const WCHAR invalid[] = { | 
|  | '{','|','}','~','[','\\',']','^','\'',':',';','<','=','>', | 
|  | '?','@','!','\"','#','$','%','^','`','(',')','+','/',',',0 }; | 
|  |  | 
|  | TRACE( "(%s, %d)\n", debugstr_w(name), format ); | 
|  |  | 
|  | if (!name) return ERROR_INVALID_NAME; | 
|  |  | 
|  | for (p = name, i = 0, j = 0; *p; p++, i++, j++) | 
|  | { | 
|  | if (*p == '.') | 
|  | { | 
|  | j = 0; | 
|  | state |= HAS_DOT; | 
|  | if (p[1] == '.') state |= HAS_DOT_DOT; | 
|  | } | 
|  | else if (*p < '0' || *p > '9') state |= HAS_NON_NUMERIC; | 
|  | else state |= HAS_NUMERIC; | 
|  |  | 
|  | if (j > 62) state |= HAS_LONG_LABEL; | 
|  |  | 
|  | if (strchrW( invalid, *p )) state |= HAS_INVALID; | 
|  | else if ((unsigned)*p > 127) state |= HAS_EXTENDED; | 
|  | else if (*p == ' ') state |= HAS_SPACE; | 
|  | else if (*p == '_') state |= HAS_UNDERSCORE; | 
|  | else if (*p == '*') state |= HAS_ASTERISK; | 
|  | } | 
|  |  | 
|  | if (i == 0 || i > 255 || | 
|  | (state & HAS_LONG_LABEL) || | 
|  | (state & HAS_DOT_DOT) || | 
|  | (name[0] == '.' && name[1])) return ERROR_INVALID_NAME; | 
|  |  | 
|  | switch (format) | 
|  | { | 
|  | case DnsNameDomain: | 
|  | { | 
|  | if (!(state & HAS_NON_NUMERIC) && (state & HAS_NUMERIC)) | 
|  | return DNS_ERROR_NUMERIC_NAME; | 
|  | if ((state & HAS_EXTENDED) || (state & HAS_UNDERSCORE)) | 
|  | return DNS_ERROR_NON_RFC_NAME; | 
|  | if ((state & HAS_SPACE) || | 
|  | (state & HAS_INVALID) || | 
|  | (state & HAS_ASTERISK)) return DNS_ERROR_INVALID_NAME_CHAR; | 
|  | break; | 
|  | } | 
|  | case DnsNameDomainLabel: | 
|  | { | 
|  | if (state & HAS_DOT) return ERROR_INVALID_NAME; | 
|  | if ((state & HAS_EXTENDED) || (state & HAS_UNDERSCORE)) | 
|  | return DNS_ERROR_NON_RFC_NAME; | 
|  | if ((state & HAS_SPACE) || | 
|  | (state & HAS_INVALID) || | 
|  | (state & HAS_ASTERISK)) return DNS_ERROR_INVALID_NAME_CHAR; | 
|  | break; | 
|  | } | 
|  | case DnsNameHostnameFull: | 
|  | { | 
|  | if (!(state & HAS_NON_NUMERIC) && (state & HAS_NUMERIC)) | 
|  | return DNS_ERROR_NUMERIC_NAME; | 
|  | if ((state & HAS_EXTENDED) || (state & HAS_UNDERSCORE)) | 
|  | return DNS_ERROR_NON_RFC_NAME; | 
|  | if ((state & HAS_SPACE) || | 
|  | (state & HAS_INVALID) || | 
|  | (state & HAS_ASTERISK)) return DNS_ERROR_INVALID_NAME_CHAR; | 
|  | break; | 
|  | } | 
|  | case DnsNameHostnameLabel: | 
|  | { | 
|  | if (state & HAS_DOT) return ERROR_INVALID_NAME; | 
|  | if (!(state & HAS_NON_NUMERIC) && (state & HAS_NUMERIC)) | 
|  | return DNS_ERROR_NUMERIC_NAME; | 
|  | if ((state & HAS_EXTENDED) || (state & HAS_UNDERSCORE)) | 
|  | return DNS_ERROR_NON_RFC_NAME; | 
|  | if ((state & HAS_SPACE) || | 
|  | (state & HAS_INVALID) || | 
|  | (state & HAS_ASTERISK)) return DNS_ERROR_INVALID_NAME_CHAR; | 
|  | break; | 
|  | } | 
|  | case DnsNameWildcard: | 
|  | { | 
|  | if (!(state & HAS_NON_NUMERIC) && (state & HAS_NUMERIC)) | 
|  | return ERROR_INVALID_NAME; | 
|  | if (name[0] != '*') return ERROR_INVALID_NAME; | 
|  | if (name[1] && name[1] != '.') | 
|  | return DNS_ERROR_INVALID_NAME_CHAR; | 
|  | if ((state & HAS_EXTENDED) || | 
|  | (state & HAS_SPACE) || | 
|  | (state & HAS_INVALID)) return ERROR_INVALID_NAME; | 
|  | break; | 
|  | } | 
|  | case DnsNameSrvRecord: | 
|  | { | 
|  | if (!(state & HAS_NON_NUMERIC) && (state & HAS_NUMERIC)) | 
|  | return ERROR_INVALID_NAME; | 
|  | if (name[0] != '_') return ERROR_INVALID_NAME; | 
|  | if ((state & HAS_UNDERSCORE) && !name[1]) | 
|  | return DNS_ERROR_NON_RFC_NAME; | 
|  | if ((state & HAS_EXTENDED) || | 
|  | (state & HAS_SPACE) || | 
|  | (state & HAS_INVALID)) return ERROR_INVALID_NAME; | 
|  | break; | 
|  | } | 
|  | default: | 
|  | WARN( "unknown format: %d\n", format ); | 
|  | break; | 
|  | } | 
|  | return ERROR_SUCCESS; | 
|  | } |