winspool/tests: Add tests for GetFormA().
[wine.git] / dlls / adsldp / schema.c
blobabf8793b8403de18f86e12411ca56d61d9515b50
1 /*
2 * Copyright 2020 Dmitry Timoshkov
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <stdarg.h>
21 #include "windef.h"
22 #include "winbase.h"
23 #include "iads.h"
24 #include "winldap.h"
26 #include "adsldp_private.h"
28 #include "wine/heap.h"
29 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(adsldp);
33 static const struct attribute_type *find_schema_type_sorted(const WCHAR *name, const struct attribute_type *at, ULONG count)
35 int idx, min, max, res;
37 if (!count) return NULL;
39 min = 0;
40 max = count - 1;
42 while (min <= max)
44 idx = (min + max) / 2;
45 res = wcsicmp(name, at[idx].name);
46 if (!res) return &at[idx];
47 if (res > 0) min = idx + 1;
48 else max = idx - 1;
51 return NULL;
55 static const struct attribute_type *find_schema_type(const WCHAR *name, const struct attribute_type *at, ULONG single, ULONG multiple)
57 const struct attribute_type *found;
58 ULONG i, n, off;
60 /* Perform binary search within definitions with single name */
61 found = find_schema_type_sorted(name, at, single);
62 if (found) return found;
64 /* Perform linear search within definitions with multiple names */
65 at += single;
67 for (i = 0; i < multiple; i++)
69 off = 0;
71 for (n = 0; n < at[i].name_count; n++)
73 if (!wcsicmp(at[i].name + off, name)) return &at[i];
74 off += wcslen(at[i].name + off) + 1;
78 FIXME("%s not found\n", debugstr_w(name));
79 return NULL;
82 /* RFC 4517 */
83 ADSTYPEENUM get_schema_type(const WCHAR *name, const struct attribute_type *at, ULONG single, ULONG multiple)
85 const struct attribute_type *type;
87 type = find_schema_type(name, at, single, multiple);
88 if (!type || !type->syntax) return ADSTYPE_CASE_IGNORE_STRING;
90 if (!wcscmp(type->syntax, L"1.3.6.1.4.1.1466.115.121.1.7"))
91 return ADSTYPE_BOOLEAN;
92 if (!wcscmp(type->syntax, L"1.3.6.1.4.1.1466.115.121.1.12"))
93 return ADSTYPE_DN_STRING;
94 if (!wcscmp(type->syntax, L"1.3.6.1.4.1.1466.115.121.1.15"))
95 return ADSTYPE_CASE_IGNORE_STRING;
96 if (!wcscmp(type->syntax, L"1.3.6.1.4.1.1466.115.121.1.24"))
97 return ADSTYPE_UTC_TIME;
98 if (!wcscmp(type->syntax, L"1.3.6.1.4.1.1466.115.121.1.26"))
99 return ADSTYPE_CASE_IGNORE_STRING;
100 if (!wcscmp(type->syntax, L"1.3.6.1.4.1.1466.115.121.1.27"))
101 return ADSTYPE_INTEGER;
102 if (!wcscmp(type->syntax, L"1.3.6.1.4.1.1466.115.121.1.38"))
103 return ADSTYPE_CASE_IGNORE_STRING;
104 if (!wcscmp(type->syntax, L"1.3.6.1.4.1.1466.115.121.1.40"))
105 return ADSTYPE_OCTET_STRING;
106 if (!wcscmp(type->syntax, L"1.2.840.113556.1.4.903"))
107 return ADSTYPE_DN_WITH_BINARY;
108 if (!wcscmp(type->syntax, L"1.2.840.113556.1.4.906"))
109 return ADSTYPE_LARGE_INTEGER;
110 if (!wcscmp(type->syntax, L"1.2.840.113556.1.4.907"))
111 return ADSTYPE_NT_SECURITY_DESCRIPTOR;
113 FIXME("not handled type syntax %s for %s\n", debugstr_w(type->syntax), debugstr_w(name));
114 return ADSTYPE_CASE_IGNORE_STRING;
117 static void free_attribute_type(struct attribute_type *at)
119 heap_free(at->oid);
120 heap_free(at->name);
121 heap_free(at->syntax);
124 void free_attribute_types(struct attribute_type *at, ULONG count)
126 ULONG i;
128 for (i = 0; i < count; i++)
129 free_attribute_type(&at[i]);
131 heap_free(at);
134 static BOOL is_space(WCHAR c)
136 return c == ' ' || c == '\t' || c == '\r' || c == '\n';
139 static WCHAR *parse_oid(WCHAR **str)
141 WCHAR *oid, *p = *str, *end;
142 int count;
144 while (is_space(*p)) p++;
146 if (*p == '\'')
148 p++;
149 end = wcschr(p, '\'');
150 if (!end) return NULL;
152 else
154 end = p;
155 while (!is_space(*end)) end++;
158 count = end - p;
159 oid = heap_alloc((count + 1) * sizeof(WCHAR));
160 if (!oid) return NULL;
162 memcpy(oid, p, count * sizeof(WCHAR));
163 oid[count] = 0;
165 *str = end + 1;
167 return oid;
170 static WCHAR *parse_name(WCHAR **str, ULONG *name_count)
172 WCHAR *name, *p = *str, *end;
173 int count;
175 *name_count = 0;
177 while (is_space(*p)) p++;
179 if (*p == '(')
181 int total_count = 0;
183 p++;
184 name = NULL;
186 while (*p)
188 WCHAR *tmp_name, *new_name;
189 ULONG dummy;
191 while (is_space(*p)) p++;
192 if (*p == ')')
194 *str = p + 1;
195 return name;
198 tmp_name = parse_name(&p, &dummy);
199 if (!tmp_name) break;
201 TRACE("NAME[%u] %s\n", *name_count, debugstr_w(tmp_name));
203 count = wcslen(tmp_name);
205 if (!name)
206 new_name = heap_alloc((count + 1) * sizeof(WCHAR));
207 else
208 new_name = heap_realloc(name, (total_count + count + 1) * sizeof(WCHAR));
210 if (!new_name) break;
212 memcpy(new_name + total_count, tmp_name, (count + 1) * sizeof(WCHAR));
214 name = new_name;
215 heap_free(tmp_name);
216 total_count += count + 1;
218 *name_count += 1;
219 *str = p;
222 *str = *p ? p + 1 : p;
224 heap_free(name);
225 return NULL;
228 if (*p != '\'')
230 FIXME("not supported NAME start at %s\n", debugstr_w(p));
231 return NULL;
234 p++;
235 end = wcschr(p, '\'');
236 if (!end) return NULL;
238 count = end - p;
239 name = heap_alloc((count + 1) * sizeof(WCHAR));
240 if (!name) return NULL;
242 memcpy(name, p, count * sizeof(WCHAR));
243 name[count] = 0;
245 *name_count = 1;
247 *str = end + 1;
249 return name;
252 static void skip_token(WCHAR **str)
254 WCHAR *p = *str;
256 while (is_space(*p)) p++;
258 if (*p == '\'')
260 p++;
261 while (*p && *p != '\'') p++;
263 else
265 while (*p && !is_space(*p)) p++;
268 *str = *p ? p + 1 : p;
271 static BOOL parse_attribute_type(WCHAR *str, struct attribute_type *at)
273 static const WCHAR * const not_supported[] = { L"DESC", L"EQUALITY",
274 L"ORDERING", L"SUBSTR", L"SUP", L"USAGE", L"X-ORDERED" };
275 int i;
276 WCHAR *p = str;
278 at->oid = NULL;
279 at->name = NULL;
280 at->name_count = 0;
281 at->syntax = NULL;
282 at->single_value = 0;
284 while (is_space(*p)) p++;
285 if (*p++ != '(') return FALSE;
287 at->oid = parse_oid(&p);
288 if (!at->oid) return FALSE;
290 while (*p)
292 while (is_space(*p)) p++;
293 if (*p == ')') return TRUE;
295 if (!wcsnicmp(p, L"NAME", 4))
297 p += 4;
298 at->name = parse_name(&p, &at->name_count);
300 else if (!wcsnicmp(p, L"SYNTAX", 6))
302 p += 6;
303 at->syntax = parse_oid(&p);
305 else if (!wcsnicmp(p, L"SINGLE-VALUE", 12))
307 p += 12;
308 at->single_value = 1;
310 else if (!wcsnicmp(p, L"NO-USER-MODIFICATION", 20))
312 p += 20;
314 else
316 BOOL recognized = FALSE;
318 for (i = 0; i < ARRAY_SIZE(not_supported); i++)
320 if (!wcsnicmp(p, not_supported[i], wcslen(not_supported[i])))
322 p += wcslen(not_supported[i]);
323 skip_token(&p);
324 recognized = TRUE;
325 break;
329 if (!recognized)
331 FIXME("not supported token at %s\n", debugstr_w(p));
332 free_attribute_type(at);
333 return FALSE;
338 WARN("attribute definition is not terminated\n");
340 free_attribute_type(at);
341 return FALSE;
344 static int __cdecl at_cmp(const void *a1, const void *a2)
346 const struct attribute_type *at1 = a1;
347 const struct attribute_type *at2 = a2;
349 if (at1->name_count == 1 && at2->name_count == 1)
350 return wcsicmp(at1->name, at2->name);
352 /* put definitions with multiple names at the end */
353 return at1->name_count - at2->name_count;
356 struct attribute_type *load_schema(LDAP *ld, ULONG *at_single_count, ULONG *at_multiple_count)
358 WCHAR *subschema[] = { (WCHAR *)L"subschemaSubentry", NULL };
359 WCHAR *attribute_types[] = { (WCHAR *)L"attributeTypes", NULL };
360 ULONG err, count, multiple_count;
361 LDAPMessage *res, *entry;
362 WCHAR **schema = NULL;
363 struct attribute_type *at = NULL;
365 *at_single_count = 0;
366 *at_multiple_count = 0;
368 err = ldap_search_sW(ld, NULL, LDAP_SCOPE_BASE, (WCHAR *)L"(objectClass=*)", subschema, FALSE, &res);
369 if (err != LDAP_SUCCESS)
371 TRACE("ldap_search_sW error %#x\n", err);
372 return NULL;
375 entry = ldap_first_entry(ld, res);
376 if (entry)
377 schema = ldap_get_valuesW(ld, entry, subschema[0]);
379 ldap_msgfree(res);
380 if (!schema) return NULL;
382 err = ldap_search_sW(ld, schema[0], LDAP_SCOPE_BASE, (WCHAR *)L"(objectClass=*)", attribute_types, FALSE, &res);
383 if (err != LDAP_SUCCESS)
385 TRACE("ldap_search_sW error %#x\n", err);
386 ldap_value_freeW(schema);
387 return NULL;
390 count = 0;
391 multiple_count = 0;
393 entry = ldap_first_entry(ld, res);
394 if (entry)
396 WCHAR **types;
398 types = ldap_get_valuesW(ld, entry, attribute_types[0]);
399 if (types)
401 ULONG i, total = ldap_count_valuesW(types);
403 at = heap_alloc(total * sizeof(*at));
404 if (!at) goto exit;
406 for (i = 0; i < total; i++)
408 TRACE("%s\n", debugstr_w(types[i]));
410 if (!parse_attribute_type(types[i], &at[count]))
412 WARN("parse_attribute_type failed\n");
413 continue;
416 if (!at[count].name)
418 free_attribute_type(&at[count]);
419 continue;
422 TRACE("oid %s, name %s, name_count %u, syntax %s, single-value %d\n", debugstr_w(at[count].oid),
423 debugstr_w(at[count].name), at[count].name_count, debugstr_w(at[count].syntax), at[count].single_value);
425 if (at[count].name_count > 1)
426 multiple_count++;
428 count++;
431 ldap_value_freeW(types);
435 exit:
436 ldap_value_freeW(schema);
437 ldap_msgfree(res);
438 if (at)
440 *at_single_count = count - multiple_count;
441 *at_multiple_count = multiple_count;
443 qsort(at, count, sizeof(at[0]), at_cmp);
446 return at;