| /* |
| * 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> |
| #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( LPSTR name1, LPSTR name2 ) |
| { |
| BOOL ret; |
| LPWSTR 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 ); |
| |
| dns_free( name1W ); |
| dns_free( name2W ); |
| |
| return ret; |
| } |
| |
| /****************************************************************************** |
| * DnsNameCompare_W [DNSAPI.@] |
| * |
| */ |
| BOOL WINAPI DnsNameCompare_W( LPWSTR name1, LPWSTR name2 ) |
| { |
| WCHAR *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( LPCSTR name, DNS_NAME_FORMAT format ) |
| { |
| LPWSTR nameW; |
| DNS_STATUS ret; |
| |
| TRACE( "(%s, %d)\n", debugstr_a(name), format ); |
| |
| nameW = dns_strdup_aw( name ); |
| ret = DnsValidateName_W( nameW, format ); |
| |
| dns_free( nameW ); |
| return ret; |
| } |
| |
| /****************************************************************************** |
| * DnsValidateName_UTF8 [DNSAPI.@] |
| * |
| */ |
| DNS_STATUS WINAPI DnsValidateName_UTF8( LPCSTR name, DNS_NAME_FORMAT format ) |
| { |
| LPWSTR nameW; |
| DNS_STATUS ret; |
| |
| TRACE( "(%s, %d)\n", debugstr_a(name), format ); |
| |
| nameW = dns_strdup_uw( name ); |
| ret = DnsValidateName_W( nameW, format ); |
| |
| dns_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( LPCWSTR name, DNS_NAME_FORMAT format ) |
| { |
| const WCHAR *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; |
| } |