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