1 /* 2 * DNS support 3 * 4 * Copyright (C) 2006 Matthew Kehrer 5 * Copyright (C) 2006 Hans Leidekker 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 */ 21 22 #include "precomp.h" 23 24 #define NDEBUG 25 #include <debug.h> 26 27 /****************************************************************************** 28 * DnsNameCompare_A [DNSAPI.@] 29 * 30 */ 31 BOOL WINAPI DnsNameCompare_A( LPCSTR name1, LPCSTR name2 ) 32 { 33 BOOL ret; 34 PWSTR name1W, name2W; 35 36 name1W = dns_strdup_aw( name1 ); 37 name2W = dns_strdup_aw( name2 ); 38 39 ret = DnsNameCompare_W( name1W, name2W ); 40 41 HeapFree(GetProcessHeap(), 0, name1W ); 42 HeapFree(GetProcessHeap(), 0, name2W ); 43 44 return ret; 45 } 46 47 /****************************************************************************** 48 * DnsNameCompare_W [DNSAPI.@] 49 * 50 */ 51 BOOL WINAPI DnsNameCompare_W( PCWSTR name1, PCWSTR name2 ) 52 { 53 PCWSTR p, q; 54 55 if (!name1 && !name2) return TRUE; 56 if (!name1 || !name2) return FALSE; 57 58 p = name1 + lstrlenW( name1 ) - 1; 59 q = name2 + lstrlenW( name2 ) - 1; 60 61 while (*p == '.' && p >= name1) p--; 62 while (*q == '.' && q >= name2) q--; 63 64 if (p - name1 != q - name2) return FALSE; 65 66 while (name1 <= p) 67 { 68 if (towupper( *name1 ) != towupper( *name2 )) 69 return FALSE; 70 71 name1++; 72 name2++; 73 } 74 return TRUE; 75 } 76 77 /****************************************************************************** 78 * DnsValidateName_A [DNSAPI.@] 79 * 80 */ 81 DNS_STATUS WINAPI DnsValidateName_A( PCSTR name, DNS_NAME_FORMAT format ) 82 { 83 PWSTR nameW; 84 DNS_STATUS ret; 85 86 nameW = dns_strdup_aw( name ); 87 ret = DnsValidateName_W( nameW, format ); 88 89 HeapFree(GetProcessHeap(), 0, nameW ); 90 return ret; 91 } 92 93 /****************************************************************************** 94 * DnsValidateName_UTF8 [DNSAPI.@] 95 * 96 */ 97 DNS_STATUS WINAPI DnsValidateName_UTF8( PCSTR name, DNS_NAME_FORMAT format ) 98 { 99 PWSTR nameW; 100 DNS_STATUS ret; 101 102 nameW = dns_strdup_uw( name ); 103 ret = DnsValidateName_W( nameW, format ); 104 105 HeapFree(GetProcessHeap(), 0, nameW ); 106 return ret; 107 } 108 109 #define HAS_EXTENDED 0x0001 110 #define HAS_NUMERIC 0x0002 111 #define HAS_NON_NUMERIC 0x0004 112 #define HAS_DOT 0x0008 113 #define HAS_DOT_DOT 0x0010 114 #define HAS_SPACE 0x0020 115 #define HAS_INVALID 0x0040 116 #define HAS_ASTERISK 0x0080 117 #define HAS_UNDERSCORE 0x0100 118 #define HAS_LONG_LABEL 0x0200 119 120 /****************************************************************************** 121 * DnsValidateName_W [DNSAPI.@] 122 * 123 */ 124 DNS_STATUS WINAPI DnsValidateName_W( PCWSTR name, DNS_NAME_FORMAT format ) 125 { 126 PCWSTR p; 127 unsigned int i, j, state = 0; 128 static const WCHAR invalid[] = { 129 '{','|','}','~','[','\\',']','^','\'',':',';','<','=','>', 130 '?','@','!','\"','#','$','%','^','`','(',')','+','/',',',0 }; 131 132 if (!name) return ERROR_INVALID_NAME; 133 134 for (p = name, i = 0, j = 0; *p; p++, i++, j++) 135 { 136 if (*p == '.') 137 { 138 j = 0; 139 state |= HAS_DOT; 140 if (p[1] == '.') state |= HAS_DOT_DOT; 141 } 142 else if (*p < '0' || *p > '9') state |= HAS_NON_NUMERIC; 143 else state |= HAS_NUMERIC; 144 145 if (j > 62) state |= HAS_LONG_LABEL; 146 147 if (wcschr( invalid, *p )) state |= HAS_INVALID; 148 else if ((unsigned)*p > 127) state |= HAS_EXTENDED; 149 else if (*p == ' ') state |= HAS_SPACE; 150 else if (*p == '_') state |= HAS_UNDERSCORE; 151 else if (*p == '*') state |= HAS_ASTERISK; 152 } 153 154 if (i == 0 || i > 255 || 155 (state & HAS_LONG_LABEL) || 156 (state & HAS_DOT_DOT) || 157 (name[0] == '.' && name[1])) return ERROR_INVALID_NAME; 158 159 switch (format) 160 { 161 case DnsNameDomain: 162 { 163 if (!(state & HAS_NON_NUMERIC) && (state & HAS_NUMERIC)) 164 return DNS_ERROR_NUMERIC_NAME; 165 if ((state & HAS_EXTENDED) || (state & HAS_UNDERSCORE)) 166 return DNS_ERROR_NON_RFC_NAME; 167 if ((state & HAS_SPACE) || 168 (state & HAS_INVALID) || 169 (state & HAS_ASTERISK)) return DNS_ERROR_INVALID_NAME_CHAR; 170 break; 171 } 172 case DnsNameDomainLabel: 173 { 174 if (state & HAS_DOT) return ERROR_INVALID_NAME; 175 if ((state & HAS_EXTENDED) || (state & HAS_UNDERSCORE)) 176 return DNS_ERROR_NON_RFC_NAME; 177 if ((state & HAS_SPACE) || 178 (state & HAS_INVALID) || 179 (state & HAS_ASTERISK)) return DNS_ERROR_INVALID_NAME_CHAR; 180 break; 181 } 182 case DnsNameHostnameFull: 183 { 184 if (!(state & HAS_NON_NUMERIC) && (state & HAS_NUMERIC)) 185 return DNS_ERROR_NUMERIC_NAME; 186 if ((state & HAS_EXTENDED) || (state & HAS_UNDERSCORE)) 187 return DNS_ERROR_NON_RFC_NAME; 188 if ((state & HAS_SPACE) || 189 (state & HAS_INVALID) || 190 (state & HAS_ASTERISK)) return DNS_ERROR_INVALID_NAME_CHAR; 191 break; 192 } 193 case DnsNameHostnameLabel: 194 { 195 if (state & HAS_DOT) return ERROR_INVALID_NAME; 196 if (!(state & HAS_NON_NUMERIC) && (state & HAS_NUMERIC)) 197 return DNS_ERROR_NUMERIC_NAME; 198 if ((state & HAS_EXTENDED) || (state & HAS_UNDERSCORE)) 199 return DNS_ERROR_NON_RFC_NAME; 200 if ((state & HAS_SPACE) || 201 (state & HAS_INVALID) || 202 (state & HAS_ASTERISK)) return DNS_ERROR_INVALID_NAME_CHAR; 203 break; 204 } 205 case DnsNameWildcard: 206 { 207 if (!(state & HAS_NON_NUMERIC) && (state & HAS_NUMERIC)) 208 return ERROR_INVALID_NAME; 209 if (name[0] != '*') return ERROR_INVALID_NAME; 210 if (name[1] && name[1] != '.') 211 return DNS_ERROR_INVALID_NAME_CHAR; 212 if ((state & HAS_EXTENDED) || 213 (state & HAS_SPACE) || 214 (state & HAS_INVALID)) return ERROR_INVALID_NAME; 215 break; 216 } 217 case DnsNameSrvRecord: 218 { 219 if (!(state & HAS_NON_NUMERIC) && (state & HAS_NUMERIC)) 220 return ERROR_INVALID_NAME; 221 if (name[0] != '_') return ERROR_INVALID_NAME; 222 if ((state & HAS_UNDERSCORE) && !name[1]) 223 return DNS_ERROR_NON_RFC_NAME; 224 if ((state & HAS_EXTENDED) || 225 (state & HAS_SPACE) || 226 (state & HAS_INVALID)) return ERROR_INVALID_NAME; 227 break; 228 } 229 default: 230 DPRINT1( "unknown format: %d\n", format ); 231 break; 232 } 233 return ERROR_SUCCESS; 234 } 235