/* * 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; }