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
43 #include "adsldp_private.h"
45 #include "wine/debug.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(adsldp
);
49 #ifndef LDAP_OPT_SERVER_CONTROLS
50 #define LDAP_OPT_SERVER_CONTROLS 0x0012
53 DEFINE_GUID(CLSID_LDAP
,0x228d9a81,0xc302,0x11cf,0x9a,0xa4,0x00,0xaa,0x00,0x4a,0x56,0x91);
54 DEFINE_GUID(CLSID_LDAPNamespace
,0x228d9a82,0xc302,0x11cf,0x9a,0xa4,0x00,0xaa,0x00,0x4a,0x56,0x91);
56 static HRESULT
LDAPNamespace_create(REFIID riid
, void **obj
);
60 IParseDisplayName IParseDisplayName_iface
;
64 static inline LDAP_PARSE
*impl_from_IParseDisplayName(IParseDisplayName
*iface
)
66 return CONTAINING_RECORD(iface
, LDAP_PARSE
, IParseDisplayName_iface
);
69 static HRESULT WINAPI
ldap_QueryInterface(IParseDisplayName
*iface
, REFIID riid
, void **obj
)
71 TRACE("%p,%s,%p\n", iface
, debugstr_guid(riid
), obj
);
73 if (!riid
|| !obj
) return E_INVALIDARG
;
75 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
76 IsEqualGUID(riid
, &IID_IParseDisplayName
))
78 IParseDisplayName_AddRef(iface
);
84 FIXME("interface %s is not implemented\n", debugstr_guid(riid
));
88 static ULONG WINAPI
ldap_AddRef(IParseDisplayName
*iface
)
90 LDAP_PARSE
*ldap
= impl_from_IParseDisplayName(iface
);
91 return InterlockedIncrement(&ldap
->ref
);
94 static ULONG WINAPI
ldap_Release(IParseDisplayName
*iface
)
96 LDAP_PARSE
*ldap
= impl_from_IParseDisplayName(iface
);
97 LONG ref
= InterlockedDecrement(&ldap
->ref
);
101 TRACE("destroying %p\n", iface
);
108 static HRESULT WINAPI
ldap_ParseDisplayName(IParseDisplayName
*iface
, IBindCtx
*bc
,
109 LPOLESTR name
, ULONG
*eaten
, IMoniker
**mk
)
112 IADsOpenDSObject
*ads_open
;
115 TRACE("%p,%p,%s,%p,%p\n", iface
, bc
, debugstr_w(name
), eaten
, mk
);
117 hr
= LDAPNamespace_create(&IID_IADsOpenDSObject
, (void **)&ads_open
);
118 if (hr
!= S_OK
) return hr
;
120 hr
= IADsOpenDSObject_OpenDSObject(ads_open
, name
, NULL
, NULL
, ADS_SECURE_AUTHENTICATION
, &disp
);
122 hr
= IADsOpenDSObject_OpenDSObject(ads_open
, name
, NULL
, NULL
, 0, &disp
);
125 hr
= CreatePointerMoniker((IUnknown
*)disp
, mk
);
127 *eaten
= wcslen(name
);
129 IDispatch_Release(disp
);
132 IADsOpenDSObject_Release(ads_open
);
137 static const IParseDisplayNameVtbl LDAP_PARSE_vtbl
=
142 ldap_ParseDisplayName
145 static HRESULT
LDAP_create(REFIID riid
, void **obj
)
150 ldap
= heap_alloc(sizeof(*ldap
));
151 if (!ldap
) return E_OUTOFMEMORY
;
153 ldap
->IParseDisplayName_iface
.lpVtbl
= &LDAP_PARSE_vtbl
;
156 hr
= IParseDisplayName_QueryInterface(&ldap
->IParseDisplayName_iface
, riid
, obj
);
157 IParseDisplayName_Release(&ldap
->IParseDisplayName_iface
);
164 IADsADSystemInfo IADsADSystemInfo_iface
;
168 static inline AD_sysinfo
*impl_from_IADsADSystemInfo(IADsADSystemInfo
*iface
)
170 return CONTAINING_RECORD(iface
, AD_sysinfo
, IADsADSystemInfo_iface
);
173 static HRESULT WINAPI
sysinfo_QueryInterface(IADsADSystemInfo
*iface
, REFIID riid
, void **obj
)
175 TRACE("%p,%s,%p\n", iface
, debugstr_guid(riid
), obj
);
177 if (!riid
|| !obj
) return E_INVALIDARG
;
179 if (IsEqualGUID(riid
, &IID_IADsADSystemInfo
) ||
180 IsEqualGUID(riid
, &IID_IDispatch
) ||
181 IsEqualGUID(riid
, &IID_IUnknown
))
183 IADsADSystemInfo_AddRef(iface
);
189 FIXME("interface %s is not implemented\n", debugstr_guid(riid
));
190 return E_NOINTERFACE
;
193 static ULONG WINAPI
sysinfo_AddRef(IADsADSystemInfo
*iface
)
195 AD_sysinfo
*sysinfo
= impl_from_IADsADSystemInfo(iface
);
196 return InterlockedIncrement(&sysinfo
->ref
);
199 static ULONG WINAPI
sysinfo_Release(IADsADSystemInfo
*iface
)
201 AD_sysinfo
*sysinfo
= impl_from_IADsADSystemInfo(iface
);
202 LONG ref
= InterlockedDecrement(&sysinfo
->ref
);
206 TRACE("destroying %p\n", iface
);
213 static HRESULT WINAPI
sysinfo_GetTypeInfoCount(IADsADSystemInfo
*iface
, UINT
*count
)
215 FIXME("%p,%p: stub\n", iface
, count
);
219 static HRESULT WINAPI
sysinfo_GetTypeInfo(IADsADSystemInfo
*iface
, UINT index
, LCID lcid
, ITypeInfo
**info
)
221 FIXME("%p,%u,%#x,%p: stub\n", iface
, index
, lcid
, info
);
225 static HRESULT WINAPI
sysinfo_GetIDsOfNames(IADsADSystemInfo
*iface
, REFIID riid
, LPOLESTR
*names
,
226 UINT count
, LCID lcid
, DISPID
*dispid
)
228 FIXME("%p,%s,%p,%u,%u,%p: stub\n", iface
, debugstr_guid(riid
), names
, count
, lcid
, dispid
);
232 static HRESULT WINAPI
sysinfo_Invoke(IADsADSystemInfo
*iface
, DISPID dispid
, REFIID riid
, LCID lcid
, WORD flags
,
233 DISPPARAMS
*params
, VARIANT
*result
, EXCEPINFO
*excepinfo
, UINT
*argerr
)
235 FIXME("%p,%d,%s,%04x,%04x,%p,%p,%p,%p: stub\n", iface
, dispid
, debugstr_guid(riid
), lcid
, flags
,
236 params
, result
, excepinfo
, argerr
);
240 static HRESULT WINAPI
sysinfo_get_UserName(IADsADSystemInfo
*iface
, BSTR
*retval
)
242 FIXME("%p,%p: stub\n", iface
, retval
);
246 static HRESULT WINAPI
sysinfo_get_ComputerName(IADsADSystemInfo
*iface
, BSTR
*retval
)
251 TRACE("%p,%p\n", iface
, retval
);
254 GetComputerObjectNameW(NameFullyQualifiedDN
, NULL
, &size
);
255 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
256 return HRESULT_FROM_WIN32(GetLastError());
258 name
= SysAllocStringLen(NULL
, size
);
259 if (!name
) return E_OUTOFMEMORY
;
261 if (!GetComputerObjectNameW(NameFullyQualifiedDN
, name
, &size
))
264 return HRESULT_FROM_WIN32(GetLastError());
271 static HRESULT WINAPI
sysinfo_get_SiteName(IADsADSystemInfo
*iface
, BSTR
*retval
)
273 FIXME("%p,%p: stub\n", iface
, retval
);
277 static HRESULT WINAPI
sysinfo_get_DomainShortName(IADsADSystemInfo
*iface
, BSTR
*retval
)
279 FIXME("%p,%p: stub\n", iface
, retval
);
283 static HRESULT WINAPI
sysinfo_get_DomainDNSName(IADsADSystemInfo
*iface
, BSTR
*retval
)
285 FIXME("%p,%p: stub\n", iface
, retval
);
289 static HRESULT WINAPI
sysinfo_get_ForestDNSName(IADsADSystemInfo
*iface
, BSTR
*retval
)
291 FIXME("%p,%p: stub\n", iface
, retval
);
295 static HRESULT WINAPI
sysinfo_get_PDCRoleOwner(IADsADSystemInfo
*iface
, BSTR
*retval
)
297 FIXME("%p,%p: stub\n", iface
, retval
);
301 static HRESULT WINAPI
sysinfo_get_SchemaRoleOwner(IADsADSystemInfo
*iface
, BSTR
*retval
)
303 FIXME("%p,%p: stub\n", iface
, retval
);
307 static HRESULT WINAPI
sysinfo_get_IsNativeMode(IADsADSystemInfo
*iface
, VARIANT_BOOL
*retval
)
309 FIXME("%p,%p: stub\n", iface
, retval
);
313 static HRESULT WINAPI
sysinfo_GetAnyDCName(IADsADSystemInfo
*iface
, BSTR
*retval
)
315 FIXME("%p,%p: stub\n", iface
, retval
);
319 static HRESULT WINAPI
sysinfo_GetDCSiteName(IADsADSystemInfo
*iface
, BSTR server
, BSTR
*retval
)
321 FIXME("%p,%s,%p: stub\n", iface
, debugstr_w(server
), retval
);
325 static HRESULT WINAPI
sysinfo_RefreshSchemaCache(IADsADSystemInfo
*iface
)
327 FIXME("%p: stub\n", iface
);
331 static HRESULT WINAPI
sysinfo_GetTrees(IADsADSystemInfo
*iface
, VARIANT
*retval
)
333 FIXME("%p,%p: stub\n", iface
, retval
);
337 static const IADsADSystemInfoVtbl IADsADSystemInfo_vtbl
=
339 sysinfo_QueryInterface
,
342 sysinfo_GetTypeInfoCount
,
344 sysinfo_GetIDsOfNames
,
346 sysinfo_get_UserName
,
347 sysinfo_get_ComputerName
,
348 sysinfo_get_SiteName
,
349 sysinfo_get_DomainShortName
,
350 sysinfo_get_DomainDNSName
,
351 sysinfo_get_ForestDNSName
,
352 sysinfo_get_PDCRoleOwner
,
353 sysinfo_get_SchemaRoleOwner
,
354 sysinfo_get_IsNativeMode
,
355 sysinfo_GetAnyDCName
,
356 sysinfo_GetDCSiteName
,
357 sysinfo_RefreshSchemaCache
,
361 static HRESULT
ADSystemInfo_create(REFIID riid
, void **obj
)
366 sysinfo
= heap_alloc(sizeof(*sysinfo
));
367 if (!sysinfo
) return E_OUTOFMEMORY
;
369 sysinfo
->IADsADSystemInfo_iface
.lpVtbl
= &IADsADSystemInfo_vtbl
;
372 hr
= IADsADSystemInfo_QueryInterface(&sysinfo
->IADsADSystemInfo_iface
, riid
, obj
);
373 IADsADSystemInfo_Release(&sysinfo
->IADsADSystemInfo_iface
);
378 struct ldap_attribute
387 IADsOpenDSObject IADsOpenDSObject_iface
;
388 IDirectorySearch IDirectorySearch_iface
;
389 IDirectoryObject IDirectoryObject_iface
;
395 ULONG attrs_count
, attrs_count_allocated
;
396 struct ldap_attribute
*attrs
;
397 struct attribute_type
*at
;
398 ULONG at_single_count
, at_multiple_count
;
404 BOOL attribtypes_only
;
409 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
);
791 attr
= ldap_next_attributeW(ldap
->ld
, entry
, ber
);
795 entry
= ldap_next_entry(ldap
->ld
, res
);
799 if (res
) ldap_msgfree(res
);
801 SafeArrayUnaccessData(sa
);
805 static const IADsVtbl IADs_vtbl
=
807 ldapns_QueryInterface
,
810 ldapns_GetTypeInfoCount
,
812 ldapns_GetIDsOfNames
,
829 static inline LDAP_namespace
*impl_from_IADsOpenDSObject(IADsOpenDSObject
*iface
)
831 return CONTAINING_RECORD(iface
, LDAP_namespace
, IADsOpenDSObject_iface
);
834 static HRESULT WINAPI
openobj_QueryInterface(IADsOpenDSObject
*iface
, REFIID riid
, void **obj
)
836 TRACE("%p,%s,%p\n", iface
, debugstr_guid(riid
), obj
);
838 if (!riid
|| !obj
) return E_INVALIDARG
;
840 if (IsEqualGUID(riid
, &IID_IADsOpenDSObject
) ||
841 IsEqualGUID(riid
, &IID_IDispatch
) ||
842 IsEqualGUID(riid
, &IID_IUnknown
))
844 IADsOpenDSObject_AddRef(iface
);
849 FIXME("interface %s is not implemented\n", debugstr_guid(riid
));
850 return E_NOINTERFACE
;
853 static ULONG WINAPI
openobj_AddRef(IADsOpenDSObject
*iface
)
855 LDAP_namespace
*ldap
= impl_from_IADsOpenDSObject(iface
);
856 return IADs_AddRef(&ldap
->IADs_iface
);
859 static ULONG WINAPI
openobj_Release(IADsOpenDSObject
*iface
)
861 LDAP_namespace
*ldap
= impl_from_IADsOpenDSObject(iface
);
862 return IADs_Release(&ldap
->IADs_iface
);
865 static HRESULT WINAPI
openobj_GetTypeInfoCount(IADsOpenDSObject
*iface
, UINT
*count
)
867 FIXME("%p,%p: stub\n", iface
, count
);
871 static HRESULT WINAPI
openobj_GetTypeInfo(IADsOpenDSObject
*iface
, UINT index
, LCID lcid
, ITypeInfo
**info
)
873 FIXME("%p,%u,%#x,%p: stub\n", iface
, index
, lcid
, info
);
877 static HRESULT WINAPI
openobj_GetIDsOfNames(IADsOpenDSObject
*iface
, REFIID riid
, LPOLESTR
*names
,
878 UINT count
, LCID lcid
, DISPID
*dispid
)
880 FIXME("%p,%s,%p,%u,%u,%p: stub\n", iface
, debugstr_guid(riid
), names
, count
, lcid
, dispid
);
884 static HRESULT WINAPI
openobj_Invoke(IADsOpenDSObject
*iface
, DISPID dispid
, REFIID riid
, LCID lcid
, WORD flags
,
885 DISPPARAMS
*params
, VARIANT
*result
, EXCEPINFO
*excepinfo
, UINT
*argerr
)
887 FIXME("%p,%d,%s,%04x,%04x,%p,%p,%p,%p: stub\n", iface
, dispid
, debugstr_guid(riid
), lcid
, flags
,
888 params
, result
, excepinfo
, argerr
);
892 static HRESULT
parse_path(WCHAR
*path
, BSTR
*host
, ULONG
*port
, BSTR
*object
)
897 if (host
) *host
= NULL
;
899 if (object
) *object
= NULL
;
901 if (wcsnicmp(path
, L
"LDAP:", 5) != 0)
902 return E_ADS_BAD_PATHNAME
;
905 if (!*p
) return S_OK
;
907 if (*p
++ != '/' || *p
++ != '/' || !*p
)
908 return E_ADS_BAD_PATHNAME
;
912 while (*p
&& *p
!= '/')
917 if (!port
) port
= &dummy
;
918 *port
= wcstol(p
+ 1, &p
, 10);
919 if (*p
&& *p
!= '/') return E_ADS_BAD_PATHNAME
;
927 if (host_len
== 0) return E_ADS_BAD_PATHNAME
;
931 *host
= SysAllocStringLen(p_host
, host_len
);
932 if (!*host
) return E_OUTOFMEMORY
;
935 if (!*p
) return S_OK
;
937 if (*p
++ != '/' || !*p
)
939 SysFreeString(*host
);
940 return E_ADS_BAD_PATHNAME
;
945 *object
= SysAllocString(p
);
948 SysFreeString(*host
);
949 return E_OUTOFMEMORY
;
956 static HRESULT WINAPI
openobj_OpenDSObject(IADsOpenDSObject
*iface
, BSTR path
, BSTR user
, BSTR password
,
957 LONG flags
, IDispatch
**obj
)
964 ULONG err
, at_single_count
= 0, at_multiple_count
= 0;
965 struct attribute_type
*at
= NULL
;
967 TRACE("%p,%s,%s,%p,%08x,%p\n", iface
, debugstr_w(path
), debugstr_w(user
), password
, flags
, obj
);
969 hr
= parse_path(path
, &host
, &port
, &object
);
970 if (hr
!= S_OK
) return hr
;
972 TRACE("host %s, port %u, object %s\n", debugstr_w(host
), port
, debugstr_w(object
));
978 if (!wcsicmp(host
, L
"rootDSE"))
980 DOMAIN_CONTROLLER_INFOW
*dcinfo
;
984 hr
= E_ADS_BAD_PATHNAME
;
990 err
= DsGetDcNameW(NULL
, NULL
, NULL
, NULL
, DS_RETURN_DNS_NAME
, &dcinfo
);
991 if (err
!= ERROR_SUCCESS
)
993 hr
= HRESULT_FROM_WIN32(LdapGetLastError());
997 host
= SysAllocString(dcinfo
->DomainName
);
998 NetApiBufferFree(dcinfo
);
1007 ld
= ldap_initW(host
, port
);
1010 hr
= HRESULT_FROM_WIN32(LdapGetLastError());
1014 version
= LDAP_VERSION3
;
1015 err
= ldap_set_optionW(ld
, LDAP_OPT_PROTOCOL_VERSION
, &version
);
1016 if (err
!= LDAP_SUCCESS
)
1018 hr
= HRESULT_FROM_WIN32(map_ldap_error(err
));
1023 err
= ldap_connect(ld
, NULL
);
1024 if (err
!= LDAP_SUCCESS
)
1026 hr
= HRESULT_FROM_WIN32(map_ldap_error(err
));
1031 if (flags
& ADS_SECURE_AUTHENTICATION
)
1033 SEC_WINNT_AUTH_IDENTITY_W id
;
1035 id
.Flags
= SEC_WINNT_AUTH_IDENTITY_UNICODE
;
1036 id
.Domain
= (unsigned short *)host
;
1037 id
.DomainLength
= wcslen(host
);
1038 id
.User
= (unsigned short *)user
;
1039 id
.UserLength
= user
? wcslen(user
) : 0;
1040 id
.Password
= (unsigned short *)password
;
1041 id
.PasswordLength
= password
? wcslen(password
) : 0;
1043 err
= ldap_bind_sW(ld
, NULL
, (WCHAR
*)&id
, LDAP_AUTH_NEGOTIATE
);
1044 if (err
!= LDAP_SUCCESS
)
1046 TRACE("ldap_bind_sW error %#x\n", err
);
1047 hr
= HRESULT_FROM_WIN32(map_ldap_error(err
));
1054 err
= ldap_simple_bind_sW(ld
, user
, password
);
1055 if (err
!= LDAP_SUCCESS
)
1057 TRACE("ldap_simple_bind_sW error %#x\n", err
);
1058 hr
= HRESULT_FROM_WIN32(map_ldap_error(err
));
1064 at
= load_schema(ld
, &at_single_count
, &at_multiple_count
);
1067 hr
= LDAPNamespace_create(&IID_IADs
, (void **)&ads
);
1070 LDAP_namespace
*ldap
= impl_from_IADs(ads
);
1074 ldap
->object
= object
;
1076 ldap
->at_single_count
= at_single_count
;
1077 ldap
->at_multiple_count
= at_multiple_count
;
1078 hr
= IADs_QueryInterface(ads
, &IID_IDispatch
, (void **)obj
);
1084 SysFreeString(host
);
1085 SysFreeString(object
);
1090 static const IADsOpenDSObjectVtbl IADsOpenDSObject_vtbl
=
1092 openobj_QueryInterface
,
1095 openobj_GetTypeInfoCount
,
1096 openobj_GetTypeInfo
,
1097 openobj_GetIDsOfNames
,
1099 openobj_OpenDSObject
1102 static inline LDAP_namespace
*impl_from_IDirectorySearch(IDirectorySearch
*iface
)
1104 return CONTAINING_RECORD(iface
, LDAP_namespace
, IDirectorySearch_iface
);
1107 static HRESULT WINAPI
search_QueryInterface(IDirectorySearch
*iface
, REFIID riid
, void **obj
)
1109 TRACE("%p,%s,%p\n", iface
, debugstr_guid(riid
), obj
);
1111 if (!riid
|| !obj
) return E_INVALIDARG
;
1113 if (IsEqualGUID(riid
, &IID_IDirectorySearch
) ||
1114 IsEqualGUID(riid
, &IID_IUnknown
))
1116 IDirectorySearch_AddRef(iface
);
1121 FIXME("interface %s is not implemented\n", debugstr_guid(riid
));
1122 return E_NOINTERFACE
;
1125 static ULONG WINAPI
search_AddRef(IDirectorySearch
*iface
)
1127 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1128 return IADs_AddRef(&ldap
->IADs_iface
);
1131 static ULONG WINAPI
search_Release(IDirectorySearch
*iface
)
1133 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1134 return IADs_Release(&ldap
->IADs_iface
);
1137 static HRESULT WINAPI
search_SetSearchPreference(IDirectorySearch
*iface
, PADS_SEARCHPREF_INFO prefs
, DWORD count
)
1139 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1143 TRACE("%p,%p,%u\n", iface
, prefs
, count
);
1145 for (i
= 0; i
< count
; i
++)
1147 switch (prefs
[i
].dwSearchPref
)
1149 case ADS_SEARCHPREF_SEARCH_SCOPE
:
1150 if (prefs
[i
].vValue
.dwType
!= ADSTYPE_INTEGER
)
1152 FIXME("ADS_SEARCHPREF_SEARCH_SCOPE: unsupported dwType %d\n", prefs
[i
].vValue
.dwType
);
1153 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1157 switch (prefs
[i
].vValue
.u
.Integer
)
1159 case ADS_SCOPE_BASE
:
1160 case ADS_SCOPE_ONELEVEL
:
1161 case ADS_SCOPE_SUBTREE
:
1162 TRACE("SEARCH_SCOPE: %d\n", prefs
[i
].vValue
.u
.Integer
);
1163 ldap
->search
.scope
= prefs
[i
].vValue
.u
.Integer
;
1164 prefs
[i
].dwStatus
= ADS_STATUS_S_OK
;
1168 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1173 case ADS_SEARCHPREF_SECURITY_MASK
:
1178 struct berval
*berval
;
1179 LDAPControlW
*ctrls
[2], mask
;
1181 if (prefs
[i
].vValue
.dwType
!= ADSTYPE_INTEGER
)
1183 FIXME("ADS_SEARCHPREF_SECURITY_MASK: not supported dwType %d\n", prefs
[i
].vValue
.dwType
);
1184 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1188 TRACE("SECURITY_MASK: %08x\n", prefs
[i
].vValue
.u
.Integer
);
1189 security_mask
= prefs
[i
].vValue
.u
.Integer
;
1191 security_mask
= ADS_SECURITY_INFO_OWNER
;
1193 ber
= ber_alloc_t(LBER_USE_DER
);
1194 if (!ber
|| ber_printf(ber
, (char *)"{i}", security_mask
) == -1 || ber_flatten(ber
, &berval
) == -1)
1197 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREF
;
1200 TRACE("ber: %s\n", debugstr_an(berval
->bv_val
, berval
->bv_len
));
1202 mask
.ldctl_oid
= (WCHAR
*)L
"1.2.840.113556.1.4.801";
1203 mask
.ldctl_iscritical
= TRUE
;
1204 mask
.ldctl_value
.bv_val
= berval
->bv_val
;
1205 mask
.ldctl_value
.bv_len
= berval
->bv_len
;
1208 err
= ldap_set_optionW(ldap
->ld
, LDAP_OPT_SERVER_CONTROLS
, ctrls
);
1209 if (err
!= LDAP_SUCCESS
)
1211 TRACE("ldap_set_option error %#x\n", err
);
1212 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREF
;
1213 hr
= S_ADS_ERRORSOCCURRED
;
1216 prefs
[i
].dwStatus
= ADS_STATUS_S_OK
;
1223 case ADS_SEARCHPREF_PAGESIZE
:
1224 if (prefs
[i
].vValue
.dwType
!= ADSTYPE_INTEGER
)
1226 FIXME("ADS_SEARCHPREF_PAGESIZE: unsupported dwType %d\n", prefs
[i
].vValue
.dwType
);
1227 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1231 TRACE("PAGESIZE: %d\n", prefs
[i
].vValue
.u
.Integer
);
1232 ldap
->search
.pagesize
= prefs
[i
].vValue
.u
.Integer
;
1233 prefs
[i
].dwStatus
= ADS_STATUS_S_OK
;
1236 case ADS_SEARCHPREF_CACHE_RESULTS
:
1237 if (prefs
[i
].vValue
.dwType
!= ADSTYPE_BOOLEAN
)
1239 FIXME("ADS_SEARCHPREF_CACHE_RESULTS: unsupported dwType %d\n", prefs
[i
].vValue
.dwType
);
1240 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1244 TRACE("CACHE_RESULTS: %d\n", prefs
[i
].vValue
.u
.Boolean
);
1245 ldap
->search
.cache_results
= prefs
[i
].vValue
.u
.Boolean
;
1246 prefs
[i
].dwStatus
= ADS_STATUS_S_OK
;
1249 case ADS_SEARCHPREF_ATTRIBTYPES_ONLY
:
1250 if (prefs
[i
].vValue
.dwType
!= ADSTYPE_BOOLEAN
)
1252 FIXME("ADS_SEARCHPREF_ATTRIBTYPES_ONLY: unsupported dwType %d\n", prefs
[i
].vValue
.dwType
);
1253 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1257 TRACE("ATTRIBTYPES_ONLY: %d\n", prefs
[i
].vValue
.u
.Boolean
);
1258 ldap
->search
.attribtypes_only
= prefs
[i
].vValue
.u
.Boolean
;
1259 prefs
[i
].dwStatus
= ADS_STATUS_S_OK
;
1262 case ADS_SEARCHPREF_TOMBSTONE
:
1263 if (prefs
[i
].vValue
.dwType
!= ADSTYPE_BOOLEAN
)
1265 FIXME("ADS_SEARCHPREF_TOMBSTONE: unsupported dwType %d\n", prefs
[i
].vValue
.dwType
);
1266 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1270 TRACE("TOMBSTONE: %d\n", prefs
[i
].vValue
.u
.Boolean
);
1271 ldap
->search
.tombstone
= prefs
[i
].vValue
.u
.Boolean
;
1272 prefs
[i
].dwStatus
= ADS_STATUS_S_OK
;
1276 FIXME("pref %d, type %u: stub\n", prefs
[i
].dwSearchPref
, prefs
[i
].vValue
.dwType
);
1277 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREF
;
1285 static HRESULT WINAPI
search_ExecuteSearch(IDirectorySearch
*iface
, LPWSTR filter
, LPWSTR
*names
,
1286 DWORD count
, PADS_SEARCH_HANDLE res
)
1288 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1291 LDAPControlW
**ctrls
= NULL
, *ctrls_a
[2], tombstone
;
1292 struct ldap_search_context
*ldap_ctx
;
1294 TRACE("%p,%s,%p,%u,%p\n", iface
, debugstr_w(filter
), names
, count
, res
);
1296 if (!res
) return E_ADS_BAD_PARAMETER
;
1298 ldap_ctx
= heap_alloc_zero(sizeof(*ldap_ctx
));
1299 if (!ldap_ctx
) return E_OUTOFMEMORY
;
1301 if (count
== 0xffffffff)
1305 if (count
&& !names
) return E_ADS_BAD_PARAMETER
;
1307 props
= heap_alloc((count
+ 1) * sizeof(props
[0]));
1310 heap_free(ldap_ctx
);
1311 return E_OUTOFMEMORY
;
1314 for (i
= 0; i
< count
; i
++)
1316 TRACE("=> %s\n", debugstr_w(names
[i
]));
1317 props
[i
] = names
[i
];
1320 props
[count
] = NULL
;
1323 if (ldap
->search
.tombstone
)
1325 tombstone
.ldctl_oid
= (WCHAR
*)L
"1.2.840.113556.1.4.417";
1326 tombstone
.ldctl_iscritical
= TRUE
;
1327 tombstone
.ldctl_value
.bv_val
= NULL
;
1328 tombstone
.ldctl_value
.bv_len
= 0;
1329 ctrls_a
[0] = &tombstone
;
1334 if (ldap
->search
.pagesize
)
1336 ldap_ctx
->page
= ldap_search_init_pageW(ldap
->ld
, ldap
->object
, ldap
->search
.scope
,
1337 filter
, props
, ldap
->search
.attribtypes_only
,
1338 ctrls
, NULL
, 0, 0, NULL
);
1340 err
= ldap_get_next_page_s(ldap
->ld
, ldap_ctx
->page
, NULL
,
1341 ldap
->search
.pagesize
, &count
, &ldap_ctx
->res
);
1343 err
= LDAP_NO_MEMORY
;
1346 err
= ldap_search_ext_sW(ldap
->ld
, ldap
->object
, ldap
->search
.scope
, filter
, props
,
1347 ldap
->search
.attribtypes_only
, ctrls
, NULL
, NULL
, 0, &ldap_ctx
->res
);
1349 if (err
!= LDAP_SUCCESS
)
1351 TRACE("ldap_search_sW error %#x\n", err
);
1353 ldap_search_abandon_page(ldap
->ld
, ldap_ctx
->page
);
1354 heap_free(ldap_ctx
);
1355 return HRESULT_FROM_WIN32(map_ldap_error(err
));
1362 static HRESULT WINAPI
search_AbandonSearch(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
)
1364 FIXME("%p,%p: stub\n", iface
, res
);
1368 static HRESULT WINAPI
search_GetFirstRow(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
)
1370 struct ldap_search_context
*ldap_ctx
= res
;
1372 TRACE("%p,%p\n", iface
, res
);
1374 if (!res
) return E_ADS_BAD_PARAMETER
;
1376 ldap_ctx
->entry
= NULL
;
1378 return IDirectorySearch_GetNextRow(iface
, res
);
1381 static HRESULT WINAPI
search_GetNextRow(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
)
1383 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1384 struct ldap_search_context
*ldap_ctx
= res
;
1386 TRACE("%p,%p\n", iface
, res
);
1388 if (!res
) return E_ADS_BAD_PARAMETER
;
1390 if (!ldap_ctx
->entry
)
1392 ldap_ctx
->count
= ldap_count_entries(ldap
->ld
, ldap_ctx
->res
);
1395 if (ldap_ctx
->pos
>= ldap_ctx
->count
)
1396 return S_ADS_NOMORE_ROWS
;
1398 ldap_ctx
->entry
= ldap_first_entry(ldap
->ld
, ldap_ctx
->res
);
1402 if (ldap_ctx
->pos
>= ldap_ctx
->count
)
1408 ldap_msgfree(ldap_ctx
->res
);
1409 ldap_ctx
->res
= NULL
;
1411 err
= ldap_get_next_page_s(ldap
->ld
, ldap_ctx
->page
, NULL
, ldap
->search
.pagesize
, &count
, &ldap_ctx
->res
);
1412 if (err
== LDAP_SUCCESS
)
1414 ldap_ctx
->count
= ldap_count_entries(ldap
->ld
, ldap_ctx
->res
);
1417 if (ldap_ctx
->pos
>= ldap_ctx
->count
)
1418 return S_ADS_NOMORE_ROWS
;
1420 ldap_ctx
->entry
= ldap_first_entry(ldap
->ld
, ldap_ctx
->res
);
1424 if (err
!= LDAP_NO_RESULTS_RETURNED
)
1426 TRACE("ldap_get_next_page_s error %#x\n", err
);
1427 return HRESULT_FROM_WIN32(map_ldap_error(err
));
1432 return S_ADS_NOMORE_ROWS
;
1435 ldap_ctx
->entry
= ldap_next_entry(ldap
->ld
, ldap_ctx
->entry
);
1439 if (!ldap_ctx
->entry
)
1440 return S_ADS_NOMORE_ROWS
;
1443 ldap_ctx
->ber
= NULL
;
1448 static HRESULT WINAPI
search_GetPreviousRow(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
)
1450 FIXME("%p,%p: stub\n", iface
, res
);
1454 static HRESULT WINAPI
search_GetNextColumnName(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
, LPWSTR
*name
)
1456 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1457 struct ldap_search_context
*ldap_ctx
= res
;
1460 TRACE("%p,%p,%p\n", iface
, res
, name
);
1462 if (!name
|| !ldap_ctx
|| !ldap_ctx
->entry
) return E_ADS_BAD_PARAMETER
;
1466 attr
= ldap_first_attributeW(ldap
->ld
, ldap_ctx
->entry
, &ldap_ctx
->ber
);
1467 ldap_ctx
->add_ADsPath
= TRUE
;
1470 attr
= ldap_next_attributeW(ldap
->ld
, ldap_ctx
->entry
, ldap_ctx
->ber
);
1474 TRACE("=> %s\n", debugstr_w(attr
));
1475 *name
= AllocADsStr(attr
);
1476 ldap_memfreeW(attr
);
1477 return *name
? S_OK
: E_OUTOFMEMORY
;
1479 else if (ldap_ctx
->add_ADsPath
)
1481 ldap_ctx
->add_ADsPath
= FALSE
;
1482 *name
= AllocADsStr((WCHAR
*)L
"ADsPath");
1483 TRACE("=> %s\n", debugstr_w(*name
));
1484 return *name
? S_OK
: E_OUTOFMEMORY
;
1488 return S_ADS_NOMORE_COLUMNS
;
1491 static HRESULT
add_column_values(LDAP_namespace
*ldap
, struct ldap_search_context
*ldap_ctx
,
1492 LPWSTR name
, ADS_SEARCH_COLUMN
*col
)
1497 type
= get_schema_type(name
, ldap
->at
, ldap
->at_single_count
, ldap
->at_multiple_count
);
1498 TRACE("%s => type %d\n", debugstr_w(name
), type
);
1503 FIXME("no special handling for type %d\n", type
);
1505 case ADSTYPE_DN_STRING
:
1506 case ADSTYPE_CASE_EXACT_STRING
:
1507 case ADSTYPE_CASE_IGNORE_STRING
:
1508 case ADSTYPE_PRINTABLE_STRING
:
1510 WCHAR
**values
= ldap_get_valuesW(ldap
->ld
, ldap_ctx
->entry
, name
);
1512 return E_ADS_COLUMN_NOT_SET
;
1513 count
= ldap_count_valuesW(values
);
1515 col
->pADsValues
= heap_alloc_zero(count
* sizeof(col
->pADsValues
[0]));
1516 if (!col
->pADsValues
)
1518 ldap_value_freeW(values
);
1519 return E_OUTOFMEMORY
;
1522 for (i
= 0; i
< count
; i
++)
1524 TRACE("=> %s\n", debugstr_w(values
[i
]));
1525 col
->pADsValues
[i
].dwType
= type
;
1526 col
->pADsValues
[i
].u
.CaseIgnoreString
= values
[i
];
1529 col
->hReserved
= values
;
1533 case ADSTYPE_BOOLEAN
:
1535 WCHAR
**values
= ldap_get_valuesW(ldap
->ld
, ldap_ctx
->entry
, name
);
1537 return E_ADS_COLUMN_NOT_SET
;
1538 count
= ldap_count_valuesW(values
);
1540 col
->pADsValues
= heap_alloc_zero(count
* sizeof(col
->pADsValues
[0]));
1541 if (!col
->pADsValues
)
1543 ldap_value_freeW(values
);
1544 return E_OUTOFMEMORY
;
1547 for (i
= 0; i
< count
; i
++)
1549 col
->pADsValues
[i
].dwType
= type
;
1551 if (!wcsicmp(values
[i
], L
"TRUE"))
1552 col
->pADsValues
[i
].u
.Boolean
= 1;
1553 else if (!wcsicmp(values
[i
], L
"FALSE"))
1554 col
->pADsValues
[i
].u
.Boolean
= 0;
1557 FIXME("not recognized boolean value %s\n", debugstr_w(values
[i
]));
1558 col
->pADsValues
[i
].u
.Boolean
= 0;
1560 TRACE("%s => %d\n", debugstr_w(values
[i
]), col
->pADsValues
[i
].u
.Boolean
);
1563 ldap_value_freeW(values
);
1564 col
->hReserved
= NULL
;
1568 case ADSTYPE_INTEGER
:
1569 case ADSTYPE_LARGE_INTEGER
:
1571 struct berval
**values
= ldap_get_values_lenW(ldap
->ld
, ldap_ctx
->entry
, name
);
1573 return E_ADS_COLUMN_NOT_SET
;
1574 count
= ldap_count_values_len(values
);
1576 col
->pADsValues
= heap_alloc_zero(count
* sizeof(col
->pADsValues
[0]));
1577 if (!col
->pADsValues
)
1579 ldap_value_free_len(values
);
1580 return E_OUTOFMEMORY
;
1583 for (i
= 0; i
< count
; i
++)
1585 col
->pADsValues
[i
].dwType
= type
;
1587 if (type
== ADSTYPE_LARGE_INTEGER
)
1589 col
->pADsValues
[i
].u
.LargeInteger
.QuadPart
= _atoi64(values
[i
]->bv_val
);
1590 TRACE("%s => %s\n", debugstr_an(values
[i
]->bv_val
, values
[i
]->bv_len
), wine_dbgstr_longlong(col
->pADsValues
[i
].u
.LargeInteger
.QuadPart
));
1594 col
->pADsValues
[i
].u
.Integer
= atol(values
[i
]->bv_val
);
1595 TRACE("%s => %d\n", debugstr_an(values
[i
]->bv_val
, values
[i
]->bv_len
), col
->pADsValues
[i
].u
.Integer
);
1599 ldap_value_free_len(values
);
1600 col
->hReserved
= NULL
;
1604 case ADSTYPE_OCTET_STRING
:
1605 case ADSTYPE_NT_SECURITY_DESCRIPTOR
:
1607 struct berval
**values
= ldap_get_values_lenW(ldap
->ld
, ldap_ctx
->entry
, name
);
1609 return E_ADS_COLUMN_NOT_SET
;
1610 count
= ldap_count_values_len(values
);
1612 col
->pADsValues
= heap_alloc_zero(count
* sizeof(col
->pADsValues
[0]));
1613 if (!col
->pADsValues
)
1615 ldap_value_free_len(values
);
1616 return E_OUTOFMEMORY
;
1619 for (i
= 0; i
< count
; i
++)
1621 TRACE("=> %s\n", debugstr_an(values
[i
]->bv_val
, values
[i
]->bv_len
));
1622 col
->pADsValues
[i
].dwType
= type
;
1623 col
->pADsValues
[i
].u
.OctetString
.dwLength
= values
[i
]->bv_len
;
1624 col
->pADsValues
[i
].u
.OctetString
.lpValue
= (BYTE
*)values
[i
]->bv_val
;
1627 col
->hReserved
= values
;
1631 case ADSTYPE_UTC_TIME
:
1633 struct berval
**values
= ldap_get_values_lenW(ldap
->ld
, ldap_ctx
->entry
, name
);
1635 return E_ADS_COLUMN_NOT_SET
;
1636 count
= ldap_count_values_len(values
);
1638 col
->pADsValues
= heap_alloc_zero(count
* sizeof(col
->pADsValues
[0]));
1639 if (!col
->pADsValues
)
1641 ldap_value_free_len(values
);
1642 return E_OUTOFMEMORY
;
1645 for (i
= 0; i
< count
; i
++)
1647 col
->pADsValues
[i
].dwType
= type
;
1648 if (values
[i
]->bv_len
< 14 ||
1649 _snscanf_l(values
[i
]->bv_val
, values
[i
]->bv_len
, "%04hu%02hu%02hu%02hu%02hu%02hu", NULL
,
1650 &col
->pADsValues
[i
].u
.UTCTime
.wYear
, &col
->pADsValues
[i
].u
.UTCTime
.wMonth
,
1651 &col
->pADsValues
[i
].u
.UTCTime
.wDay
, &col
->pADsValues
[i
].u
.UTCTime
.wHour
,
1652 &col
->pADsValues
[i
].u
.UTCTime
.wMinute
, &col
->pADsValues
[i
].u
.UTCTime
.wSecond
) != 6)
1654 FIXME("not recognized UTCTime: %s\n", debugstr_an(values
[i
]->bv_val
, values
[i
]->bv_len
));
1655 memset(&col
->pADsValues
[i
].u
.UTCTime
, 0, sizeof(col
->pADsValues
[i
].u
.UTCTime
));
1659 if ((values
[i
]->bv_val
[14] != '.' && values
[i
]->bv_val
[14] != ',') ||
1660 values
[i
]->bv_val
[15] != '0' || values
[i
]->bv_val
[16] != 'Z')
1661 FIXME("not handled time zone: %s\n", debugstr_an(values
[i
]->bv_val
+ 14, values
[i
]->bv_len
- 14));
1663 TRACE("%s => %02u.%02u.%04u %02u:%02u:%02u\n", debugstr_an(values
[i
]->bv_val
, values
[i
]->bv_len
),
1664 col
->pADsValues
[i
].u
.UTCTime
.wDay
, col
->pADsValues
[i
].u
.UTCTime
.wMonth
,
1665 col
->pADsValues
[i
].u
.UTCTime
.wYear
, col
->pADsValues
[i
].u
.UTCTime
.wHour
,
1666 col
->pADsValues
[i
].u
.UTCTime
.wMinute
, col
->pADsValues
[i
].u
.UTCTime
.wSecond
);
1669 ldap_value_free_len(values
);
1670 col
->hReserved
= NULL
;
1674 case ADSTYPE_DN_WITH_BINARY
:
1676 static const BYTE hex2bin
[] =
1678 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x00 */
1679 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x10 */
1680 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x20 */
1681 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, /* 0x30 */
1682 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0, /* 0x40 */
1683 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x50 */
1684 0,10,11,12,13,14,15 /* 0x60 */
1686 ADS_DN_WITH_BINARY
*dnb
;
1687 WCHAR
**values
= ldap_get_valuesW(ldap
->ld
, ldap_ctx
->entry
, name
);
1689 return E_ADS_COLUMN_NOT_SET
;
1690 count
= ldap_count_valuesW(values
);
1692 col
->pADsValues
= heap_alloc_zero(count
* (sizeof(col
->pADsValues
[0]) + sizeof(col
->pADsValues
[0].u
.pDNWithBinary
[0])));
1693 if (!col
->pADsValues
)
1695 ldap_value_freeW(values
);
1696 return E_OUTOFMEMORY
;
1699 dnb
= (ADS_DN_WITH_BINARY
*)(col
->pADsValues
+ count
);
1701 for (i
= 0; i
< count
; i
++)
1703 WCHAR
*p
= values
[i
];
1706 col
->pADsValues
[i
].dwType
= type
;
1707 col
->pADsValues
[i
].u
.pDNWithBinary
= dnb
++;
1709 if ((p
[0] != 'b' && p
[0] != 'B') || p
[1] != ':')
1710 FIXME("wrong DN with binary tag '%c%c'\n", p
[0], p
[1]);
1713 col
->pADsValues
[i
].u
.pDNWithBinary
->dwLength
= wcstol(p
, &p
, 10) / 2;
1715 FIXME("wrong DN with binary separator '%c'\n", *p
);
1717 col
->pADsValues
[i
].u
.pDNWithBinary
->lpBinaryValue
= (BYTE
*)p
;
1718 /* decode values in-place */
1719 for (n
= 0; n
< col
->pADsValues
[i
].u
.pDNWithBinary
->dwLength
; n
++, p
+= 2)
1723 if (p
[0] > 'f' || (p
[0] != '0' && !hex2bin
[p
[0]]) ||
1724 p
[1] > 'f' || (p
[1] != '0' && !hex2bin
[p
[1]]))
1726 FIXME("bad hex encoding at %s\n", debugstr_w(p
));
1730 b
= (hex2bin
[p
[0]] << 4) | hex2bin
[p
[1]];
1731 col
->pADsValues
[i
].u
.pDNWithBinary
->lpBinaryValue
[n
] = b
;
1734 FIXME("wrong DN with binary separator '%c'\n", *p
);
1735 col
->pADsValues
[i
].u
.pDNWithBinary
->pszDNString
= p
+ 1;
1737 TRACE("%s => %u,%s,%s\n", debugstr_w(values
[i
]),
1738 col
->pADsValues
[i
].u
.pDNWithBinary
->dwLength
,
1739 debugstr_an((char *)col
->pADsValues
[i
].u
.pDNWithBinary
->lpBinaryValue
, col
->pADsValues
[i
].u
.pDNWithBinary
->dwLength
),
1740 debugstr_w(col
->pADsValues
[i
].u
.pDNWithBinary
->pszDNString
));
1743 col
->hReserved
= values
;
1748 col
->dwADsType
= type
;
1749 col
->dwNumValues
= count
;
1750 col
->pszAttrName
= strdupW(name
);
1755 static HRESULT WINAPI
search_GetColumn(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
,
1756 LPWSTR name
, PADS_SEARCH_COLUMN col
)
1758 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1759 struct ldap_search_context
*ldap_ctx
= res
;
1763 TRACE("%p,%p,%s,%p\n", iface
, res
, debugstr_w(name
), col
);
1765 if (!res
|| !name
|| !ldap_ctx
->entry
) return E_ADS_BAD_PARAMETER
;
1767 memset(col
, 0, sizeof(*col
));
1769 if (!wcsicmp(name
, L
"ADsPath"))
1771 WCHAR
*dn
= ldap_get_dnW(ldap
->ld
, ldap_ctx
->entry
);
1773 col
->pADsValues
= heap_alloc(sizeof(col
->pADsValues
[0]));
1774 if (!col
->pADsValues
)
1780 count
= sizeof(L
"LDAP://") + (wcslen(ldap
->host
) + 1 /* '/' */) * sizeof(WCHAR
);
1781 if (dn
) count
+= wcslen(dn
) * sizeof(WCHAR
);
1783 col
->pADsValues
[0].u
.CaseIgnoreString
= heap_alloc(count
);
1784 if (!col
->pADsValues
[0].u
.CaseIgnoreString
)
1790 wcscpy(col
->pADsValues
[0].u
.CaseIgnoreString
, L
"LDAP://");
1791 wcscat(col
->pADsValues
[0].u
.CaseIgnoreString
, ldap
->host
);
1792 wcscat(col
->pADsValues
[0].u
.CaseIgnoreString
, L
"/");
1793 if (dn
) wcscat(col
->pADsValues
[0].u
.CaseIgnoreString
, dn
);
1794 col
->pADsValues
[0].dwType
= ADSTYPE_CASE_IGNORE_STRING
;
1795 col
->dwADsType
= ADSTYPE_CASE_IGNORE_STRING
;
1796 col
->dwNumValues
= 1;
1797 col
->pszAttrName
= strdupW(name
);
1798 col
->hReserved
= NULL
;
1800 TRACE("=> %s\n", debugstr_w(col
->pADsValues
[0].u
.CaseIgnoreString
));
1807 return add_column_values(ldap
, ldap_ctx
, name
, col
);
1810 static HRESULT WINAPI
search_FreeColumn(IDirectorySearch
*iface
, PADS_SEARCH_COLUMN col
)
1812 TRACE("%p,%p\n", iface
, col
);
1814 if (!col
) return E_ADS_BAD_PARAMETER
;
1816 if (!wcsicmp(col
->pszAttrName
, L
"ADsPath"))
1817 heap_free(col
->pADsValues
[0].u
.CaseIgnoreString
);
1818 heap_free(col
->pADsValues
);
1819 heap_free(col
->pszAttrName
);
1823 if (col
->dwADsType
== ADSTYPE_OCTET_STRING
|| col
->dwADsType
== ADSTYPE_NT_SECURITY_DESCRIPTOR
)
1824 ldap_value_free_len(col
->hReserved
);
1826 ldap_value_freeW(col
->hReserved
);
1832 static HRESULT WINAPI
search_CloseSearchHandle(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
)
1834 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1835 struct ldap_search_context
*ldap_ctx
= res
;
1837 TRACE("%p,%p\n", iface
, res
);
1839 if (!res
) return E_ADS_BAD_PARAMETER
;
1842 ldap_search_abandon_page(ldap
->ld
, ldap_ctx
->page
);
1844 ldap_msgfree(ldap_ctx
->res
);
1846 ber_free(ldap_ctx
->ber
, 0);
1847 heap_free(ldap_ctx
);
1852 static const IDirectorySearchVtbl IDirectorySearch_vtbl
=
1854 search_QueryInterface
,
1857 search_SetSearchPreference
,
1858 search_ExecuteSearch
,
1859 search_AbandonSearch
,
1862 search_GetPreviousRow
,
1863 search_GetNextColumnName
,
1866 search_CloseSearchHandle
1869 static inline LDAP_namespace
*impl_from_IDirectoryObject(IDirectoryObject
*iface
)
1871 return CONTAINING_RECORD(iface
, LDAP_namespace
, IDirectoryObject_iface
);
1874 static HRESULT WINAPI
dirobj_QueryInterface(IDirectoryObject
*iface
, REFIID riid
, void **obj
)
1876 LDAP_namespace
*ldap
= impl_from_IDirectoryObject(iface
);
1878 TRACE("%p,%s,%p\n", iface
, debugstr_guid(riid
), obj
);
1880 if (!riid
|| !obj
) return E_INVALIDARG
;
1882 if (IsEqualGUID(riid
, &IID_IDirectoryObject
) ||
1883 IsEqualGUID(riid
, &IID_IUnknown
))
1885 IDirectoryObject_AddRef(iface
);
1890 return IADs_QueryInterface(&ldap
->IADs_iface
, riid
, obj
);
1893 static ULONG WINAPI
dirobj_AddRef(IDirectoryObject
*iface
)
1895 LDAP_namespace
*ldap
= impl_from_IDirectoryObject(iface
);
1896 return IADs_AddRef(&ldap
->IADs_iface
);
1899 static ULONG WINAPI
dirobj_Release(IDirectoryObject
*iface
)
1901 LDAP_namespace
*ldap
= impl_from_IDirectoryObject(iface
);
1902 return IADs_Release(&ldap
->IADs_iface
);
1905 static HRESULT WINAPI
dirobj_GetObjectInformation(IDirectoryObject
*iface
, PADS_OBJECT_INFO
*info
)
1907 FIXME("%p,%p: stub\n", iface
, info
);
1911 static HRESULT WINAPI
dirobj_GetObjectAttributes(IDirectoryObject
*iface
, LPWSTR
*names
,
1912 DWORD count
, PADS_ATTR_INFO
*attrs
, DWORD
*count_returned
)
1914 FIXME("%p,%p,%u,%p,%p: stub\n", iface
, names
, count
, attrs
, count_returned
);
1918 static HRESULT WINAPI
dirobj_SetObjectAttributes(IDirectoryObject
*iface
, PADS_ATTR_INFO attrs
,
1919 DWORD count
, DWORD
*count_set
)
1921 FIXME("%p,%p,%u,%p: stub\n", iface
, attrs
, count
, count_set
);
1925 static HRESULT WINAPI
dirobj_CreateDSObject(IDirectoryObject
*iface
, LPWSTR name
,
1926 PADS_ATTR_INFO attrs
, DWORD count
, IDispatch
**obj
)
1928 FIXME("%p,%s,%p,%u,%p: stub\n", iface
, debugstr_w(name
), attrs
, count
, obj
);
1932 static HRESULT WINAPI
dirobj_DeleteDSObject(IDirectoryObject
*iface
, LPWSTR name
)
1934 FIXME("%p,%s: stub\n", iface
, debugstr_w(name
));
1938 static const IDirectoryObjectVtbl IDirectoryObject_vtbl
=
1940 dirobj_QueryInterface
,
1943 dirobj_GetObjectInformation
,
1944 dirobj_GetObjectAttributes
,
1945 dirobj_SetObjectAttributes
,
1946 dirobj_CreateDSObject
,
1947 dirobj_DeleteDSObject
1950 static HRESULT
LDAPNamespace_create(REFIID riid
, void **obj
)
1952 LDAP_namespace
*ldap
;
1955 ldap
= heap_alloc(sizeof(*ldap
));
1956 if (!ldap
) return E_OUTOFMEMORY
;
1958 ldap
->IADs_iface
.lpVtbl
= &IADs_vtbl
;
1959 ldap
->IADsOpenDSObject_iface
.lpVtbl
= &IADsOpenDSObject_vtbl
;
1960 ldap
->IDirectorySearch_iface
.lpVtbl
= &IDirectorySearch_vtbl
;
1961 ldap
->IDirectoryObject_iface
.lpVtbl
= &IDirectoryObject_vtbl
;
1965 ldap
->object
= NULL
;
1966 ldap
->attrs_count
= 0;
1967 ldap
->attrs_count_allocated
= 0;
1969 ldap
->search
.scope
= ADS_SCOPE_SUBTREE
;
1970 ldap
->search
.pagesize
= 0;
1971 ldap
->search
.cache_results
= TRUE
;
1972 ldap
->search
.attribtypes_only
= FALSE
;
1973 ldap
->search
.tombstone
= FALSE
;
1975 ldap
->at_single_count
= 0;
1976 ldap
->at_multiple_count
= 0;
1978 hr
= IADs_QueryInterface(&ldap
->IADs_iface
, riid
, obj
);
1979 IADs_Release(&ldap
->IADs_iface
);
1984 static const struct class_info
1987 HRESULT (*constructor
)(REFIID
, void **);
1990 { &CLSID_ADSystemInfo
, ADSystemInfo_create
},
1991 { &CLSID_LDAP
, LDAP_create
},
1992 { &CLSID_LDAPNamespace
, LDAPNamespace_create
},
1997 IClassFactory IClassFactory_iface
;
1999 const struct class_info
*info
;
2002 static inline class_factory
*impl_from_IClassFactory(IClassFactory
*iface
)
2004 return CONTAINING_RECORD(iface
, class_factory
, IClassFactory_iface
);
2007 static HRESULT WINAPI
factory_QueryInterface(IClassFactory
*iface
, REFIID riid
, LPVOID
*obj
)
2009 TRACE("%p,%s,%p\n", iface
, debugstr_guid(riid
), obj
);
2011 if (!riid
|| !obj
) return E_INVALIDARG
;
2013 if (IsEqualIID(riid
, &IID_IUnknown
) ||
2014 IsEqualIID(riid
, &IID_IClassFactory
))
2016 IClassFactory_AddRef(iface
);
2022 FIXME("interface %s is not implemented\n", debugstr_guid(riid
));
2023 return E_NOINTERFACE
;
2026 static ULONG WINAPI
factory_AddRef(IClassFactory
*iface
)
2028 class_factory
*factory
= impl_from_IClassFactory(iface
);
2029 ULONG ref
= InterlockedIncrement(&factory
->ref
);
2031 TRACE("(%p) ref %u\n", iface
, ref
);
2036 static ULONG WINAPI
factory_Release(IClassFactory
*iface
)
2038 class_factory
*factory
= impl_from_IClassFactory(iface
);
2039 ULONG ref
= InterlockedDecrement(&factory
->ref
);
2041 TRACE("(%p) ref %u\n", iface
, ref
);
2049 static HRESULT WINAPI
factory_CreateInstance(IClassFactory
*iface
, IUnknown
*outer
, REFIID riid
, void **obj
)
2051 class_factory
*factory
= impl_from_IClassFactory(iface
);
2053 TRACE("%p,%s,%p\n", outer
, debugstr_guid(riid
), obj
);
2055 if (!riid
|| !obj
) return E_INVALIDARG
;
2058 if (outer
) return CLASS_E_NOAGGREGATION
;
2060 return factory
->info
->constructor(riid
, obj
);
2063 static HRESULT WINAPI
factory_LockServer(IClassFactory
*iface
, BOOL lock
)
2065 FIXME("%p,%d: stub\n", iface
, lock
);
2069 static const struct IClassFactoryVtbl factory_vtbl
=
2071 factory_QueryInterface
,
2074 factory_CreateInstance
,
2078 static HRESULT
factory_constructor(const struct class_info
*info
, REFIID riid
, void **obj
)
2080 class_factory
*factory
;
2083 factory
= heap_alloc(sizeof(*factory
));
2084 if (!factory
) return E_OUTOFMEMORY
;
2086 factory
->IClassFactory_iface
.lpVtbl
= &factory_vtbl
;
2088 factory
->info
= info
;
2090 hr
= IClassFactory_QueryInterface(&factory
->IClassFactory_iface
, riid
, obj
);
2091 IClassFactory_Release(&factory
->IClassFactory_iface
);
2096 HRESULT WINAPI
DllGetClassObject(REFCLSID clsid
, REFIID iid
, LPVOID
*obj
)
2100 TRACE("%s,%s,%p\n", debugstr_guid(clsid
), debugstr_guid(iid
), obj
);
2102 if (!clsid
|| !iid
|| !obj
) return E_INVALIDARG
;
2106 for (i
= 0; i
< ARRAY_SIZE(class_info
); i
++)
2108 if (IsEqualCLSID(class_info
[i
].clsid
, clsid
))
2109 return factory_constructor(&class_info
[i
], iid
, obj
);
2112 FIXME("class %s/%s is not implemented\n", debugstr_guid(clsid
), debugstr_guid(iid
));
2113 return CLASS_E_CLASSNOTAVAILABLE
;