Sync with trunk (r48008)
[reactos.git] / dll / win32 / dnsapi / dnsapi / names.c
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 }