2 * Active Directory services LDAP Provider
4 * Copyright 2018 Dmitry Timoshkov
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #define NONAMELESSUNION
35 #define SECURITY_WIN32
42 #include "adsldp_private.h"
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(adsldp
);
48 #ifndef LDAP_OPT_SERVER_CONTROLS
49 #define LDAP_OPT_SERVER_CONTROLS 0x0012
52 DEFINE_GUID(CLSID_LDAP
,0x228d9a81,0xc302,0x11cf,0x9a,0xa4,0x00,0xaa,0x00,0x4a,0x56,0x91);
53 DEFINE_GUID(CLSID_LDAPNamespace
,0x228d9a82,0xc302,0x11cf,0x9a,0xa4,0x00,0xaa,0x00,0x4a,0x56,0x91);
55 static HMODULE adsldp_hinst
;
57 static HRESULT
LDAPNamespace_create(REFIID riid
, void **obj
);
61 IParseDisplayName IParseDisplayName_iface
;
65 static inline LDAP_PARSE
*impl_from_IParseDisplayName(IParseDisplayName
*iface
)
67 return CONTAINING_RECORD(iface
, LDAP_PARSE
, IParseDisplayName_iface
);
70 static HRESULT WINAPI
ldap_QueryInterface(IParseDisplayName
*iface
, REFIID riid
, void **obj
)
72 TRACE("%p,%s,%p\n", iface
, debugstr_guid(riid
), obj
);
74 if (!riid
|| !obj
) return E_INVALIDARG
;
76 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
77 IsEqualGUID(riid
, &IID_IParseDisplayName
))
79 IParseDisplayName_AddRef(iface
);
85 FIXME("interface %s is not implemented\n", debugstr_guid(riid
));
89 static ULONG WINAPI
ldap_AddRef(IParseDisplayName
*iface
)
91 LDAP_PARSE
*ldap
= impl_from_IParseDisplayName(iface
);
92 return InterlockedIncrement(&ldap
->ref
);
95 static ULONG WINAPI
ldap_Release(IParseDisplayName
*iface
)
97 LDAP_PARSE
*ldap
= impl_from_IParseDisplayName(iface
);
98 LONG ref
= InterlockedDecrement(&ldap
->ref
);
102 TRACE("destroying %p\n", iface
);
109 static HRESULT WINAPI
ldap_ParseDisplayName(IParseDisplayName
*iface
, IBindCtx
*bc
,
110 LPOLESTR name
, ULONG
*eaten
, IMoniker
**mk
)
113 IADsOpenDSObject
*ads_open
;
116 TRACE("%p,%p,%s,%p,%p\n", iface
, bc
, debugstr_w(name
), eaten
, mk
);
118 hr
= LDAPNamespace_create(&IID_IADsOpenDSObject
, (void **)&ads_open
);
119 if (hr
!= S_OK
) return hr
;
121 hr
= IADsOpenDSObject_OpenDSObject(ads_open
, name
, NULL
, NULL
, ADS_SECURE_AUTHENTICATION
, &disp
);
123 hr
= IADsOpenDSObject_OpenDSObject(ads_open
, name
, NULL
, NULL
, 0, &disp
);
126 hr
= CreatePointerMoniker((IUnknown
*)disp
, mk
);
128 *eaten
= wcslen(name
);
130 IDispatch_Release(disp
);
133 IADsOpenDSObject_Release(ads_open
);
138 static const IParseDisplayNameVtbl LDAP_PARSE_vtbl
=
143 ldap_ParseDisplayName
146 static HRESULT
LDAP_create(REFIID riid
, void **obj
)
151 ldap
= heap_alloc(sizeof(*ldap
));
152 if (!ldap
) return E_OUTOFMEMORY
;
154 ldap
->IParseDisplayName_iface
.lpVtbl
= &LDAP_PARSE_vtbl
;
157 hr
= IParseDisplayName_QueryInterface(&ldap
->IParseDisplayName_iface
, riid
, obj
);
158 IParseDisplayName_Release(&ldap
->IParseDisplayName_iface
);
165 IADsADSystemInfo IADsADSystemInfo_iface
;
169 static inline AD_sysinfo
*impl_from_IADsADSystemInfo(IADsADSystemInfo
*iface
)
171 return CONTAINING_RECORD(iface
, AD_sysinfo
, IADsADSystemInfo_iface
);
174 static HRESULT WINAPI
sysinfo_QueryInterface(IADsADSystemInfo
*iface
, REFIID riid
, void **obj
)
176 TRACE("%p,%s,%p\n", iface
, debugstr_guid(riid
), obj
);
178 if (!riid
|| !obj
) return E_INVALIDARG
;
180 if (IsEqualGUID(riid
, &IID_IADsADSystemInfo
) ||
181 IsEqualGUID(riid
, &IID_IDispatch
) ||
182 IsEqualGUID(riid
, &IID_IUnknown
))
184 IADsADSystemInfo_AddRef(iface
);
190 FIXME("interface %s is not implemented\n", debugstr_guid(riid
));
191 return E_NOINTERFACE
;
194 static ULONG WINAPI
sysinfo_AddRef(IADsADSystemInfo
*iface
)
196 AD_sysinfo
*sysinfo
= impl_from_IADsADSystemInfo(iface
);
197 return InterlockedIncrement(&sysinfo
->ref
);
200 static ULONG WINAPI
sysinfo_Release(IADsADSystemInfo
*iface
)
202 AD_sysinfo
*sysinfo
= impl_from_IADsADSystemInfo(iface
);
203 LONG ref
= InterlockedDecrement(&sysinfo
->ref
);
207 TRACE("destroying %p\n", iface
);
214 static HRESULT WINAPI
sysinfo_GetTypeInfoCount(IADsADSystemInfo
*iface
, UINT
*count
)
216 FIXME("%p,%p: stub\n", iface
, count
);
220 static HRESULT WINAPI
sysinfo_GetTypeInfo(IADsADSystemInfo
*iface
, UINT index
, LCID lcid
, ITypeInfo
**info
)
222 FIXME("%p,%u,%#x,%p: stub\n", iface
, index
, lcid
, info
);
226 static HRESULT WINAPI
sysinfo_GetIDsOfNames(IADsADSystemInfo
*iface
, REFIID riid
, LPOLESTR
*names
,
227 UINT count
, LCID lcid
, DISPID
*dispid
)
229 FIXME("%p,%s,%p,%u,%u,%p: stub\n", iface
, debugstr_guid(riid
), names
, count
, lcid
, dispid
);
233 static HRESULT WINAPI
sysinfo_Invoke(IADsADSystemInfo
*iface
, DISPID dispid
, REFIID riid
, LCID lcid
, WORD flags
,
234 DISPPARAMS
*params
, VARIANT
*result
, EXCEPINFO
*excepinfo
, UINT
*argerr
)
236 FIXME("%p,%d,%s,%04x,%04x,%p,%p,%p,%p: stub\n", iface
, dispid
, debugstr_guid(riid
), lcid
, flags
,
237 params
, result
, excepinfo
, argerr
);
241 static HRESULT WINAPI
sysinfo_get_UserName(IADsADSystemInfo
*iface
, BSTR
*retval
)
243 FIXME("%p,%p: stub\n", iface
, retval
);
247 static HRESULT WINAPI
sysinfo_get_ComputerName(IADsADSystemInfo
*iface
, BSTR
*retval
)
252 TRACE("%p,%p\n", iface
, retval
);
255 GetComputerObjectNameW(NameFullyQualifiedDN
, NULL
, &size
);
256 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
257 return HRESULT_FROM_WIN32(GetLastError());
259 name
= SysAllocStringLen(NULL
, size
);
260 if (!name
) return E_OUTOFMEMORY
;
262 if (!GetComputerObjectNameW(NameFullyQualifiedDN
, name
, &size
))
265 return HRESULT_FROM_WIN32(GetLastError());
272 static HRESULT WINAPI
sysinfo_get_SiteName(IADsADSystemInfo
*iface
, BSTR
*retval
)
274 FIXME("%p,%p: stub\n", iface
, retval
);
278 static HRESULT WINAPI
sysinfo_get_DomainShortName(IADsADSystemInfo
*iface
, BSTR
*retval
)
280 FIXME("%p,%p: stub\n", iface
, retval
);
284 static HRESULT WINAPI
sysinfo_get_DomainDNSName(IADsADSystemInfo
*iface
, BSTR
*retval
)
286 FIXME("%p,%p: stub\n", iface
, retval
);
290 static HRESULT WINAPI
sysinfo_get_ForestDNSName(IADsADSystemInfo
*iface
, BSTR
*retval
)
292 FIXME("%p,%p: stub\n", iface
, retval
);
296 static HRESULT WINAPI
sysinfo_get_PDCRoleOwner(IADsADSystemInfo
*iface
, BSTR
*retval
)
298 FIXME("%p,%p: stub\n", iface
, retval
);
302 static HRESULT WINAPI
sysinfo_get_SchemaRoleOwner(IADsADSystemInfo
*iface
, BSTR
*retval
)
304 FIXME("%p,%p: stub\n", iface
, retval
);
308 static HRESULT WINAPI
sysinfo_get_IsNativeMode(IADsADSystemInfo
*iface
, VARIANT_BOOL
*retval
)
310 FIXME("%p,%p: stub\n", iface
, retval
);
314 static HRESULT WINAPI
sysinfo_GetAnyDCName(IADsADSystemInfo
*iface
, BSTR
*retval
)
316 FIXME("%p,%p: stub\n", iface
, retval
);
320 static HRESULT WINAPI
sysinfo_GetDCSiteName(IADsADSystemInfo
*iface
, BSTR server
, BSTR
*retval
)
322 FIXME("%p,%s,%p: stub\n", iface
, debugstr_w(server
), retval
);
326 static HRESULT WINAPI
sysinfo_RefreshSchemaCache(IADsADSystemInfo
*iface
)
328 FIXME("%p: stub\n", iface
);
332 static HRESULT WINAPI
sysinfo_GetTrees(IADsADSystemInfo
*iface
, VARIANT
*retval
)
334 FIXME("%p,%p: stub\n", iface
, retval
);
338 static const IADsADSystemInfoVtbl IADsADSystemInfo_vtbl
=
340 sysinfo_QueryInterface
,
343 sysinfo_GetTypeInfoCount
,
345 sysinfo_GetIDsOfNames
,
347 sysinfo_get_UserName
,
348 sysinfo_get_ComputerName
,
349 sysinfo_get_SiteName
,
350 sysinfo_get_DomainShortName
,
351 sysinfo_get_DomainDNSName
,
352 sysinfo_get_ForestDNSName
,
353 sysinfo_get_PDCRoleOwner
,
354 sysinfo_get_SchemaRoleOwner
,
355 sysinfo_get_IsNativeMode
,
356 sysinfo_GetAnyDCName
,
357 sysinfo_GetDCSiteName
,
358 sysinfo_RefreshSchemaCache
,
362 static HRESULT
ADSystemInfo_create(REFIID riid
, void **obj
)
367 sysinfo
= heap_alloc(sizeof(*sysinfo
));
368 if (!sysinfo
) return E_OUTOFMEMORY
;
370 sysinfo
->IADsADSystemInfo_iface
.lpVtbl
= &IADsADSystemInfo_vtbl
;
373 hr
= IADsADSystemInfo_QueryInterface(&sysinfo
->IADsADSystemInfo_iface
, riid
, obj
);
374 IADsADSystemInfo_Release(&sysinfo
->IADsADSystemInfo_iface
);
379 struct ldap_attribute
388 IADsOpenDSObject IADsOpenDSObject_iface
;
389 IDirectorySearch IDirectorySearch_iface
;
390 IDirectoryObject IDirectoryObject_iface
;
396 ULONG attrs_count
, attrs_count_allocated
;
397 struct ldap_attribute
*attrs
;
398 struct attribute_type
*at
;
399 ULONG at_single_count
, at_multiple_count
;
405 BOOL attribtypes_only
;
410 struct ldap_search_context
412 LDAPMessage
*res
, *entry
;
418 static inline LDAP_namespace
*impl_from_IADs(IADs
*iface
)
420 return CONTAINING_RECORD(iface
, LDAP_namespace
, IADs_iface
);
423 static HRESULT WINAPI
ldapns_QueryInterface(IADs
*iface
, REFIID riid
, void **obj
)
425 LDAP_namespace
*ldap
= impl_from_IADs(iface
);
427 TRACE("%p,%s,%p\n", iface
, debugstr_guid(riid
), obj
);
429 if (!riid
|| !obj
) return E_INVALIDARG
;
431 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
432 IsEqualGUID(riid
, &IID_IDispatch
) ||
433 IsEqualGUID(riid
, &IID_IADs
))
440 if (IsEqualGUID(riid
, &IID_IADsOpenDSObject
))
443 *obj
= &ldap
->IADsOpenDSObject_iface
;
447 if (IsEqualGUID(riid
, &IID_IDirectorySearch
))
449 if (!ldap
->ld
|| (ldap
->object
&& !wcsicmp(ldap
->object
, L
"rootDSE")))
450 return E_NOINTERFACE
;
453 *obj
= &ldap
->IDirectorySearch_iface
;
457 if (IsEqualGUID(riid
, &IID_IDirectoryObject
))
460 *obj
= &ldap
->IDirectoryObject_iface
;
464 FIXME("interface %s is not implemented\n", debugstr_guid(riid
));
465 return E_NOINTERFACE
;
468 static ULONG WINAPI
ldapns_AddRef(IADs
*iface
)
470 LDAP_namespace
*ldap
= impl_from_IADs(iface
);
471 return InterlockedIncrement(&ldap
->ref
);
474 static void free_attributes(LDAP_namespace
*ldap
)
478 if (!ldap
->attrs
) return;
480 for (i
= 0; i
< ldap
->attrs_count
; i
++)
482 ldap_memfreeW(ldap
->attrs
[i
].name
);
483 ldap_value_freeW(ldap
->attrs
[i
].values
);
486 heap_free(ldap
->attrs
);
488 ldap
->attrs_count
= 0;
491 static ULONG WINAPI
ldapns_Release(IADs
*iface
)
493 LDAP_namespace
*ldap
= impl_from_IADs(iface
);
494 LONG ref
= InterlockedDecrement(&ldap
->ref
);
498 TRACE("destroying %p\n", iface
);
499 if (ldap
->ld
) ldap_unbind(ldap
->ld
);
500 SysFreeString(ldap
->host
);
501 SysFreeString(ldap
->object
);
502 free_attributes(ldap
);
503 free_attribute_types(ldap
->at
, ldap
->at_single_count
+ ldap
->at_multiple_count
);
510 static HRESULT WINAPI
ldapns_GetTypeInfoCount(IADs
*iface
, UINT
*count
)
512 FIXME("%p,%p: stub\n", iface
, count
);
516 static HRESULT WINAPI
ldapns_GetTypeInfo(IADs
*iface
, UINT index
, LCID lcid
, ITypeInfo
**info
)
518 FIXME("%p,%u,%#x,%p: stub\n", iface
, index
, lcid
, info
);
522 static HRESULT WINAPI
ldapns_GetIDsOfNames(IADs
*iface
, REFIID riid
, LPOLESTR
*names
,
523 UINT count
, LCID lcid
, DISPID
*dispid
)
525 FIXME("%p,%s,%p,%u,%u,%p: stub\n", iface
, debugstr_guid(riid
), names
, count
, lcid
, dispid
);
529 static HRESULT WINAPI
ldapns_Invoke(IADs
*iface
, DISPID dispid
, REFIID riid
, LCID lcid
, WORD flags
,
530 DISPPARAMS
*params
, VARIANT
*result
, EXCEPINFO
*excepinfo
, UINT
*argerr
)
532 FIXME("%p,%d,%s,%04x,%04x,%p,%p,%p,%p: stub\n", iface
, dispid
, debugstr_guid(riid
), lcid
, flags
,
533 params
, result
, excepinfo
, argerr
);
537 static HRESULT WINAPI
ldapns_get_Name(IADs
*iface
, BSTR
*retval
)
539 FIXME("%p,%p: stub\n", iface
, retval
);
543 static HRESULT WINAPI
ldapns_get_Class(IADs
*iface
, BSTR
*retval
)
545 FIXME("%p,%p: stub\n", iface
, retval
);
549 static HRESULT WINAPI
ldapns_get_GUID(IADs
*iface
, BSTR
*retval
)
551 FIXME("%p,%p: stub\n", iface
, retval
);
555 static HRESULT WINAPI
ldapns_get_ADsPath(IADs
*iface
, BSTR
*retval
)
557 FIXME("%p,%p: stub\n", iface
, retval
);
561 static HRESULT WINAPI
ldapns_get_Parent(IADs
*iface
, BSTR
*retval
)
563 FIXME("%p,%p: stub\n", iface
, retval
);
567 static HRESULT WINAPI
ldapns_get_Schema(IADs
*iface
, BSTR
*retval
)
569 FIXME("%p,%p: stub\n", iface
, retval
);
573 static HRESULT WINAPI
ldapns_GetInfo(IADs
*iface
)
578 TRACE("%p\n", iface
);
580 hr
= ADsBuildVarArrayStr(NULL
, 0, &var
);
583 hr
= IADs_GetInfoEx(iface
, var
, 0);
589 static HRESULT WINAPI
ldapns_SetInfo(IADs
*iface
)
591 FIXME("%p: stub\n", iface
);
595 static HRESULT WINAPI
ldapns_Get(IADs
*iface
, BSTR name
, VARIANT
*prop
)
597 LDAP_namespace
*ldap
= impl_from_IADs(iface
);
601 TRACE("%p,%s,%p\n", iface
, debugstr_w(name
), prop
);
603 if (!name
|| !prop
) return E_ADS_BAD_PARAMETER
;
605 if (!ldap
->attrs_count
)
607 hr
= IADs_GetInfo(iface
);
608 if (hr
!= S_OK
) return hr
;
611 for (i
= 0; i
< ldap
->attrs_count
; i
++)
613 if (!wcsicmp(name
, ldap
->attrs
[i
].name
))
615 LONG count
= ldap_count_valuesW(ldap
->attrs
[i
].values
);
619 V_VT(prop
) = VT_BSTR
;
629 TRACE("attr %s has %u values\n", debugstr_w(ldap
->attrs
[i
].name
), count
);
631 sa
= SafeArrayCreateVector(VT_VARIANT
, 0, count
);
632 if (!sa
) return E_OUTOFMEMORY
;
634 for (idx
= 0; idx
< count
; idx
++)
636 TRACE("=> %s\n", debugstr_w(ldap
->attrs
[i
].values
[idx
]));
637 V_VT(&item
) = VT_BSTR
;
638 V_BSTR(&item
) = SysAllocString(ldap
->attrs
[i
].values
[idx
]);
645 hr
= SafeArrayPutElement(sa
, &idx
, &item
);
646 SysFreeString(V_BSTR(&item
));
647 if (hr
!= S_OK
) goto fail
;
650 V_VT(prop
) = VT_ARRAY
| VT_VARIANT
;
654 SafeArrayDestroy(sa
);
659 TRACE("=> %s\n", debugstr_w(ldap
->attrs
[i
].values
[0]));
660 V_BSTR(prop
) = SysAllocString(ldap
->attrs
[i
].values
[0]);
661 if (!V_BSTR(prop
)) return E_OUTOFMEMORY
;
662 V_VT(prop
) = VT_BSTR
;
668 return E_ADS_PROPERTY_NOT_FOUND
;
671 static HRESULT WINAPI
ldapns_Put(IADs
*iface
, BSTR name
, VARIANT prop
)
673 FIXME("%p,%s,%s: stub\n", iface
, debugstr_w(name
), wine_dbgstr_variant(&prop
));
677 static HRESULT WINAPI
ldapns_GetEx(IADs
*iface
, BSTR name
, VARIANT
*prop
)
679 FIXME("%p,%s,%p: stub\n", iface
, debugstr_w(name
), prop
);
683 static HRESULT WINAPI
ldapns_PutEx(IADs
*iface
, LONG code
, BSTR name
, VARIANT prop
)
685 FIXME("%p,%d,%s,%s: stub\n", iface
, code
, debugstr_w(name
), wine_dbgstr_variant(&prop
));
689 static HRESULT
add_attribute(LDAP_namespace
*ldap
, WCHAR
*name
, WCHAR
**values
)
691 struct ldap_attribute
*new_attrs
;
695 ldap
->attrs
= heap_alloc(256 * sizeof(ldap
->attrs
[0]));
696 if (!ldap
->attrs
) return E_OUTOFMEMORY
;
697 ldap
->attrs_count_allocated
= 256;
699 else if (ldap
->attrs_count_allocated
< ldap
->attrs_count
+ 1)
701 new_attrs
= heap_realloc(ldap
->attrs
, (ldap
->attrs_count_allocated
* 2) * sizeof(*new_attrs
));
702 if (!new_attrs
) return E_OUTOFMEMORY
;
704 ldap
->attrs_count_allocated
*= 2;
705 ldap
->attrs
= new_attrs
;
708 ldap
->attrs
[ldap
->attrs_count
].name
= name
;
709 ldap
->attrs
[ldap
->attrs_count
].values
= values
;
715 static HRESULT WINAPI
ldapns_GetInfoEx(IADs
*iface
, VARIANT prop
, LONG reserved
)
717 LDAP_namespace
*ldap
= impl_from_IADs(iface
);
721 WCHAR
**props
= NULL
, *attr
, **values
;
723 LDAPMessage
*res
= NULL
, *entry
;
726 TRACE("%p,%s,%d\n", iface
, wine_dbgstr_variant(&prop
), reserved
);
728 free_attributes(ldap
);
730 if (!ldap
->ld
) return E_NOTIMPL
;
732 if (V_VT(&prop
) != (VT_ARRAY
| VT_VARIANT
))
733 return E_ADS_BAD_PARAMETER
;
737 return E_ADS_BAD_PARAMETER
;
739 hr
= SafeArrayAccessData(sa
, (void *)&item
);
740 if (hr
!= S_OK
) return hr
;
742 count
= sa
->rgsabound
[0].cElements
;
745 props
= heap_alloc((count
+ 1) * sizeof(props
[0]));
752 for (i
= 0; i
< count
; i
++)
754 if (V_VT(&item
[i
]) != VT_BSTR
)
756 hr
= E_ADS_BAD_PARAMETER
;
759 props
[i
] = V_BSTR(&item
[i
]);
761 props
[sa
->rgsabound
[0].cElements
] = NULL
;
764 err
= ldap_search_sW(ldap
->ld
, NULL
, LDAP_SCOPE_BASE
, (WCHAR
*)L
"(objectClass=*)", props
, FALSE
, &res
);
765 if (err
!= LDAP_SUCCESS
)
767 TRACE("ldap_search_sW error %#x\n", err
);
768 hr
= HRESULT_FROM_WIN32(map_ldap_error(err
));
772 entry
= ldap_first_entry(ldap
->ld
, res
);
775 attr
= ldap_first_attributeW(ldap
->ld
, entry
, &ber
);
778 TRACE("attr: %s\n", debugstr_w(attr
));
780 values
= ldap_get_valuesW(ldap
->ld
, entry
, attr
);
782 hr
= add_attribute(ldap
, attr
, values
);
785 ldap_value_freeW(values
);
790 attr
= ldap_next_attributeW(ldap
->ld
, entry
, ber
);
793 entry
= ldap_next_entry(ldap
->ld
, res
);
797 if (res
) ldap_msgfree(res
);
799 SafeArrayUnaccessData(sa
);
803 static const IADsVtbl IADs_vtbl
=
805 ldapns_QueryInterface
,
808 ldapns_GetTypeInfoCount
,
810 ldapns_GetIDsOfNames
,
827 static inline LDAP_namespace
*impl_from_IADsOpenDSObject(IADsOpenDSObject
*iface
)
829 return CONTAINING_RECORD(iface
, LDAP_namespace
, IADsOpenDSObject_iface
);
832 static HRESULT WINAPI
openobj_QueryInterface(IADsOpenDSObject
*iface
, REFIID riid
, void **obj
)
834 TRACE("%p,%s,%p\n", iface
, debugstr_guid(riid
), obj
);
836 if (!riid
|| !obj
) return E_INVALIDARG
;
838 if (IsEqualGUID(riid
, &IID_IADsOpenDSObject
) ||
839 IsEqualGUID(riid
, &IID_IDispatch
) ||
840 IsEqualGUID(riid
, &IID_IUnknown
))
842 IADsOpenDSObject_AddRef(iface
);
847 FIXME("interface %s is not implemented\n", debugstr_guid(riid
));
848 return E_NOINTERFACE
;
851 static ULONG WINAPI
openobj_AddRef(IADsOpenDSObject
*iface
)
853 LDAP_namespace
*ldap
= impl_from_IADsOpenDSObject(iface
);
854 return IADs_AddRef(&ldap
->IADs_iface
);
857 static ULONG WINAPI
openobj_Release(IADsOpenDSObject
*iface
)
859 LDAP_namespace
*ldap
= impl_from_IADsOpenDSObject(iface
);
860 return IADs_Release(&ldap
->IADs_iface
);
863 static HRESULT WINAPI
openobj_GetTypeInfoCount(IADsOpenDSObject
*iface
, UINT
*count
)
865 FIXME("%p,%p: stub\n", iface
, count
);
869 static HRESULT WINAPI
openobj_GetTypeInfo(IADsOpenDSObject
*iface
, UINT index
, LCID lcid
, ITypeInfo
**info
)
871 FIXME("%p,%u,%#x,%p: stub\n", iface
, index
, lcid
, info
);
875 static HRESULT WINAPI
openobj_GetIDsOfNames(IADsOpenDSObject
*iface
, REFIID riid
, LPOLESTR
*names
,
876 UINT count
, LCID lcid
, DISPID
*dispid
)
878 FIXME("%p,%s,%p,%u,%u,%p: stub\n", iface
, debugstr_guid(riid
), names
, count
, lcid
, dispid
);
882 static HRESULT WINAPI
openobj_Invoke(IADsOpenDSObject
*iface
, DISPID dispid
, REFIID riid
, LCID lcid
, WORD flags
,
883 DISPPARAMS
*params
, VARIANT
*result
, EXCEPINFO
*excepinfo
, UINT
*argerr
)
885 FIXME("%p,%d,%s,%04x,%04x,%p,%p,%p,%p: stub\n", iface
, dispid
, debugstr_guid(riid
), lcid
, flags
,
886 params
, result
, excepinfo
, argerr
);
890 static HRESULT
parse_path(WCHAR
*path
, BSTR
*host
, ULONG
*port
, BSTR
*object
)
895 if (host
) *host
= NULL
;
897 if (object
) *object
= NULL
;
899 if (wcsnicmp(path
, L
"LDAP:", 5) != 0)
900 return E_ADS_BAD_PATHNAME
;
903 if (!*p
) return S_OK
;
905 if (*p
++ != '/' || *p
++ != '/' || !*p
)
906 return E_ADS_BAD_PATHNAME
;
910 while (*p
&& *p
!= '/')
915 if (!port
) port
= &dummy
;
916 *port
= wcstol(p
+ 1, &p
, 10);
917 if (*p
&& *p
!= '/') return E_ADS_BAD_PATHNAME
;
925 if (host_len
== 0) return E_ADS_BAD_PATHNAME
;
929 *host
= SysAllocStringLen(p_host
, host_len
);
930 if (!*host
) return E_OUTOFMEMORY
;
933 if (!*p
) return S_OK
;
935 if (*p
++ != '/' || !*p
)
937 SysFreeString(*host
);
938 return E_ADS_BAD_PATHNAME
;
943 *object
= SysAllocString(p
);
946 SysFreeString(*host
);
947 return E_OUTOFMEMORY
;
954 static HRESULT WINAPI
openobj_OpenDSObject(IADsOpenDSObject
*iface
, BSTR path
, BSTR user
, BSTR password
,
955 LONG flags
, IDispatch
**obj
)
962 ULONG err
, at_single_count
= 0, at_multiple_count
= 0;
963 struct attribute_type
*at
= NULL
;
965 TRACE("%p,%s,%s,%p,%08x,%p\n", iface
, debugstr_w(path
), debugstr_w(user
), password
, flags
, obj
);
967 hr
= parse_path(path
, &host
, &port
, &object
);
968 if (hr
!= S_OK
) return hr
;
970 TRACE("host %s, port %u, object %s\n", debugstr_w(host
), port
, debugstr_w(object
));
976 if (!wcsicmp(host
, L
"rootDSE"))
978 DOMAIN_CONTROLLER_INFOW
*dcinfo
;
982 hr
= E_ADS_BAD_PATHNAME
;
988 err
= DsGetDcNameW(NULL
, NULL
, NULL
, NULL
, DS_RETURN_DNS_NAME
, &dcinfo
);
989 if (err
!= ERROR_SUCCESS
)
991 hr
= HRESULT_FROM_WIN32(LdapGetLastError());
995 host
= SysAllocString(dcinfo
->DomainName
);
996 NetApiBufferFree(dcinfo
);
1005 ld
= ldap_initW(host
, port
);
1008 hr
= HRESULT_FROM_WIN32(LdapGetLastError());
1012 version
= LDAP_VERSION3
;
1013 err
= ldap_set_optionW(ld
, LDAP_OPT_PROTOCOL_VERSION
, &version
);
1014 if (err
!= LDAP_SUCCESS
)
1016 hr
= HRESULT_FROM_WIN32(map_ldap_error(err
));
1021 err
= ldap_connect(ld
, NULL
);
1022 if (err
!= LDAP_SUCCESS
)
1024 hr
= HRESULT_FROM_WIN32(map_ldap_error(err
));
1029 if (flags
& ADS_SECURE_AUTHENTICATION
)
1031 SEC_WINNT_AUTH_IDENTITY_W id
;
1033 id
.Flags
= SEC_WINNT_AUTH_IDENTITY_UNICODE
;
1034 id
.Domain
= (unsigned short *)host
;
1035 id
.DomainLength
= wcslen(host
);
1036 id
.User
= (unsigned short *)user
;
1037 id
.UserLength
= user
? wcslen(user
) : 0;
1038 id
.Password
= (unsigned short *)password
;
1039 id
.PasswordLength
= password
? wcslen(password
) : 0;
1041 err
= ldap_bind_sW(ld
, NULL
, (WCHAR
*)&id
, LDAP_AUTH_NEGOTIATE
);
1042 if (err
!= LDAP_SUCCESS
)
1044 TRACE("ldap_bind_sW error %#x\n", err
);
1045 hr
= HRESULT_FROM_WIN32(map_ldap_error(err
));
1052 err
= ldap_simple_bind_sW(ld
, user
, password
);
1053 if (err
!= LDAP_SUCCESS
)
1055 TRACE("ldap_simple_bind_sW error %#x\n", err
);
1056 hr
= HRESULT_FROM_WIN32(map_ldap_error(err
));
1062 at
= load_schema(ld
, &at_single_count
, &at_multiple_count
);
1065 hr
= LDAPNamespace_create(&IID_IADs
, (void **)&ads
);
1068 LDAP_namespace
*ldap
= impl_from_IADs(ads
);
1072 ldap
->object
= object
;
1074 ldap
->at_single_count
= at_single_count
;
1075 ldap
->at_multiple_count
= at_multiple_count
;
1076 hr
= IADs_QueryInterface(ads
, &IID_IDispatch
, (void **)obj
);
1082 SysFreeString(host
);
1083 SysFreeString(object
);
1088 static const IADsOpenDSObjectVtbl IADsOpenDSObject_vtbl
=
1090 openobj_QueryInterface
,
1093 openobj_GetTypeInfoCount
,
1094 openobj_GetTypeInfo
,
1095 openobj_GetIDsOfNames
,
1097 openobj_OpenDSObject
1100 static inline LDAP_namespace
*impl_from_IDirectorySearch(IDirectorySearch
*iface
)
1102 return CONTAINING_RECORD(iface
, LDAP_namespace
, IDirectorySearch_iface
);
1105 static HRESULT WINAPI
search_QueryInterface(IDirectorySearch
*iface
, REFIID riid
, void **obj
)
1107 TRACE("%p,%s,%p\n", iface
, debugstr_guid(riid
), obj
);
1109 if (!riid
|| !obj
) return E_INVALIDARG
;
1111 if (IsEqualGUID(riid
, &IID_IDirectorySearch
) ||
1112 IsEqualGUID(riid
, &IID_IUnknown
))
1114 IDirectorySearch_AddRef(iface
);
1119 FIXME("interface %s is not implemented\n", debugstr_guid(riid
));
1120 return E_NOINTERFACE
;
1123 static ULONG WINAPI
search_AddRef(IDirectorySearch
*iface
)
1125 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1126 return IADs_AddRef(&ldap
->IADs_iface
);
1129 static ULONG WINAPI
search_Release(IDirectorySearch
*iface
)
1131 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1132 return IADs_Release(&ldap
->IADs_iface
);
1135 static HRESULT WINAPI
search_SetSearchPreference(IDirectorySearch
*iface
, PADS_SEARCHPREF_INFO prefs
, DWORD count
)
1137 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1141 TRACE("%p,%p,%u\n", iface
, prefs
, count
);
1143 for (i
= 0; i
< count
; i
++)
1145 switch (prefs
[i
].dwSearchPref
)
1147 case ADS_SEARCHPREF_SEARCH_SCOPE
:
1148 if (prefs
[i
].vValue
.dwType
!= ADSTYPE_INTEGER
)
1150 FIXME("ADS_SEARCHPREF_SEACH_SCOPE: not supportd dwType %d\n", prefs
[i
].vValue
.dwType
);
1151 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1155 switch (prefs
[i
].vValue
.u
.Integer
)
1157 case ADS_SCOPE_BASE
:
1158 case ADS_SCOPE_ONELEVEL
:
1159 case ADS_SCOPE_SUBTREE
:
1160 TRACE("SEARCH_SCOPE: %d\n", prefs
[i
].vValue
.u
.Integer
);
1161 ldap
->search
.scope
= prefs
[i
].vValue
.u
.Integer
;
1162 prefs
[i
].dwStatus
= ADS_STATUS_S_OK
;
1166 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1171 case ADS_SEARCHPREF_SECURITY_MASK
:
1176 struct berval
*berval
;
1177 LDAPControlW
*ctrls
[2], mask
;
1179 if (prefs
[i
].vValue
.dwType
!= ADSTYPE_INTEGER
)
1181 FIXME("ADS_SEARCHPREF_SECURITY_MASK: not supportd dwType %d\n", prefs
[i
].vValue
.dwType
);
1182 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1186 TRACE("SECURITY_MASK: %08x\n", prefs
[i
].vValue
.u
.Integer
);
1187 security_mask
= prefs
[i
].vValue
.u
.Integer
;
1189 security_mask
= ADS_SECURITY_INFO_OWNER
;
1191 ber
= ber_alloc_t(LBER_USE_DER
);
1192 if (!ber
|| ber_printf(ber
, (char *)"{i}", security_mask
) == -1 || ber_flatten(ber
, &berval
) == -1)
1195 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREF
;
1198 TRACE("ber: %s\n", debugstr_an(berval
->bv_val
, berval
->bv_len
));
1200 mask
.ldctl_oid
= (WCHAR
*)L
"1.2.840.113556.1.4.801";
1201 mask
.ldctl_iscritical
= TRUE
;
1202 mask
.ldctl_value
.bv_val
= berval
->bv_val
;
1203 mask
.ldctl_value
.bv_len
= berval
->bv_len
;
1206 err
= ldap_set_optionW(ldap
->ld
, LDAP_OPT_SERVER_CONTROLS
, ctrls
);
1207 if (err
!= LDAP_SUCCESS
)
1209 TRACE("ldap_set_option error %#x\n", err
);
1210 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREF
;
1211 hr
= S_ADS_ERRORSOCCURRED
;
1214 prefs
[i
].dwStatus
= ADS_STATUS_S_OK
;
1221 case ADS_SEARCHPREF_PAGESIZE
:
1222 if (prefs
[i
].vValue
.dwType
!= ADSTYPE_INTEGER
)
1224 FIXME("ADS_SEARCHPREF_PAGESIZE: not supportd dwType %d\n", prefs
[i
].vValue
.dwType
);
1225 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1229 TRACE("PAGESIZE: %d\n", prefs
[i
].vValue
.u
.Integer
);
1230 ldap
->search
.pagesize
= prefs
[i
].vValue
.u
.Integer
;
1231 prefs
[i
].dwStatus
= ADS_STATUS_S_OK
;
1234 case ADS_SEARCHPREF_CACHE_RESULTS
:
1235 if (prefs
[i
].vValue
.dwType
!= ADSTYPE_BOOLEAN
)
1237 FIXME("ADS_SEARCHPREF_CACHE_RESULTS: not supportd dwType %d\n", prefs
[i
].vValue
.dwType
);
1238 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1242 TRACE("CACHE_RESULTS: %d\n", prefs
[i
].vValue
.u
.Boolean
);
1243 ldap
->search
.cache_results
= prefs
[i
].vValue
.u
.Boolean
;
1244 prefs
[i
].dwStatus
= ADS_STATUS_S_OK
;
1247 case ADS_SEARCHPREF_ATTRIBTYPES_ONLY
:
1248 if (prefs
[i
].vValue
.dwType
!= ADSTYPE_BOOLEAN
)
1250 FIXME("ADS_SEARCHPREF_ATTRIBTYPES_ONLY: not supportd dwType %d\n", prefs
[i
].vValue
.dwType
);
1251 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1255 TRACE("ATTRIBTYPES_ONLY: %d\n", prefs
[i
].vValue
.u
.Boolean
);
1256 ldap
->search
.attribtypes_only
= prefs
[i
].vValue
.u
.Boolean
;
1257 prefs
[i
].dwStatus
= ADS_STATUS_S_OK
;
1260 case ADS_SEARCHPREF_TOMBSTONE
:
1261 if (prefs
[i
].vValue
.dwType
!= ADSTYPE_BOOLEAN
)
1263 FIXME("ADS_SEARCHPREF_TOMBSTONE: not supportd dwType %d\n", prefs
[i
].vValue
.dwType
);
1264 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1268 TRACE("TOMBSTONE: %d\n", prefs
[i
].vValue
.u
.Boolean
);
1269 ldap
->search
.tombstone
= prefs
[i
].vValue
.u
.Boolean
;
1270 prefs
[i
].dwStatus
= ADS_STATUS_S_OK
;
1274 FIXME("pref %d, type %u: stub\n", prefs
[i
].dwSearchPref
, prefs
[i
].vValue
.dwType
);
1275 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREF
;
1283 static HRESULT WINAPI
search_ExecuteSearch(IDirectorySearch
*iface
, LPWSTR filter
, LPWSTR
*names
,
1284 DWORD count
, PADS_SEARCH_HANDLE res
)
1286 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1289 struct ldap_search_context
*ldap_ctx
;
1291 TRACE("%p,%s,%p,%u,%p\n", iface
, debugstr_w(filter
), names
, count
, res
);
1293 if (!res
) return E_ADS_BAD_PARAMETER
;
1295 ldap_ctx
= heap_alloc_zero(sizeof(*ldap_ctx
));
1296 if (!ldap_ctx
) return E_OUTOFMEMORY
;
1298 if (count
== 0xffffffff)
1302 if (count
&& !names
) return E_ADS_BAD_PARAMETER
;
1304 props
= heap_alloc((count
+ 1) * sizeof(props
[0]));
1307 heap_free(ldap_ctx
);
1308 return E_OUTOFMEMORY
;
1311 for (i
= 0; i
< count
; i
++)
1313 TRACE("=> %s\n", debugstr_w(names
[i
]));
1314 props
[i
] = names
[i
];
1317 props
[count
] = NULL
;
1320 err
= ldap_search_sW(ldap
->ld
, ldap
->object
, ldap
->search
.scope
, filter
, props
, ldap
->search
.attribtypes_only
, &ldap_ctx
->res
);
1322 if (err
!= LDAP_SUCCESS
)
1324 TRACE("ldap_search_sW error %#x\n", err
);
1325 heap_free(ldap_ctx
);
1326 return HRESULT_FROM_WIN32(map_ldap_error(err
));
1333 static HRESULT WINAPI
search_AbandonSearch(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
)
1335 FIXME("%p,%p: stub\n", iface
, res
);
1339 static HRESULT WINAPI
search_GetFirstRow(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
)
1341 struct ldap_search_context
*ldap_ctx
= res
;
1343 TRACE("%p,%p\n", iface
, res
);
1345 if (!res
) return E_ADS_BAD_PARAMETER
;
1347 ldap_ctx
->entry
= NULL
;
1349 return IDirectorySearch_GetNextRow(iface
, res
);
1352 static HRESULT WINAPI
search_GetNextRow(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
)
1354 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1355 struct ldap_search_context
*ldap_ctx
= res
;
1357 TRACE("%p,%p\n", iface
, res
);
1359 if (!res
) return E_ADS_BAD_PARAMETER
;
1361 if (!ldap_ctx
->entry
)
1363 ldap_ctx
->count
= ldap_count_entries(ldap
->ld
, ldap_ctx
->res
);
1366 if (ldap_ctx
->pos
>= ldap_ctx
->count
)
1367 return S_ADS_NOMORE_ROWS
;
1369 ldap_ctx
->entry
= ldap_first_entry(ldap
->ld
, ldap_ctx
->res
);
1373 if (ldap_ctx
->pos
>= ldap_ctx
->count
)
1374 return S_ADS_NOMORE_ROWS
;
1376 ldap_ctx
->entry
= ldap_next_entry(ldap
->ld
, ldap_ctx
->entry
);
1379 if (!ldap_ctx
->entry
)
1380 return S_ADS_NOMORE_ROWS
;
1383 ldap_ctx
->ber
= NULL
;
1388 static HRESULT WINAPI
search_GetPreviousRow(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
)
1390 FIXME("%p,%p: stub\n", iface
, res
);
1394 static HRESULT WINAPI
search_GetNextColumnName(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
, LPWSTR
*name
)
1396 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1397 struct ldap_search_context
*ldap_ctx
= res
;
1400 TRACE("%p,%p,%p\n", iface
, res
, name
);
1402 if (!name
|| !ldap_ctx
|| !ldap_ctx
->entry
) return E_ADS_BAD_PARAMETER
;
1406 attr
= ldap_first_attributeW(ldap
->ld
, ldap_ctx
->entry
, &ldap_ctx
->ber
);
1407 ldap_ctx
->add_ADsPath
= TRUE
;
1410 attr
= ldap_next_attributeW(ldap
->ld
, ldap_ctx
->entry
, ldap_ctx
->ber
);
1414 TRACE("=> %s\n", debugstr_w(attr
));
1415 *name
= AllocADsStr(attr
);
1416 ldap_memfreeW(attr
);
1417 return *name
? S_OK
: E_OUTOFMEMORY
;
1419 else if (ldap_ctx
->add_ADsPath
)
1421 ldap_ctx
->add_ADsPath
= FALSE
;
1422 *name
= AllocADsStr((WCHAR
*)L
"ADsPath");
1423 TRACE("=> %s\n", debugstr_w(*name
));
1424 return *name
? S_OK
: E_OUTOFMEMORY
;
1428 return S_ADS_NOMORE_COLUMNS
;
1431 static HRESULT
add_column_values(LDAP_namespace
*ldap
, struct ldap_search_context
*ldap_ctx
,
1432 LPWSTR name
, ADS_SEARCH_COLUMN
*col
)
1437 type
= get_schema_type(name
, ldap
->at
, ldap
->at_single_count
, ldap
->at_multiple_count
);
1438 TRACE("%s => type %d\n", debugstr_w(name
), type
);
1443 FIXME("no special handling for type %d\n", type
);
1445 case ADSTYPE_DN_STRING
:
1446 case ADSTYPE_CASE_EXACT_STRING
:
1447 case ADSTYPE_CASE_IGNORE_STRING
:
1448 case ADSTYPE_PRINTABLE_STRING
:
1450 WCHAR
**values
= ldap_get_valuesW(ldap
->ld
, ldap_ctx
->entry
, name
);
1452 return E_ADS_COLUMN_NOT_SET
;
1453 count
= ldap_count_valuesW(values
);
1455 col
->pADsValues
= heap_alloc_zero(count
* sizeof(col
->pADsValues
[0]));
1456 if (!col
->pADsValues
)
1458 ldap_value_freeW(values
);
1459 return E_OUTOFMEMORY
;
1462 for (i
= 0; i
< count
; i
++)
1464 TRACE("=> %s\n", debugstr_w(values
[i
]));
1465 col
->pADsValues
[i
].dwType
= type
;
1466 col
->pADsValues
[i
].u
.CaseIgnoreString
= values
[i
];
1469 col
->hReserved
= values
;
1473 case ADSTYPE_BOOLEAN
:
1475 WCHAR
**values
= ldap_get_valuesW(ldap
->ld
, ldap_ctx
->entry
, name
);
1477 return E_ADS_COLUMN_NOT_SET
;
1478 count
= ldap_count_valuesW(values
);
1480 col
->pADsValues
= heap_alloc_zero(count
* sizeof(col
->pADsValues
[0]));
1481 if (!col
->pADsValues
)
1483 ldap_value_freeW(values
);
1484 return E_OUTOFMEMORY
;
1487 for (i
= 0; i
< count
; i
++)
1489 col
->pADsValues
[i
].dwType
= type
;
1491 if (wcsicmp(values
[i
], L
"TRUE"))
1492 col
->pADsValues
[i
].u
.Boolean
= 1;
1493 else if (wcsicmp(values
[i
], L
"FALSE"))
1494 col
->pADsValues
[i
].u
.Boolean
= 0;
1497 FIXME("not recognized boolean value %s\n", debugstr_w(values
[i
]));
1498 col
->pADsValues
[i
].u
.Boolean
= 0;
1500 TRACE("=> %d\n", col
->pADsValues
[i
].u
.Boolean
);
1503 ldap_value_freeW(values
);
1504 col
->hReserved
= NULL
;
1508 case ADSTYPE_INTEGER
:
1509 case ADSTYPE_LARGE_INTEGER
:
1511 struct berval
**values
= ldap_get_values_lenW(ldap
->ld
, ldap_ctx
->entry
, name
);
1513 return E_ADS_COLUMN_NOT_SET
;
1514 count
= ldap_count_values_len(values
);
1516 col
->pADsValues
= heap_alloc_zero(count
* sizeof(col
->pADsValues
[0]));
1517 if (!col
->pADsValues
)
1519 ldap_value_free_len(values
);
1520 return E_OUTOFMEMORY
;
1523 for (i
= 0; i
< count
; i
++)
1525 col
->pADsValues
[i
].dwType
= type
;
1527 if (type
== ADSTYPE_LARGE_INTEGER
)
1529 col
->pADsValues
[i
].u
.LargeInteger
.QuadPart
= _atoi64(values
[i
]->bv_val
);
1530 TRACE("%s => %s\n", debugstr_an(values
[i
]->bv_val
, values
[i
]->bv_len
), wine_dbgstr_longlong(col
->pADsValues
[i
].u
.LargeInteger
.QuadPart
));
1534 col
->pADsValues
[i
].u
.Integer
= atol(values
[i
]->bv_val
);
1535 TRACE("%s => %d\n", debugstr_an(values
[i
]->bv_val
, values
[i
]->bv_len
), col
->pADsValues
[i
].u
.Integer
);
1539 ldap_value_free_len(values
);
1540 col
->hReserved
= NULL
;
1544 case ADSTYPE_OCTET_STRING
:
1545 case ADSTYPE_NT_SECURITY_DESCRIPTOR
:
1547 struct berval
**values
= ldap_get_values_lenW(ldap
->ld
, ldap_ctx
->entry
, name
);
1549 return E_ADS_COLUMN_NOT_SET
;
1550 count
= ldap_count_values_len(values
);
1552 col
->pADsValues
= heap_alloc_zero(count
* sizeof(col
->pADsValues
[0]));
1553 if (!col
->pADsValues
)
1555 ldap_value_free_len(values
);
1556 return E_OUTOFMEMORY
;
1559 for (i
= 0; i
< count
; i
++)
1561 TRACE("=> %s\n", debugstr_an(values
[i
]->bv_val
, values
[i
]->bv_len
));
1562 col
->pADsValues
[i
].dwType
= type
;
1563 col
->pADsValues
[i
].u
.OctetString
.dwLength
= values
[i
]->bv_len
;
1564 col
->pADsValues
[i
].u
.OctetString
.lpValue
= (BYTE
*)values
[i
]->bv_val
;
1567 col
->hReserved
= values
;
1571 case ADSTYPE_UTC_TIME
:
1573 struct berval
**values
= ldap_get_values_lenW(ldap
->ld
, ldap_ctx
->entry
, name
);
1575 return E_ADS_COLUMN_NOT_SET
;
1576 count
= ldap_count_values_len(values
);
1578 col
->pADsValues
= heap_alloc_zero(count
* sizeof(col
->pADsValues
[0]));
1579 if (!col
->pADsValues
)
1581 ldap_value_free_len(values
);
1582 return E_OUTOFMEMORY
;
1585 for (i
= 0; i
< count
; i
++)
1587 col
->pADsValues
[i
].dwType
= type
;
1588 if (values
[i
]->bv_len
< 14 ||
1589 _snscanf_l(values
[i
]->bv_val
, values
[i
]->bv_len
, "%04u%02u%02u%02u%02u%02u", NULL
,
1590 &col
->pADsValues
[i
].u
.UTCTime
.wYear
, &col
->pADsValues
[i
].u
.UTCTime
.wMonth
,
1591 &col
->pADsValues
[i
].u
.UTCTime
.wDay
, &col
->pADsValues
[i
].u
.UTCTime
.wHour
,
1592 &col
->pADsValues
[i
].u
.UTCTime
.wMinute
, &col
->pADsValues
[i
].u
.UTCTime
.wSecond
) != 6)
1594 FIXME("not recognized UTCTime: %s\n", debugstr_an(values
[i
]->bv_val
, values
[i
]->bv_len
));
1595 memset(&col
->pADsValues
[i
].u
.UTCTime
, 0, sizeof(col
->pADsValues
[i
].u
.UTCTime
));
1599 if ((values
[i
]->bv_val
[14] != '.' && values
[i
]->bv_val
[14] != ',') ||
1600 values
[i
]->bv_val
[15] != '0' || values
[i
]->bv_val
[16] != 'Z')
1601 FIXME("not handled time zone: %s\n", debugstr_an(values
[i
]->bv_val
+ 14, values
[i
]->bv_len
- 14));
1603 TRACE("%s => %02u.%02u.%04u %02u:%02u:%02u\n", debugstr_an(values
[i
]->bv_val
, values
[i
]->bv_len
),
1604 col
->pADsValues
[i
].u
.UTCTime
.wDay
, col
->pADsValues
[i
].u
.UTCTime
.wMonth
,
1605 col
->pADsValues
[i
].u
.UTCTime
.wYear
, col
->pADsValues
[i
].u
.UTCTime
.wHour
,
1606 col
->pADsValues
[i
].u
.UTCTime
.wMinute
, col
->pADsValues
[i
].u
.UTCTime
.wSecond
);
1609 ldap_value_free_len(values
);
1610 col
->hReserved
= NULL
;
1614 case ADSTYPE_DN_WITH_BINARY
:
1616 static const BYTE hex2bin
[] =
1618 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x00 */
1619 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x10 */
1620 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x20 */
1621 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, /* 0x30 */
1622 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0, /* 0x40 */
1623 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x50 */
1624 0,10,11,12,13,14,15 /* 0x60 */
1626 ADS_DN_WITH_BINARY
*dnb
;
1627 WCHAR
**values
= ldap_get_valuesW(ldap
->ld
, ldap_ctx
->entry
, name
);
1629 return E_ADS_COLUMN_NOT_SET
;
1630 count
= ldap_count_valuesW(values
);
1632 col
->pADsValues
= heap_alloc_zero(count
* (sizeof(col
->pADsValues
[0]) + sizeof(col
->pADsValues
[0].u
.pDNWithBinary
[0])));
1633 if (!col
->pADsValues
)
1635 ldap_value_freeW(values
);
1636 return E_OUTOFMEMORY
;
1639 dnb
= (ADS_DN_WITH_BINARY
*)(col
->pADsValues
+ count
);
1641 for (i
= 0; i
< count
; i
++)
1643 WCHAR
*p
= values
[i
];
1646 col
->pADsValues
[i
].dwType
= type
;
1647 col
->pADsValues
[i
].u
.pDNWithBinary
= dnb
++;
1649 if ((p
[0] != 'b' && p
[0] != 'B') || p
[1] != ':')
1650 FIXME("wrong DN with binary tag '%c%c'\n", p
[0], p
[1]);
1653 col
->pADsValues
[i
].u
.pDNWithBinary
->dwLength
= wcstol(p
, &p
, 10) / 2;
1655 FIXME("wrong DN with binary separator '%c'\n", *p
);
1657 col
->pADsValues
[i
].u
.pDNWithBinary
->lpBinaryValue
= (BYTE
*)p
;
1658 /* decode values in-place */
1659 for (n
= 0; n
< col
->pADsValues
[i
].u
.pDNWithBinary
->dwLength
; n
++, p
+= 2)
1663 if (p
[0] > 'f' || (p
[0] != '0' && !hex2bin
[p
[0]]) ||
1664 p
[1] > 'f' || (p
[1] != '0' && !hex2bin
[p
[1]]))
1666 FIXME("bad hex encoding at %s\n", debugstr_w(p
));
1670 b
= (hex2bin
[p
[0]] << 4) | hex2bin
[p
[1]];
1671 col
->pADsValues
[i
].u
.pDNWithBinary
->lpBinaryValue
[n
] = b
;
1674 FIXME("wrong DN with binary separator '%c'\n", *p
);
1675 col
->pADsValues
[i
].u
.pDNWithBinary
->pszDNString
= p
+ 1;
1677 TRACE("%s => %u,%s,%s\n", debugstr_w(values
[i
]),
1678 col
->pADsValues
[i
].u
.pDNWithBinary
->dwLength
,
1679 debugstr_an((char *)col
->pADsValues
[i
].u
.pDNWithBinary
->lpBinaryValue
, col
->pADsValues
[i
].u
.pDNWithBinary
->dwLength
),
1680 debugstr_w(col
->pADsValues
[i
].u
.pDNWithBinary
->pszDNString
));
1683 col
->hReserved
= values
;
1688 col
->dwADsType
= type
;
1689 col
->dwNumValues
= count
;
1690 col
->pszAttrName
= strdupW(name
);
1695 static HRESULT WINAPI
search_GetColumn(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
,
1696 LPWSTR name
, PADS_SEARCH_COLUMN col
)
1698 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1699 struct ldap_search_context
*ldap_ctx
= res
;
1703 TRACE("%p,%p,%s,%p\n", iface
, res
, debugstr_w(name
), col
);
1705 if (!res
|| !name
|| !ldap_ctx
->entry
) return E_ADS_BAD_PARAMETER
;
1707 memset(col
, 0, sizeof(*col
));
1709 if (!wcsicmp(name
, L
"ADsPath"))
1711 WCHAR
*dn
= ldap_get_dnW(ldap
->ld
, ldap_ctx
->entry
);
1713 col
->pADsValues
= heap_alloc(sizeof(col
->pADsValues
[0]));
1714 if (!col
->pADsValues
)
1720 count
= sizeof(L
"LDAP://") + (wcslen(ldap
->host
) + 1 /* '/' */) * sizeof(WCHAR
);
1721 if (dn
) count
+= wcslen(dn
) * sizeof(WCHAR
);
1723 col
->pADsValues
[0].u
.CaseIgnoreString
= heap_alloc(count
);
1724 if (!col
->pADsValues
[0].u
.CaseIgnoreString
)
1730 wcscpy(col
->pADsValues
[0].u
.CaseIgnoreString
, L
"LDAP://");
1731 wcscat(col
->pADsValues
[0].u
.CaseIgnoreString
, ldap
->host
);
1732 wcscat(col
->pADsValues
[0].u
.CaseIgnoreString
, L
"/");
1733 if (dn
) wcscat(col
->pADsValues
[0].u
.CaseIgnoreString
, dn
);
1734 col
->pADsValues
[0].dwType
= ADSTYPE_CASE_IGNORE_STRING
;
1735 col
->dwADsType
= ADSTYPE_CASE_IGNORE_STRING
;
1736 col
->dwNumValues
= 1;
1737 col
->pszAttrName
= strdupW(name
);
1738 col
->hReserved
= NULL
;
1740 TRACE("=> %s\n", debugstr_w(col
->pADsValues
[0].u
.CaseIgnoreString
));
1747 return add_column_values(ldap
, ldap_ctx
, name
, col
);
1750 static HRESULT WINAPI
search_FreeColumn(IDirectorySearch
*iface
, PADS_SEARCH_COLUMN col
)
1752 TRACE("%p,%p\n", iface
, col
);
1754 if (!col
) return E_ADS_BAD_PARAMETER
;
1756 heap_free(col
->pADsValues
);
1757 heap_free(col
->pszAttrName
);
1761 if (col
->dwADsType
== ADSTYPE_OCTET_STRING
)
1762 ldap_value_free_len(col
->hReserved
);
1764 ldap_value_freeW(col
->hReserved
);
1770 static HRESULT WINAPI
search_CloseSearchHandle(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
)
1772 struct ldap_search_context
*ldap_ctx
= res
;
1774 TRACE("%p,%p\n", iface
, res
);
1776 if (!res
) return E_ADS_BAD_PARAMETER
;
1778 ldap_msgfree(ldap_ctx
->res
);
1783 static const IDirectorySearchVtbl IDirectorySearch_vtbl
=
1785 search_QueryInterface
,
1788 search_SetSearchPreference
,
1789 search_ExecuteSearch
,
1790 search_AbandonSearch
,
1793 search_GetPreviousRow
,
1794 search_GetNextColumnName
,
1797 search_CloseSearchHandle
1800 static inline LDAP_namespace
*impl_from_IDirectoryObject(IDirectoryObject
*iface
)
1802 return CONTAINING_RECORD(iface
, LDAP_namespace
, IDirectoryObject_iface
);
1805 static HRESULT WINAPI
dirobj_QueryInterface(IDirectoryObject
*iface
, REFIID riid
, void **obj
)
1807 LDAP_namespace
*ldap
= impl_from_IDirectoryObject(iface
);
1809 TRACE("%p,%s,%p\n", iface
, debugstr_guid(riid
), obj
);
1811 if (!riid
|| !obj
) return E_INVALIDARG
;
1813 if (IsEqualGUID(riid
, &IID_IDirectoryObject
) ||
1814 IsEqualGUID(riid
, &IID_IUnknown
))
1816 IDirectoryObject_AddRef(iface
);
1821 return IADs_QueryInterface(&ldap
->IADs_iface
, riid
, obj
);
1824 static ULONG WINAPI
dirobj_AddRef(IDirectoryObject
*iface
)
1826 LDAP_namespace
*ldap
= impl_from_IDirectoryObject(iface
);
1827 return IADs_AddRef(&ldap
->IADs_iface
);
1830 static ULONG WINAPI
dirobj_Release(IDirectoryObject
*iface
)
1832 LDAP_namespace
*ldap
= impl_from_IDirectoryObject(iface
);
1833 return IADs_Release(&ldap
->IADs_iface
);
1836 static HRESULT WINAPI
dirobj_GetObjectInformation(IDirectoryObject
*iface
, PADS_OBJECT_INFO
*info
)
1838 FIXME("%p,%p: stub\n", iface
, info
);
1842 static HRESULT WINAPI
dirobj_GetObjectAttributes(IDirectoryObject
*iface
, LPWSTR
*names
,
1843 DWORD count
, PADS_ATTR_INFO
*attrs
, DWORD
*count_returned
)
1845 FIXME("%p,%p,%u,%p,%p: stub\n", iface
, names
, count
, attrs
, count_returned
);
1849 static HRESULT WINAPI
dirobj_SetObjectAttributes(IDirectoryObject
*iface
, PADS_ATTR_INFO attrs
,
1850 DWORD count
, DWORD
*count_set
)
1852 FIXME("%p,%p,%u,%p: stub\n", iface
, attrs
, count
, count_set
);
1856 static HRESULT WINAPI
dirobj_CreateDSObject(IDirectoryObject
*iface
, LPWSTR name
,
1857 PADS_ATTR_INFO attrs
, DWORD count
, IDispatch
**obj
)
1859 FIXME("%p,%s,%p,%u,%p: stub\n", iface
, debugstr_w(name
), attrs
, count
, obj
);
1863 static HRESULT WINAPI
dirobj_DeleteDSObject(IDirectoryObject
*iface
, LPWSTR name
)
1865 FIXME("%p,%s: stub\n", iface
, debugstr_w(name
));
1869 static const IDirectoryObjectVtbl IDirectoryObject_vtbl
=
1871 dirobj_QueryInterface
,
1874 dirobj_GetObjectInformation
,
1875 dirobj_GetObjectAttributes
,
1876 dirobj_SetObjectAttributes
,
1877 dirobj_CreateDSObject
,
1878 dirobj_DeleteDSObject
1881 static HRESULT
LDAPNamespace_create(REFIID riid
, void **obj
)
1883 LDAP_namespace
*ldap
;
1886 ldap
= heap_alloc(sizeof(*ldap
));
1887 if (!ldap
) return E_OUTOFMEMORY
;
1889 ldap
->IADs_iface
.lpVtbl
= &IADs_vtbl
;
1890 ldap
->IADsOpenDSObject_iface
.lpVtbl
= &IADsOpenDSObject_vtbl
;
1891 ldap
->IDirectorySearch_iface
.lpVtbl
= &IDirectorySearch_vtbl
;
1892 ldap
->IDirectoryObject_iface
.lpVtbl
= &IDirectoryObject_vtbl
;
1896 ldap
->object
= NULL
;
1897 ldap
->attrs_count
= 0;
1898 ldap
->attrs_count_allocated
= 0;
1900 ldap
->search
.scope
= ADS_SCOPE_SUBTREE
;
1901 ldap
->search
.pagesize
= 0;
1902 ldap
->search
.cache_results
= TRUE
;
1903 ldap
->search
.attribtypes_only
= FALSE
;
1904 ldap
->search
.tombstone
= FALSE
;
1906 ldap
->at_single_count
= 0;
1907 ldap
->at_multiple_count
= 0;
1909 hr
= IADs_QueryInterface(&ldap
->IADs_iface
, riid
, obj
);
1910 IADs_Release(&ldap
->IADs_iface
);
1915 static const struct class_info
1918 HRESULT (*constructor
)(REFIID
, void **);
1921 { &CLSID_ADSystemInfo
, ADSystemInfo_create
},
1922 { &CLSID_LDAP
, LDAP_create
},
1923 { &CLSID_LDAPNamespace
, LDAPNamespace_create
},
1928 IClassFactory IClassFactory_iface
;
1930 const struct class_info
*info
;
1933 static inline class_factory
*impl_from_IClassFactory(IClassFactory
*iface
)
1935 return CONTAINING_RECORD(iface
, class_factory
, IClassFactory_iface
);
1938 static HRESULT WINAPI
factory_QueryInterface(IClassFactory
*iface
, REFIID riid
, LPVOID
*obj
)
1940 TRACE("%p,%s,%p\n", iface
, debugstr_guid(riid
), obj
);
1942 if (!riid
|| !obj
) return E_INVALIDARG
;
1944 if (IsEqualIID(riid
, &IID_IUnknown
) ||
1945 IsEqualIID(riid
, &IID_IClassFactory
))
1947 IClassFactory_AddRef(iface
);
1953 FIXME("interface %s is not implemented\n", debugstr_guid(riid
));
1954 return E_NOINTERFACE
;
1957 static ULONG WINAPI
factory_AddRef(IClassFactory
*iface
)
1959 class_factory
*factory
= impl_from_IClassFactory(iface
);
1960 ULONG ref
= InterlockedIncrement(&factory
->ref
);
1962 TRACE("(%p) ref %u\n", iface
, ref
);
1967 static ULONG WINAPI
factory_Release(IClassFactory
*iface
)
1969 class_factory
*factory
= impl_from_IClassFactory(iface
);
1970 ULONG ref
= InterlockedDecrement(&factory
->ref
);
1972 TRACE("(%p) ref %u\n", iface
, ref
);
1980 static HRESULT WINAPI
factory_CreateInstance(IClassFactory
*iface
, IUnknown
*outer
, REFIID riid
, void **obj
)
1982 class_factory
*factory
= impl_from_IClassFactory(iface
);
1984 TRACE("%p,%s,%p\n", outer
, debugstr_guid(riid
), obj
);
1986 if (!riid
|| !obj
) return E_INVALIDARG
;
1989 if (outer
) return CLASS_E_NOAGGREGATION
;
1991 return factory
->info
->constructor(riid
, obj
);
1994 static HRESULT WINAPI
factory_LockServer(IClassFactory
*iface
, BOOL lock
)
1996 FIXME("%p,%d: stub\n", iface
, lock
);
2000 static const struct IClassFactoryVtbl factory_vtbl
=
2002 factory_QueryInterface
,
2005 factory_CreateInstance
,
2009 static HRESULT
factory_constructor(const struct class_info
*info
, REFIID riid
, void **obj
)
2011 class_factory
*factory
;
2014 factory
= heap_alloc(sizeof(*factory
));
2015 if (!factory
) return E_OUTOFMEMORY
;
2017 factory
->IClassFactory_iface
.lpVtbl
= &factory_vtbl
;
2019 factory
->info
= info
;
2021 hr
= IClassFactory_QueryInterface(&factory
->IClassFactory_iface
, riid
, obj
);
2022 IClassFactory_Release(&factory
->IClassFactory_iface
);
2027 HRESULT WINAPI
DllGetClassObject(REFCLSID clsid
, REFIID iid
, LPVOID
*obj
)
2031 TRACE("%s,%s,%p\n", debugstr_guid(clsid
), debugstr_guid(iid
), obj
);
2033 if (!clsid
|| !iid
|| !obj
) return E_INVALIDARG
;
2037 for (i
= 0; i
< ARRAY_SIZE(class_info
); i
++)
2039 if (IsEqualCLSID(class_info
[i
].clsid
, clsid
))
2040 return factory_constructor(&class_info
[i
], iid
, obj
);
2043 FIXME("class %s/%s is not implemented\n", debugstr_guid(clsid
), debugstr_guid(iid
));
2044 return CLASS_E_CLASSNOTAVAILABLE
;
2047 HRESULT WINAPI
DllCanUnloadNow(void)
2052 HRESULT WINAPI
DllRegisterServer(void)
2054 return __wine_register_resources(adsldp_hinst
);
2057 HRESULT WINAPI
DllUnregisterServer(void)
2059 return __wine_unregister_resources(adsldp_hinst
);
2062 BOOL WINAPI
DllMain(HINSTANCE hinst
, DWORD reason
, void *reserved
)
2064 TRACE("%p,%u,%p\n", hinst
, reason
, reserved
);
2068 case DLL_WINE_PREATTACH
:
2069 return FALSE
; /* prefer native version */
2071 case DLL_PROCESS_ATTACH
:
2072 adsldp_hinst
= hinst
;
2073 DisableThreadLibraryCalls(hinst
);