Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/dlls/adsldp/schema.c
4388 views
1
/*
2
* Copyright 2020 Dmitry Timoshkov
3
*
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.
8
*
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.
13
*
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
17
*/
18
19
#include <stdarg.h>
20
21
#include "windef.h"
22
#include "winbase.h"
23
#include "iads.h"
24
#include "winldap.h"
25
26
#include "adsldp_private.h"
27
28
#include "wine/debug.h"
29
30
WINE_DEFAULT_DEBUG_CHANNEL(adsldp);
31
32
static const struct attribute_type *find_schema_type_sorted(const WCHAR *name, const struct attribute_type *at, ULONG count)
33
{
34
int idx, min, max, res;
35
36
if (!count) return NULL;
37
38
min = 0;
39
max = count - 1;
40
41
while (min <= max)
42
{
43
idx = (min + max) / 2;
44
res = wcsicmp(name, at[idx].name);
45
if (!res) return &at[idx];
46
if (res > 0) min = idx + 1;
47
else max = idx - 1;
48
}
49
50
return NULL;
51
}
52
53
54
static const struct attribute_type *find_schema_type(const WCHAR *name, const struct attribute_type *at, ULONG single, ULONG multiple)
55
{
56
const struct attribute_type *found;
57
ULONG i, n, off;
58
59
/* Perform binary search within definitions with single name */
60
found = find_schema_type_sorted(name, at, single);
61
if (found) return found;
62
63
/* Perform linear search within definitions with multiple names */
64
at += single;
65
66
for (i = 0; i < multiple; i++)
67
{
68
off = 0;
69
70
for (n = 0; n < at[i].name_count; n++)
71
{
72
if (!wcsicmp(at[i].name + off, name)) return &at[i];
73
off += wcslen(at[i].name + off) + 1;
74
}
75
}
76
77
FIXME("%s not found\n", debugstr_w(name));
78
return NULL;
79
}
80
81
/* RFC 4517 */
82
ADSTYPEENUM get_schema_type(const WCHAR *name, const struct attribute_type *at, ULONG single, ULONG multiple)
83
{
84
const struct attribute_type *type;
85
86
type = find_schema_type(name, at, single, multiple);
87
if (!type || !type->syntax) return ADSTYPE_CASE_IGNORE_STRING;
88
89
if (!wcscmp(type->syntax, L"1.3.6.1.4.1.1466.115.121.1.7"))
90
return ADSTYPE_BOOLEAN;
91
if (!wcscmp(type->syntax, L"1.3.6.1.4.1.1466.115.121.1.12"))
92
return ADSTYPE_DN_STRING;
93
if (!wcscmp(type->syntax, L"1.3.6.1.4.1.1466.115.121.1.15"))
94
return ADSTYPE_CASE_IGNORE_STRING;
95
if (!wcscmp(type->syntax, L"1.3.6.1.4.1.1466.115.121.1.24"))
96
return ADSTYPE_UTC_TIME;
97
if (!wcscmp(type->syntax, L"1.3.6.1.4.1.1466.115.121.1.26"))
98
return ADSTYPE_CASE_IGNORE_STRING;
99
if (!wcscmp(type->syntax, L"1.3.6.1.4.1.1466.115.121.1.27"))
100
return ADSTYPE_INTEGER;
101
if (!wcscmp(type->syntax, L"1.3.6.1.4.1.1466.115.121.1.38"))
102
return ADSTYPE_CASE_IGNORE_STRING;
103
if (!wcscmp(type->syntax, L"1.3.6.1.4.1.1466.115.121.1.40"))
104
return ADSTYPE_OCTET_STRING;
105
if (!wcscmp(type->syntax, L"1.2.840.113556.1.4.903"))
106
return ADSTYPE_DN_WITH_BINARY;
107
if (!wcscmp(type->syntax, L"1.2.840.113556.1.4.906"))
108
return ADSTYPE_LARGE_INTEGER;
109
if (!wcscmp(type->syntax, L"1.2.840.113556.1.4.907"))
110
return ADSTYPE_NT_SECURITY_DESCRIPTOR;
111
112
FIXME("not handled type syntax %s for %s\n", debugstr_w(type->syntax), debugstr_w(name));
113
return ADSTYPE_CASE_IGNORE_STRING;
114
}
115
116
static void free_attribute_type(struct attribute_type *at)
117
{
118
free(at->oid);
119
free(at->name);
120
free(at->syntax);
121
}
122
123
void free_attribute_types(struct attribute_type *at, ULONG count)
124
{
125
ULONG i;
126
127
for (i = 0; i < count; i++)
128
free_attribute_type(&at[i]);
129
130
free(at);
131
}
132
133
static BOOL is_space(WCHAR c)
134
{
135
return c == ' ' || c == '\t' || c == '\r' || c == '\n';
136
}
137
138
static WCHAR *parse_oid(WCHAR **str)
139
{
140
WCHAR *oid, *p = *str, *end;
141
int count;
142
143
while (is_space(*p)) p++;
144
145
if (*p == '\'')
146
{
147
p++;
148
end = wcschr(p, '\'');
149
if (!end) return NULL;
150
}
151
else
152
{
153
end = p;
154
while (!is_space(*end)) end++;
155
}
156
157
count = end - p;
158
oid = malloc((count + 1) * sizeof(WCHAR));
159
if (!oid) return NULL;
160
161
memcpy(oid, p, count * sizeof(WCHAR));
162
oid[count] = 0;
163
164
*str = end + 1;
165
166
return oid;
167
}
168
169
static WCHAR *parse_name(WCHAR **str, ULONG *name_count)
170
{
171
WCHAR *name, *p = *str, *end;
172
int count;
173
174
*name_count = 0;
175
176
while (is_space(*p)) p++;
177
178
if (*p == '(')
179
{
180
int total_count = 0;
181
182
p++;
183
name = NULL;
184
185
while (*p)
186
{
187
WCHAR *tmp_name, *new_name;
188
ULONG dummy;
189
190
while (is_space(*p)) p++;
191
if (*p == ')')
192
{
193
*str = p + 1;
194
return name;
195
}
196
197
tmp_name = parse_name(&p, &dummy);
198
if (!tmp_name) break;
199
200
TRACE("NAME[%lu] %s\n", *name_count, debugstr_w(tmp_name));
201
202
count = wcslen(tmp_name);
203
204
new_name = realloc(name, (total_count + count + 1) * sizeof(WCHAR));
205
206
if (!new_name) break;
207
208
memcpy(new_name + total_count, tmp_name, (count + 1) * sizeof(WCHAR));
209
210
name = new_name;
211
free(tmp_name);
212
total_count += count + 1;
213
214
*name_count += 1;
215
*str = p;
216
}
217
218
*str = *p ? p + 1 : p;
219
220
free(name);
221
return NULL;
222
}
223
224
if (*p != '\'')
225
{
226
FIXME("not supported NAME start at %s\n", debugstr_w(p));
227
return NULL;
228
}
229
230
p++;
231
end = wcschr(p, '\'');
232
if (!end) return NULL;
233
234
count = end - p;
235
name = malloc((count + 1) * sizeof(WCHAR));
236
if (!name) return NULL;
237
238
memcpy(name, p, count * sizeof(WCHAR));
239
name[count] = 0;
240
241
*name_count = 1;
242
243
*str = end + 1;
244
245
return name;
246
}
247
248
static void skip_token(WCHAR **str)
249
{
250
WCHAR *p = *str;
251
252
while (is_space(*p)) p++;
253
254
if (*p == '\'')
255
{
256
p++;
257
while (*p && *p != '\'') p++;
258
}
259
else
260
{
261
while (*p && !is_space(*p)) p++;
262
}
263
264
*str = *p ? p + 1 : p;
265
}
266
267
static BOOL parse_attribute_type(WCHAR *str, struct attribute_type *at)
268
{
269
static const WCHAR * const not_supported[] = { L"DESC", L"EQUALITY",
270
L"ORDERING", L"SUBSTR", L"SUP", L"USAGE", L"X-ORDERED" };
271
int i;
272
WCHAR *p = str;
273
274
at->oid = NULL;
275
at->name = NULL;
276
at->name_count = 0;
277
at->syntax = NULL;
278
at->single_value = 0;
279
280
while (is_space(*p)) p++;
281
if (*p++ != '(') return FALSE;
282
283
at->oid = parse_oid(&p);
284
if (!at->oid) return FALSE;
285
286
while (*p)
287
{
288
while (is_space(*p)) p++;
289
if (*p == ')') return TRUE;
290
291
if (!wcsnicmp(p, L"NAME", 4))
292
{
293
p += 4;
294
at->name = parse_name(&p, &at->name_count);
295
}
296
else if (!wcsnicmp(p, L"SYNTAX", 6))
297
{
298
p += 6;
299
at->syntax = parse_oid(&p);
300
}
301
else if (!wcsnicmp(p, L"SINGLE-VALUE", 12))
302
{
303
p += 12;
304
at->single_value = 1;
305
}
306
else if (!wcsnicmp(p, L"NO-USER-MODIFICATION", 20))
307
{
308
p += 20;
309
}
310
else
311
{
312
BOOL recognized = FALSE;
313
314
for (i = 0; i < ARRAY_SIZE(not_supported); i++)
315
{
316
if (!wcsnicmp(p, not_supported[i], wcslen(not_supported[i])))
317
{
318
p += wcslen(not_supported[i]);
319
skip_token(&p);
320
recognized = TRUE;
321
break;
322
}
323
}
324
325
if (!recognized)
326
{
327
FIXME("not supported token at %s\n", debugstr_w(p));
328
free_attribute_type(at);
329
return FALSE;
330
}
331
}
332
}
333
334
WARN("attribute definition is not terminated\n");
335
336
free_attribute_type(at);
337
return FALSE;
338
}
339
340
static int __cdecl at_cmp(const void *a1, const void *a2)
341
{
342
const struct attribute_type *at1 = a1;
343
const struct attribute_type *at2 = a2;
344
345
if (at1->name_count == 1 && at2->name_count == 1)
346
return wcsicmp(at1->name, at2->name);
347
348
/* put definitions with multiple names at the end */
349
return at1->name_count - at2->name_count;
350
}
351
352
struct attribute_type *load_schema(LDAP *ld, ULONG *at_single_count, ULONG *at_multiple_count)
353
{
354
WCHAR *subschema[] = { (WCHAR *)L"subschemaSubentry", NULL };
355
WCHAR *attribute_types[] = { (WCHAR *)L"attributeTypes", NULL };
356
ULONG err, count, multiple_count;
357
LDAPMessage *res, *entry;
358
WCHAR **schema = NULL;
359
struct attribute_type *at = NULL;
360
361
*at_single_count = 0;
362
*at_multiple_count = 0;
363
364
err = ldap_search_sW(ld, NULL, LDAP_SCOPE_BASE, (WCHAR *)L"(objectClass=*)", subschema, FALSE, &res);
365
if (err != LDAP_SUCCESS)
366
{
367
TRACE("ldap_search_sW error %#lx\n", err);
368
return NULL;
369
}
370
371
entry = ldap_first_entry(ld, res);
372
if (entry)
373
schema = ldap_get_valuesW(ld, entry, subschema[0]);
374
375
ldap_msgfree(res);
376
if (!schema) return NULL;
377
378
err = ldap_search_sW(ld, schema[0], LDAP_SCOPE_BASE, (WCHAR *)L"(objectClass=*)", attribute_types, FALSE, &res);
379
if (err != LDAP_SUCCESS)
380
{
381
TRACE("ldap_search_sW error %#lx\n", err);
382
ldap_value_freeW(schema);
383
return NULL;
384
}
385
386
count = 0;
387
multiple_count = 0;
388
389
entry = ldap_first_entry(ld, res);
390
if (entry)
391
{
392
WCHAR **types;
393
394
types = ldap_get_valuesW(ld, entry, attribute_types[0]);
395
if (types)
396
{
397
ULONG i, total = ldap_count_valuesW(types);
398
399
at = malloc(total * sizeof(*at));
400
if (!at) goto exit;
401
402
for (i = 0; i < total; i++)
403
{
404
TRACE("%s\n", debugstr_w(types[i]));
405
406
if (!parse_attribute_type(types[i], &at[count]))
407
{
408
WARN("parse_attribute_type failed\n");
409
continue;
410
}
411
412
if (!at[count].name)
413
{
414
free_attribute_type(&at[count]);
415
continue;
416
}
417
418
TRACE("oid %s, name %s, name_count %lu, syntax %s, single-value %d\n", debugstr_w(at[count].oid),
419
debugstr_w(at[count].name), at[count].name_count, debugstr_w(at[count].syntax), at[count].single_value);
420
421
if (at[count].name_count > 1)
422
multiple_count++;
423
424
count++;
425
}
426
427
ldap_value_freeW(types);
428
}
429
}
430
431
exit:
432
ldap_value_freeW(schema);
433
ldap_msgfree(res);
434
if (at)
435
{
436
*at_single_count = count - multiple_count;
437
*at_multiple_count = multiple_count;
438
439
qsort(at, count, sizeof(at[0]), at_cmp);
440
}
441
442
return at;
443
}
444
445