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
413 LDAPMessage
*res
, *entry
;
419 static inline LDAP_namespace
*impl_from_IADs(IADs
*iface
)
421 return CONTAINING_RECORD(iface
, LDAP_namespace
, IADs_iface
);
424 static HRESULT WINAPI
ldapns_QueryInterface(IADs
*iface
, REFIID riid
, void **obj
)
426 LDAP_namespace
*ldap
= impl_from_IADs(iface
);
428 TRACE("%p,%s,%p\n", iface
, debugstr_guid(riid
), obj
);
430 if (!riid
|| !obj
) return E_INVALIDARG
;
432 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
433 IsEqualGUID(riid
, &IID_IDispatch
) ||
434 IsEqualGUID(riid
, &IID_IADs
))
441 if (IsEqualGUID(riid
, &IID_IADsOpenDSObject
))
444 *obj
= &ldap
->IADsOpenDSObject_iface
;
448 if (IsEqualGUID(riid
, &IID_IDirectorySearch
))
450 if (!ldap
->ld
|| (ldap
->object
&& !wcsicmp(ldap
->object
, L
"rootDSE")))
451 return E_NOINTERFACE
;
454 *obj
= &ldap
->IDirectorySearch_iface
;
458 if (IsEqualGUID(riid
, &IID_IDirectoryObject
))
461 *obj
= &ldap
->IDirectoryObject_iface
;
465 FIXME("interface %s is not implemented\n", debugstr_guid(riid
));
466 return E_NOINTERFACE
;
469 static ULONG WINAPI
ldapns_AddRef(IADs
*iface
)
471 LDAP_namespace
*ldap
= impl_from_IADs(iface
);
472 return InterlockedIncrement(&ldap
->ref
);
475 static void free_attributes(LDAP_namespace
*ldap
)
479 if (!ldap
->attrs
) return;
481 for (i
= 0; i
< ldap
->attrs_count
; i
++)
483 ldap_memfreeW(ldap
->attrs
[i
].name
);
484 ldap_value_freeW(ldap
->attrs
[i
].values
);
487 heap_free(ldap
->attrs
);
489 ldap
->attrs_count
= 0;
492 static ULONG WINAPI
ldapns_Release(IADs
*iface
)
494 LDAP_namespace
*ldap
= impl_from_IADs(iface
);
495 LONG ref
= InterlockedDecrement(&ldap
->ref
);
499 TRACE("destroying %p\n", iface
);
500 if (ldap
->ld
) ldap_unbind(ldap
->ld
);
501 SysFreeString(ldap
->host
);
502 SysFreeString(ldap
->object
);
503 free_attributes(ldap
);
504 free_attribute_types(ldap
->at
, ldap
->at_single_count
+ ldap
->at_multiple_count
);
511 static HRESULT WINAPI
ldapns_GetTypeInfoCount(IADs
*iface
, UINT
*count
)
513 FIXME("%p,%p: stub\n", iface
, count
);
517 static HRESULT WINAPI
ldapns_GetTypeInfo(IADs
*iface
, UINT index
, LCID lcid
, ITypeInfo
**info
)
519 FIXME("%p,%u,%#x,%p: stub\n", iface
, index
, lcid
, info
);
523 static HRESULT WINAPI
ldapns_GetIDsOfNames(IADs
*iface
, REFIID riid
, LPOLESTR
*names
,
524 UINT count
, LCID lcid
, DISPID
*dispid
)
526 FIXME("%p,%s,%p,%u,%u,%p: stub\n", iface
, debugstr_guid(riid
), names
, count
, lcid
, dispid
);
530 static HRESULT WINAPI
ldapns_Invoke(IADs
*iface
, DISPID dispid
, REFIID riid
, LCID lcid
, WORD flags
,
531 DISPPARAMS
*params
, VARIANT
*result
, EXCEPINFO
*excepinfo
, UINT
*argerr
)
533 FIXME("%p,%d,%s,%04x,%04x,%p,%p,%p,%p: stub\n", iface
, dispid
, debugstr_guid(riid
), lcid
, flags
,
534 params
, result
, excepinfo
, argerr
);
538 static HRESULT WINAPI
ldapns_get_Name(IADs
*iface
, BSTR
*retval
)
540 FIXME("%p,%p: stub\n", iface
, retval
);
544 static HRESULT WINAPI
ldapns_get_Class(IADs
*iface
, BSTR
*retval
)
546 FIXME("%p,%p: stub\n", iface
, retval
);
550 static HRESULT WINAPI
ldapns_get_GUID(IADs
*iface
, BSTR
*retval
)
552 FIXME("%p,%p: stub\n", iface
, retval
);
556 static HRESULT WINAPI
ldapns_get_ADsPath(IADs
*iface
, BSTR
*retval
)
558 FIXME("%p,%p: stub\n", iface
, retval
);
562 static HRESULT WINAPI
ldapns_get_Parent(IADs
*iface
, BSTR
*retval
)
564 FIXME("%p,%p: stub\n", iface
, retval
);
568 static HRESULT WINAPI
ldapns_get_Schema(IADs
*iface
, BSTR
*retval
)
570 FIXME("%p,%p: stub\n", iface
, retval
);
574 static HRESULT WINAPI
ldapns_GetInfo(IADs
*iface
)
579 TRACE("%p\n", iface
);
581 hr
= ADsBuildVarArrayStr(NULL
, 0, &var
);
584 hr
= IADs_GetInfoEx(iface
, var
, 0);
590 static HRESULT WINAPI
ldapns_SetInfo(IADs
*iface
)
592 FIXME("%p: stub\n", iface
);
596 static HRESULT WINAPI
ldapns_Get(IADs
*iface
, BSTR name
, VARIANT
*prop
)
598 LDAP_namespace
*ldap
= impl_from_IADs(iface
);
602 TRACE("%p,%s,%p\n", iface
, debugstr_w(name
), prop
);
604 if (!name
|| !prop
) return E_ADS_BAD_PARAMETER
;
606 if (!ldap
->attrs_count
)
608 hr
= IADs_GetInfo(iface
);
609 if (hr
!= S_OK
) return hr
;
612 for (i
= 0; i
< ldap
->attrs_count
; i
++)
614 if (!wcsicmp(name
, ldap
->attrs
[i
].name
))
616 LONG count
= ldap_count_valuesW(ldap
->attrs
[i
].values
);
620 V_VT(prop
) = VT_BSTR
;
630 TRACE("attr %s has %u values\n", debugstr_w(ldap
->attrs
[i
].name
), count
);
632 sa
= SafeArrayCreateVector(VT_VARIANT
, 0, count
);
633 if (!sa
) return E_OUTOFMEMORY
;
635 for (idx
= 0; idx
< count
; idx
++)
637 TRACE("=> %s\n", debugstr_w(ldap
->attrs
[i
].values
[idx
]));
638 V_VT(&item
) = VT_BSTR
;
639 V_BSTR(&item
) = SysAllocString(ldap
->attrs
[i
].values
[idx
]);
646 hr
= SafeArrayPutElement(sa
, &idx
, &item
);
647 SysFreeString(V_BSTR(&item
));
648 if (hr
!= S_OK
) goto fail
;
651 V_VT(prop
) = VT_ARRAY
| VT_VARIANT
;
655 SafeArrayDestroy(sa
);
660 TRACE("=> %s\n", debugstr_w(ldap
->attrs
[i
].values
[0]));
661 V_BSTR(prop
) = SysAllocString(ldap
->attrs
[i
].values
[0]);
662 if (!V_BSTR(prop
)) return E_OUTOFMEMORY
;
663 V_VT(prop
) = VT_BSTR
;
669 return E_ADS_PROPERTY_NOT_FOUND
;
672 static HRESULT WINAPI
ldapns_Put(IADs
*iface
, BSTR name
, VARIANT prop
)
674 FIXME("%p,%s,%s: stub\n", iface
, debugstr_w(name
), wine_dbgstr_variant(&prop
));
678 static HRESULT WINAPI
ldapns_GetEx(IADs
*iface
, BSTR name
, VARIANT
*prop
)
680 FIXME("%p,%s,%p: stub\n", iface
, debugstr_w(name
), prop
);
684 static HRESULT WINAPI
ldapns_PutEx(IADs
*iface
, LONG code
, BSTR name
, VARIANT prop
)
686 FIXME("%p,%d,%s,%s: stub\n", iface
, code
, debugstr_w(name
), wine_dbgstr_variant(&prop
));
690 static HRESULT
add_attribute(LDAP_namespace
*ldap
, WCHAR
*name
, WCHAR
**values
)
692 struct ldap_attribute
*new_attrs
;
696 ldap
->attrs
= heap_alloc(256 * sizeof(ldap
->attrs
[0]));
697 if (!ldap
->attrs
) return E_OUTOFMEMORY
;
698 ldap
->attrs_count_allocated
= 256;
700 else if (ldap
->attrs_count_allocated
< ldap
->attrs_count
+ 1)
702 new_attrs
= heap_realloc(ldap
->attrs
, (ldap
->attrs_count_allocated
* 2) * sizeof(*new_attrs
));
703 if (!new_attrs
) return E_OUTOFMEMORY
;
705 ldap
->attrs_count_allocated
*= 2;
706 ldap
->attrs
= new_attrs
;
709 ldap
->attrs
[ldap
->attrs_count
].name
= name
;
710 ldap
->attrs
[ldap
->attrs_count
].values
= values
;
716 static HRESULT WINAPI
ldapns_GetInfoEx(IADs
*iface
, VARIANT prop
, LONG reserved
)
718 LDAP_namespace
*ldap
= impl_from_IADs(iface
);
722 WCHAR
**props
= NULL
, *attr
, **values
;
724 LDAPMessage
*res
= NULL
, *entry
;
727 TRACE("%p,%s,%d\n", iface
, wine_dbgstr_variant(&prop
), reserved
);
729 free_attributes(ldap
);
731 if (!ldap
->ld
) return E_NOTIMPL
;
733 if (V_VT(&prop
) != (VT_ARRAY
| VT_VARIANT
))
734 return E_ADS_BAD_PARAMETER
;
738 return E_ADS_BAD_PARAMETER
;
740 hr
= SafeArrayAccessData(sa
, (void *)&item
);
741 if (hr
!= S_OK
) return hr
;
743 count
= sa
->rgsabound
[0].cElements
;
746 props
= heap_alloc((count
+ 1) * sizeof(props
[0]));
753 for (i
= 0; i
< count
; i
++)
755 if (V_VT(&item
[i
]) != VT_BSTR
)
757 hr
= E_ADS_BAD_PARAMETER
;
760 props
[i
] = V_BSTR(&item
[i
]);
762 props
[sa
->rgsabound
[0].cElements
] = NULL
;
765 err
= ldap_search_sW(ldap
->ld
, NULL
, LDAP_SCOPE_BASE
, (WCHAR
*)L
"(objectClass=*)", props
, FALSE
, &res
);
766 if (err
!= LDAP_SUCCESS
)
768 TRACE("ldap_search_sW error %#x\n", err
);
769 hr
= HRESULT_FROM_WIN32(map_ldap_error(err
));
773 entry
= ldap_first_entry(ldap
->ld
, res
);
776 attr
= ldap_first_attributeW(ldap
->ld
, entry
, &ber
);
779 TRACE("attr: %s\n", debugstr_w(attr
));
781 values
= ldap_get_valuesW(ldap
->ld
, entry
, attr
);
783 hr
= add_attribute(ldap
, attr
, values
);
786 ldap_value_freeW(values
);
792 attr
= ldap_next_attributeW(ldap
->ld
, entry
, ber
);
796 entry
= ldap_next_entry(ldap
->ld
, res
);
800 if (res
) ldap_msgfree(res
);
802 SafeArrayUnaccessData(sa
);
806 static const IADsVtbl IADs_vtbl
=
808 ldapns_QueryInterface
,
811 ldapns_GetTypeInfoCount
,
813 ldapns_GetIDsOfNames
,
830 static inline LDAP_namespace
*impl_from_IADsOpenDSObject(IADsOpenDSObject
*iface
)
832 return CONTAINING_RECORD(iface
, LDAP_namespace
, IADsOpenDSObject_iface
);
835 static HRESULT WINAPI
openobj_QueryInterface(IADsOpenDSObject
*iface
, REFIID riid
, void **obj
)
837 TRACE("%p,%s,%p\n", iface
, debugstr_guid(riid
), obj
);
839 if (!riid
|| !obj
) return E_INVALIDARG
;
841 if (IsEqualGUID(riid
, &IID_IADsOpenDSObject
) ||
842 IsEqualGUID(riid
, &IID_IDispatch
) ||
843 IsEqualGUID(riid
, &IID_IUnknown
))
845 IADsOpenDSObject_AddRef(iface
);
850 FIXME("interface %s is not implemented\n", debugstr_guid(riid
));
851 return E_NOINTERFACE
;
854 static ULONG WINAPI
openobj_AddRef(IADsOpenDSObject
*iface
)
856 LDAP_namespace
*ldap
= impl_from_IADsOpenDSObject(iface
);
857 return IADs_AddRef(&ldap
->IADs_iface
);
860 static ULONG WINAPI
openobj_Release(IADsOpenDSObject
*iface
)
862 LDAP_namespace
*ldap
= impl_from_IADsOpenDSObject(iface
);
863 return IADs_Release(&ldap
->IADs_iface
);
866 static HRESULT WINAPI
openobj_GetTypeInfoCount(IADsOpenDSObject
*iface
, UINT
*count
)
868 FIXME("%p,%p: stub\n", iface
, count
);
872 static HRESULT WINAPI
openobj_GetTypeInfo(IADsOpenDSObject
*iface
, UINT index
, LCID lcid
, ITypeInfo
**info
)
874 FIXME("%p,%u,%#x,%p: stub\n", iface
, index
, lcid
, info
);
878 static HRESULT WINAPI
openobj_GetIDsOfNames(IADsOpenDSObject
*iface
, REFIID riid
, LPOLESTR
*names
,
879 UINT count
, LCID lcid
, DISPID
*dispid
)
881 FIXME("%p,%s,%p,%u,%u,%p: stub\n", iface
, debugstr_guid(riid
), names
, count
, lcid
, dispid
);
885 static HRESULT WINAPI
openobj_Invoke(IADsOpenDSObject
*iface
, DISPID dispid
, REFIID riid
, LCID lcid
, WORD flags
,
886 DISPPARAMS
*params
, VARIANT
*result
, EXCEPINFO
*excepinfo
, UINT
*argerr
)
888 FIXME("%p,%d,%s,%04x,%04x,%p,%p,%p,%p: stub\n", iface
, dispid
, debugstr_guid(riid
), lcid
, flags
,
889 params
, result
, excepinfo
, argerr
);
893 static HRESULT
parse_path(WCHAR
*path
, BSTR
*host
, ULONG
*port
, BSTR
*object
)
898 if (host
) *host
= NULL
;
900 if (object
) *object
= NULL
;
902 if (wcsnicmp(path
, L
"LDAP:", 5) != 0)
903 return E_ADS_BAD_PATHNAME
;
906 if (!*p
) return S_OK
;
908 if (*p
++ != '/' || *p
++ != '/' || !*p
)
909 return E_ADS_BAD_PATHNAME
;
913 while (*p
&& *p
!= '/')
918 if (!port
) port
= &dummy
;
919 *port
= wcstol(p
+ 1, &p
, 10);
920 if (*p
&& *p
!= '/') return E_ADS_BAD_PATHNAME
;
928 if (host_len
== 0) return E_ADS_BAD_PATHNAME
;
932 *host
= SysAllocStringLen(p_host
, host_len
);
933 if (!*host
) return E_OUTOFMEMORY
;
936 if (!*p
) return S_OK
;
938 if (*p
++ != '/' || !*p
)
940 SysFreeString(*host
);
941 return E_ADS_BAD_PATHNAME
;
946 *object
= SysAllocString(p
);
949 SysFreeString(*host
);
950 return E_OUTOFMEMORY
;
957 static HRESULT WINAPI
openobj_OpenDSObject(IADsOpenDSObject
*iface
, BSTR path
, BSTR user
, BSTR password
,
958 LONG flags
, IDispatch
**obj
)
965 ULONG err
, at_single_count
= 0, at_multiple_count
= 0;
966 struct attribute_type
*at
= NULL
;
968 TRACE("%p,%s,%s,%p,%08x,%p\n", iface
, debugstr_w(path
), debugstr_w(user
), password
, flags
, obj
);
970 hr
= parse_path(path
, &host
, &port
, &object
);
971 if (hr
!= S_OK
) return hr
;
973 TRACE("host %s, port %u, object %s\n", debugstr_w(host
), port
, debugstr_w(object
));
979 if (!wcsicmp(host
, L
"rootDSE"))
981 DOMAIN_CONTROLLER_INFOW
*dcinfo
;
985 hr
= E_ADS_BAD_PATHNAME
;
991 err
= DsGetDcNameW(NULL
, NULL
, NULL
, NULL
, DS_RETURN_DNS_NAME
, &dcinfo
);
992 if (err
!= ERROR_SUCCESS
)
994 hr
= HRESULT_FROM_WIN32(LdapGetLastError());
998 host
= SysAllocString(dcinfo
->DomainName
);
999 NetApiBufferFree(dcinfo
);
1008 ld
= ldap_initW(host
, port
);
1011 hr
= HRESULT_FROM_WIN32(LdapGetLastError());
1015 version
= LDAP_VERSION3
;
1016 err
= ldap_set_optionW(ld
, LDAP_OPT_PROTOCOL_VERSION
, &version
);
1017 if (err
!= LDAP_SUCCESS
)
1019 hr
= HRESULT_FROM_WIN32(map_ldap_error(err
));
1024 err
= ldap_connect(ld
, NULL
);
1025 if (err
!= LDAP_SUCCESS
)
1027 hr
= HRESULT_FROM_WIN32(map_ldap_error(err
));
1032 if (flags
& ADS_SECURE_AUTHENTICATION
)
1034 SEC_WINNT_AUTH_IDENTITY_W id
;
1036 id
.Flags
= SEC_WINNT_AUTH_IDENTITY_UNICODE
;
1037 id
.Domain
= (unsigned short *)host
;
1038 id
.DomainLength
= wcslen(host
);
1039 id
.User
= (unsigned short *)user
;
1040 id
.UserLength
= user
? wcslen(user
) : 0;
1041 id
.Password
= (unsigned short *)password
;
1042 id
.PasswordLength
= password
? wcslen(password
) : 0;
1044 err
= ldap_bind_sW(ld
, NULL
, (WCHAR
*)&id
, LDAP_AUTH_NEGOTIATE
);
1045 if (err
!= LDAP_SUCCESS
)
1047 TRACE("ldap_bind_sW error %#x\n", err
);
1048 hr
= HRESULT_FROM_WIN32(map_ldap_error(err
));
1055 err
= ldap_simple_bind_sW(ld
, user
, password
);
1056 if (err
!= LDAP_SUCCESS
)
1058 TRACE("ldap_simple_bind_sW error %#x\n", err
);
1059 hr
= HRESULT_FROM_WIN32(map_ldap_error(err
));
1065 at
= load_schema(ld
, &at_single_count
, &at_multiple_count
);
1068 hr
= LDAPNamespace_create(&IID_IADs
, (void **)&ads
);
1071 LDAP_namespace
*ldap
= impl_from_IADs(ads
);
1075 ldap
->object
= object
;
1077 ldap
->at_single_count
= at_single_count
;
1078 ldap
->at_multiple_count
= at_multiple_count
;
1079 hr
= IADs_QueryInterface(ads
, &IID_IDispatch
, (void **)obj
);
1085 SysFreeString(host
);
1086 SysFreeString(object
);
1091 static const IADsOpenDSObjectVtbl IADsOpenDSObject_vtbl
=
1093 openobj_QueryInterface
,
1096 openobj_GetTypeInfoCount
,
1097 openobj_GetTypeInfo
,
1098 openobj_GetIDsOfNames
,
1100 openobj_OpenDSObject
1103 static inline LDAP_namespace
*impl_from_IDirectorySearch(IDirectorySearch
*iface
)
1105 return CONTAINING_RECORD(iface
, LDAP_namespace
, IDirectorySearch_iface
);
1108 static HRESULT WINAPI
search_QueryInterface(IDirectorySearch
*iface
, REFIID riid
, void **obj
)
1110 TRACE("%p,%s,%p\n", iface
, debugstr_guid(riid
), obj
);
1112 if (!riid
|| !obj
) return E_INVALIDARG
;
1114 if (IsEqualGUID(riid
, &IID_IDirectorySearch
) ||
1115 IsEqualGUID(riid
, &IID_IUnknown
))
1117 IDirectorySearch_AddRef(iface
);
1122 FIXME("interface %s is not implemented\n", debugstr_guid(riid
));
1123 return E_NOINTERFACE
;
1126 static ULONG WINAPI
search_AddRef(IDirectorySearch
*iface
)
1128 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1129 return IADs_AddRef(&ldap
->IADs_iface
);
1132 static ULONG WINAPI
search_Release(IDirectorySearch
*iface
)
1134 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1135 return IADs_Release(&ldap
->IADs_iface
);
1138 static HRESULT WINAPI
search_SetSearchPreference(IDirectorySearch
*iface
, PADS_SEARCHPREF_INFO prefs
, DWORD count
)
1140 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1144 TRACE("%p,%p,%u\n", iface
, prefs
, count
);
1146 for (i
= 0; i
< count
; i
++)
1148 switch (prefs
[i
].dwSearchPref
)
1150 case ADS_SEARCHPREF_SEARCH_SCOPE
:
1151 if (prefs
[i
].vValue
.dwType
!= ADSTYPE_INTEGER
)
1153 FIXME("ADS_SEARCHPREF_SEARCH_SCOPE: unsupported dwType %d\n", prefs
[i
].vValue
.dwType
);
1154 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1158 switch (prefs
[i
].vValue
.u
.Integer
)
1160 case ADS_SCOPE_BASE
:
1161 case ADS_SCOPE_ONELEVEL
:
1162 case ADS_SCOPE_SUBTREE
:
1163 TRACE("SEARCH_SCOPE: %d\n", prefs
[i
].vValue
.u
.Integer
);
1164 ldap
->search
.scope
= prefs
[i
].vValue
.u
.Integer
;
1165 prefs
[i
].dwStatus
= ADS_STATUS_S_OK
;
1169 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1174 case ADS_SEARCHPREF_SECURITY_MASK
:
1179 struct berval
*berval
;
1180 LDAPControlW
*ctrls
[2], mask
;
1182 if (prefs
[i
].vValue
.dwType
!= ADSTYPE_INTEGER
)
1184 FIXME("ADS_SEARCHPREF_SECURITY_MASK: not supported dwType %d\n", prefs
[i
].vValue
.dwType
);
1185 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1189 TRACE("SECURITY_MASK: %08x\n", prefs
[i
].vValue
.u
.Integer
);
1190 security_mask
= prefs
[i
].vValue
.u
.Integer
;
1192 security_mask
= ADS_SECURITY_INFO_OWNER
;
1194 ber
= ber_alloc_t(LBER_USE_DER
);
1195 if (!ber
|| ber_printf(ber
, (char *)"{i}", security_mask
) == -1 || ber_flatten(ber
, &berval
) == -1)
1198 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREF
;
1201 TRACE("ber: %s\n", debugstr_an(berval
->bv_val
, berval
->bv_len
));
1203 mask
.ldctl_oid
= (WCHAR
*)L
"1.2.840.113556.1.4.801";
1204 mask
.ldctl_iscritical
= TRUE
;
1205 mask
.ldctl_value
.bv_val
= berval
->bv_val
;
1206 mask
.ldctl_value
.bv_len
= berval
->bv_len
;
1209 err
= ldap_set_optionW(ldap
->ld
, LDAP_OPT_SERVER_CONTROLS
, ctrls
);
1210 if (err
!= LDAP_SUCCESS
)
1212 TRACE("ldap_set_option error %#x\n", err
);
1213 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREF
;
1214 hr
= S_ADS_ERRORSOCCURRED
;
1217 prefs
[i
].dwStatus
= ADS_STATUS_S_OK
;
1224 case ADS_SEARCHPREF_PAGESIZE
:
1225 if (prefs
[i
].vValue
.dwType
!= ADSTYPE_INTEGER
)
1227 FIXME("ADS_SEARCHPREF_PAGESIZE: unsupported dwType %d\n", prefs
[i
].vValue
.dwType
);
1228 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1232 TRACE("PAGESIZE: %d\n", prefs
[i
].vValue
.u
.Integer
);
1233 ldap
->search
.pagesize
= prefs
[i
].vValue
.u
.Integer
;
1234 prefs
[i
].dwStatus
= ADS_STATUS_S_OK
;
1237 case ADS_SEARCHPREF_CACHE_RESULTS
:
1238 if (prefs
[i
].vValue
.dwType
!= ADSTYPE_BOOLEAN
)
1240 FIXME("ADS_SEARCHPREF_CACHE_RESULTS: unsupported dwType %d\n", prefs
[i
].vValue
.dwType
);
1241 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1245 TRACE("CACHE_RESULTS: %d\n", prefs
[i
].vValue
.u
.Boolean
);
1246 ldap
->search
.cache_results
= prefs
[i
].vValue
.u
.Boolean
;
1247 prefs
[i
].dwStatus
= ADS_STATUS_S_OK
;
1250 case ADS_SEARCHPREF_ATTRIBTYPES_ONLY
:
1251 if (prefs
[i
].vValue
.dwType
!= ADSTYPE_BOOLEAN
)
1253 FIXME("ADS_SEARCHPREF_ATTRIBTYPES_ONLY: unsupported dwType %d\n", prefs
[i
].vValue
.dwType
);
1254 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1258 TRACE("ATTRIBTYPES_ONLY: %d\n", prefs
[i
].vValue
.u
.Boolean
);
1259 ldap
->search
.attribtypes_only
= prefs
[i
].vValue
.u
.Boolean
;
1260 prefs
[i
].dwStatus
= ADS_STATUS_S_OK
;
1263 case ADS_SEARCHPREF_TOMBSTONE
:
1264 if (prefs
[i
].vValue
.dwType
!= ADSTYPE_BOOLEAN
)
1266 FIXME("ADS_SEARCHPREF_TOMBSTONE: unsupported dwType %d\n", prefs
[i
].vValue
.dwType
);
1267 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1271 TRACE("TOMBSTONE: %d\n", prefs
[i
].vValue
.u
.Boolean
);
1272 ldap
->search
.tombstone
= prefs
[i
].vValue
.u
.Boolean
;
1273 prefs
[i
].dwStatus
= ADS_STATUS_S_OK
;
1277 FIXME("pref %d, type %u: stub\n", prefs
[i
].dwSearchPref
, prefs
[i
].vValue
.dwType
);
1278 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREF
;
1286 static HRESULT WINAPI
search_ExecuteSearch(IDirectorySearch
*iface
, LPWSTR filter
, LPWSTR
*names
,
1287 DWORD count
, PADS_SEARCH_HANDLE res
)
1289 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1292 LDAPControlW
**ctrls
= NULL
, *ctrls_a
[2], tombstone
;
1293 struct ldap_search_context
*ldap_ctx
;
1295 TRACE("%p,%s,%p,%u,%p\n", iface
, debugstr_w(filter
), names
, count
, res
);
1297 if (!res
) return E_ADS_BAD_PARAMETER
;
1299 ldap_ctx
= heap_alloc_zero(sizeof(*ldap_ctx
));
1300 if (!ldap_ctx
) return E_OUTOFMEMORY
;
1302 if (count
== 0xffffffff)
1306 if (count
&& !names
) return E_ADS_BAD_PARAMETER
;
1308 props
= heap_alloc((count
+ 1) * sizeof(props
[0]));
1311 heap_free(ldap_ctx
);
1312 return E_OUTOFMEMORY
;
1315 for (i
= 0; i
< count
; i
++)
1317 TRACE("=> %s\n", debugstr_w(names
[i
]));
1318 props
[i
] = names
[i
];
1321 props
[count
] = NULL
;
1324 if (ldap
->search
.tombstone
)
1326 tombstone
.ldctl_oid
= (WCHAR
*)L
"1.2.840.113556.1.4.417";
1327 tombstone
.ldctl_iscritical
= TRUE
;
1328 tombstone
.ldctl_value
.bv_val
= NULL
;
1329 tombstone
.ldctl_value
.bv_len
= 0;
1330 ctrls_a
[0] = &tombstone
;
1335 if (ldap
->search
.pagesize
)
1337 ldap_ctx
->page
= ldap_search_init_pageW(ldap
->ld
, ldap
->object
, ldap
->search
.scope
,
1338 filter
, props
, ldap
->search
.attribtypes_only
,
1339 ctrls
, NULL
, 0, 0, NULL
);
1341 err
= ldap_get_next_page_s(ldap
->ld
, ldap_ctx
->page
, NULL
,
1342 ldap
->search
.pagesize
, &count
, &ldap_ctx
->res
);
1344 err
= LDAP_NO_MEMORY
;
1347 err
= ldap_search_ext_sW(ldap
->ld
, ldap
->object
, ldap
->search
.scope
, filter
, props
,
1348 ldap
->search
.attribtypes_only
, ctrls
, NULL
, NULL
, 0, &ldap_ctx
->res
);
1350 if (err
!= LDAP_SUCCESS
)
1352 TRACE("ldap_search_sW error %#x\n", err
);
1354 ldap_search_abandon_page(ldap
->ld
, ldap_ctx
->page
);
1355 heap_free(ldap_ctx
);
1356 return HRESULT_FROM_WIN32(map_ldap_error(err
));
1363 static HRESULT WINAPI
search_AbandonSearch(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
)
1365 FIXME("%p,%p: stub\n", iface
, res
);
1369 static HRESULT WINAPI
search_GetFirstRow(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
)
1371 struct ldap_search_context
*ldap_ctx
= res
;
1373 TRACE("%p,%p\n", iface
, res
);
1375 if (!res
) return E_ADS_BAD_PARAMETER
;
1377 ldap_ctx
->entry
= NULL
;
1379 return IDirectorySearch_GetNextRow(iface
, res
);
1382 static HRESULT WINAPI
search_GetNextRow(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
)
1384 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1385 struct ldap_search_context
*ldap_ctx
= res
;
1387 TRACE("%p,%p\n", iface
, res
);
1389 if (!res
) return E_ADS_BAD_PARAMETER
;
1391 if (!ldap_ctx
->entry
)
1393 ldap_ctx
->count
= ldap_count_entries(ldap
->ld
, ldap_ctx
->res
);
1396 if (ldap_ctx
->pos
>= ldap_ctx
->count
)
1397 return S_ADS_NOMORE_ROWS
;
1399 ldap_ctx
->entry
= ldap_first_entry(ldap
->ld
, ldap_ctx
->res
);
1403 if (ldap_ctx
->pos
>= ldap_ctx
->count
)
1409 ldap_msgfree(ldap_ctx
->res
);
1410 ldap_ctx
->res
= NULL
;
1412 err
= ldap_get_next_page_s(ldap
->ld
, ldap_ctx
->page
, NULL
, ldap
->search
.pagesize
, &count
, &ldap_ctx
->res
);
1413 if (err
== LDAP_SUCCESS
)
1415 ldap_ctx
->count
= ldap_count_entries(ldap
->ld
, ldap_ctx
->res
);
1418 if (ldap_ctx
->pos
>= ldap_ctx
->count
)
1419 return S_ADS_NOMORE_ROWS
;
1421 ldap_ctx
->entry
= ldap_first_entry(ldap
->ld
, ldap_ctx
->res
);
1425 if (err
!= LDAP_NO_RESULTS_RETURNED
)
1427 TRACE("ldap_get_next_page_s error %#x\n", err
);
1428 return HRESULT_FROM_WIN32(map_ldap_error(err
));
1433 return S_ADS_NOMORE_ROWS
;
1436 ldap_ctx
->entry
= ldap_next_entry(ldap
->ld
, ldap_ctx
->entry
);
1440 if (!ldap_ctx
->entry
)
1441 return S_ADS_NOMORE_ROWS
;
1444 ldap_ctx
->ber
= NULL
;
1449 static HRESULT WINAPI
search_GetPreviousRow(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
)
1451 FIXME("%p,%p: stub\n", iface
, res
);
1455 static HRESULT WINAPI
search_GetNextColumnName(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
, LPWSTR
*name
)
1457 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1458 struct ldap_search_context
*ldap_ctx
= res
;
1461 TRACE("%p,%p,%p\n", iface
, res
, name
);
1463 if (!name
|| !ldap_ctx
|| !ldap_ctx
->entry
) return E_ADS_BAD_PARAMETER
;
1467 attr
= ldap_first_attributeW(ldap
->ld
, ldap_ctx
->entry
, &ldap_ctx
->ber
);
1468 ldap_ctx
->add_ADsPath
= TRUE
;
1471 attr
= ldap_next_attributeW(ldap
->ld
, ldap_ctx
->entry
, ldap_ctx
->ber
);
1475 TRACE("=> %s\n", debugstr_w(attr
));
1476 *name
= AllocADsStr(attr
);
1477 ldap_memfreeW(attr
);
1478 return *name
? S_OK
: E_OUTOFMEMORY
;
1480 else if (ldap_ctx
->add_ADsPath
)
1482 ldap_ctx
->add_ADsPath
= FALSE
;
1483 *name
= AllocADsStr((WCHAR
*)L
"ADsPath");
1484 TRACE("=> %s\n", debugstr_w(*name
));
1485 return *name
? S_OK
: E_OUTOFMEMORY
;
1489 return S_ADS_NOMORE_COLUMNS
;
1492 static HRESULT
add_column_values(LDAP_namespace
*ldap
, struct ldap_search_context
*ldap_ctx
,
1493 LPWSTR name
, ADS_SEARCH_COLUMN
*col
)
1498 type
= get_schema_type(name
, ldap
->at
, ldap
->at_single_count
, ldap
->at_multiple_count
);
1499 TRACE("%s => type %d\n", debugstr_w(name
), type
);
1504 FIXME("no special handling for type %d\n", type
);
1506 case ADSTYPE_DN_STRING
:
1507 case ADSTYPE_CASE_EXACT_STRING
:
1508 case ADSTYPE_CASE_IGNORE_STRING
:
1509 case ADSTYPE_PRINTABLE_STRING
:
1511 WCHAR
**values
= ldap_get_valuesW(ldap
->ld
, ldap_ctx
->entry
, name
);
1513 return E_ADS_COLUMN_NOT_SET
;
1514 count
= ldap_count_valuesW(values
);
1516 col
->pADsValues
= heap_alloc_zero(count
* sizeof(col
->pADsValues
[0]));
1517 if (!col
->pADsValues
)
1519 ldap_value_freeW(values
);
1520 return E_OUTOFMEMORY
;
1523 for (i
= 0; i
< count
; i
++)
1525 TRACE("=> %s\n", debugstr_w(values
[i
]));
1526 col
->pADsValues
[i
].dwType
= type
;
1527 col
->pADsValues
[i
].u
.CaseIgnoreString
= values
[i
];
1530 col
->hReserved
= values
;
1534 case ADSTYPE_BOOLEAN
:
1536 WCHAR
**values
= ldap_get_valuesW(ldap
->ld
, ldap_ctx
->entry
, name
);
1538 return E_ADS_COLUMN_NOT_SET
;
1539 count
= ldap_count_valuesW(values
);
1541 col
->pADsValues
= heap_alloc_zero(count
* sizeof(col
->pADsValues
[0]));
1542 if (!col
->pADsValues
)
1544 ldap_value_freeW(values
);
1545 return E_OUTOFMEMORY
;
1548 for (i
= 0; i
< count
; i
++)
1550 col
->pADsValues
[i
].dwType
= type
;
1552 if (!wcsicmp(values
[i
], L
"TRUE"))
1553 col
->pADsValues
[i
].u
.Boolean
= 1;
1554 else if (!wcsicmp(values
[i
], L
"FALSE"))
1555 col
->pADsValues
[i
].u
.Boolean
= 0;
1558 FIXME("not recognized boolean value %s\n", debugstr_w(values
[i
]));
1559 col
->pADsValues
[i
].u
.Boolean
= 0;
1561 TRACE("%s => %d\n", debugstr_w(values
[i
]), col
->pADsValues
[i
].u
.Boolean
);
1564 ldap_value_freeW(values
);
1565 col
->hReserved
= NULL
;
1569 case ADSTYPE_INTEGER
:
1570 case ADSTYPE_LARGE_INTEGER
:
1572 struct berval
**values
= ldap_get_values_lenW(ldap
->ld
, ldap_ctx
->entry
, name
);
1574 return E_ADS_COLUMN_NOT_SET
;
1575 count
= ldap_count_values_len(values
);
1577 col
->pADsValues
= heap_alloc_zero(count
* sizeof(col
->pADsValues
[0]));
1578 if (!col
->pADsValues
)
1580 ldap_value_free_len(values
);
1581 return E_OUTOFMEMORY
;
1584 for (i
= 0; i
< count
; i
++)
1586 col
->pADsValues
[i
].dwType
= type
;
1588 if (type
== ADSTYPE_LARGE_INTEGER
)
1590 col
->pADsValues
[i
].u
.LargeInteger
.QuadPart
= _atoi64(values
[i
]->bv_val
);
1591 TRACE("%s => %s\n", debugstr_an(values
[i
]->bv_val
, values
[i
]->bv_len
), wine_dbgstr_longlong(col
->pADsValues
[i
].u
.LargeInteger
.QuadPart
));
1595 col
->pADsValues
[i
].u
.Integer
= atol(values
[i
]->bv_val
);
1596 TRACE("%s => %d\n", debugstr_an(values
[i
]->bv_val
, values
[i
]->bv_len
), col
->pADsValues
[i
].u
.Integer
);
1600 ldap_value_free_len(values
);
1601 col
->hReserved
= NULL
;
1605 case ADSTYPE_OCTET_STRING
:
1606 case ADSTYPE_NT_SECURITY_DESCRIPTOR
:
1608 struct berval
**values
= ldap_get_values_lenW(ldap
->ld
, ldap_ctx
->entry
, name
);
1610 return E_ADS_COLUMN_NOT_SET
;
1611 count
= ldap_count_values_len(values
);
1613 col
->pADsValues
= heap_alloc_zero(count
* sizeof(col
->pADsValues
[0]));
1614 if (!col
->pADsValues
)
1616 ldap_value_free_len(values
);
1617 return E_OUTOFMEMORY
;
1620 for (i
= 0; i
< count
; i
++)
1622 TRACE("=> %s\n", debugstr_an(values
[i
]->bv_val
, values
[i
]->bv_len
));
1623 col
->pADsValues
[i
].dwType
= type
;
1624 col
->pADsValues
[i
].u
.OctetString
.dwLength
= values
[i
]->bv_len
;
1625 col
->pADsValues
[i
].u
.OctetString
.lpValue
= (BYTE
*)values
[i
]->bv_val
;
1628 col
->hReserved
= values
;
1632 case ADSTYPE_UTC_TIME
:
1634 struct berval
**values
= ldap_get_values_lenW(ldap
->ld
, ldap_ctx
->entry
, name
);
1636 return E_ADS_COLUMN_NOT_SET
;
1637 count
= ldap_count_values_len(values
);
1639 col
->pADsValues
= heap_alloc_zero(count
* sizeof(col
->pADsValues
[0]));
1640 if (!col
->pADsValues
)
1642 ldap_value_free_len(values
);
1643 return E_OUTOFMEMORY
;
1646 for (i
= 0; i
< count
; i
++)
1648 col
->pADsValues
[i
].dwType
= type
;
1649 if (values
[i
]->bv_len
< 14 ||
1650 _snscanf_l(values
[i
]->bv_val
, values
[i
]->bv_len
, "%04hu%02hu%02hu%02hu%02hu%02hu", NULL
,
1651 &col
->pADsValues
[i
].u
.UTCTime
.wYear
, &col
->pADsValues
[i
].u
.UTCTime
.wMonth
,
1652 &col
->pADsValues
[i
].u
.UTCTime
.wDay
, &col
->pADsValues
[i
].u
.UTCTime
.wHour
,
1653 &col
->pADsValues
[i
].u
.UTCTime
.wMinute
, &col
->pADsValues
[i
].u
.UTCTime
.wSecond
) != 6)
1655 FIXME("not recognized UTCTime: %s\n", debugstr_an(values
[i
]->bv_val
, values
[i
]->bv_len
));
1656 memset(&col
->pADsValues
[i
].u
.UTCTime
, 0, sizeof(col
->pADsValues
[i
].u
.UTCTime
));
1660 if ((values
[i
]->bv_val
[14] != '.' && values
[i
]->bv_val
[14] != ',') ||
1661 values
[i
]->bv_val
[15] != '0' || values
[i
]->bv_val
[16] != 'Z')
1662 FIXME("not handled time zone: %s\n", debugstr_an(values
[i
]->bv_val
+ 14, values
[i
]->bv_len
- 14));
1664 TRACE("%s => %02u.%02u.%04u %02u:%02u:%02u\n", debugstr_an(values
[i
]->bv_val
, values
[i
]->bv_len
),
1665 col
->pADsValues
[i
].u
.UTCTime
.wDay
, col
->pADsValues
[i
].u
.UTCTime
.wMonth
,
1666 col
->pADsValues
[i
].u
.UTCTime
.wYear
, col
->pADsValues
[i
].u
.UTCTime
.wHour
,
1667 col
->pADsValues
[i
].u
.UTCTime
.wMinute
, col
->pADsValues
[i
].u
.UTCTime
.wSecond
);
1670 ldap_value_free_len(values
);
1671 col
->hReserved
= NULL
;
1675 case ADSTYPE_DN_WITH_BINARY
:
1677 static const BYTE hex2bin
[] =
1679 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x00 */
1680 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x10 */
1681 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x20 */
1682 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, /* 0x30 */
1683 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0, /* 0x40 */
1684 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x50 */
1685 0,10,11,12,13,14,15 /* 0x60 */
1687 ADS_DN_WITH_BINARY
*dnb
;
1688 WCHAR
**values
= ldap_get_valuesW(ldap
->ld
, ldap_ctx
->entry
, name
);
1690 return E_ADS_COLUMN_NOT_SET
;
1691 count
= ldap_count_valuesW(values
);
1693 col
->pADsValues
= heap_alloc_zero(count
* (sizeof(col
->pADsValues
[0]) + sizeof(col
->pADsValues
[0].u
.pDNWithBinary
[0])));
1694 if (!col
->pADsValues
)
1696 ldap_value_freeW(values
);
1697 return E_OUTOFMEMORY
;
1700 dnb
= (ADS_DN_WITH_BINARY
*)(col
->pADsValues
+ count
);
1702 for (i
= 0; i
< count
; i
++)
1704 WCHAR
*p
= values
[i
];
1707 col
->pADsValues
[i
].dwType
= type
;
1708 col
->pADsValues
[i
].u
.pDNWithBinary
= dnb
++;
1710 if ((p
[0] != 'b' && p
[0] != 'B') || p
[1] != ':')
1711 FIXME("wrong DN with binary tag '%c%c'\n", p
[0], p
[1]);
1714 col
->pADsValues
[i
].u
.pDNWithBinary
->dwLength
= wcstol(p
, &p
, 10) / 2;
1716 FIXME("wrong DN with binary separator '%c'\n", *p
);
1718 col
->pADsValues
[i
].u
.pDNWithBinary
->lpBinaryValue
= (BYTE
*)p
;
1719 /* decode values in-place */
1720 for (n
= 0; n
< col
->pADsValues
[i
].u
.pDNWithBinary
->dwLength
; n
++, p
+= 2)
1724 if (p
[0] > 'f' || (p
[0] != '0' && !hex2bin
[p
[0]]) ||
1725 p
[1] > 'f' || (p
[1] != '0' && !hex2bin
[p
[1]]))
1727 FIXME("bad hex encoding at %s\n", debugstr_w(p
));
1731 b
= (hex2bin
[p
[0]] << 4) | hex2bin
[p
[1]];
1732 col
->pADsValues
[i
].u
.pDNWithBinary
->lpBinaryValue
[n
] = b
;
1735 FIXME("wrong DN with binary separator '%c'\n", *p
);
1736 col
->pADsValues
[i
].u
.pDNWithBinary
->pszDNString
= p
+ 1;
1738 TRACE("%s => %u,%s,%s\n", debugstr_w(values
[i
]),
1739 col
->pADsValues
[i
].u
.pDNWithBinary
->dwLength
,
1740 debugstr_an((char *)col
->pADsValues
[i
].u
.pDNWithBinary
->lpBinaryValue
, col
->pADsValues
[i
].u
.pDNWithBinary
->dwLength
),
1741 debugstr_w(col
->pADsValues
[i
].u
.pDNWithBinary
->pszDNString
));
1744 col
->hReserved
= values
;
1749 col
->dwADsType
= type
;
1750 col
->dwNumValues
= count
;
1751 col
->pszAttrName
= strdupW(name
);
1756 static HRESULT WINAPI
search_GetColumn(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
,
1757 LPWSTR name
, PADS_SEARCH_COLUMN col
)
1759 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1760 struct ldap_search_context
*ldap_ctx
= res
;
1764 TRACE("%p,%p,%s,%p\n", iface
, res
, debugstr_w(name
), col
);
1766 if (!res
|| !name
|| !ldap_ctx
->entry
) return E_ADS_BAD_PARAMETER
;
1768 memset(col
, 0, sizeof(*col
));
1770 if (!wcsicmp(name
, L
"ADsPath"))
1772 WCHAR
*dn
= ldap_get_dnW(ldap
->ld
, ldap_ctx
->entry
);
1774 col
->pADsValues
= heap_alloc(sizeof(col
->pADsValues
[0]));
1775 if (!col
->pADsValues
)
1781 count
= sizeof(L
"LDAP://") + (wcslen(ldap
->host
) + 1 /* '/' */) * sizeof(WCHAR
);
1782 if (dn
) count
+= wcslen(dn
) * sizeof(WCHAR
);
1784 col
->pADsValues
[0].u
.CaseIgnoreString
= heap_alloc(count
);
1785 if (!col
->pADsValues
[0].u
.CaseIgnoreString
)
1791 wcscpy(col
->pADsValues
[0].u
.CaseIgnoreString
, L
"LDAP://");
1792 wcscat(col
->pADsValues
[0].u
.CaseIgnoreString
, ldap
->host
);
1793 wcscat(col
->pADsValues
[0].u
.CaseIgnoreString
, L
"/");
1794 if (dn
) wcscat(col
->pADsValues
[0].u
.CaseIgnoreString
, dn
);
1795 col
->pADsValues
[0].dwType
= ADSTYPE_CASE_IGNORE_STRING
;
1796 col
->dwADsType
= ADSTYPE_CASE_IGNORE_STRING
;
1797 col
->dwNumValues
= 1;
1798 col
->pszAttrName
= strdupW(name
);
1799 col
->hReserved
= NULL
;
1801 TRACE("=> %s\n", debugstr_w(col
->pADsValues
[0].u
.CaseIgnoreString
));
1808 return add_column_values(ldap
, ldap_ctx
, name
, col
);
1811 static HRESULT WINAPI
search_FreeColumn(IDirectorySearch
*iface
, PADS_SEARCH_COLUMN col
)
1813 TRACE("%p,%p\n", iface
, col
);
1815 if (!col
) return E_ADS_BAD_PARAMETER
;
1817 if (!wcsicmp(col
->pszAttrName
, L
"ADsPath"))
1818 heap_free(col
->pADsValues
[0].u
.CaseIgnoreString
);
1819 heap_free(col
->pADsValues
);
1820 heap_free(col
->pszAttrName
);
1824 if (col
->dwADsType
== ADSTYPE_OCTET_STRING
|| col
->dwADsType
== ADSTYPE_NT_SECURITY_DESCRIPTOR
)
1825 ldap_value_free_len(col
->hReserved
);
1827 ldap_value_freeW(col
->hReserved
);
1833 static HRESULT WINAPI
search_CloseSearchHandle(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
)
1835 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1836 struct ldap_search_context
*ldap_ctx
= res
;
1838 TRACE("%p,%p\n", iface
, res
);
1840 if (!res
) return E_ADS_BAD_PARAMETER
;
1843 ldap_search_abandon_page(ldap
->ld
, ldap_ctx
->page
);
1845 ldap_msgfree(ldap_ctx
->res
);
1847 ber_free(ldap_ctx
->ber
, 0);
1848 heap_free(ldap_ctx
);
1853 static const IDirectorySearchVtbl IDirectorySearch_vtbl
=
1855 search_QueryInterface
,
1858 search_SetSearchPreference
,
1859 search_ExecuteSearch
,
1860 search_AbandonSearch
,
1863 search_GetPreviousRow
,
1864 search_GetNextColumnName
,
1867 search_CloseSearchHandle
1870 static inline LDAP_namespace
*impl_from_IDirectoryObject(IDirectoryObject
*iface
)
1872 return CONTAINING_RECORD(iface
, LDAP_namespace
, IDirectoryObject_iface
);
1875 static HRESULT WINAPI
dirobj_QueryInterface(IDirectoryObject
*iface
, REFIID riid
, void **obj
)
1877 LDAP_namespace
*ldap
= impl_from_IDirectoryObject(iface
);
1879 TRACE("%p,%s,%p\n", iface
, debugstr_guid(riid
), obj
);
1881 if (!riid
|| !obj
) return E_INVALIDARG
;
1883 if (IsEqualGUID(riid
, &IID_IDirectoryObject
) ||
1884 IsEqualGUID(riid
, &IID_IUnknown
))
1886 IDirectoryObject_AddRef(iface
);
1891 return IADs_QueryInterface(&ldap
->IADs_iface
, riid
, obj
);
1894 static ULONG WINAPI
dirobj_AddRef(IDirectoryObject
*iface
)
1896 LDAP_namespace
*ldap
= impl_from_IDirectoryObject(iface
);
1897 return IADs_AddRef(&ldap
->IADs_iface
);
1900 static ULONG WINAPI
dirobj_Release(IDirectoryObject
*iface
)
1902 LDAP_namespace
*ldap
= impl_from_IDirectoryObject(iface
);
1903 return IADs_Release(&ldap
->IADs_iface
);
1906 static HRESULT WINAPI
dirobj_GetObjectInformation(IDirectoryObject
*iface
, PADS_OBJECT_INFO
*info
)
1908 FIXME("%p,%p: stub\n", iface
, info
);
1912 static HRESULT WINAPI
dirobj_GetObjectAttributes(IDirectoryObject
*iface
, LPWSTR
*names
,
1913 DWORD count
, PADS_ATTR_INFO
*attrs
, DWORD
*count_returned
)
1915 FIXME("%p,%p,%u,%p,%p: stub\n", iface
, names
, count
, attrs
, count_returned
);
1919 static HRESULT WINAPI
dirobj_SetObjectAttributes(IDirectoryObject
*iface
, PADS_ATTR_INFO attrs
,
1920 DWORD count
, DWORD
*count_set
)
1922 FIXME("%p,%p,%u,%p: stub\n", iface
, attrs
, count
, count_set
);
1926 static HRESULT WINAPI
dirobj_CreateDSObject(IDirectoryObject
*iface
, LPWSTR name
,
1927 PADS_ATTR_INFO attrs
, DWORD count
, IDispatch
**obj
)
1929 FIXME("%p,%s,%p,%u,%p: stub\n", iface
, debugstr_w(name
), attrs
, count
, obj
);
1933 static HRESULT WINAPI
dirobj_DeleteDSObject(IDirectoryObject
*iface
, LPWSTR name
)
1935 FIXME("%p,%s: stub\n", iface
, debugstr_w(name
));
1939 static const IDirectoryObjectVtbl IDirectoryObject_vtbl
=
1941 dirobj_QueryInterface
,
1944 dirobj_GetObjectInformation
,
1945 dirobj_GetObjectAttributes
,
1946 dirobj_SetObjectAttributes
,
1947 dirobj_CreateDSObject
,
1948 dirobj_DeleteDSObject
1951 static HRESULT
LDAPNamespace_create(REFIID riid
, void **obj
)
1953 LDAP_namespace
*ldap
;
1956 ldap
= heap_alloc(sizeof(*ldap
));
1957 if (!ldap
) return E_OUTOFMEMORY
;
1959 ldap
->IADs_iface
.lpVtbl
= &IADs_vtbl
;
1960 ldap
->IADsOpenDSObject_iface
.lpVtbl
= &IADsOpenDSObject_vtbl
;
1961 ldap
->IDirectorySearch_iface
.lpVtbl
= &IDirectorySearch_vtbl
;
1962 ldap
->IDirectoryObject_iface
.lpVtbl
= &IDirectoryObject_vtbl
;
1966 ldap
->object
= NULL
;
1967 ldap
->attrs_count
= 0;
1968 ldap
->attrs_count_allocated
= 0;
1970 ldap
->search
.scope
= ADS_SCOPE_SUBTREE
;
1971 ldap
->search
.pagesize
= 0;
1972 ldap
->search
.cache_results
= TRUE
;
1973 ldap
->search
.attribtypes_only
= FALSE
;
1974 ldap
->search
.tombstone
= FALSE
;
1976 ldap
->at_single_count
= 0;
1977 ldap
->at_multiple_count
= 0;
1979 hr
= IADs_QueryInterface(&ldap
->IADs_iface
, riid
, obj
);
1980 IADs_Release(&ldap
->IADs_iface
);
1985 static const struct class_info
1988 HRESULT (*constructor
)(REFIID
, void **);
1991 { &CLSID_ADSystemInfo
, ADSystemInfo_create
},
1992 { &CLSID_LDAP
, LDAP_create
},
1993 { &CLSID_LDAPNamespace
, LDAPNamespace_create
},
1998 IClassFactory IClassFactory_iface
;
2000 const struct class_info
*info
;
2003 static inline class_factory
*impl_from_IClassFactory(IClassFactory
*iface
)
2005 return CONTAINING_RECORD(iface
, class_factory
, IClassFactory_iface
);
2008 static HRESULT WINAPI
factory_QueryInterface(IClassFactory
*iface
, REFIID riid
, LPVOID
*obj
)
2010 TRACE("%p,%s,%p\n", iface
, debugstr_guid(riid
), obj
);
2012 if (!riid
|| !obj
) return E_INVALIDARG
;
2014 if (IsEqualIID(riid
, &IID_IUnknown
) ||
2015 IsEqualIID(riid
, &IID_IClassFactory
))
2017 IClassFactory_AddRef(iface
);
2023 FIXME("interface %s is not implemented\n", debugstr_guid(riid
));
2024 return E_NOINTERFACE
;
2027 static ULONG WINAPI
factory_AddRef(IClassFactory
*iface
)
2029 class_factory
*factory
= impl_from_IClassFactory(iface
);
2030 ULONG ref
= InterlockedIncrement(&factory
->ref
);
2032 TRACE("(%p) ref %u\n", iface
, ref
);
2037 static ULONG WINAPI
factory_Release(IClassFactory
*iface
)
2039 class_factory
*factory
= impl_from_IClassFactory(iface
);
2040 ULONG ref
= InterlockedDecrement(&factory
->ref
);
2042 TRACE("(%p) ref %u\n", iface
, ref
);
2050 static HRESULT WINAPI
factory_CreateInstance(IClassFactory
*iface
, IUnknown
*outer
, REFIID riid
, void **obj
)
2052 class_factory
*factory
= impl_from_IClassFactory(iface
);
2054 TRACE("%p,%s,%p\n", outer
, debugstr_guid(riid
), obj
);
2056 if (!riid
|| !obj
) return E_INVALIDARG
;
2059 if (outer
) return CLASS_E_NOAGGREGATION
;
2061 return factory
->info
->constructor(riid
, obj
);
2064 static HRESULT WINAPI
factory_LockServer(IClassFactory
*iface
, BOOL lock
)
2066 FIXME("%p,%d: stub\n", iface
, lock
);
2070 static const struct IClassFactoryVtbl factory_vtbl
=
2072 factory_QueryInterface
,
2075 factory_CreateInstance
,
2079 static HRESULT
factory_constructor(const struct class_info
*info
, REFIID riid
, void **obj
)
2081 class_factory
*factory
;
2084 factory
= heap_alloc(sizeof(*factory
));
2085 if (!factory
) return E_OUTOFMEMORY
;
2087 factory
->IClassFactory_iface
.lpVtbl
= &factory_vtbl
;
2089 factory
->info
= info
;
2091 hr
= IClassFactory_QueryInterface(&factory
->IClassFactory_iface
, riid
, obj
);
2092 IClassFactory_Release(&factory
->IClassFactory_iface
);
2097 HRESULT WINAPI
DllGetClassObject(REFCLSID clsid
, REFIID iid
, LPVOID
*obj
)
2101 TRACE("%s,%s,%p\n", debugstr_guid(clsid
), debugstr_guid(iid
), obj
);
2103 if (!clsid
|| !iid
|| !obj
) return E_INVALIDARG
;
2107 for (i
= 0; i
< ARRAY_SIZE(class_info
); i
++)
2109 if (IsEqualCLSID(class_info
[i
].clsid
, clsid
))
2110 return factory_constructor(&class_info
[i
], iid
, obj
);
2113 FIXME("class %s/%s is not implemented\n", debugstr_guid(clsid
), debugstr_guid(iid
));
2114 return CLASS_E_CLASSNOTAVAILABLE
;
2117 HRESULT WINAPI
DllCanUnloadNow(void)
2122 HRESULT WINAPI
DllRegisterServer(void)
2124 return __wine_register_resources(adsldp_hinst
);
2127 HRESULT WINAPI
DllUnregisterServer(void)
2129 return __wine_unregister_resources(adsldp_hinst
);
2132 BOOL WINAPI
DllMain(HINSTANCE hinst
, DWORD reason
, void *reserved
)
2134 TRACE("%p,%u,%p\n", hinst
, reason
, reserved
);
2138 case DLL_WINE_PREATTACH
:
2139 return FALSE
; /* prefer native version */
2141 case DLL_PROCESS_ATTACH
:
2142 adsldp_hinst
= hinst
;
2143 DisableThreadLibraryCalls(hinst
);