Final edit for tonight.
[reactos.git] / reactos / lib / dnsapi / dnsapi / names.c
1 #include <windows.h>
2 #include <WinError.h>
3 #include <WinDNS.h>
4 #include <internal/windns.h>
5 #include <wchar.h>
6 #include <string.h>
7 #include <ctype.h>
8
9 static BOOL DnsIntNameContainsDots( LPCWSTR Name ) {
10 return wcschr( Name, '.' ) ? TRUE : FALSE;
11 }
12
13 static BOOL DnsIntTwoConsecutiveDots( LPCWSTR Name ) {
14 return wcsstr( Name, L".." ) ? TRUE : FALSE;
15 }
16
17 static BOOL DnsIntContainsUnderscore( LPCWSTR Name ) {
18 return wcschr( Name, '_' ) ? TRUE : FALSE;
19 }
20
21 /* DnsValidateName *********************
22 * Use some different algorithms to validate the given name as suitable for
23 * use with DNS.
24 *
25 * Name -- The name to evaluate.
26 * Format -- Format to use:
27 * DnsNameDomain
28 * DnsNameDomainLabel
29 * DnsNameHostnameFull
30 * DnsNameHostnameLabel
31 * DnsNameWildcard
32 * DnsNameSrvRecord
33 * RETURNS:
34 * ERROR_SUCCESS -- All good
35 * ERROR_INVALID_NAME --
36 * Name greater than 255 chars.
37 * Label greater than 63 chars.
38 * Two consecutive dots, or starts with dot.
39 * Contains a dot, but a Label check was specified.
40 * DNS_ERROR_INVALID_NAME_CHAR
41 * Contains any invalid char: " {|}~[\]^':;<=>?@!"#$%^`()+/,"
42 * Contains an *, except when it is the first label and Wildcard was
43 * specified.
44 * DNS_ERROR_NUMERIC_NAME
45 * Set if the name contains only numerics, unless Domain is specified.
46 * DNS_ERROR_NON_RFC_NAME
47 * If the name contains underscore.
48 * If there is an underscore in any position but the first in the SrvRecord
49 * case.
50 * If the name contains a non-ascii character.
51 */
52
53 DNS_STATUS DnsValidateName_W
54 ( LPCWSTR Name,
55 DNS_NAME_FORMAT Format ) {
56 BOOL AllowDot = FALSE;
57 BOOL AllowLeadingAst = FALSE;
58 BOOL AllowLeadingUnderscore = FALSE;
59 BOOL AllowAllDigits = FALSE;
60 const WCHAR *NextLabel, *CurrentLabel, *CurrentChar;
61
62 switch( Format ) {
63 case DnsNameDomain:
64 AllowAllDigits = TRUE;
65 AllowDot = TRUE;
66 break;
67 case DnsNameDomainLabel:
68 AllowAllDigits = TRUE;
69 break;
70 case DnsNameHostnameFull:
71 AllowDot = TRUE;
72 break;
73 case DnsNameHostnameLabel:
74 break;
75 case DnsNameWildcard:
76 AllowLeadingAst = TRUE;
77 AllowDot = TRUE;
78 break;
79 case DnsNameSrvRecord:
80 AllowLeadingUnderscore = TRUE;
81 break;
82 default:
83 break;
84 }
85
86 /* Preliminary checks */
87 if( Name[0] == 0 ) return ERROR_INVALID_NAME; /* XXX arty: Check this */
88
89 /* Name too long */
90 if( wcslen( Name ) > 255 ) {
91 return ERROR_INVALID_NAME;
92 }
93
94 /* Violations about dots */
95 if( (!AllowDot && DnsIntNameContainsDots( Name )) ||
96 Name[0] == '.' || DnsIntTwoConsecutiveDots( Name ) )
97 return ERROR_INVALID_NAME;
98
99 /* Check component sizes */
100 CurrentLabel = Name;
101 do {
102 NextLabel = CurrentLabel;
103 while( *NextLabel && *NextLabel != '.' ) NextLabel++;
104
105 if( NextLabel - CurrentLabel > 63 )
106 return ERROR_INVALID_NAME;
107
108 CurrentLabel = NextLabel;
109 } while( *CurrentLabel );
110
111 CurrentChar = Name;
112
113 while( *CurrentChar ) {
114 if( wcschr(L" {|}~[\\]^':;<=>?@!\"#$%^`()+/,",*CurrentChar) )
115 return DNS_ERROR_INVALID_NAME_CHAR;
116 CurrentChar++;
117 }
118
119 if( (!AllowLeadingAst && Name[0] == '*') ||
120 (AllowLeadingAst && Name[0] == '*' && Name[1] && Name[1] != '.') )
121 return DNS_ERROR_INVALID_NAME_CHAR;
122
123 if( wcschr( Name + 1, '*' ) )
124 return DNS_ERROR_INVALID_NAME_CHAR;
125
126 CurrentChar = Name;
127 while( !AllowAllDigits && *CurrentChar ) {
128 if( *CurrentChar == '.' || (*CurrentChar >= '0' && *CurrentChar <= '9') )
129 return DNS_ERROR_NUMERIC_NAME;
130 }
131
132 if( ((AllowLeadingUnderscore && Name[0] == '_') || Name[0] != '_') &&
133 !DnsIntContainsUnderscore( Name + 1 ) )
134 return DNS_ERROR_NON_RFC_NAME;
135
136 return ERROR_SUCCESS;
137 }
138
139 DNS_STATUS DnsValidateName_UTF8
140 ( LPCSTR Name,
141 DNS_NAME_FORMAT Format ) {
142 PWCHAR Buffer;
143 int StrLenWc;
144 DNS_STATUS Status;
145
146 StrLenWc = mbstowcs( NULL, Name, 0 );
147 Buffer = RtlAllocateHeap( GetProcessHeap(), 0,
148 sizeof( WCHAR ) * (StrLenWc + 1) );
149 mbstowcs( Buffer, Name, StrLenWc + 1 );
150 Status = DnsValidateName_W( Buffer, Format );
151 RtlFreeHeap( GetProcessHeap(), 0, Buffer );
152
153 return Status;
154 }
155
156 DNS_STATUS DnsValidateName_A
157 ( LPCSTR Name,
158 DNS_NAME_FORMAT Format ) {
159 return DnsValidateName_UTF8( Name, Format );
160 }
161
162 /* DnsNameCompare **********************
163 * Return TRUE if the names are identical.
164 *
165 * Name1 & Name2 -- Names.
166 */
167
168 BOOL WINAPI DnsNameCompare_W
169 ( LPWSTR Name1,
170 LPWSTR Name2 ) {
171 int offset = 0;
172
173 while( Name1[offset] && Name2[offset] &&
174 towupper( Name1[offset] ) == towupper( Name2[offset] ) ) offset++;
175 return
176 (!Name1[offset] && !Name2[offset]) ||
177 (!Name1[offset] && !wcscmp( Name2 + offset, L"." )) ||
178 (!Name2[offset] && !wcscmp( Name1 + offset, L"." ));
179 }
180
181 BOOL WINAPI DnsNameCompare_UTF8
182 ( LPCSTR Name1,
183 LPCSTR Name2 ) {
184 int offset = 0;
185
186 while( Name1[offset] && Name2[offset] &&
187 toupper( Name1[offset] ) == toupper( Name2[offset] ) ) offset++;
188 return
189 (!Name1[offset] && !Name2[offset]) ||
190 (!Name1[offset] && !strcmp( Name2 + offset, ".")) ||
191 (!Name2[offset] && !strcmp( Name1 + offset, "."));
192 }
193
194 BOOL WINAPI DnsNameCompare_A
195 ( LPCSTR Name1,
196 LPCSTR Name2 ) {
197 return DnsNameCompare_UTF8( Name1, Name2 );
198 }
199