adsldp: Add initial version of attribute schema parser.
Signed-off-by: Dmitry Timoshkov <dmitry@baikal.ru> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
dbe8d61c70
commit
5875a659c1
|
@ -6,7 +6,8 @@ EXTRADLLFLAGS = -mno-cygwin
|
|||
|
||||
C_SRCS = \
|
||||
adsldp.c \
|
||||
ldap.c
|
||||
ldap.c \
|
||||
schema.c
|
||||
|
||||
IDL_SRCS = \
|
||||
adsldp.idl
|
||||
|
|
|
@ -390,6 +390,8 @@ typedef struct
|
|||
ULONG port;
|
||||
ULONG attrs_count, attrs_count_allocated;
|
||||
struct ldap_attribute *attrs;
|
||||
struct attribute_type *at;
|
||||
ULONG at_count;
|
||||
struct
|
||||
{
|
||||
ADS_SCOPEENUM scope;
|
||||
|
@ -479,6 +481,7 @@ static ULONG WINAPI ldapns_Release(IADs *iface)
|
|||
SysFreeString(ldap->host);
|
||||
SysFreeString(ldap->object);
|
||||
free_attributes(ldap);
|
||||
free_attribute_types(ldap->at, ldap->at_count);
|
||||
heap_free(ldap);
|
||||
}
|
||||
|
||||
|
@ -937,7 +940,8 @@ static HRESULT WINAPI openobj_OpenDSObject(IADsOpenDSObject *iface, BSTR path, B
|
|||
IADs *ads;
|
||||
LDAP *ld = NULL;
|
||||
HRESULT hr;
|
||||
ULONG err;
|
||||
ULONG err, at_count = 0;
|
||||
struct attribute_type *at = NULL;
|
||||
|
||||
TRACE("%p,%s,%s,%p,%08x,%p\n", iface, debugstr_w(path), debugstr_w(user), password, flags, obj);
|
||||
|
||||
|
@ -1035,6 +1039,8 @@ static HRESULT WINAPI openobj_OpenDSObject(IADsOpenDSObject *iface, BSTR path, B
|
|||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
at = load_schema(ld, &at_count);
|
||||
}
|
||||
|
||||
hr = LDAPNamespace_create(&IID_IADs, (void **)&ads);
|
||||
|
@ -1045,6 +1051,8 @@ static HRESULT WINAPI openobj_OpenDSObject(IADsOpenDSObject *iface, BSTR path, B
|
|||
ldap->host = host;
|
||||
ldap->port = port;
|
||||
ldap->object = object;
|
||||
ldap->at = at;
|
||||
ldap->at_count = at_count;
|
||||
hr = IADs_QueryInterface(ads, &IID_IDispatch, (void **)obj);
|
||||
IADs_Release(ads);
|
||||
return hr;
|
||||
|
@ -1306,28 +1314,58 @@ static HRESULT WINAPI search_GetNextColumnName(IDirectorySearch *iface, ADS_SEAR
|
|||
return S_ADS_NOMORE_COLUMNS;
|
||||
}
|
||||
|
||||
static HRESULT add_column_values(ADS_SEARCH_COLUMN *col, struct berval **values, DWORD count)
|
||||
static HRESULT add_column_values(LDAP_namespace *ldap, ADS_SEARCH_COLUMN *col,
|
||||
const WCHAR *name, struct berval **values, DWORD count)
|
||||
{
|
||||
ADSTYPEENUM type;
|
||||
DWORD i;
|
||||
|
||||
type = get_schema_type(name, ldap->at, ldap->at_count);
|
||||
|
||||
col->pADsValues = heap_alloc(count * sizeof(col->pADsValues[0]));
|
||||
if (!col->pADsValues)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
default:
|
||||
FIXME("no special handling for type %d\n", type);
|
||||
/* fall through */
|
||||
case ADSTYPE_DN_STRING:
|
||||
case ADSTYPE_CASE_EXACT_STRING:
|
||||
case ADSTYPE_CASE_IGNORE_STRING:
|
||||
case ADSTYPE_PRINTABLE_STRING:
|
||||
case ADSTYPE_NT_SECURITY_DESCRIPTOR:
|
||||
{
|
||||
DWORD outlen;
|
||||
TRACE("=> %s\n", debugstr_an(values[i]->bv_val, values[i]->bv_len));
|
||||
col->pADsValues[i].u.CaseIgnoreString = strnAtoW(values[i]->bv_val, values[i]->bv_len, &outlen);
|
||||
col->pADsValues[i].u.CaseIgnoreString = strnUtoW(values[i]->bv_val, values[i]->bv_len, &outlen);
|
||||
if (!col->pADsValues[i].u.CaseIgnoreString)
|
||||
{
|
||||
heap_free(col->pADsValues);
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
col->dwADsType = ADSTYPE_CASE_IGNORE_STRING;
|
||||
case ADSTYPE_INTEGER:
|
||||
col->pADsValues[i].u.Integer = strtol(values[i]->bv_val, NULL, 10);
|
||||
TRACE("%s => %d\n", debugstr_an(values[i]->bv_val, values[i]->bv_len), col->pADsValues[i].u.Integer);
|
||||
break;
|
||||
|
||||
case ADSTYPE_OCTET_STRING:
|
||||
TRACE("=> %s\n", debugstr_an(values[i]->bv_val, values[i]->bv_len));
|
||||
col->pADsValues[i].u.OctetString.dwLength = values[i]->bv_len;
|
||||
col->pADsValues[i].u.OctetString.lpValue = (BYTE *)values[i]->bv_val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
col->dwADsType = type;
|
||||
col->dwNumValues = count;
|
||||
col->pszAttrName = strdupW(name);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -1388,10 +1426,8 @@ exit:
|
|||
|
||||
count = ldap_count_values_len(values);
|
||||
|
||||
hr = add_column_values(col, values, count);
|
||||
hr = add_column_values(ldap, col, name, values, count);
|
||||
ldap_value_free_len(values);
|
||||
if (hr == S_OK)
|
||||
col->pszAttrName = strdupW(name);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
@ -1451,6 +1487,8 @@ static HRESULT LDAPNamespace_create(REFIID riid, void **obj)
|
|||
ldap->attrs_count_allocated = 0;
|
||||
ldap->attrs = NULL;
|
||||
ldap->search.scope = ADS_SCOPE_SUBTREE;
|
||||
ldap->at = NULL;
|
||||
ldap->at_count = 0;
|
||||
|
||||
hr = IADs_QueryInterface(&ldap->IADs_iface, riid, obj);
|
||||
IADs_Release(&ldap->IADs_iface);
|
||||
|
|
|
@ -29,16 +29,16 @@ static inline WCHAR *strdupW(const WCHAR *src)
|
|||
return dst;
|
||||
}
|
||||
|
||||
static inline LPWSTR strnAtoW( LPCSTR str, DWORD inlen, DWORD *outlen )
|
||||
static inline LPWSTR strnUtoW( LPCSTR str, DWORD inlen, DWORD *outlen )
|
||||
{
|
||||
LPWSTR ret = NULL;
|
||||
*outlen = 0;
|
||||
if (str)
|
||||
{
|
||||
DWORD len = MultiByteToWideChar( CP_ACP, 0, str, inlen, NULL, 0 );
|
||||
DWORD len = MultiByteToWideChar( CP_UTF8, 0, str, inlen, NULL, 0 );
|
||||
if ((ret = heap_alloc( (len + 1) * sizeof(WCHAR) )))
|
||||
{
|
||||
MultiByteToWideChar( CP_ACP, 0, str, inlen, ret, len );
|
||||
MultiByteToWideChar( CP_UTF8, 0, str, inlen, ret, len );
|
||||
ret[len] = 0;
|
||||
*outlen = len;
|
||||
}
|
||||
|
@ -46,6 +46,17 @@ static inline LPWSTR strnAtoW( LPCSTR str, DWORD inlen, DWORD *outlen )
|
|||
return ret;
|
||||
}
|
||||
|
||||
struct attribute_type
|
||||
{
|
||||
WCHAR *oid;
|
||||
WCHAR *name;
|
||||
WCHAR *syntax;
|
||||
int single_value;
|
||||
};
|
||||
|
||||
DWORD map_ldap_error(DWORD) DECLSPEC_HIDDEN;
|
||||
struct attribute_type *load_schema(LDAP *ld, ULONG *) DECLSPEC_HIDDEN;
|
||||
ADSTYPEENUM get_schema_type(const WCHAR *, const struct attribute_type *, ULONG) DECLSPEC_HIDDEN;
|
||||
void free_attribute_types(struct attribute_type *, ULONG) DECLSPEC_HIDDEN;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,269 @@
|
|||
/*
|
||||
* Copyright 2020 Dmitry Timoshkov
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "iads.h"
|
||||
#include "winldap.h"
|
||||
|
||||
#include "adsldp_private.h"
|
||||
|
||||
#include "wine/heap.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(adsldp);
|
||||
|
||||
static const struct attribute_type *find_schema_type(const WCHAR *name, const struct attribute_type *at, ULONG count)
|
||||
{
|
||||
ULONG i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
if (at[i].name && !wcsicmp(at[i].name, name)) return &at[i];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* RFC 4517 */
|
||||
ADSTYPEENUM get_schema_type(const WCHAR *name, const struct attribute_type *at, ULONG at_count)
|
||||
{
|
||||
const struct attribute_type *type;
|
||||
|
||||
type = find_schema_type(name, at, at_count);
|
||||
if (!type || !type->syntax) return ADSTYPE_CASE_IGNORE_STRING;
|
||||
|
||||
if (!wcscmp(type->syntax, L"1.3.6.1.4.1.1466.115.121.1.12"))
|
||||
return ADSTYPE_DN_STRING;
|
||||
if (!wcscmp(type->syntax, L"1.3.6.1.4.1.1466.115.121.1.15"))
|
||||
return ADSTYPE_NT_SECURITY_DESCRIPTOR;
|
||||
if (!wcscmp(type->syntax, L"1.3.6.1.4.1.1466.115.121.1.27"))
|
||||
return ADSTYPE_INTEGER;
|
||||
if (!wcscmp(type->syntax, L"1.3.6.1.4.1.1466.115.121.1.40"))
|
||||
return ADSTYPE_OCTET_STRING;
|
||||
|
||||
FIXME("not handled type syntax %s for %s\n", debugstr_w(type->syntax), debugstr_w(name));
|
||||
return ADSTYPE_CASE_IGNORE_STRING;
|
||||
}
|
||||
|
||||
static void free_attribute_type(struct attribute_type *at)
|
||||
{
|
||||
heap_free(at->oid);
|
||||
heap_free(at->name);
|
||||
heap_free(at->syntax);
|
||||
}
|
||||
|
||||
void free_attribute_types(struct attribute_type *at, ULONG count)
|
||||
{
|
||||
ULONG i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
free_attribute_type(&at[i]);
|
||||
|
||||
heap_free(at);
|
||||
}
|
||||
|
||||
static BOOL is_space(WCHAR c)
|
||||
{
|
||||
return c == ' ' || c == '\t' || c == '\r' || c == '\n';
|
||||
}
|
||||
|
||||
static WCHAR *parse_oid(WCHAR **str)
|
||||
{
|
||||
WCHAR *oid, *p = *str, *end;
|
||||
int count;
|
||||
|
||||
while (is_space(*p)) p++;
|
||||
|
||||
if (*p == '\'')
|
||||
{
|
||||
p++;
|
||||
end = wcschr(p, '\'');
|
||||
if (!end) return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
end = p;
|
||||
while (!is_space(*end)) end++;
|
||||
}
|
||||
|
||||
count = end - p;
|
||||
oid = heap_alloc((count + 1) * sizeof(WCHAR));
|
||||
if (!oid) return NULL;
|
||||
|
||||
memcpy(oid, p, count * sizeof(WCHAR));
|
||||
oid[count] = 0;
|
||||
|
||||
*str = end + 1;
|
||||
|
||||
return oid;
|
||||
}
|
||||
|
||||
static WCHAR *parse_name(WCHAR **str)
|
||||
{
|
||||
WCHAR *name, *p = *str, *end;
|
||||
int count;
|
||||
|
||||
while (is_space(*p)) p++;
|
||||
|
||||
if (*p != '\'')
|
||||
{
|
||||
FIXME("not suported NAME start at %s\n", debugstr_w(p));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p++;
|
||||
end = wcschr(p, '\'');
|
||||
if (!end) return NULL;
|
||||
|
||||
count = end - p;
|
||||
name = heap_alloc((count + 1) * sizeof(WCHAR));
|
||||
if (!name) return NULL;
|
||||
|
||||
memcpy(name, p, count * sizeof(WCHAR));
|
||||
name[count] = 0;
|
||||
|
||||
*str = end + 1;
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
static BOOL parse_attribute_type(WCHAR *str, struct attribute_type *at)
|
||||
{
|
||||
WCHAR *p = str;
|
||||
|
||||
at->oid = NULL;
|
||||
at->name = NULL;
|
||||
at->syntax = NULL;
|
||||
at->single_value = 0;
|
||||
|
||||
while (is_space(*p)) p++;
|
||||
if (*p++ != '(') return FALSE;
|
||||
|
||||
at->oid = parse_oid(&p);
|
||||
if (!at->oid) return FALSE;
|
||||
|
||||
while (*p)
|
||||
{
|
||||
while (is_space(*p)) p++;
|
||||
if (*p == ')') break;
|
||||
|
||||
if (!wcsnicmp(p, L"NAME", 4))
|
||||
{
|
||||
p += 4;
|
||||
at->name = parse_name(&p);
|
||||
}
|
||||
else if (!wcsnicmp(p, L"SYNTAX", 6))
|
||||
{
|
||||
p += 6;
|
||||
at->syntax = parse_oid(&p);
|
||||
}
|
||||
else if (!wcsnicmp(p, L"SINGLE-VALUE", 12))
|
||||
{
|
||||
p += 12;
|
||||
at->single_value = 1;
|
||||
}
|
||||
else if (!wcsnicmp(p, L"NO-USER-MODIFICATION", 20))
|
||||
{
|
||||
p += 20;
|
||||
}
|
||||
else
|
||||
{
|
||||
FIXME("not supported token at %s\n", debugstr_w(p));
|
||||
free_attribute_type(at);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
struct attribute_type *load_schema(LDAP *ld, ULONG *at_count)
|
||||
{
|
||||
WCHAR *subschema[] = { (WCHAR *)L"subschemaSubentry", NULL };
|
||||
WCHAR *attribute_types[] = { (WCHAR *)L"attributeTypes", NULL };
|
||||
ULONG err, count;
|
||||
LDAPMessage *res, *entry;
|
||||
WCHAR **schema = NULL;
|
||||
struct attribute_type *at = NULL;
|
||||
|
||||
*at_count = 0;
|
||||
|
||||
err = ldap_search_sW(ld, NULL, LDAP_SCOPE_BASE, (WCHAR *)L"(objectClass=*)", subschema, FALSE, &res);
|
||||
if (err != LDAP_SUCCESS)
|
||||
{
|
||||
TRACE("ldap_search_sW error %#x\n", err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
entry = ldap_first_entry(ld, res);
|
||||
if (entry)
|
||||
schema = ldap_get_valuesW(ld, entry, subschema[0]);
|
||||
|
||||
ldap_msgfree(res);
|
||||
if (!schema) return NULL;
|
||||
|
||||
err = ldap_search_sW(ld, schema[0], LDAP_SCOPE_BASE, (WCHAR *)L"(objectClass=*)", attribute_types, FALSE, &res);
|
||||
if (err != LDAP_SUCCESS)
|
||||
{
|
||||
TRACE("ldap_search_sW error %#x\n", err);
|
||||
ldap_value_freeW(schema);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
|
||||
entry = ldap_first_entry(ld, res);
|
||||
if (entry)
|
||||
{
|
||||
WCHAR **types;
|
||||
|
||||
types = ldap_get_valuesW(ld, entry, attribute_types[0]);
|
||||
if (types)
|
||||
{
|
||||
ULONG i, total = ldap_count_valuesW(types);
|
||||
|
||||
at = heap_alloc(total * sizeof(*at));
|
||||
if (!at) goto exit;
|
||||
|
||||
for (i = 0; i < total; i++)
|
||||
{
|
||||
TRACE("%s\n", debugstr_w(types[i]));
|
||||
|
||||
if (!parse_attribute_type(types[i], &at[count]))
|
||||
{
|
||||
WARN("parse_attribute_type failed\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
TRACE("oid %s, name %s, syntax %s, single-value %d\n", debugstr_w(at[i].oid),
|
||||
debugstr_w(at[i].name), debugstr_w(at[i].syntax), at[i].single_value);
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
ldap_value_freeW(types);
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
ldap_msgfree(res);
|
||||
if (at) *at_count = count;
|
||||
|
||||
return at;
|
||||
}
|
Loading…
Reference in New Issue