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
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
;
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;
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
;
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 */
67 for (i
= 0; i
< multiple
; i
++)
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
));
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
)
121 heap_free(at
->syntax
);
124 void free_attribute_types(struct attribute_type
*at
, ULONG count
)
128 for (i
= 0; i
< count
; i
++)
129 free_attribute_type(&at
[i
]);
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
;
144 while (is_space(*p
)) p
++;
149 end
= wcschr(p
, '\'');
150 if (!end
) return NULL
;
155 while (!is_space(*end
)) end
++;
159 oid
= heap_alloc((count
+ 1) * sizeof(WCHAR
));
160 if (!oid
) return NULL
;
162 memcpy(oid
, p
, count
* sizeof(WCHAR
));
170 static WCHAR
*parse_name(WCHAR
**str
, ULONG
*name_count
)
172 WCHAR
*name
, *p
= *str
, *end
;
177 while (is_space(*p
)) p
++;
188 WCHAR
*tmp_name
, *new_name
;
191 while (is_space(*p
)) p
++;
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
);
206 new_name
= heap_alloc((count
+ 1) * sizeof(WCHAR
));
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
));
216 total_count
+= count
+ 1;
222 *str
= *p
? p
+ 1 : p
;
230 FIXME("not supported NAME start at %s\n", debugstr_w(p
));
235 end
= wcschr(p
, '\'');
236 if (!end
) return NULL
;
239 name
= heap_alloc((count
+ 1) * sizeof(WCHAR
));
240 if (!name
) return NULL
;
242 memcpy(name
, p
, count
* sizeof(WCHAR
));
252 static void skip_token(WCHAR
**str
)
256 while (is_space(*p
)) p
++;
261 while (*p
&& *p
!= '\'') p
++;
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" };
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
;
292 while (is_space(*p
)) p
++;
293 if (*p
== ')') return TRUE
;
295 if (!wcsnicmp(p
, L
"NAME", 4))
298 at
->name
= parse_name(&p
, &at
->name_count
);
300 else if (!wcsnicmp(p
, L
"SYNTAX", 6))
303 at
->syntax
= parse_oid(&p
);
305 else if (!wcsnicmp(p
, L
"SINGLE-VALUE", 12))
308 at
->single_value
= 1;
310 else if (!wcsnicmp(p
, L
"NO-USER-MODIFICATION", 20))
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
]);
331 FIXME("not supported token at %s\n", debugstr_w(p
));
332 free_attribute_type(at
);
338 WARN("attribute definition is not terminated\n");
340 free_attribute_type(at
);
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
);
375 entry
= ldap_first_entry(ld
, res
);
377 schema
= ldap_get_valuesW(ld
, entry
, subschema
[0]);
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
);
393 entry
= ldap_first_entry(ld
, res
);
398 types
= ldap_get_valuesW(ld
, entry
, attribute_types
[0]);
401 ULONG i
, total
= ldap_count_valuesW(types
);
403 at
= heap_alloc(total
* sizeof(*at
));
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");
418 free_attribute_type(&at
[count
]);
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)
431 ldap_value_freeW(types
);
436 ldap_value_freeW(schema
);
440 *at_single_count
= count
- multiple_count
;
441 *at_multiple_count
= multiple_count
;
443 qsort(at
, count
, sizeof(at
[0]), at_cmp
);