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
33 #define SECURITY_WIN32
41 #include "adsldp_private.h"
43 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(adsldp
);
47 #ifndef LDAP_OPT_SERVER_CONTROLS
48 #define LDAP_OPT_SERVER_CONTROLS 0x0012
51 DEFINE_GUID(CLSID_LDAP
,0x228d9a81,0xc302,0x11cf,0x9a,0xa4,0x00,0xaa,0x00,0x4a,0x56,0x91);
52 DEFINE_GUID(CLSID_LDAPNamespace
,0x228d9a82,0xc302,0x11cf,0x9a,0xa4,0x00,0xaa,0x00,0x4a,0x56,0x91);
54 static HRESULT
LDAPNamespace_create(REFIID riid
, void **obj
);
58 IParseDisplayName IParseDisplayName_iface
;
62 static inline LDAP_PARSE
*impl_from_IParseDisplayName(IParseDisplayName
*iface
)
64 return CONTAINING_RECORD(iface
, LDAP_PARSE
, IParseDisplayName_iface
);
67 static HRESULT WINAPI
ldap_QueryInterface(IParseDisplayName
*iface
, REFIID riid
, void **obj
)
69 TRACE("%p,%s,%p\n", iface
, debugstr_guid(riid
), obj
);
71 if (!riid
|| !obj
) return E_INVALIDARG
;
73 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
74 IsEqualGUID(riid
, &IID_IParseDisplayName
))
76 IParseDisplayName_AddRef(iface
);
82 FIXME("interface %s is not implemented\n", debugstr_guid(riid
));
86 static ULONG WINAPI
ldap_AddRef(IParseDisplayName
*iface
)
88 LDAP_PARSE
*ldap
= impl_from_IParseDisplayName(iface
);
89 return InterlockedIncrement(&ldap
->ref
);
92 static ULONG WINAPI
ldap_Release(IParseDisplayName
*iface
)
94 LDAP_PARSE
*ldap
= impl_from_IParseDisplayName(iface
);
95 LONG ref
= InterlockedDecrement(&ldap
->ref
);
99 TRACE("destroying %p\n", iface
);
106 static HRESULT WINAPI
ldap_ParseDisplayName(IParseDisplayName
*iface
, IBindCtx
*bc
,
107 LPOLESTR name
, ULONG
*eaten
, IMoniker
**mk
)
110 IADsOpenDSObject
*ads_open
;
113 TRACE("%p,%p,%s,%p,%p\n", iface
, bc
, debugstr_w(name
), eaten
, mk
);
115 hr
= LDAPNamespace_create(&IID_IADsOpenDSObject
, (void **)&ads_open
);
116 if (hr
!= S_OK
) return hr
;
118 hr
= IADsOpenDSObject_OpenDSObject(ads_open
, name
, NULL
, NULL
, ADS_SECURE_AUTHENTICATION
, &disp
);
120 hr
= IADsOpenDSObject_OpenDSObject(ads_open
, name
, NULL
, NULL
, 0, &disp
);
123 hr
= CreatePointerMoniker((IUnknown
*)disp
, mk
);
125 *eaten
= wcslen(name
);
127 IDispatch_Release(disp
);
130 IADsOpenDSObject_Release(ads_open
);
135 static const IParseDisplayNameVtbl LDAP_PARSE_vtbl
=
140 ldap_ParseDisplayName
143 static HRESULT
LDAP_create(REFIID riid
, void **obj
)
148 ldap
= malloc(sizeof(*ldap
));
149 if (!ldap
) return E_OUTOFMEMORY
;
151 ldap
->IParseDisplayName_iface
.lpVtbl
= &LDAP_PARSE_vtbl
;
154 hr
= IParseDisplayName_QueryInterface(&ldap
->IParseDisplayName_iface
, riid
, obj
);
155 IParseDisplayName_Release(&ldap
->IParseDisplayName_iface
);
162 IADsADSystemInfo IADsADSystemInfo_iface
;
166 static inline AD_sysinfo
*impl_from_IADsADSystemInfo(IADsADSystemInfo
*iface
)
168 return CONTAINING_RECORD(iface
, AD_sysinfo
, IADsADSystemInfo_iface
);
171 static HRESULT WINAPI
sysinfo_QueryInterface(IADsADSystemInfo
*iface
, REFIID riid
, void **obj
)
173 TRACE("%p,%s,%p\n", iface
, debugstr_guid(riid
), obj
);
175 if (!riid
|| !obj
) return E_INVALIDARG
;
177 if (IsEqualGUID(riid
, &IID_IADsADSystemInfo
) ||
178 IsEqualGUID(riid
, &IID_IDispatch
) ||
179 IsEqualGUID(riid
, &IID_IUnknown
))
181 IADsADSystemInfo_AddRef(iface
);
187 FIXME("interface %s is not implemented\n", debugstr_guid(riid
));
188 return E_NOINTERFACE
;
191 static ULONG WINAPI
sysinfo_AddRef(IADsADSystemInfo
*iface
)
193 AD_sysinfo
*sysinfo
= impl_from_IADsADSystemInfo(iface
);
194 return InterlockedIncrement(&sysinfo
->ref
);
197 static ULONG WINAPI
sysinfo_Release(IADsADSystemInfo
*iface
)
199 AD_sysinfo
*sysinfo
= impl_from_IADsADSystemInfo(iface
);
200 LONG ref
= InterlockedDecrement(&sysinfo
->ref
);
204 TRACE("destroying %p\n", iface
);
211 static HRESULT WINAPI
sysinfo_GetTypeInfoCount(IADsADSystemInfo
*iface
, UINT
*count
)
213 FIXME("%p,%p: stub\n", iface
, count
);
217 static HRESULT WINAPI
sysinfo_GetTypeInfo(IADsADSystemInfo
*iface
, UINT index
, LCID lcid
, ITypeInfo
**info
)
219 FIXME("%p,%u,%#lx,%p: stub\n", iface
, index
, lcid
, info
);
223 static HRESULT WINAPI
sysinfo_GetIDsOfNames(IADsADSystemInfo
*iface
, REFIID riid
, LPOLESTR
*names
,
224 UINT count
, LCID lcid
, DISPID
*dispid
)
226 FIXME("%p,%s,%p,%u,%lu,%p: stub\n", iface
, debugstr_guid(riid
), names
, count
, lcid
, dispid
);
230 static HRESULT WINAPI
sysinfo_Invoke(IADsADSystemInfo
*iface
, DISPID dispid
, REFIID riid
, LCID lcid
, WORD flags
,
231 DISPPARAMS
*params
, VARIANT
*result
, EXCEPINFO
*excepinfo
, UINT
*argerr
)
233 FIXME("%p,%ld,%s,%04lx,%04x,%p,%p,%p,%p: stub\n", iface
, dispid
, debugstr_guid(riid
), lcid
, flags
,
234 params
, result
, excepinfo
, argerr
);
238 static HRESULT WINAPI
sysinfo_get_UserName(IADsADSystemInfo
*iface
, BSTR
*retval
)
240 FIXME("%p,%p: stub\n", iface
, retval
);
244 static HRESULT WINAPI
sysinfo_get_ComputerName(IADsADSystemInfo
*iface
, BSTR
*retval
)
249 TRACE("%p,%p\n", iface
, retval
);
252 GetComputerObjectNameW(NameFullyQualifiedDN
, NULL
, &size
);
253 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
254 return HRESULT_FROM_WIN32(GetLastError());
256 name
= SysAllocStringLen(NULL
, size
);
257 if (!name
) return E_OUTOFMEMORY
;
259 if (!GetComputerObjectNameW(NameFullyQualifiedDN
, name
, &size
))
262 return HRESULT_FROM_WIN32(GetLastError());
269 static HRESULT WINAPI
sysinfo_get_SiteName(IADsADSystemInfo
*iface
, BSTR
*retval
)
271 FIXME("%p,%p: stub\n", iface
, retval
);
275 static HRESULT WINAPI
sysinfo_get_DomainShortName(IADsADSystemInfo
*iface
, BSTR
*retval
)
277 FIXME("%p,%p: stub\n", iface
, retval
);
281 static HRESULT WINAPI
sysinfo_get_DomainDNSName(IADsADSystemInfo
*iface
, BSTR
*retval
)
283 FIXME("%p,%p: stub\n", iface
, retval
);
287 static HRESULT WINAPI
sysinfo_get_ForestDNSName(IADsADSystemInfo
*iface
, BSTR
*retval
)
289 FIXME("%p,%p: stub\n", iface
, retval
);
293 static HRESULT WINAPI
sysinfo_get_PDCRoleOwner(IADsADSystemInfo
*iface
, BSTR
*retval
)
295 FIXME("%p,%p: stub\n", iface
, retval
);
299 static HRESULT WINAPI
sysinfo_get_SchemaRoleOwner(IADsADSystemInfo
*iface
, BSTR
*retval
)
301 FIXME("%p,%p: stub\n", iface
, retval
);
305 static HRESULT WINAPI
sysinfo_get_IsNativeMode(IADsADSystemInfo
*iface
, VARIANT_BOOL
*retval
)
307 FIXME("%p,%p: stub\n", iface
, retval
);
311 static HRESULT WINAPI
sysinfo_GetAnyDCName(IADsADSystemInfo
*iface
, BSTR
*retval
)
313 FIXME("%p,%p: stub\n", iface
, retval
);
317 static HRESULT WINAPI
sysinfo_GetDCSiteName(IADsADSystemInfo
*iface
, BSTR server
, BSTR
*retval
)
319 FIXME("%p,%s,%p: stub\n", iface
, debugstr_w(server
), retval
);
323 static HRESULT WINAPI
sysinfo_RefreshSchemaCache(IADsADSystemInfo
*iface
)
325 FIXME("%p: stub\n", iface
);
329 static HRESULT WINAPI
sysinfo_GetTrees(IADsADSystemInfo
*iface
, VARIANT
*retval
)
331 FIXME("%p,%p: stub\n", iface
, retval
);
335 static const IADsADSystemInfoVtbl IADsADSystemInfo_vtbl
=
337 sysinfo_QueryInterface
,
340 sysinfo_GetTypeInfoCount
,
342 sysinfo_GetIDsOfNames
,
344 sysinfo_get_UserName
,
345 sysinfo_get_ComputerName
,
346 sysinfo_get_SiteName
,
347 sysinfo_get_DomainShortName
,
348 sysinfo_get_DomainDNSName
,
349 sysinfo_get_ForestDNSName
,
350 sysinfo_get_PDCRoleOwner
,
351 sysinfo_get_SchemaRoleOwner
,
352 sysinfo_get_IsNativeMode
,
353 sysinfo_GetAnyDCName
,
354 sysinfo_GetDCSiteName
,
355 sysinfo_RefreshSchemaCache
,
359 static HRESULT
ADSystemInfo_create(REFIID riid
, void **obj
)
364 sysinfo
= malloc(sizeof(*sysinfo
));
365 if (!sysinfo
) return E_OUTOFMEMORY
;
367 sysinfo
->IADsADSystemInfo_iface
.lpVtbl
= &IADsADSystemInfo_vtbl
;
370 hr
= IADsADSystemInfo_QueryInterface(&sysinfo
->IADsADSystemInfo_iface
, riid
, obj
);
371 IADsADSystemInfo_Release(&sysinfo
->IADsADSystemInfo_iface
);
376 struct ldap_attribute
385 IADsOpenDSObject IADsOpenDSObject_iface
;
386 IDirectorySearch IDirectorySearch_iface
;
387 IDirectoryObject IDirectoryObject_iface
;
393 ULONG attrs_count
, attrs_count_allocated
;
394 struct ldap_attribute
*attrs
;
395 struct attribute_type
*at
;
396 ULONG at_single_count
, at_multiple_count
;
403 BOOL attribtypes_only
;
408 struct ldap_search_context
411 LDAPMessage
*res
, *entry
;
417 static inline LDAP_namespace
*impl_from_IADs(IADs
*iface
)
419 return CONTAINING_RECORD(iface
, LDAP_namespace
, IADs_iface
);
422 static HRESULT WINAPI
ldapns_QueryInterface(IADs
*iface
, REFIID riid
, void **obj
)
424 LDAP_namespace
*ldap
= impl_from_IADs(iface
);
426 TRACE("%p,%s,%p\n", iface
, debugstr_guid(riid
), obj
);
428 if (!riid
|| !obj
) return E_INVALIDARG
;
430 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
431 IsEqualGUID(riid
, &IID_IDispatch
) ||
432 IsEqualGUID(riid
, &IID_IADs
))
439 if (IsEqualGUID(riid
, &IID_IADsOpenDSObject
))
442 *obj
= &ldap
->IADsOpenDSObject_iface
;
446 if (IsEqualGUID(riid
, &IID_IDirectorySearch
))
448 if (!ldap
->ld
|| (ldap
->object
&& !wcsicmp(ldap
->object
, L
"rootDSE")))
449 return E_NOINTERFACE
;
452 *obj
= &ldap
->IDirectorySearch_iface
;
456 if (IsEqualGUID(riid
, &IID_IDirectoryObject
))
459 *obj
= &ldap
->IDirectoryObject_iface
;
463 FIXME("interface %s is not implemented\n", debugstr_guid(riid
));
464 return E_NOINTERFACE
;
467 static ULONG WINAPI
ldapns_AddRef(IADs
*iface
)
469 LDAP_namespace
*ldap
= impl_from_IADs(iface
);
470 return InterlockedIncrement(&ldap
->ref
);
473 static void free_attributes(LDAP_namespace
*ldap
)
477 if (!ldap
->attrs
) return;
479 for (i
= 0; i
< ldap
->attrs_count
; i
++)
481 ldap_memfreeW(ldap
->attrs
[i
].name
);
482 ldap_value_freeW(ldap
->attrs
[i
].values
);
487 ldap
->attrs_count
= 0;
490 static ULONG WINAPI
ldapns_Release(IADs
*iface
)
492 LDAP_namespace
*ldap
= impl_from_IADs(iface
);
493 LONG ref
= InterlockedDecrement(&ldap
->ref
);
497 TRACE("destroying %p\n", iface
);
498 if (ldap
->ld
) ldap_unbind(ldap
->ld
);
499 SysFreeString(ldap
->host
);
500 SysFreeString(ldap
->object
);
501 free_attributes(ldap
);
502 free_attribute_types(ldap
->at
, ldap
->at_single_count
+ ldap
->at_multiple_count
);
509 static HRESULT WINAPI
ldapns_GetTypeInfoCount(IADs
*iface
, UINT
*count
)
511 FIXME("%p,%p: stub\n", iface
, count
);
515 static HRESULT WINAPI
ldapns_GetTypeInfo(IADs
*iface
, UINT index
, LCID lcid
, ITypeInfo
**info
)
517 FIXME("%p,%u,%#lx,%p: stub\n", iface
, index
, lcid
, info
);
521 static HRESULT WINAPI
ldapns_GetIDsOfNames(IADs
*iface
, REFIID riid
, LPOLESTR
*names
,
522 UINT count
, LCID lcid
, DISPID
*dispid
)
524 FIXME("%p,%s,%p,%u,%lu,%p: stub\n", iface
, debugstr_guid(riid
), names
, count
, lcid
, dispid
);
528 static HRESULT WINAPI
ldapns_Invoke(IADs
*iface
, DISPID dispid
, REFIID riid
, LCID lcid
, WORD flags
,
529 DISPPARAMS
*params
, VARIANT
*result
, EXCEPINFO
*excepinfo
, UINT
*argerr
)
531 FIXME("%p,%ld,%s,%04lx,%04x,%p,%p,%p,%p: stub\n", iface
, dispid
, debugstr_guid(riid
), lcid
, flags
,
532 params
, result
, excepinfo
, argerr
);
536 static HRESULT WINAPI
ldapns_get_Name(IADs
*iface
, BSTR
*retval
)
538 FIXME("%p,%p: stub\n", iface
, retval
);
542 static HRESULT WINAPI
ldapns_get_Class(IADs
*iface
, BSTR
*retval
)
544 FIXME("%p,%p: stub\n", iface
, retval
);
548 static HRESULT WINAPI
ldapns_get_GUID(IADs
*iface
, BSTR
*retval
)
550 FIXME("%p,%p: stub\n", iface
, retval
);
554 static HRESULT WINAPI
ldapns_get_ADsPath(IADs
*iface
, BSTR
*retval
)
556 FIXME("%p,%p: stub\n", iface
, retval
);
560 static HRESULT WINAPI
ldapns_get_Parent(IADs
*iface
, BSTR
*retval
)
562 FIXME("%p,%p: stub\n", iface
, retval
);
566 static HRESULT WINAPI
ldapns_get_Schema(IADs
*iface
, BSTR
*retval
)
568 FIXME("%p,%p: stub\n", iface
, retval
);
572 static HRESULT WINAPI
ldapns_GetInfo(IADs
*iface
)
577 TRACE("%p\n", iface
);
579 hr
= ADsBuildVarArrayStr(NULL
, 0, &var
);
582 hr
= IADs_GetInfoEx(iface
, var
, 0);
588 static HRESULT WINAPI
ldapns_SetInfo(IADs
*iface
)
590 FIXME("%p: stub\n", iface
);
594 static HRESULT WINAPI
ldapns_Get(IADs
*iface
, BSTR name
, VARIANT
*prop
)
596 LDAP_namespace
*ldap
= impl_from_IADs(iface
);
600 TRACE("%p,%s,%p\n", iface
, debugstr_w(name
), prop
);
602 if (!name
|| !prop
) return E_ADS_BAD_PARAMETER
;
604 if (!ldap
->attrs_count
)
606 hr
= IADs_GetInfo(iface
);
607 if (hr
!= S_OK
) return hr
;
610 for (i
= 0; i
< ldap
->attrs_count
; i
++)
612 if (!wcsicmp(name
, ldap
->attrs
[i
].name
))
614 LONG count
= ldap_count_valuesW(ldap
->attrs
[i
].values
);
618 V_VT(prop
) = VT_BSTR
;
628 TRACE("attr %s has %lu values\n", debugstr_w(ldap
->attrs
[i
].name
), count
);
630 sa
= SafeArrayCreateVector(VT_VARIANT
, 0, count
);
631 if (!sa
) return E_OUTOFMEMORY
;
633 for (idx
= 0; idx
< count
; idx
++)
635 TRACE("=> %s\n", debugstr_w(ldap
->attrs
[i
].values
[idx
]));
636 V_VT(&item
) = VT_BSTR
;
637 V_BSTR(&item
) = SysAllocString(ldap
->attrs
[i
].values
[idx
]);
644 hr
= SafeArrayPutElement(sa
, &idx
, &item
);
645 SysFreeString(V_BSTR(&item
));
646 if (hr
!= S_OK
) goto fail
;
649 V_VT(prop
) = VT_ARRAY
| VT_VARIANT
;
653 SafeArrayDestroy(sa
);
658 TRACE("=> %s\n", debugstr_w(ldap
->attrs
[i
].values
[0]));
659 V_BSTR(prop
) = SysAllocString(ldap
->attrs
[i
].values
[0]);
660 if (!V_BSTR(prop
)) return E_OUTOFMEMORY
;
661 V_VT(prop
) = VT_BSTR
;
667 return E_ADS_PROPERTY_NOT_FOUND
;
670 static HRESULT WINAPI
ldapns_Put(IADs
*iface
, BSTR name
, VARIANT prop
)
672 FIXME("%p,%s,%s: stub\n", iface
, debugstr_w(name
), wine_dbgstr_variant(&prop
));
676 static HRESULT WINAPI
ldapns_GetEx(IADs
*iface
, BSTR name
, VARIANT
*prop
)
678 FIXME("%p,%s,%p: stub\n", iface
, debugstr_w(name
), prop
);
682 static HRESULT WINAPI
ldapns_PutEx(IADs
*iface
, LONG code
, BSTR name
, VARIANT prop
)
684 FIXME("%p,%ld,%s,%s: stub\n", iface
, code
, debugstr_w(name
), wine_dbgstr_variant(&prop
));
688 static HRESULT
add_attribute(LDAP_namespace
*ldap
, WCHAR
*name
, WCHAR
**values
)
690 struct ldap_attribute
*new_attrs
;
694 ldap
->attrs
= malloc(256 * sizeof(ldap
->attrs
[0]));
695 if (!ldap
->attrs
) return E_OUTOFMEMORY
;
696 ldap
->attrs_count_allocated
= 256;
698 else if (ldap
->attrs_count_allocated
< ldap
->attrs_count
+ 1)
700 new_attrs
= realloc(ldap
->attrs
, (ldap
->attrs_count_allocated
* 2) * sizeof(*new_attrs
));
701 if (!new_attrs
) return E_OUTOFMEMORY
;
703 ldap
->attrs_count_allocated
*= 2;
704 ldap
->attrs
= new_attrs
;
707 ldap
->attrs
[ldap
->attrs_count
].name
= name
;
708 ldap
->attrs
[ldap
->attrs_count
].values
= values
;
714 static HRESULT WINAPI
ldapns_GetInfoEx(IADs
*iface
, VARIANT prop
, LONG reserved
)
716 LDAP_namespace
*ldap
= impl_from_IADs(iface
);
720 WCHAR
**props
= NULL
, *attr
, **values
;
722 LDAPMessage
*res
= NULL
, *entry
;
725 TRACE("%p,%s,%ld\n", iface
, wine_dbgstr_variant(&prop
), reserved
);
727 free_attributes(ldap
);
729 if (!ldap
->ld
) return E_NOTIMPL
;
731 if (V_VT(&prop
) != (VT_ARRAY
| VT_VARIANT
))
732 return E_ADS_BAD_PARAMETER
;
736 return E_ADS_BAD_PARAMETER
;
738 hr
= SafeArrayAccessData(sa
, (void *)&item
);
739 if (hr
!= S_OK
) return hr
;
741 count
= sa
->rgsabound
[0].cElements
;
744 props
= malloc((count
+ 1) * sizeof(props
[0]));
751 for (i
= 0; i
< count
; i
++)
753 if (V_VT(&item
[i
]) != VT_BSTR
)
755 hr
= E_ADS_BAD_PARAMETER
;
758 props
[i
] = V_BSTR(&item
[i
]);
760 props
[sa
->rgsabound
[0].cElements
] = NULL
;
763 err
= ldap_search_sW(ldap
->ld
, NULL
, LDAP_SCOPE_BASE
, (WCHAR
*)L
"(objectClass=*)", props
, FALSE
, &res
);
764 if (err
!= LDAP_SUCCESS
)
766 TRACE("ldap_search_sW error %#lx\n", err
);
767 hr
= HRESULT_FROM_WIN32(map_ldap_error(err
));
771 entry
= ldap_first_entry(ldap
->ld
, res
);
774 attr
= ldap_first_attributeW(ldap
->ld
, entry
, &ber
);
777 TRACE("attr: %s\n", debugstr_w(attr
));
779 values
= ldap_get_valuesW(ldap
->ld
, entry
, attr
);
781 hr
= add_attribute(ldap
, attr
, values
);
784 ldap_value_freeW(values
);
790 attr
= ldap_next_attributeW(ldap
->ld
, entry
, ber
);
794 entry
= ldap_next_entry(ldap
->ld
, res
);
798 if (res
) ldap_msgfree(res
);
800 SafeArrayUnaccessData(sa
);
804 static const IADsVtbl IADs_vtbl
=
806 ldapns_QueryInterface
,
809 ldapns_GetTypeInfoCount
,
811 ldapns_GetIDsOfNames
,
828 static inline LDAP_namespace
*impl_from_IADsOpenDSObject(IADsOpenDSObject
*iface
)
830 return CONTAINING_RECORD(iface
, LDAP_namespace
, IADsOpenDSObject_iface
);
833 static HRESULT WINAPI
openobj_QueryInterface(IADsOpenDSObject
*iface
, REFIID riid
, void **obj
)
835 TRACE("%p,%s,%p\n", iface
, debugstr_guid(riid
), obj
);
837 if (!riid
|| !obj
) return E_INVALIDARG
;
839 if (IsEqualGUID(riid
, &IID_IADsOpenDSObject
) ||
840 IsEqualGUID(riid
, &IID_IDispatch
) ||
841 IsEqualGUID(riid
, &IID_IUnknown
))
843 IADsOpenDSObject_AddRef(iface
);
848 FIXME("interface %s is not implemented\n", debugstr_guid(riid
));
849 return E_NOINTERFACE
;
852 static ULONG WINAPI
openobj_AddRef(IADsOpenDSObject
*iface
)
854 LDAP_namespace
*ldap
= impl_from_IADsOpenDSObject(iface
);
855 return IADs_AddRef(&ldap
->IADs_iface
);
858 static ULONG WINAPI
openobj_Release(IADsOpenDSObject
*iface
)
860 LDAP_namespace
*ldap
= impl_from_IADsOpenDSObject(iface
);
861 return IADs_Release(&ldap
->IADs_iface
);
864 static HRESULT WINAPI
openobj_GetTypeInfoCount(IADsOpenDSObject
*iface
, UINT
*count
)
866 FIXME("%p,%p: stub\n", iface
, count
);
870 static HRESULT WINAPI
openobj_GetTypeInfo(IADsOpenDSObject
*iface
, UINT index
, LCID lcid
, ITypeInfo
**info
)
872 FIXME("%p,%u,%#lx,%p: stub\n", iface
, index
, lcid
, info
);
876 static HRESULT WINAPI
openobj_GetIDsOfNames(IADsOpenDSObject
*iface
, REFIID riid
, LPOLESTR
*names
,
877 UINT count
, LCID lcid
, DISPID
*dispid
)
879 FIXME("%p,%s,%p,%u,%lu,%p: stub\n", iface
, debugstr_guid(riid
), names
, count
, lcid
, dispid
);
883 static HRESULT WINAPI
openobj_Invoke(IADsOpenDSObject
*iface
, DISPID dispid
, REFIID riid
, LCID lcid
, WORD flags
,
884 DISPPARAMS
*params
, VARIANT
*result
, EXCEPINFO
*excepinfo
, UINT
*argerr
)
886 FIXME("%p,%ld,%s,%04lx,%04x,%p,%p,%p,%p: stub\n", iface
, dispid
, debugstr_guid(riid
), lcid
, flags
,
887 params
, result
, excepinfo
, argerr
);
891 static HRESULT
parse_path(WCHAR
*path
, BSTR
*host
, ULONG
*port
, BSTR
*object
)
896 if (host
) *host
= NULL
;
898 if (object
) *object
= NULL
;
900 if (wcsnicmp(path
, L
"LDAP:", 5) != 0)
901 return E_ADS_BAD_PATHNAME
;
904 if (!*p
) return S_OK
;
906 if (*p
++ != '/' || *p
++ != '/' || !*p
)
907 return E_ADS_BAD_PATHNAME
;
911 while (*p
&& *p
!= '/')
916 if (!port
) port
= &dummy
;
917 *port
= wcstol(p
+ 1, &p
, 10);
918 if (*p
&& *p
!= '/') return E_ADS_BAD_PATHNAME
;
926 if (host_len
== 0) return E_ADS_BAD_PATHNAME
;
930 *host
= SysAllocStringLen(p_host
, host_len
);
931 if (!*host
) return E_OUTOFMEMORY
;
934 if (!*p
) return S_OK
;
936 if (*p
++ != '/' || !*p
)
938 SysFreeString(*host
);
939 return E_ADS_BAD_PATHNAME
;
944 *object
= SysAllocString(p
);
947 SysFreeString(*host
);
948 return E_OUTOFMEMORY
;
955 static HRESULT WINAPI
openobj_OpenDSObject(IADsOpenDSObject
*iface
, BSTR path
, BSTR user
, BSTR password
,
956 LONG flags
, IDispatch
**obj
)
963 ULONG err
, at_single_count
= 0, at_multiple_count
= 0;
964 struct attribute_type
*at
= NULL
;
966 TRACE("%p,%s,%s,%p,%08lx,%p\n", iface
, debugstr_w(path
), debugstr_w(user
), password
, flags
, obj
);
968 hr
= parse_path(path
, &host
, &port
, &object
);
969 if (hr
!= S_OK
) return hr
;
971 TRACE("host %s, port %lu, object %s\n", debugstr_w(host
), port
, debugstr_w(object
));
977 if (!wcsicmp(host
, L
"rootDSE"))
979 DOMAIN_CONTROLLER_INFOW
*dcinfo
;
983 hr
= E_ADS_BAD_PATHNAME
;
989 err
= DsGetDcNameW(NULL
, NULL
, NULL
, NULL
, DS_RETURN_DNS_NAME
, &dcinfo
);
990 if (err
!= ERROR_SUCCESS
)
992 hr
= HRESULT_FROM_WIN32(err
);
996 host
= SysAllocString(dcinfo
->DomainName
);
997 NetApiBufferFree(dcinfo
);
1006 ld
= ldap_initW(host
, port
);
1009 hr
= HRESULT_FROM_WIN32(LdapGetLastError());
1013 version
= LDAP_VERSION3
;
1014 err
= ldap_set_optionW(ld
, LDAP_OPT_PROTOCOL_VERSION
, &version
);
1015 if (err
!= LDAP_SUCCESS
)
1017 hr
= HRESULT_FROM_WIN32(map_ldap_error(err
));
1022 err
= ldap_connect(ld
, NULL
);
1023 if (err
!= LDAP_SUCCESS
)
1025 hr
= HRESULT_FROM_WIN32(map_ldap_error(err
));
1030 if (flags
& ADS_SECURE_AUTHENTICATION
)
1032 SEC_WINNT_AUTH_IDENTITY_W id
;
1034 id
.Flags
= SEC_WINNT_AUTH_IDENTITY_UNICODE
;
1035 id
.Domain
= (unsigned short *)host
;
1036 id
.DomainLength
= wcslen(host
);
1037 id
.User
= (unsigned short *)user
;
1038 id
.UserLength
= user
? wcslen(user
) : 0;
1039 id
.Password
= (unsigned short *)password
;
1040 id
.PasswordLength
= password
? wcslen(password
) : 0;
1042 err
= ldap_bind_sW(ld
, NULL
, (WCHAR
*)&id
, LDAP_AUTH_NEGOTIATE
);
1043 if (err
!= LDAP_SUCCESS
)
1045 TRACE("ldap_bind_sW error %#lx\n", err
);
1046 hr
= HRESULT_FROM_WIN32(map_ldap_error(err
));
1053 err
= ldap_simple_bind_sW(ld
, user
, password
);
1054 if (err
!= LDAP_SUCCESS
)
1056 TRACE("ldap_simple_bind_sW error %#lx\n", err
);
1057 hr
= HRESULT_FROM_WIN32(map_ldap_error(err
));
1063 at
= load_schema(ld
, &at_single_count
, &at_multiple_count
);
1066 hr
= LDAPNamespace_create(&IID_IADs
, (void **)&ads
);
1069 LDAP_namespace
*ldap
= impl_from_IADs(ads
);
1073 ldap
->object
= object
;
1075 ldap
->at_single_count
= at_single_count
;
1076 ldap
->at_multiple_count
= at_multiple_count
;
1077 hr
= IADs_QueryInterface(ads
, &IID_IDispatch
, (void **)obj
);
1083 SysFreeString(host
);
1084 SysFreeString(object
);
1089 static const IADsOpenDSObjectVtbl IADsOpenDSObject_vtbl
=
1091 openobj_QueryInterface
,
1094 openobj_GetTypeInfoCount
,
1095 openobj_GetTypeInfo
,
1096 openobj_GetIDsOfNames
,
1098 openobj_OpenDSObject
1101 static inline LDAP_namespace
*impl_from_IDirectorySearch(IDirectorySearch
*iface
)
1103 return CONTAINING_RECORD(iface
, LDAP_namespace
, IDirectorySearch_iface
);
1106 static HRESULT WINAPI
search_QueryInterface(IDirectorySearch
*iface
, REFIID riid
, void **obj
)
1108 TRACE("%p,%s,%p\n", iface
, debugstr_guid(riid
), obj
);
1110 if (!riid
|| !obj
) return E_INVALIDARG
;
1112 if (IsEqualGUID(riid
, &IID_IDirectorySearch
) ||
1113 IsEqualGUID(riid
, &IID_IUnknown
))
1115 IDirectorySearch_AddRef(iface
);
1120 FIXME("interface %s is not implemented\n", debugstr_guid(riid
));
1121 return E_NOINTERFACE
;
1124 static ULONG WINAPI
search_AddRef(IDirectorySearch
*iface
)
1126 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1127 return IADs_AddRef(&ldap
->IADs_iface
);
1130 static ULONG WINAPI
search_Release(IDirectorySearch
*iface
)
1132 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1133 return IADs_Release(&ldap
->IADs_iface
);
1136 static HRESULT WINAPI
search_SetSearchPreference(IDirectorySearch
*iface
, PADS_SEARCHPREF_INFO prefs
, DWORD count
)
1138 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1142 TRACE("%p,%p,%lu\n", iface
, prefs
, count
);
1144 for (i
= 0; i
< count
; i
++)
1146 switch (prefs
[i
].dwSearchPref
)
1148 case ADS_SEARCHPREF_SEARCH_SCOPE
:
1149 if (prefs
[i
].vValue
.dwType
!= ADSTYPE_INTEGER
)
1151 FIXME("ADS_SEARCHPREF_SEARCH_SCOPE: unsupported dwType %d\n", prefs
[i
].vValue
.dwType
);
1152 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1156 switch (prefs
[i
].vValue
.Integer
)
1158 case ADS_SCOPE_BASE
:
1159 case ADS_SCOPE_ONELEVEL
:
1160 case ADS_SCOPE_SUBTREE
:
1161 TRACE("SEARCH_SCOPE: %ld\n", prefs
[i
].vValue
.Integer
);
1162 ldap
->search
.scope
= prefs
[i
].vValue
.Integer
;
1163 prefs
[i
].dwStatus
= ADS_STATUS_S_OK
;
1167 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1172 case ADS_SEARCHPREF_SECURITY_MASK
:
1177 struct berval
*berval
;
1178 LDAPControlW
*ctrls
[2], mask
;
1180 if (prefs
[i
].vValue
.dwType
!= ADSTYPE_INTEGER
)
1182 FIXME("ADS_SEARCHPREF_SECURITY_MASK: not supported dwType %d\n", prefs
[i
].vValue
.dwType
);
1183 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1187 TRACE("SECURITY_MASK: %08lx\n", prefs
[i
].vValue
.Integer
);
1188 security_mask
= prefs
[i
].vValue
.Integer
;
1190 security_mask
= ADS_SECURITY_INFO_OWNER
;
1192 ber
= ber_alloc_t(LBER_USE_DER
);
1193 if (!ber
|| ber_printf(ber
, (char *)"{i}", security_mask
) == -1 || ber_flatten(ber
, &berval
) == -1)
1196 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREF
;
1199 TRACE("ber: %s\n", debugstr_an(berval
->bv_val
, berval
->bv_len
));
1201 mask
.ldctl_oid
= (WCHAR
*)L
"1.2.840.113556.1.4.801";
1202 mask
.ldctl_iscritical
= TRUE
;
1203 mask
.ldctl_value
.bv_val
= berval
->bv_val
;
1204 mask
.ldctl_value
.bv_len
= berval
->bv_len
;
1207 err
= ldap_set_optionW(ldap
->ld
, LDAP_OPT_SERVER_CONTROLS
, ctrls
);
1208 if (err
!= LDAP_SUCCESS
)
1210 TRACE("ldap_set_option error %#lx\n", err
);
1211 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREF
;
1212 hr
= S_ADS_ERRORSOCCURRED
;
1215 prefs
[i
].dwStatus
= ADS_STATUS_S_OK
;
1222 case ADS_SEARCHPREF_PAGESIZE
:
1223 if (prefs
[i
].vValue
.dwType
!= ADSTYPE_INTEGER
)
1225 FIXME("ADS_SEARCHPREF_PAGESIZE: unsupported dwType %d\n", prefs
[i
].vValue
.dwType
);
1226 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1230 TRACE("PAGESIZE: %ld\n", prefs
[i
].vValue
.Integer
);
1231 ldap
->search
.pagesize
= prefs
[i
].vValue
.Integer
;
1232 prefs
[i
].dwStatus
= ADS_STATUS_S_OK
;
1235 case ADS_SEARCHPREF_CACHE_RESULTS
:
1236 if (prefs
[i
].vValue
.dwType
!= ADSTYPE_BOOLEAN
)
1238 FIXME("ADS_SEARCHPREF_CACHE_RESULTS: unsupported dwType %d\n", prefs
[i
].vValue
.dwType
);
1239 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1243 TRACE("CACHE_RESULTS: %ld\n", prefs
[i
].vValue
.Boolean
);
1244 ldap
->search
.cache_results
= prefs
[i
].vValue
.Boolean
;
1245 prefs
[i
].dwStatus
= ADS_STATUS_S_OK
;
1248 case ADS_SEARCHPREF_ATTRIBTYPES_ONLY
:
1249 if (prefs
[i
].vValue
.dwType
!= ADSTYPE_BOOLEAN
)
1251 FIXME("ADS_SEARCHPREF_ATTRIBTYPES_ONLY: unsupported dwType %d\n", prefs
[i
].vValue
.dwType
);
1252 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1256 TRACE("ATTRIBTYPES_ONLY: %ld\n", prefs
[i
].vValue
.Boolean
);
1257 ldap
->search
.attribtypes_only
= prefs
[i
].vValue
.Boolean
;
1258 prefs
[i
].dwStatus
= ADS_STATUS_S_OK
;
1261 case ADS_SEARCHPREF_TOMBSTONE
:
1262 if (prefs
[i
].vValue
.dwType
!= ADSTYPE_BOOLEAN
)
1264 FIXME("ADS_SEARCHPREF_TOMBSTONE: unsupported dwType %d\n", prefs
[i
].vValue
.dwType
);
1265 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1269 TRACE("TOMBSTONE: %ld\n", prefs
[i
].vValue
.Boolean
);
1270 ldap
->search
.tombstone
= prefs
[i
].vValue
.Boolean
;
1271 prefs
[i
].dwStatus
= ADS_STATUS_S_OK
;
1274 case ADS_SEARCHPREF_SIZE_LIMIT
:
1275 if (prefs
[i
].vValue
.dwType
!= ADSTYPE_INTEGER
)
1277 FIXME("ADS_SEARCHPREF_SIZE_LIMIT: unsupported dwType %d\n", prefs
[i
].vValue
.dwType
);
1278 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1282 TRACE("SIZE_LIMIT: %ld\n", prefs
[i
].vValue
.Integer
);
1283 ldap
->search
.size_limit
= prefs
[i
].vValue
.Integer
;
1284 prefs
[i
].dwStatus
= ADS_STATUS_S_OK
;
1288 FIXME("pref %d, type %u: stub\n", prefs
[i
].dwSearchPref
, prefs
[i
].vValue
.dwType
);
1289 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREF
;
1297 static HRESULT WINAPI
search_ExecuteSearch(IDirectorySearch
*iface
, LPWSTR filter
, LPWSTR
*names
,
1298 DWORD count
, PADS_SEARCH_HANDLE res
)
1300 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1303 LDAPControlW
**ctrls
= NULL
, *ctrls_a
[2], tombstone
;
1304 struct ldap_search_context
*ldap_ctx
;
1306 TRACE("%p,%s,%p,%lu,%p\n", iface
, debugstr_w(filter
), names
, count
, res
);
1308 if (!res
) return E_ADS_BAD_PARAMETER
;
1310 ldap_ctx
= calloc(1, sizeof(*ldap_ctx
));
1311 if (!ldap_ctx
) return E_OUTOFMEMORY
;
1313 if (count
== 0xffffffff)
1317 if (count
&& !names
)
1320 return E_ADS_BAD_PARAMETER
;
1323 props
= malloc((count
+ 1) * sizeof(props
[0]));
1327 return E_OUTOFMEMORY
;
1330 for (i
= 0; i
< count
; i
++)
1332 TRACE("=> %s\n", debugstr_w(names
[i
]));
1333 props
[i
] = names
[i
];
1336 props
[count
] = NULL
;
1339 if (ldap
->search
.tombstone
)
1341 tombstone
.ldctl_oid
= (WCHAR
*)L
"1.2.840.113556.1.4.417";
1342 tombstone
.ldctl_iscritical
= TRUE
;
1343 tombstone
.ldctl_value
.bv_val
= NULL
;
1344 tombstone
.ldctl_value
.bv_len
= 0;
1345 ctrls_a
[0] = &tombstone
;
1350 if (ldap
->search
.pagesize
)
1352 ldap_ctx
->page
= ldap_search_init_pageW(ldap
->ld
, ldap
->object
, ldap
->search
.scope
,
1353 filter
, props
, ldap
->search
.attribtypes_only
,
1354 ctrls
, NULL
, 0, ldap
->search
.size_limit
, NULL
);
1356 err
= ldap_get_next_page_s(ldap
->ld
, ldap_ctx
->page
, NULL
,
1357 ldap
->search
.pagesize
, &count
, &ldap_ctx
->res
);
1359 err
= LDAP_NO_MEMORY
;
1362 err
= ldap_search_ext_sW(ldap
->ld
, ldap
->object
, ldap
->search
.scope
, filter
, props
,
1363 ldap
->search
.attribtypes_only
, ctrls
, NULL
, NULL
, ldap
->search
.size_limit
,
1366 if (err
!= LDAP_SUCCESS
)
1368 TRACE("ldap_search_sW error %#lx\n", err
);
1370 ldap_search_abandon_page(ldap
->ld
, ldap_ctx
->page
);
1372 return HRESULT_FROM_WIN32(map_ldap_error(err
));
1379 static HRESULT WINAPI
search_AbandonSearch(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
)
1381 FIXME("%p,%p: stub\n", iface
, res
);
1385 static HRESULT WINAPI
search_GetFirstRow(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
)
1387 struct ldap_search_context
*ldap_ctx
= res
;
1389 TRACE("%p,%p\n", iface
, res
);
1391 if (!res
) return E_ADS_BAD_PARAMETER
;
1393 ldap_ctx
->entry
= NULL
;
1395 return IDirectorySearch_GetNextRow(iface
, res
);
1398 static HRESULT WINAPI
search_GetNextRow(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
)
1400 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1401 struct ldap_search_context
*ldap_ctx
= res
;
1403 TRACE("%p,%p\n", iface
, res
);
1405 if (!res
) return E_ADS_BAD_PARAMETER
;
1407 if (!ldap_ctx
->entry
)
1409 ldap_ctx
->count
= ldap_count_entries(ldap
->ld
, ldap_ctx
->res
);
1412 if (ldap_ctx
->pos
>= ldap_ctx
->count
)
1413 return S_ADS_NOMORE_ROWS
;
1415 ldap_ctx
->entry
= ldap_first_entry(ldap
->ld
, ldap_ctx
->res
);
1419 if (ldap_ctx
->pos
>= ldap_ctx
->count
)
1425 ldap_msgfree(ldap_ctx
->res
);
1426 ldap_ctx
->res
= NULL
;
1428 err
= ldap_get_next_page_s(ldap
->ld
, ldap_ctx
->page
, NULL
, ldap
->search
.pagesize
, &count
, &ldap_ctx
->res
);
1429 if (err
== LDAP_SUCCESS
)
1431 ldap_ctx
->count
= ldap_count_entries(ldap
->ld
, ldap_ctx
->res
);
1434 if (ldap_ctx
->pos
>= ldap_ctx
->count
)
1435 return S_ADS_NOMORE_ROWS
;
1437 ldap_ctx
->entry
= ldap_first_entry(ldap
->ld
, ldap_ctx
->res
);
1441 if (err
!= LDAP_NO_RESULTS_RETURNED
)
1443 TRACE("ldap_get_next_page_s error %#lx\n", err
);
1444 return HRESULT_FROM_WIN32(map_ldap_error(err
));
1449 return S_ADS_NOMORE_ROWS
;
1452 ldap_ctx
->entry
= ldap_next_entry(ldap
->ld
, ldap_ctx
->entry
);
1456 if (!ldap_ctx
->entry
)
1457 return S_ADS_NOMORE_ROWS
;
1460 ldap_ctx
->ber
= NULL
;
1465 static HRESULT WINAPI
search_GetPreviousRow(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
)
1467 FIXME("%p,%p: stub\n", iface
, res
);
1471 static HRESULT WINAPI
search_GetNextColumnName(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
, LPWSTR
*name
)
1473 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1474 struct ldap_search_context
*ldap_ctx
= res
;
1477 TRACE("%p,%p,%p\n", iface
, res
, name
);
1479 if (!name
|| !ldap_ctx
|| !ldap_ctx
->entry
) return E_ADS_BAD_PARAMETER
;
1483 attr
= ldap_first_attributeW(ldap
->ld
, ldap_ctx
->entry
, &ldap_ctx
->ber
);
1484 ldap_ctx
->add_ADsPath
= TRUE
;
1487 attr
= ldap_next_attributeW(ldap
->ld
, ldap_ctx
->entry
, ldap_ctx
->ber
);
1491 TRACE("=> %s\n", debugstr_w(attr
));
1492 *name
= AllocADsStr(attr
);
1493 ldap_memfreeW(attr
);
1494 return *name
? S_OK
: E_OUTOFMEMORY
;
1496 else if (ldap_ctx
->add_ADsPath
)
1498 ldap_ctx
->add_ADsPath
= FALSE
;
1499 *name
= AllocADsStr((WCHAR
*)L
"ADsPath");
1500 TRACE("=> %s\n", debugstr_w(*name
));
1501 return *name
? S_OK
: E_OUTOFMEMORY
;
1505 return S_ADS_NOMORE_COLUMNS
;
1508 static HRESULT
add_column_values(LDAP_namespace
*ldap
, struct ldap_search_context
*ldap_ctx
,
1509 LPWSTR name
, ADS_SEARCH_COLUMN
*col
)
1514 type
= get_schema_type(name
, ldap
->at
, ldap
->at_single_count
, ldap
->at_multiple_count
);
1515 TRACE("%s => type %d\n", debugstr_w(name
), type
);
1520 FIXME("no special handling for type %d\n", type
);
1522 case ADSTYPE_DN_STRING
:
1523 case ADSTYPE_CASE_EXACT_STRING
:
1524 case ADSTYPE_CASE_IGNORE_STRING
:
1525 case ADSTYPE_PRINTABLE_STRING
:
1527 WCHAR
**values
= ldap_get_valuesW(ldap
->ld
, ldap_ctx
->entry
, name
);
1529 return E_ADS_COLUMN_NOT_SET
;
1530 count
= ldap_count_valuesW(values
);
1532 col
->pADsValues
= calloc(count
, sizeof(col
->pADsValues
[0]));
1533 if (!col
->pADsValues
)
1535 ldap_value_freeW(values
);
1536 return E_OUTOFMEMORY
;
1539 for (i
= 0; i
< count
; i
++)
1541 TRACE("=> %s\n", debugstr_w(values
[i
]));
1542 col
->pADsValues
[i
].dwType
= type
;
1543 col
->pADsValues
[i
].CaseIgnoreString
= values
[i
];
1546 col
->hReserved
= values
;
1550 case ADSTYPE_BOOLEAN
:
1552 WCHAR
**values
= ldap_get_valuesW(ldap
->ld
, ldap_ctx
->entry
, name
);
1554 return E_ADS_COLUMN_NOT_SET
;
1555 count
= ldap_count_valuesW(values
);
1557 col
->pADsValues
= calloc(count
, sizeof(col
->pADsValues
[0]));
1558 if (!col
->pADsValues
)
1560 ldap_value_freeW(values
);
1561 return E_OUTOFMEMORY
;
1564 for (i
= 0; i
< count
; i
++)
1566 col
->pADsValues
[i
].dwType
= type
;
1568 if (!wcsicmp(values
[i
], L
"TRUE"))
1569 col
->pADsValues
[i
].Boolean
= 1;
1570 else if (!wcsicmp(values
[i
], L
"FALSE"))
1571 col
->pADsValues
[i
].Boolean
= 0;
1574 FIXME("not recognized boolean value %s\n", debugstr_w(values
[i
]));
1575 col
->pADsValues
[i
].Boolean
= 0;
1577 TRACE("%s => %ld\n", debugstr_w(values
[i
]), col
->pADsValues
[i
].Boolean
);
1580 ldap_value_freeW(values
);
1581 col
->hReserved
= NULL
;
1585 case ADSTYPE_INTEGER
:
1586 case ADSTYPE_LARGE_INTEGER
:
1588 struct berval
**values
= ldap_get_values_lenW(ldap
->ld
, ldap_ctx
->entry
, name
);
1590 return E_ADS_COLUMN_NOT_SET
;
1591 count
= ldap_count_values_len(values
);
1593 col
->pADsValues
= calloc(count
, sizeof(col
->pADsValues
[0]));
1594 if (!col
->pADsValues
)
1596 ldap_value_free_len(values
);
1597 return E_OUTOFMEMORY
;
1600 for (i
= 0; i
< count
; i
++)
1602 col
->pADsValues
[i
].dwType
= type
;
1604 if (type
== ADSTYPE_LARGE_INTEGER
)
1606 col
->pADsValues
[i
].LargeInteger
.QuadPart
= _atoi64(values
[i
]->bv_val
);
1607 TRACE("%s => %s\n", debugstr_an(values
[i
]->bv_val
, values
[i
]->bv_len
), wine_dbgstr_longlong(col
->pADsValues
[i
].LargeInteger
.QuadPart
));
1611 col
->pADsValues
[i
].Integer
= atol(values
[i
]->bv_val
);
1612 TRACE("%s => %ld\n", debugstr_an(values
[i
]->bv_val
, values
[i
]->bv_len
), col
->pADsValues
[i
].Integer
);
1616 ldap_value_free_len(values
);
1617 col
->hReserved
= NULL
;
1621 case ADSTYPE_OCTET_STRING
:
1622 case ADSTYPE_NT_SECURITY_DESCRIPTOR
:
1624 struct berval
**values
= ldap_get_values_lenW(ldap
->ld
, ldap_ctx
->entry
, name
);
1626 return E_ADS_COLUMN_NOT_SET
;
1627 count
= ldap_count_values_len(values
);
1629 col
->pADsValues
= calloc(count
, sizeof(col
->pADsValues
[0]));
1630 if (!col
->pADsValues
)
1632 ldap_value_free_len(values
);
1633 return E_OUTOFMEMORY
;
1636 for (i
= 0; i
< count
; i
++)
1638 TRACE("=> %s\n", debugstr_an(values
[i
]->bv_val
, values
[i
]->bv_len
));
1639 col
->pADsValues
[i
].dwType
= type
;
1640 col
->pADsValues
[i
].OctetString
.dwLength
= values
[i
]->bv_len
;
1641 col
->pADsValues
[i
].OctetString
.lpValue
= (BYTE
*)values
[i
]->bv_val
;
1644 col
->hReserved
= values
;
1648 case ADSTYPE_UTC_TIME
:
1650 struct berval
**values
= ldap_get_values_lenW(ldap
->ld
, ldap_ctx
->entry
, name
);
1652 return E_ADS_COLUMN_NOT_SET
;
1653 count
= ldap_count_values_len(values
);
1655 col
->pADsValues
= calloc(count
, sizeof(col
->pADsValues
[0]));
1656 if (!col
->pADsValues
)
1658 ldap_value_free_len(values
);
1659 return E_OUTOFMEMORY
;
1662 for (i
= 0; i
< count
; i
++)
1664 col
->pADsValues
[i
].dwType
= type
;
1665 if (values
[i
]->bv_len
< 14 ||
1666 _snscanf_l(values
[i
]->bv_val
, values
[i
]->bv_len
, "%04hu%02hu%02hu%02hu%02hu%02hu", NULL
,
1667 &col
->pADsValues
[i
].UTCTime
.wYear
, &col
->pADsValues
[i
].UTCTime
.wMonth
,
1668 &col
->pADsValues
[i
].UTCTime
.wDay
, &col
->pADsValues
[i
].UTCTime
.wHour
,
1669 &col
->pADsValues
[i
].UTCTime
.wMinute
, &col
->pADsValues
[i
].UTCTime
.wSecond
) != 6)
1671 FIXME("not recognized UTCTime: %s\n", debugstr_an(values
[i
]->bv_val
, values
[i
]->bv_len
));
1672 memset(&col
->pADsValues
[i
].UTCTime
, 0, sizeof(col
->pADsValues
[i
].UTCTime
));
1676 if ((values
[i
]->bv_val
[14] != '.' && values
[i
]->bv_val
[14] != ',') ||
1677 values
[i
]->bv_val
[15] != '0' || values
[i
]->bv_val
[16] != 'Z')
1678 FIXME("not handled time zone: %s\n", debugstr_an(values
[i
]->bv_val
+ 14, values
[i
]->bv_len
- 14));
1680 TRACE("%s => %02u.%02u.%04u %02u:%02u:%02u\n", debugstr_an(values
[i
]->bv_val
, values
[i
]->bv_len
),
1681 col
->pADsValues
[i
].UTCTime
.wDay
, col
->pADsValues
[i
].UTCTime
.wMonth
,
1682 col
->pADsValues
[i
].UTCTime
.wYear
, col
->pADsValues
[i
].UTCTime
.wHour
,
1683 col
->pADsValues
[i
].UTCTime
.wMinute
, col
->pADsValues
[i
].UTCTime
.wSecond
);
1686 ldap_value_free_len(values
);
1687 col
->hReserved
= NULL
;
1691 case ADSTYPE_DN_WITH_BINARY
:
1693 static const BYTE hex2bin
[] =
1695 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x00 */
1696 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x10 */
1697 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x20 */
1698 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, /* 0x30 */
1699 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0, /* 0x40 */
1700 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x50 */
1701 0,10,11,12,13,14,15 /* 0x60 */
1703 ADS_DN_WITH_BINARY
*dnb
;
1704 WCHAR
**values
= ldap_get_valuesW(ldap
->ld
, ldap_ctx
->entry
, name
);
1706 return E_ADS_COLUMN_NOT_SET
;
1707 count
= ldap_count_valuesW(values
);
1709 col
->pADsValues
= calloc(count
, sizeof(col
->pADsValues
[0]) + sizeof(col
->pADsValues
[0].pDNWithBinary
[0]));
1710 if (!col
->pADsValues
)
1712 ldap_value_freeW(values
);
1713 return E_OUTOFMEMORY
;
1716 dnb
= (ADS_DN_WITH_BINARY
*)(col
->pADsValues
+ count
);
1718 for (i
= 0; i
< count
; i
++)
1720 WCHAR
*p
= values
[i
];
1723 col
->pADsValues
[i
].dwType
= type
;
1724 col
->pADsValues
[i
].pDNWithBinary
= dnb
++;
1726 if ((p
[0] != 'b' && p
[0] != 'B') || p
[1] != ':')
1727 FIXME("wrong DN with binary tag '%c%c'\n", p
[0], p
[1]);
1730 col
->pADsValues
[i
].pDNWithBinary
->dwLength
= wcstol(p
, &p
, 10) / 2;
1732 FIXME("wrong DN with binary separator '%c'\n", *p
);
1734 col
->pADsValues
[i
].pDNWithBinary
->lpBinaryValue
= (BYTE
*)p
;
1735 /* decode values in-place */
1736 for (n
= 0; n
< col
->pADsValues
[i
].pDNWithBinary
->dwLength
; n
++, p
+= 2)
1740 if (p
[0] > 'f' || (p
[0] != '0' && !hex2bin
[p
[0]]) ||
1741 p
[1] > 'f' || (p
[1] != '0' && !hex2bin
[p
[1]]))
1743 FIXME("bad hex encoding at %s\n", debugstr_w(p
));
1747 b
= (hex2bin
[p
[0]] << 4) | hex2bin
[p
[1]];
1748 col
->pADsValues
[i
].pDNWithBinary
->lpBinaryValue
[n
] = b
;
1751 FIXME("wrong DN with binary separator '%c'\n", *p
);
1752 col
->pADsValues
[i
].pDNWithBinary
->pszDNString
= p
+ 1;
1754 TRACE("%s => %lu,%s,%s\n", debugstr_w(values
[i
]),
1755 col
->pADsValues
[i
].pDNWithBinary
->dwLength
,
1756 debugstr_an((char *)col
->pADsValues
[i
].pDNWithBinary
->lpBinaryValue
, col
->pADsValues
[i
].pDNWithBinary
->dwLength
),
1757 debugstr_w(col
->pADsValues
[i
].pDNWithBinary
->pszDNString
));
1760 col
->hReserved
= values
;
1765 col
->dwADsType
= type
;
1766 col
->dwNumValues
= count
;
1767 col
->pszAttrName
= wcsdup(name
);
1772 static HRESULT WINAPI
search_GetColumn(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
,
1773 LPWSTR name
, PADS_SEARCH_COLUMN col
)
1775 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1776 struct ldap_search_context
*ldap_ctx
= res
;
1780 TRACE("%p,%p,%s,%p\n", iface
, res
, debugstr_w(name
), col
);
1782 if (!res
|| !name
|| !ldap_ctx
->entry
) return E_ADS_BAD_PARAMETER
;
1784 memset(col
, 0, sizeof(*col
));
1786 if (!wcsicmp(name
, L
"ADsPath"))
1788 WCHAR
*dn
= ldap_get_dnW(ldap
->ld
, ldap_ctx
->entry
);
1790 col
->pADsValues
= malloc(sizeof(col
->pADsValues
[0]));
1791 if (!col
->pADsValues
)
1797 count
= sizeof(L
"LDAP://") + (wcslen(ldap
->host
) + 1 /* '/' */) * sizeof(WCHAR
);
1798 if (dn
) count
+= wcslen(dn
) * sizeof(WCHAR
);
1800 col
->pADsValues
[0].CaseIgnoreString
= malloc(count
);
1801 if (!col
->pADsValues
[0].CaseIgnoreString
)
1807 wcscpy(col
->pADsValues
[0].CaseIgnoreString
, L
"LDAP://");
1808 wcscat(col
->pADsValues
[0].CaseIgnoreString
, ldap
->host
);
1809 wcscat(col
->pADsValues
[0].CaseIgnoreString
, L
"/");
1810 if (dn
) wcscat(col
->pADsValues
[0].CaseIgnoreString
, dn
);
1811 col
->pADsValues
[0].dwType
= ADSTYPE_CASE_IGNORE_STRING
;
1812 col
->dwADsType
= ADSTYPE_CASE_IGNORE_STRING
;
1813 col
->dwNumValues
= 1;
1814 col
->pszAttrName
= wcsdup(name
);
1815 col
->hReserved
= NULL
;
1817 TRACE("=> %s\n", debugstr_w(col
->pADsValues
[0].CaseIgnoreString
));
1824 return add_column_values(ldap
, ldap_ctx
, name
, col
);
1827 static HRESULT WINAPI
search_FreeColumn(IDirectorySearch
*iface
, PADS_SEARCH_COLUMN col
)
1829 TRACE("%p,%p\n", iface
, col
);
1831 if (!col
) return E_ADS_BAD_PARAMETER
;
1833 if (!wcsicmp(col
->pszAttrName
, L
"ADsPath"))
1834 free(col
->pADsValues
[0].CaseIgnoreString
);
1835 free(col
->pADsValues
);
1836 free(col
->pszAttrName
);
1840 if (col
->dwADsType
== ADSTYPE_OCTET_STRING
|| col
->dwADsType
== ADSTYPE_NT_SECURITY_DESCRIPTOR
)
1841 ldap_value_free_len(col
->hReserved
);
1843 ldap_value_freeW(col
->hReserved
);
1849 static HRESULT WINAPI
search_CloseSearchHandle(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
)
1851 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1852 struct ldap_search_context
*ldap_ctx
= res
;
1854 TRACE("%p,%p\n", iface
, res
);
1856 if (!res
) return E_ADS_BAD_PARAMETER
;
1859 ldap_search_abandon_page(ldap
->ld
, ldap_ctx
->page
);
1861 ldap_msgfree(ldap_ctx
->res
);
1863 ber_free(ldap_ctx
->ber
, 0);
1869 static const IDirectorySearchVtbl IDirectorySearch_vtbl
=
1871 search_QueryInterface
,
1874 search_SetSearchPreference
,
1875 search_ExecuteSearch
,
1876 search_AbandonSearch
,
1879 search_GetPreviousRow
,
1880 search_GetNextColumnName
,
1883 search_CloseSearchHandle
1886 static inline LDAP_namespace
*impl_from_IDirectoryObject(IDirectoryObject
*iface
)
1888 return CONTAINING_RECORD(iface
, LDAP_namespace
, IDirectoryObject_iface
);
1891 static HRESULT WINAPI
dirobj_QueryInterface(IDirectoryObject
*iface
, REFIID riid
, void **obj
)
1893 LDAP_namespace
*ldap
= impl_from_IDirectoryObject(iface
);
1895 TRACE("%p,%s,%p\n", iface
, debugstr_guid(riid
), obj
);
1897 if (!riid
|| !obj
) return E_INVALIDARG
;
1899 if (IsEqualGUID(riid
, &IID_IDirectoryObject
) ||
1900 IsEqualGUID(riid
, &IID_IUnknown
))
1902 IDirectoryObject_AddRef(iface
);
1907 return IADs_QueryInterface(&ldap
->IADs_iface
, riid
, obj
);
1910 static ULONG WINAPI
dirobj_AddRef(IDirectoryObject
*iface
)
1912 LDAP_namespace
*ldap
= impl_from_IDirectoryObject(iface
);
1913 return IADs_AddRef(&ldap
->IADs_iface
);
1916 static ULONG WINAPI
dirobj_Release(IDirectoryObject
*iface
)
1918 LDAP_namespace
*ldap
= impl_from_IDirectoryObject(iface
);
1919 return IADs_Release(&ldap
->IADs_iface
);
1922 static HRESULT WINAPI
dirobj_GetObjectInformation(IDirectoryObject
*iface
, PADS_OBJECT_INFO
*info
)
1924 FIXME("%p,%p: stub\n", iface
, info
);
1928 static HRESULT WINAPI
dirobj_GetObjectAttributes(IDirectoryObject
*iface
, LPWSTR
*names
,
1929 DWORD count
, PADS_ATTR_INFO
*attrs
, DWORD
*count_returned
)
1931 FIXME("%p,%p,%lu,%p,%p: stub\n", iface
, names
, count
, attrs
, count_returned
);
1935 static HRESULT WINAPI
dirobj_SetObjectAttributes(IDirectoryObject
*iface
, PADS_ATTR_INFO attrs
,
1936 DWORD count
, DWORD
*count_set
)
1938 FIXME("%p,%p,%lu,%p: stub\n", iface
, attrs
, count
, count_set
);
1942 static HRESULT WINAPI
dirobj_CreateDSObject(IDirectoryObject
*iface
, LPWSTR name
,
1943 PADS_ATTR_INFO attrs
, DWORD count
, IDispatch
**obj
)
1945 FIXME("%p,%s,%p,%lu,%p: stub\n", iface
, debugstr_w(name
), attrs
, count
, obj
);
1949 static HRESULT WINAPI
dirobj_DeleteDSObject(IDirectoryObject
*iface
, LPWSTR name
)
1951 FIXME("%p,%s: stub\n", iface
, debugstr_w(name
));
1955 static const IDirectoryObjectVtbl IDirectoryObject_vtbl
=
1957 dirobj_QueryInterface
,
1960 dirobj_GetObjectInformation
,
1961 dirobj_GetObjectAttributes
,
1962 dirobj_SetObjectAttributes
,
1963 dirobj_CreateDSObject
,
1964 dirobj_DeleteDSObject
1967 static HRESULT
LDAPNamespace_create(REFIID riid
, void **obj
)
1969 LDAP_namespace
*ldap
;
1972 ldap
= malloc(sizeof(*ldap
));
1973 if (!ldap
) return E_OUTOFMEMORY
;
1975 ldap
->IADs_iface
.lpVtbl
= &IADs_vtbl
;
1976 ldap
->IADsOpenDSObject_iface
.lpVtbl
= &IADsOpenDSObject_vtbl
;
1977 ldap
->IDirectorySearch_iface
.lpVtbl
= &IDirectorySearch_vtbl
;
1978 ldap
->IDirectoryObject_iface
.lpVtbl
= &IDirectoryObject_vtbl
;
1982 ldap
->object
= NULL
;
1983 ldap
->attrs_count
= 0;
1984 ldap
->attrs_count_allocated
= 0;
1986 ldap
->search
.scope
= ADS_SCOPE_SUBTREE
;
1987 ldap
->search
.pagesize
= 0;
1988 ldap
->search
.size_limit
= 0;
1989 ldap
->search
.cache_results
= TRUE
;
1990 ldap
->search
.attribtypes_only
= FALSE
;
1991 ldap
->search
.tombstone
= FALSE
;
1993 ldap
->at_single_count
= 0;
1994 ldap
->at_multiple_count
= 0;
1996 hr
= IADs_QueryInterface(&ldap
->IADs_iface
, riid
, obj
);
1997 IADs_Release(&ldap
->IADs_iface
);
2002 static const struct class_info
2005 HRESULT (*constructor
)(REFIID
, void **);
2008 { &CLSID_ADSystemInfo
, ADSystemInfo_create
},
2009 { &CLSID_LDAP
, LDAP_create
},
2010 { &CLSID_LDAPNamespace
, LDAPNamespace_create
},
2015 IClassFactory IClassFactory_iface
;
2017 const struct class_info
*info
;
2020 static inline class_factory
*impl_from_IClassFactory(IClassFactory
*iface
)
2022 return CONTAINING_RECORD(iface
, class_factory
, IClassFactory_iface
);
2025 static HRESULT WINAPI
factory_QueryInterface(IClassFactory
*iface
, REFIID riid
, LPVOID
*obj
)
2027 TRACE("%p,%s,%p\n", iface
, debugstr_guid(riid
), obj
);
2029 if (!riid
|| !obj
) return E_INVALIDARG
;
2031 if (IsEqualIID(riid
, &IID_IUnknown
) ||
2032 IsEqualIID(riid
, &IID_IClassFactory
))
2034 IClassFactory_AddRef(iface
);
2040 FIXME("interface %s is not implemented\n", debugstr_guid(riid
));
2041 return E_NOINTERFACE
;
2044 static ULONG WINAPI
factory_AddRef(IClassFactory
*iface
)
2046 class_factory
*factory
= impl_from_IClassFactory(iface
);
2047 ULONG ref
= InterlockedIncrement(&factory
->ref
);
2049 TRACE("(%p) ref %lu\n", iface
, ref
);
2054 static ULONG WINAPI
factory_Release(IClassFactory
*iface
)
2056 class_factory
*factory
= impl_from_IClassFactory(iface
);
2057 ULONG ref
= InterlockedDecrement(&factory
->ref
);
2059 TRACE("(%p) ref %lu\n", iface
, ref
);
2067 static HRESULT WINAPI
factory_CreateInstance(IClassFactory
*iface
, IUnknown
*outer
, REFIID riid
, void **obj
)
2069 class_factory
*factory
= impl_from_IClassFactory(iface
);
2071 TRACE("%p,%s,%p\n", outer
, debugstr_guid(riid
), obj
);
2073 if (!riid
|| !obj
) return E_INVALIDARG
;
2076 if (outer
) return CLASS_E_NOAGGREGATION
;
2078 return factory
->info
->constructor(riid
, obj
);
2081 static HRESULT WINAPI
factory_LockServer(IClassFactory
*iface
, BOOL lock
)
2083 FIXME("%p,%d: stub\n", iface
, lock
);
2087 static const struct IClassFactoryVtbl factory_vtbl
=
2089 factory_QueryInterface
,
2092 factory_CreateInstance
,
2096 static HRESULT
factory_constructor(const struct class_info
*info
, REFIID riid
, void **obj
)
2098 class_factory
*factory
;
2101 factory
= malloc(sizeof(*factory
));
2102 if (!factory
) return E_OUTOFMEMORY
;
2104 factory
->IClassFactory_iface
.lpVtbl
= &factory_vtbl
;
2106 factory
->info
= info
;
2108 hr
= IClassFactory_QueryInterface(&factory
->IClassFactory_iface
, riid
, obj
);
2109 IClassFactory_Release(&factory
->IClassFactory_iface
);
2114 HRESULT WINAPI
DllGetClassObject(REFCLSID clsid
, REFIID iid
, LPVOID
*obj
)
2118 TRACE("%s,%s,%p\n", debugstr_guid(clsid
), debugstr_guid(iid
), obj
);
2120 if (!clsid
|| !iid
|| !obj
) return E_INVALIDARG
;
2124 for (i
= 0; i
< ARRAY_SIZE(class_info
); i
++)
2126 if (IsEqualCLSID(class_info
[i
].clsid
, clsid
))
2127 return factory_constructor(&class_info
[i
], iid
, obj
);
2130 FIXME("class %s/%s is not implemented\n", debugstr_guid(clsid
), debugstr_guid(iid
));
2131 return CLASS_E_CLASSNOTAVAILABLE
;