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
= malloc(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,%#lx,%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,%lu,%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,%ld,%s,%04lx,%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
= malloc(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
;
405 BOOL attribtypes_only
;
410 struct ldap_search_context
413 LDAPMessage
*res
, *entry
;
419 static inline LDAP_namespace
*impl_from_IADs(IADs
*iface
)
421 return CONTAINING_RECORD(iface
, LDAP_namespace
, IADs_iface
);
424 static HRESULT WINAPI
ldapns_QueryInterface(IADs
*iface
, REFIID riid
, void **obj
)
426 LDAP_namespace
*ldap
= impl_from_IADs(iface
);
428 TRACE("%p,%s,%p\n", iface
, debugstr_guid(riid
), obj
);
430 if (!riid
|| !obj
) return E_INVALIDARG
;
432 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
433 IsEqualGUID(riid
, &IID_IDispatch
) ||
434 IsEqualGUID(riid
, &IID_IADs
))
441 if (IsEqualGUID(riid
, &IID_IADsOpenDSObject
))
444 *obj
= &ldap
->IADsOpenDSObject_iface
;
448 if (IsEqualGUID(riid
, &IID_IDirectorySearch
))
450 if (!ldap
->ld
|| (ldap
->object
&& !wcsicmp(ldap
->object
, L
"rootDSE")))
451 return E_NOINTERFACE
;
454 *obj
= &ldap
->IDirectorySearch_iface
;
458 if (IsEqualGUID(riid
, &IID_IDirectoryObject
))
461 *obj
= &ldap
->IDirectoryObject_iface
;
465 FIXME("interface %s is not implemented\n", debugstr_guid(riid
));
466 return E_NOINTERFACE
;
469 static ULONG WINAPI
ldapns_AddRef(IADs
*iface
)
471 LDAP_namespace
*ldap
= impl_from_IADs(iface
);
472 return InterlockedIncrement(&ldap
->ref
);
475 static void free_attributes(LDAP_namespace
*ldap
)
479 if (!ldap
->attrs
) return;
481 for (i
= 0; i
< ldap
->attrs_count
; i
++)
483 ldap_memfreeW(ldap
->attrs
[i
].name
);
484 ldap_value_freeW(ldap
->attrs
[i
].values
);
489 ldap
->attrs_count
= 0;
492 static ULONG WINAPI
ldapns_Release(IADs
*iface
)
494 LDAP_namespace
*ldap
= impl_from_IADs(iface
);
495 LONG ref
= InterlockedDecrement(&ldap
->ref
);
499 TRACE("destroying %p\n", iface
);
500 if (ldap
->ld
) ldap_unbind(ldap
->ld
);
501 SysFreeString(ldap
->host
);
502 SysFreeString(ldap
->object
);
503 free_attributes(ldap
);
504 free_attribute_types(ldap
->at
, ldap
->at_single_count
+ ldap
->at_multiple_count
);
511 static HRESULT WINAPI
ldapns_GetTypeInfoCount(IADs
*iface
, UINT
*count
)
513 FIXME("%p,%p: stub\n", iface
, count
);
517 static HRESULT WINAPI
ldapns_GetTypeInfo(IADs
*iface
, UINT index
, LCID lcid
, ITypeInfo
**info
)
519 FIXME("%p,%u,%#lx,%p: stub\n", iface
, index
, lcid
, info
);
523 static HRESULT WINAPI
ldapns_GetIDsOfNames(IADs
*iface
, REFIID riid
, LPOLESTR
*names
,
524 UINT count
, LCID lcid
, DISPID
*dispid
)
526 FIXME("%p,%s,%p,%u,%lu,%p: stub\n", iface
, debugstr_guid(riid
), names
, count
, lcid
, dispid
);
530 static HRESULT WINAPI
ldapns_Invoke(IADs
*iface
, DISPID dispid
, REFIID riid
, LCID lcid
, WORD flags
,
531 DISPPARAMS
*params
, VARIANT
*result
, EXCEPINFO
*excepinfo
, UINT
*argerr
)
533 FIXME("%p,%ld,%s,%04lx,%04x,%p,%p,%p,%p: stub\n", iface
, dispid
, debugstr_guid(riid
), lcid
, flags
,
534 params
, result
, excepinfo
, argerr
);
538 static HRESULT WINAPI
ldapns_get_Name(IADs
*iface
, BSTR
*retval
)
540 FIXME("%p,%p: stub\n", iface
, retval
);
544 static HRESULT WINAPI
ldapns_get_Class(IADs
*iface
, BSTR
*retval
)
546 FIXME("%p,%p: stub\n", iface
, retval
);
550 static HRESULT WINAPI
ldapns_get_GUID(IADs
*iface
, BSTR
*retval
)
552 FIXME("%p,%p: stub\n", iface
, retval
);
556 static HRESULT WINAPI
ldapns_get_ADsPath(IADs
*iface
, BSTR
*retval
)
558 FIXME("%p,%p: stub\n", iface
, retval
);
562 static HRESULT WINAPI
ldapns_get_Parent(IADs
*iface
, BSTR
*retval
)
564 FIXME("%p,%p: stub\n", iface
, retval
);
568 static HRESULT WINAPI
ldapns_get_Schema(IADs
*iface
, BSTR
*retval
)
570 FIXME("%p,%p: stub\n", iface
, retval
);
574 static HRESULT WINAPI
ldapns_GetInfo(IADs
*iface
)
579 TRACE("%p\n", iface
);
581 hr
= ADsBuildVarArrayStr(NULL
, 0, &var
);
584 hr
= IADs_GetInfoEx(iface
, var
, 0);
590 static HRESULT WINAPI
ldapns_SetInfo(IADs
*iface
)
592 FIXME("%p: stub\n", iface
);
596 static HRESULT WINAPI
ldapns_Get(IADs
*iface
, BSTR name
, VARIANT
*prop
)
598 LDAP_namespace
*ldap
= impl_from_IADs(iface
);
602 TRACE("%p,%s,%p\n", iface
, debugstr_w(name
), prop
);
604 if (!name
|| !prop
) return E_ADS_BAD_PARAMETER
;
606 if (!ldap
->attrs_count
)
608 hr
= IADs_GetInfo(iface
);
609 if (hr
!= S_OK
) return hr
;
612 for (i
= 0; i
< ldap
->attrs_count
; i
++)
614 if (!wcsicmp(name
, ldap
->attrs
[i
].name
))
616 LONG count
= ldap_count_valuesW(ldap
->attrs
[i
].values
);
620 V_VT(prop
) = VT_BSTR
;
630 TRACE("attr %s has %lu values\n", debugstr_w(ldap
->attrs
[i
].name
), count
);
632 sa
= SafeArrayCreateVector(VT_VARIANT
, 0, count
);
633 if (!sa
) return E_OUTOFMEMORY
;
635 for (idx
= 0; idx
< count
; idx
++)
637 TRACE("=> %s\n", debugstr_w(ldap
->attrs
[i
].values
[idx
]));
638 V_VT(&item
) = VT_BSTR
;
639 V_BSTR(&item
) = SysAllocString(ldap
->attrs
[i
].values
[idx
]);
646 hr
= SafeArrayPutElement(sa
, &idx
, &item
);
647 SysFreeString(V_BSTR(&item
));
648 if (hr
!= S_OK
) goto fail
;
651 V_VT(prop
) = VT_ARRAY
| VT_VARIANT
;
655 SafeArrayDestroy(sa
);
660 TRACE("=> %s\n", debugstr_w(ldap
->attrs
[i
].values
[0]));
661 V_BSTR(prop
) = SysAllocString(ldap
->attrs
[i
].values
[0]);
662 if (!V_BSTR(prop
)) return E_OUTOFMEMORY
;
663 V_VT(prop
) = VT_BSTR
;
669 return E_ADS_PROPERTY_NOT_FOUND
;
672 static HRESULT WINAPI
ldapns_Put(IADs
*iface
, BSTR name
, VARIANT prop
)
674 FIXME("%p,%s,%s: stub\n", iface
, debugstr_w(name
), wine_dbgstr_variant(&prop
));
678 static HRESULT WINAPI
ldapns_GetEx(IADs
*iface
, BSTR name
, VARIANT
*prop
)
680 FIXME("%p,%s,%p: stub\n", iface
, debugstr_w(name
), prop
);
684 static HRESULT WINAPI
ldapns_PutEx(IADs
*iface
, LONG code
, BSTR name
, VARIANT prop
)
686 FIXME("%p,%ld,%s,%s: stub\n", iface
, code
, debugstr_w(name
), wine_dbgstr_variant(&prop
));
690 static HRESULT
add_attribute(LDAP_namespace
*ldap
, WCHAR
*name
, WCHAR
**values
)
692 struct ldap_attribute
*new_attrs
;
696 ldap
->attrs
= malloc(256 * sizeof(ldap
->attrs
[0]));
697 if (!ldap
->attrs
) return E_OUTOFMEMORY
;
698 ldap
->attrs_count_allocated
= 256;
700 else if (ldap
->attrs_count_allocated
< ldap
->attrs_count
+ 1)
702 new_attrs
= realloc(ldap
->attrs
, (ldap
->attrs_count_allocated
* 2) * sizeof(*new_attrs
));
703 if (!new_attrs
) return E_OUTOFMEMORY
;
705 ldap
->attrs_count_allocated
*= 2;
706 ldap
->attrs
= new_attrs
;
709 ldap
->attrs
[ldap
->attrs_count
].name
= name
;
710 ldap
->attrs
[ldap
->attrs_count
].values
= values
;
716 static HRESULT WINAPI
ldapns_GetInfoEx(IADs
*iface
, VARIANT prop
, LONG reserved
)
718 LDAP_namespace
*ldap
= impl_from_IADs(iface
);
722 WCHAR
**props
= NULL
, *attr
, **values
;
724 LDAPMessage
*res
= NULL
, *entry
;
727 TRACE("%p,%s,%ld\n", iface
, wine_dbgstr_variant(&prop
), reserved
);
729 free_attributes(ldap
);
731 if (!ldap
->ld
) return E_NOTIMPL
;
733 if (V_VT(&prop
) != (VT_ARRAY
| VT_VARIANT
))
734 return E_ADS_BAD_PARAMETER
;
738 return E_ADS_BAD_PARAMETER
;
740 hr
= SafeArrayAccessData(sa
, (void *)&item
);
741 if (hr
!= S_OK
) return hr
;
743 count
= sa
->rgsabound
[0].cElements
;
746 props
= malloc((count
+ 1) * sizeof(props
[0]));
753 for (i
= 0; i
< count
; i
++)
755 if (V_VT(&item
[i
]) != VT_BSTR
)
757 hr
= E_ADS_BAD_PARAMETER
;
760 props
[i
] = V_BSTR(&item
[i
]);
762 props
[sa
->rgsabound
[0].cElements
] = NULL
;
765 err
= ldap_search_sW(ldap
->ld
, NULL
, LDAP_SCOPE_BASE
, (WCHAR
*)L
"(objectClass=*)", props
, FALSE
, &res
);
766 if (err
!= LDAP_SUCCESS
)
768 TRACE("ldap_search_sW error %#lx\n", err
);
769 hr
= HRESULT_FROM_WIN32(map_ldap_error(err
));
773 entry
= ldap_first_entry(ldap
->ld
, res
);
776 attr
= ldap_first_attributeW(ldap
->ld
, entry
, &ber
);
779 TRACE("attr: %s\n", debugstr_w(attr
));
781 values
= ldap_get_valuesW(ldap
->ld
, entry
, attr
);
783 hr
= add_attribute(ldap
, attr
, values
);
786 ldap_value_freeW(values
);
792 attr
= ldap_next_attributeW(ldap
->ld
, entry
, ber
);
796 entry
= ldap_next_entry(ldap
->ld
, res
);
800 if (res
) ldap_msgfree(res
);
802 SafeArrayUnaccessData(sa
);
806 static const IADsVtbl IADs_vtbl
=
808 ldapns_QueryInterface
,
811 ldapns_GetTypeInfoCount
,
813 ldapns_GetIDsOfNames
,
830 static inline LDAP_namespace
*impl_from_IADsOpenDSObject(IADsOpenDSObject
*iface
)
832 return CONTAINING_RECORD(iface
, LDAP_namespace
, IADsOpenDSObject_iface
);
835 static HRESULT WINAPI
openobj_QueryInterface(IADsOpenDSObject
*iface
, REFIID riid
, void **obj
)
837 TRACE("%p,%s,%p\n", iface
, debugstr_guid(riid
), obj
);
839 if (!riid
|| !obj
) return E_INVALIDARG
;
841 if (IsEqualGUID(riid
, &IID_IADsOpenDSObject
) ||
842 IsEqualGUID(riid
, &IID_IDispatch
) ||
843 IsEqualGUID(riid
, &IID_IUnknown
))
845 IADsOpenDSObject_AddRef(iface
);
850 FIXME("interface %s is not implemented\n", debugstr_guid(riid
));
851 return E_NOINTERFACE
;
854 static ULONG WINAPI
openobj_AddRef(IADsOpenDSObject
*iface
)
856 LDAP_namespace
*ldap
= impl_from_IADsOpenDSObject(iface
);
857 return IADs_AddRef(&ldap
->IADs_iface
);
860 static ULONG WINAPI
openobj_Release(IADsOpenDSObject
*iface
)
862 LDAP_namespace
*ldap
= impl_from_IADsOpenDSObject(iface
);
863 return IADs_Release(&ldap
->IADs_iface
);
866 static HRESULT WINAPI
openobj_GetTypeInfoCount(IADsOpenDSObject
*iface
, UINT
*count
)
868 FIXME("%p,%p: stub\n", iface
, count
);
872 static HRESULT WINAPI
openobj_GetTypeInfo(IADsOpenDSObject
*iface
, UINT index
, LCID lcid
, ITypeInfo
**info
)
874 FIXME("%p,%u,%#lx,%p: stub\n", iface
, index
, lcid
, info
);
878 static HRESULT WINAPI
openobj_GetIDsOfNames(IADsOpenDSObject
*iface
, REFIID riid
, LPOLESTR
*names
,
879 UINT count
, LCID lcid
, DISPID
*dispid
)
881 FIXME("%p,%s,%p,%u,%lu,%p: stub\n", iface
, debugstr_guid(riid
), names
, count
, lcid
, dispid
);
885 static HRESULT WINAPI
openobj_Invoke(IADsOpenDSObject
*iface
, DISPID dispid
, REFIID riid
, LCID lcid
, WORD flags
,
886 DISPPARAMS
*params
, VARIANT
*result
, EXCEPINFO
*excepinfo
, UINT
*argerr
)
888 FIXME("%p,%ld,%s,%04lx,%04x,%p,%p,%p,%p: stub\n", iface
, dispid
, debugstr_guid(riid
), lcid
, flags
,
889 params
, result
, excepinfo
, argerr
);
893 static HRESULT
parse_path(WCHAR
*path
, BSTR
*host
, ULONG
*port
, BSTR
*object
)
898 if (host
) *host
= NULL
;
900 if (object
) *object
= NULL
;
902 if (wcsnicmp(path
, L
"LDAP:", 5) != 0)
903 return E_ADS_BAD_PATHNAME
;
906 if (!*p
) return S_OK
;
908 if (*p
++ != '/' || *p
++ != '/' || !*p
)
909 return E_ADS_BAD_PATHNAME
;
913 while (*p
&& *p
!= '/')
918 if (!port
) port
= &dummy
;
919 *port
= wcstol(p
+ 1, &p
, 10);
920 if (*p
&& *p
!= '/') return E_ADS_BAD_PATHNAME
;
928 if (host_len
== 0) return E_ADS_BAD_PATHNAME
;
932 *host
= SysAllocStringLen(p_host
, host_len
);
933 if (!*host
) return E_OUTOFMEMORY
;
936 if (!*p
) return S_OK
;
938 if (*p
++ != '/' || !*p
)
940 SysFreeString(*host
);
941 return E_ADS_BAD_PATHNAME
;
946 *object
= SysAllocString(p
);
949 SysFreeString(*host
);
950 return E_OUTOFMEMORY
;
957 static HRESULT WINAPI
openobj_OpenDSObject(IADsOpenDSObject
*iface
, BSTR path
, BSTR user
, BSTR password
,
958 LONG flags
, IDispatch
**obj
)
965 ULONG err
, at_single_count
= 0, at_multiple_count
= 0;
966 struct attribute_type
*at
= NULL
;
968 TRACE("%p,%s,%s,%p,%08lx,%p\n", iface
, debugstr_w(path
), debugstr_w(user
), password
, flags
, obj
);
970 hr
= parse_path(path
, &host
, &port
, &object
);
971 if (hr
!= S_OK
) return hr
;
973 TRACE("host %s, port %lu, object %s\n", debugstr_w(host
), port
, debugstr_w(object
));
979 if (!wcsicmp(host
, L
"rootDSE"))
981 DOMAIN_CONTROLLER_INFOW
*dcinfo
;
985 hr
= E_ADS_BAD_PATHNAME
;
991 err
= DsGetDcNameW(NULL
, NULL
, NULL
, NULL
, DS_RETURN_DNS_NAME
, &dcinfo
);
992 if (err
!= ERROR_SUCCESS
)
994 hr
= HRESULT_FROM_WIN32(err
);
998 host
= SysAllocString(dcinfo
->DomainName
);
999 NetApiBufferFree(dcinfo
);
1008 ld
= ldap_initW(host
, port
);
1011 hr
= HRESULT_FROM_WIN32(LdapGetLastError());
1015 version
= LDAP_VERSION3
;
1016 err
= ldap_set_optionW(ld
, LDAP_OPT_PROTOCOL_VERSION
, &version
);
1017 if (err
!= LDAP_SUCCESS
)
1019 hr
= HRESULT_FROM_WIN32(map_ldap_error(err
));
1024 err
= ldap_connect(ld
, NULL
);
1025 if (err
!= LDAP_SUCCESS
)
1027 hr
= HRESULT_FROM_WIN32(map_ldap_error(err
));
1032 if (flags
& ADS_SECURE_AUTHENTICATION
)
1034 SEC_WINNT_AUTH_IDENTITY_W id
;
1036 id
.Flags
= SEC_WINNT_AUTH_IDENTITY_UNICODE
;
1037 id
.Domain
= (unsigned short *)host
;
1038 id
.DomainLength
= wcslen(host
);
1039 id
.User
= (unsigned short *)user
;
1040 id
.UserLength
= user
? wcslen(user
) : 0;
1041 id
.Password
= (unsigned short *)password
;
1042 id
.PasswordLength
= password
? wcslen(password
) : 0;
1044 err
= ldap_bind_sW(ld
, NULL
, (WCHAR
*)&id
, LDAP_AUTH_NEGOTIATE
);
1045 if (err
!= LDAP_SUCCESS
)
1047 TRACE("ldap_bind_sW error %#lx\n", err
);
1048 hr
= HRESULT_FROM_WIN32(map_ldap_error(err
));
1055 err
= ldap_simple_bind_sW(ld
, user
, password
);
1056 if (err
!= LDAP_SUCCESS
)
1058 TRACE("ldap_simple_bind_sW error %#lx\n", err
);
1059 hr
= HRESULT_FROM_WIN32(map_ldap_error(err
));
1065 at
= load_schema(ld
, &at_single_count
, &at_multiple_count
);
1068 hr
= LDAPNamespace_create(&IID_IADs
, (void **)&ads
);
1071 LDAP_namespace
*ldap
= impl_from_IADs(ads
);
1075 ldap
->object
= object
;
1077 ldap
->at_single_count
= at_single_count
;
1078 ldap
->at_multiple_count
= at_multiple_count
;
1079 hr
= IADs_QueryInterface(ads
, &IID_IDispatch
, (void **)obj
);
1085 SysFreeString(host
);
1086 SysFreeString(object
);
1091 static const IADsOpenDSObjectVtbl IADsOpenDSObject_vtbl
=
1093 openobj_QueryInterface
,
1096 openobj_GetTypeInfoCount
,
1097 openobj_GetTypeInfo
,
1098 openobj_GetIDsOfNames
,
1100 openobj_OpenDSObject
1103 static inline LDAP_namespace
*impl_from_IDirectorySearch(IDirectorySearch
*iface
)
1105 return CONTAINING_RECORD(iface
, LDAP_namespace
, IDirectorySearch_iface
);
1108 static HRESULT WINAPI
search_QueryInterface(IDirectorySearch
*iface
, REFIID riid
, void **obj
)
1110 TRACE("%p,%s,%p\n", iface
, debugstr_guid(riid
), obj
);
1112 if (!riid
|| !obj
) return E_INVALIDARG
;
1114 if (IsEqualGUID(riid
, &IID_IDirectorySearch
) ||
1115 IsEqualGUID(riid
, &IID_IUnknown
))
1117 IDirectorySearch_AddRef(iface
);
1122 FIXME("interface %s is not implemented\n", debugstr_guid(riid
));
1123 return E_NOINTERFACE
;
1126 static ULONG WINAPI
search_AddRef(IDirectorySearch
*iface
)
1128 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1129 return IADs_AddRef(&ldap
->IADs_iface
);
1132 static ULONG WINAPI
search_Release(IDirectorySearch
*iface
)
1134 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1135 return IADs_Release(&ldap
->IADs_iface
);
1138 static HRESULT WINAPI
search_SetSearchPreference(IDirectorySearch
*iface
, PADS_SEARCHPREF_INFO prefs
, DWORD count
)
1140 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1144 TRACE("%p,%p,%lu\n", iface
, prefs
, count
);
1146 for (i
= 0; i
< count
; i
++)
1148 switch (prefs
[i
].dwSearchPref
)
1150 case ADS_SEARCHPREF_SEARCH_SCOPE
:
1151 if (prefs
[i
].vValue
.dwType
!= ADSTYPE_INTEGER
)
1153 FIXME("ADS_SEARCHPREF_SEARCH_SCOPE: unsupported dwType %d\n", prefs
[i
].vValue
.dwType
);
1154 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1158 switch (prefs
[i
].vValue
.u
.Integer
)
1160 case ADS_SCOPE_BASE
:
1161 case ADS_SCOPE_ONELEVEL
:
1162 case ADS_SCOPE_SUBTREE
:
1163 TRACE("SEARCH_SCOPE: %ld\n", prefs
[i
].vValue
.u
.Integer
);
1164 ldap
->search
.scope
= prefs
[i
].vValue
.u
.Integer
;
1165 prefs
[i
].dwStatus
= ADS_STATUS_S_OK
;
1169 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1174 case ADS_SEARCHPREF_SECURITY_MASK
:
1179 struct berval
*berval
;
1180 LDAPControlW
*ctrls
[2], mask
;
1182 if (prefs
[i
].vValue
.dwType
!= ADSTYPE_INTEGER
)
1184 FIXME("ADS_SEARCHPREF_SECURITY_MASK: not supported dwType %d\n", prefs
[i
].vValue
.dwType
);
1185 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1189 TRACE("SECURITY_MASK: %08lx\n", prefs
[i
].vValue
.u
.Integer
);
1190 security_mask
= prefs
[i
].vValue
.u
.Integer
;
1192 security_mask
= ADS_SECURITY_INFO_OWNER
;
1194 ber
= ber_alloc_t(LBER_USE_DER
);
1195 if (!ber
|| ber_printf(ber
, (char *)"{i}", security_mask
) == -1 || ber_flatten(ber
, &berval
) == -1)
1198 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREF
;
1201 TRACE("ber: %s\n", debugstr_an(berval
->bv_val
, berval
->bv_len
));
1203 mask
.ldctl_oid
= (WCHAR
*)L
"1.2.840.113556.1.4.801";
1204 mask
.ldctl_iscritical
= TRUE
;
1205 mask
.ldctl_value
.bv_val
= berval
->bv_val
;
1206 mask
.ldctl_value
.bv_len
= berval
->bv_len
;
1209 err
= ldap_set_optionW(ldap
->ld
, LDAP_OPT_SERVER_CONTROLS
, ctrls
);
1210 if (err
!= LDAP_SUCCESS
)
1212 TRACE("ldap_set_option error %#lx\n", err
);
1213 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREF
;
1214 hr
= S_ADS_ERRORSOCCURRED
;
1217 prefs
[i
].dwStatus
= ADS_STATUS_S_OK
;
1224 case ADS_SEARCHPREF_PAGESIZE
:
1225 if (prefs
[i
].vValue
.dwType
!= ADSTYPE_INTEGER
)
1227 FIXME("ADS_SEARCHPREF_PAGESIZE: unsupported dwType %d\n", prefs
[i
].vValue
.dwType
);
1228 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1232 TRACE("PAGESIZE: %ld\n", prefs
[i
].vValue
.u
.Integer
);
1233 ldap
->search
.pagesize
= prefs
[i
].vValue
.u
.Integer
;
1234 prefs
[i
].dwStatus
= ADS_STATUS_S_OK
;
1237 case ADS_SEARCHPREF_CACHE_RESULTS
:
1238 if (prefs
[i
].vValue
.dwType
!= ADSTYPE_BOOLEAN
)
1240 FIXME("ADS_SEARCHPREF_CACHE_RESULTS: unsupported dwType %d\n", prefs
[i
].vValue
.dwType
);
1241 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1245 TRACE("CACHE_RESULTS: %ld\n", prefs
[i
].vValue
.u
.Boolean
);
1246 ldap
->search
.cache_results
= prefs
[i
].vValue
.u
.Boolean
;
1247 prefs
[i
].dwStatus
= ADS_STATUS_S_OK
;
1250 case ADS_SEARCHPREF_ATTRIBTYPES_ONLY
:
1251 if (prefs
[i
].vValue
.dwType
!= ADSTYPE_BOOLEAN
)
1253 FIXME("ADS_SEARCHPREF_ATTRIBTYPES_ONLY: unsupported dwType %d\n", prefs
[i
].vValue
.dwType
);
1254 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1258 TRACE("ATTRIBTYPES_ONLY: %ld\n", prefs
[i
].vValue
.u
.Boolean
);
1259 ldap
->search
.attribtypes_only
= prefs
[i
].vValue
.u
.Boolean
;
1260 prefs
[i
].dwStatus
= ADS_STATUS_S_OK
;
1263 case ADS_SEARCHPREF_TOMBSTONE
:
1264 if (prefs
[i
].vValue
.dwType
!= ADSTYPE_BOOLEAN
)
1266 FIXME("ADS_SEARCHPREF_TOMBSTONE: unsupported dwType %d\n", prefs
[i
].vValue
.dwType
);
1267 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1271 TRACE("TOMBSTONE: %ld\n", prefs
[i
].vValue
.u
.Boolean
);
1272 ldap
->search
.tombstone
= prefs
[i
].vValue
.u
.Boolean
;
1273 prefs
[i
].dwStatus
= ADS_STATUS_S_OK
;
1276 case ADS_SEARCHPREF_SIZE_LIMIT
:
1277 if (prefs
[i
].vValue
.dwType
!= ADSTYPE_INTEGER
)
1279 FIXME("ADS_SEARCHPREF_SIZE_LIMIT: unsupported dwType %d\n", prefs
[i
].vValue
.dwType
);
1280 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREFVALUE
;
1284 TRACE("SIZE_LIMIT: %ld\n", prefs
[i
].vValue
.u
.Integer
);
1285 ldap
->search
.size_limit
= prefs
[i
].vValue
.u
.Integer
;
1286 prefs
[i
].dwStatus
= ADS_STATUS_S_OK
;
1290 FIXME("pref %d, type %u: stub\n", prefs
[i
].dwSearchPref
, prefs
[i
].vValue
.dwType
);
1291 prefs
[i
].dwStatus
= ADS_STATUS_INVALID_SEARCHPREF
;
1299 static HRESULT WINAPI
search_ExecuteSearch(IDirectorySearch
*iface
, LPWSTR filter
, LPWSTR
*names
,
1300 DWORD count
, PADS_SEARCH_HANDLE res
)
1302 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1305 LDAPControlW
**ctrls
= NULL
, *ctrls_a
[2], tombstone
;
1306 struct ldap_search_context
*ldap_ctx
;
1308 TRACE("%p,%s,%p,%lu,%p\n", iface
, debugstr_w(filter
), names
, count
, res
);
1310 if (!res
) return E_ADS_BAD_PARAMETER
;
1312 ldap_ctx
= calloc(1, sizeof(*ldap_ctx
));
1313 if (!ldap_ctx
) return E_OUTOFMEMORY
;
1315 if (count
== 0xffffffff)
1319 if (count
&& !names
)
1322 return E_ADS_BAD_PARAMETER
;
1325 props
= malloc((count
+ 1) * sizeof(props
[0]));
1329 return E_OUTOFMEMORY
;
1332 for (i
= 0; i
< count
; i
++)
1334 TRACE("=> %s\n", debugstr_w(names
[i
]));
1335 props
[i
] = names
[i
];
1338 props
[count
] = NULL
;
1341 if (ldap
->search
.tombstone
)
1343 tombstone
.ldctl_oid
= (WCHAR
*)L
"1.2.840.113556.1.4.417";
1344 tombstone
.ldctl_iscritical
= TRUE
;
1345 tombstone
.ldctl_value
.bv_val
= NULL
;
1346 tombstone
.ldctl_value
.bv_len
= 0;
1347 ctrls_a
[0] = &tombstone
;
1352 if (ldap
->search
.pagesize
)
1354 ldap_ctx
->page
= ldap_search_init_pageW(ldap
->ld
, ldap
->object
, ldap
->search
.scope
,
1355 filter
, props
, ldap
->search
.attribtypes_only
,
1356 ctrls
, NULL
, 0, ldap
->search
.size_limit
, NULL
);
1358 err
= ldap_get_next_page_s(ldap
->ld
, ldap_ctx
->page
, NULL
,
1359 ldap
->search
.pagesize
, &count
, &ldap_ctx
->res
);
1361 err
= LDAP_NO_MEMORY
;
1364 err
= ldap_search_ext_sW(ldap
->ld
, ldap
->object
, ldap
->search
.scope
, filter
, props
,
1365 ldap
->search
.attribtypes_only
, ctrls
, NULL
, NULL
, ldap
->search
.size_limit
,
1368 if (err
!= LDAP_SUCCESS
)
1370 TRACE("ldap_search_sW error %#lx\n", err
);
1372 ldap_search_abandon_page(ldap
->ld
, ldap_ctx
->page
);
1374 return HRESULT_FROM_WIN32(map_ldap_error(err
));
1381 static HRESULT WINAPI
search_AbandonSearch(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
)
1383 FIXME("%p,%p: stub\n", iface
, res
);
1387 static HRESULT WINAPI
search_GetFirstRow(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
)
1389 struct ldap_search_context
*ldap_ctx
= res
;
1391 TRACE("%p,%p\n", iface
, res
);
1393 if (!res
) return E_ADS_BAD_PARAMETER
;
1395 ldap_ctx
->entry
= NULL
;
1397 return IDirectorySearch_GetNextRow(iface
, res
);
1400 static HRESULT WINAPI
search_GetNextRow(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
)
1402 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1403 struct ldap_search_context
*ldap_ctx
= res
;
1405 TRACE("%p,%p\n", iface
, res
);
1407 if (!res
) return E_ADS_BAD_PARAMETER
;
1409 if (!ldap_ctx
->entry
)
1411 ldap_ctx
->count
= ldap_count_entries(ldap
->ld
, ldap_ctx
->res
);
1414 if (ldap_ctx
->pos
>= ldap_ctx
->count
)
1415 return S_ADS_NOMORE_ROWS
;
1417 ldap_ctx
->entry
= ldap_first_entry(ldap
->ld
, ldap_ctx
->res
);
1421 if (ldap_ctx
->pos
>= ldap_ctx
->count
)
1427 ldap_msgfree(ldap_ctx
->res
);
1428 ldap_ctx
->res
= NULL
;
1430 err
= ldap_get_next_page_s(ldap
->ld
, ldap_ctx
->page
, NULL
, ldap
->search
.pagesize
, &count
, &ldap_ctx
->res
);
1431 if (err
== LDAP_SUCCESS
)
1433 ldap_ctx
->count
= ldap_count_entries(ldap
->ld
, ldap_ctx
->res
);
1436 if (ldap_ctx
->pos
>= ldap_ctx
->count
)
1437 return S_ADS_NOMORE_ROWS
;
1439 ldap_ctx
->entry
= ldap_first_entry(ldap
->ld
, ldap_ctx
->res
);
1443 if (err
!= LDAP_NO_RESULTS_RETURNED
)
1445 TRACE("ldap_get_next_page_s error %#lx\n", err
);
1446 return HRESULT_FROM_WIN32(map_ldap_error(err
));
1451 return S_ADS_NOMORE_ROWS
;
1454 ldap_ctx
->entry
= ldap_next_entry(ldap
->ld
, ldap_ctx
->entry
);
1458 if (!ldap_ctx
->entry
)
1459 return S_ADS_NOMORE_ROWS
;
1462 ldap_ctx
->ber
= NULL
;
1467 static HRESULT WINAPI
search_GetPreviousRow(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
)
1469 FIXME("%p,%p: stub\n", iface
, res
);
1473 static HRESULT WINAPI
search_GetNextColumnName(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
, LPWSTR
*name
)
1475 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1476 struct ldap_search_context
*ldap_ctx
= res
;
1479 TRACE("%p,%p,%p\n", iface
, res
, name
);
1481 if (!name
|| !ldap_ctx
|| !ldap_ctx
->entry
) return E_ADS_BAD_PARAMETER
;
1485 attr
= ldap_first_attributeW(ldap
->ld
, ldap_ctx
->entry
, &ldap_ctx
->ber
);
1486 ldap_ctx
->add_ADsPath
= TRUE
;
1489 attr
= ldap_next_attributeW(ldap
->ld
, ldap_ctx
->entry
, ldap_ctx
->ber
);
1493 TRACE("=> %s\n", debugstr_w(attr
));
1494 *name
= AllocADsStr(attr
);
1495 ldap_memfreeW(attr
);
1496 return *name
? S_OK
: E_OUTOFMEMORY
;
1498 else if (ldap_ctx
->add_ADsPath
)
1500 ldap_ctx
->add_ADsPath
= FALSE
;
1501 *name
= AllocADsStr((WCHAR
*)L
"ADsPath");
1502 TRACE("=> %s\n", debugstr_w(*name
));
1503 return *name
? S_OK
: E_OUTOFMEMORY
;
1507 return S_ADS_NOMORE_COLUMNS
;
1510 static HRESULT
add_column_values(LDAP_namespace
*ldap
, struct ldap_search_context
*ldap_ctx
,
1511 LPWSTR name
, ADS_SEARCH_COLUMN
*col
)
1516 type
= get_schema_type(name
, ldap
->at
, ldap
->at_single_count
, ldap
->at_multiple_count
);
1517 TRACE("%s => type %d\n", debugstr_w(name
), type
);
1522 FIXME("no special handling for type %d\n", type
);
1524 case ADSTYPE_DN_STRING
:
1525 case ADSTYPE_CASE_EXACT_STRING
:
1526 case ADSTYPE_CASE_IGNORE_STRING
:
1527 case ADSTYPE_PRINTABLE_STRING
:
1529 WCHAR
**values
= ldap_get_valuesW(ldap
->ld
, ldap_ctx
->entry
, name
);
1531 return E_ADS_COLUMN_NOT_SET
;
1532 count
= ldap_count_valuesW(values
);
1534 col
->pADsValues
= calloc(count
, sizeof(col
->pADsValues
[0]));
1535 if (!col
->pADsValues
)
1537 ldap_value_freeW(values
);
1538 return E_OUTOFMEMORY
;
1541 for (i
= 0; i
< count
; i
++)
1543 TRACE("=> %s\n", debugstr_w(values
[i
]));
1544 col
->pADsValues
[i
].dwType
= type
;
1545 col
->pADsValues
[i
].u
.CaseIgnoreString
= values
[i
];
1548 col
->hReserved
= values
;
1552 case ADSTYPE_BOOLEAN
:
1554 WCHAR
**values
= ldap_get_valuesW(ldap
->ld
, ldap_ctx
->entry
, name
);
1556 return E_ADS_COLUMN_NOT_SET
;
1557 count
= ldap_count_valuesW(values
);
1559 col
->pADsValues
= calloc(count
, sizeof(col
->pADsValues
[0]));
1560 if (!col
->pADsValues
)
1562 ldap_value_freeW(values
);
1563 return E_OUTOFMEMORY
;
1566 for (i
= 0; i
< count
; i
++)
1568 col
->pADsValues
[i
].dwType
= type
;
1570 if (!wcsicmp(values
[i
], L
"TRUE"))
1571 col
->pADsValues
[i
].u
.Boolean
= 1;
1572 else if (!wcsicmp(values
[i
], L
"FALSE"))
1573 col
->pADsValues
[i
].u
.Boolean
= 0;
1576 FIXME("not recognized boolean value %s\n", debugstr_w(values
[i
]));
1577 col
->pADsValues
[i
].u
.Boolean
= 0;
1579 TRACE("%s => %ld\n", debugstr_w(values
[i
]), col
->pADsValues
[i
].u
.Boolean
);
1582 ldap_value_freeW(values
);
1583 col
->hReserved
= NULL
;
1587 case ADSTYPE_INTEGER
:
1588 case ADSTYPE_LARGE_INTEGER
:
1590 struct berval
**values
= ldap_get_values_lenW(ldap
->ld
, ldap_ctx
->entry
, name
);
1592 return E_ADS_COLUMN_NOT_SET
;
1593 count
= ldap_count_values_len(values
);
1595 col
->pADsValues
= calloc(count
, sizeof(col
->pADsValues
[0]));
1596 if (!col
->pADsValues
)
1598 ldap_value_free_len(values
);
1599 return E_OUTOFMEMORY
;
1602 for (i
= 0; i
< count
; i
++)
1604 col
->pADsValues
[i
].dwType
= type
;
1606 if (type
== ADSTYPE_LARGE_INTEGER
)
1608 col
->pADsValues
[i
].u
.LargeInteger
.QuadPart
= _atoi64(values
[i
]->bv_val
);
1609 TRACE("%s => %s\n", debugstr_an(values
[i
]->bv_val
, values
[i
]->bv_len
), wine_dbgstr_longlong(col
->pADsValues
[i
].u
.LargeInteger
.QuadPart
));
1613 col
->pADsValues
[i
].u
.Integer
= atol(values
[i
]->bv_val
);
1614 TRACE("%s => %ld\n", debugstr_an(values
[i
]->bv_val
, values
[i
]->bv_len
), col
->pADsValues
[i
].u
.Integer
);
1618 ldap_value_free_len(values
);
1619 col
->hReserved
= NULL
;
1623 case ADSTYPE_OCTET_STRING
:
1624 case ADSTYPE_NT_SECURITY_DESCRIPTOR
:
1626 struct berval
**values
= ldap_get_values_lenW(ldap
->ld
, ldap_ctx
->entry
, name
);
1628 return E_ADS_COLUMN_NOT_SET
;
1629 count
= ldap_count_values_len(values
);
1631 col
->pADsValues
= calloc(count
, sizeof(col
->pADsValues
[0]));
1632 if (!col
->pADsValues
)
1634 ldap_value_free_len(values
);
1635 return E_OUTOFMEMORY
;
1638 for (i
= 0; i
< count
; i
++)
1640 TRACE("=> %s\n", debugstr_an(values
[i
]->bv_val
, values
[i
]->bv_len
));
1641 col
->pADsValues
[i
].dwType
= type
;
1642 col
->pADsValues
[i
].u
.OctetString
.dwLength
= values
[i
]->bv_len
;
1643 col
->pADsValues
[i
].u
.OctetString
.lpValue
= (BYTE
*)values
[i
]->bv_val
;
1646 col
->hReserved
= values
;
1650 case ADSTYPE_UTC_TIME
:
1652 struct berval
**values
= ldap_get_values_lenW(ldap
->ld
, ldap_ctx
->entry
, name
);
1654 return E_ADS_COLUMN_NOT_SET
;
1655 count
= ldap_count_values_len(values
);
1657 col
->pADsValues
= calloc(count
, sizeof(col
->pADsValues
[0]));
1658 if (!col
->pADsValues
)
1660 ldap_value_free_len(values
);
1661 return E_OUTOFMEMORY
;
1664 for (i
= 0; i
< count
; i
++)
1666 col
->pADsValues
[i
].dwType
= type
;
1667 if (values
[i
]->bv_len
< 14 ||
1668 _snscanf_l(values
[i
]->bv_val
, values
[i
]->bv_len
, "%04hu%02hu%02hu%02hu%02hu%02hu", NULL
,
1669 &col
->pADsValues
[i
].u
.UTCTime
.wYear
, &col
->pADsValues
[i
].u
.UTCTime
.wMonth
,
1670 &col
->pADsValues
[i
].u
.UTCTime
.wDay
, &col
->pADsValues
[i
].u
.UTCTime
.wHour
,
1671 &col
->pADsValues
[i
].u
.UTCTime
.wMinute
, &col
->pADsValues
[i
].u
.UTCTime
.wSecond
) != 6)
1673 FIXME("not recognized UTCTime: %s\n", debugstr_an(values
[i
]->bv_val
, values
[i
]->bv_len
));
1674 memset(&col
->pADsValues
[i
].u
.UTCTime
, 0, sizeof(col
->pADsValues
[i
].u
.UTCTime
));
1678 if ((values
[i
]->bv_val
[14] != '.' && values
[i
]->bv_val
[14] != ',') ||
1679 values
[i
]->bv_val
[15] != '0' || values
[i
]->bv_val
[16] != 'Z')
1680 FIXME("not handled time zone: %s\n", debugstr_an(values
[i
]->bv_val
+ 14, values
[i
]->bv_len
- 14));
1682 TRACE("%s => %02u.%02u.%04u %02u:%02u:%02u\n", debugstr_an(values
[i
]->bv_val
, values
[i
]->bv_len
),
1683 col
->pADsValues
[i
].u
.UTCTime
.wDay
, col
->pADsValues
[i
].u
.UTCTime
.wMonth
,
1684 col
->pADsValues
[i
].u
.UTCTime
.wYear
, col
->pADsValues
[i
].u
.UTCTime
.wHour
,
1685 col
->pADsValues
[i
].u
.UTCTime
.wMinute
, col
->pADsValues
[i
].u
.UTCTime
.wSecond
);
1688 ldap_value_free_len(values
);
1689 col
->hReserved
= NULL
;
1693 case ADSTYPE_DN_WITH_BINARY
:
1695 static const BYTE hex2bin
[] =
1697 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x00 */
1698 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x10 */
1699 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x20 */
1700 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, /* 0x30 */
1701 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0, /* 0x40 */
1702 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x50 */
1703 0,10,11,12,13,14,15 /* 0x60 */
1705 ADS_DN_WITH_BINARY
*dnb
;
1706 WCHAR
**values
= ldap_get_valuesW(ldap
->ld
, ldap_ctx
->entry
, name
);
1708 return E_ADS_COLUMN_NOT_SET
;
1709 count
= ldap_count_valuesW(values
);
1711 col
->pADsValues
= calloc(count
, sizeof(col
->pADsValues
[0]) + sizeof(col
->pADsValues
[0].u
.pDNWithBinary
[0]));
1712 if (!col
->pADsValues
)
1714 ldap_value_freeW(values
);
1715 return E_OUTOFMEMORY
;
1718 dnb
= (ADS_DN_WITH_BINARY
*)(col
->pADsValues
+ count
);
1720 for (i
= 0; i
< count
; i
++)
1722 WCHAR
*p
= values
[i
];
1725 col
->pADsValues
[i
].dwType
= type
;
1726 col
->pADsValues
[i
].u
.pDNWithBinary
= dnb
++;
1728 if ((p
[0] != 'b' && p
[0] != 'B') || p
[1] != ':')
1729 FIXME("wrong DN with binary tag '%c%c'\n", p
[0], p
[1]);
1732 col
->pADsValues
[i
].u
.pDNWithBinary
->dwLength
= wcstol(p
, &p
, 10) / 2;
1734 FIXME("wrong DN with binary separator '%c'\n", *p
);
1736 col
->pADsValues
[i
].u
.pDNWithBinary
->lpBinaryValue
= (BYTE
*)p
;
1737 /* decode values in-place */
1738 for (n
= 0; n
< col
->pADsValues
[i
].u
.pDNWithBinary
->dwLength
; n
++, p
+= 2)
1742 if (p
[0] > 'f' || (p
[0] != '0' && !hex2bin
[p
[0]]) ||
1743 p
[1] > 'f' || (p
[1] != '0' && !hex2bin
[p
[1]]))
1745 FIXME("bad hex encoding at %s\n", debugstr_w(p
));
1749 b
= (hex2bin
[p
[0]] << 4) | hex2bin
[p
[1]];
1750 col
->pADsValues
[i
].u
.pDNWithBinary
->lpBinaryValue
[n
] = b
;
1753 FIXME("wrong DN with binary separator '%c'\n", *p
);
1754 col
->pADsValues
[i
].u
.pDNWithBinary
->pszDNString
= p
+ 1;
1756 TRACE("%s => %lu,%s,%s\n", debugstr_w(values
[i
]),
1757 col
->pADsValues
[i
].u
.pDNWithBinary
->dwLength
,
1758 debugstr_an((char *)col
->pADsValues
[i
].u
.pDNWithBinary
->lpBinaryValue
, col
->pADsValues
[i
].u
.pDNWithBinary
->dwLength
),
1759 debugstr_w(col
->pADsValues
[i
].u
.pDNWithBinary
->pszDNString
));
1762 col
->hReserved
= values
;
1767 col
->dwADsType
= type
;
1768 col
->dwNumValues
= count
;
1769 col
->pszAttrName
= wcsdup(name
);
1774 static HRESULT WINAPI
search_GetColumn(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
,
1775 LPWSTR name
, PADS_SEARCH_COLUMN col
)
1777 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1778 struct ldap_search_context
*ldap_ctx
= res
;
1782 TRACE("%p,%p,%s,%p\n", iface
, res
, debugstr_w(name
), col
);
1784 if (!res
|| !name
|| !ldap_ctx
->entry
) return E_ADS_BAD_PARAMETER
;
1786 memset(col
, 0, sizeof(*col
));
1788 if (!wcsicmp(name
, L
"ADsPath"))
1790 WCHAR
*dn
= ldap_get_dnW(ldap
->ld
, ldap_ctx
->entry
);
1792 col
->pADsValues
= malloc(sizeof(col
->pADsValues
[0]));
1793 if (!col
->pADsValues
)
1799 count
= sizeof(L
"LDAP://") + (wcslen(ldap
->host
) + 1 /* '/' */) * sizeof(WCHAR
);
1800 if (dn
) count
+= wcslen(dn
) * sizeof(WCHAR
);
1802 col
->pADsValues
[0].u
.CaseIgnoreString
= malloc(count
);
1803 if (!col
->pADsValues
[0].u
.CaseIgnoreString
)
1809 wcscpy(col
->pADsValues
[0].u
.CaseIgnoreString
, L
"LDAP://");
1810 wcscat(col
->pADsValues
[0].u
.CaseIgnoreString
, ldap
->host
);
1811 wcscat(col
->pADsValues
[0].u
.CaseIgnoreString
, L
"/");
1812 if (dn
) wcscat(col
->pADsValues
[0].u
.CaseIgnoreString
, dn
);
1813 col
->pADsValues
[0].dwType
= ADSTYPE_CASE_IGNORE_STRING
;
1814 col
->dwADsType
= ADSTYPE_CASE_IGNORE_STRING
;
1815 col
->dwNumValues
= 1;
1816 col
->pszAttrName
= wcsdup(name
);
1817 col
->hReserved
= NULL
;
1819 TRACE("=> %s\n", debugstr_w(col
->pADsValues
[0].u
.CaseIgnoreString
));
1826 return add_column_values(ldap
, ldap_ctx
, name
, col
);
1829 static HRESULT WINAPI
search_FreeColumn(IDirectorySearch
*iface
, PADS_SEARCH_COLUMN col
)
1831 TRACE("%p,%p\n", iface
, col
);
1833 if (!col
) return E_ADS_BAD_PARAMETER
;
1835 if (!wcsicmp(col
->pszAttrName
, L
"ADsPath"))
1836 free(col
->pADsValues
[0].u
.CaseIgnoreString
);
1837 free(col
->pADsValues
);
1838 free(col
->pszAttrName
);
1842 if (col
->dwADsType
== ADSTYPE_OCTET_STRING
|| col
->dwADsType
== ADSTYPE_NT_SECURITY_DESCRIPTOR
)
1843 ldap_value_free_len(col
->hReserved
);
1845 ldap_value_freeW(col
->hReserved
);
1851 static HRESULT WINAPI
search_CloseSearchHandle(IDirectorySearch
*iface
, ADS_SEARCH_HANDLE res
)
1853 LDAP_namespace
*ldap
= impl_from_IDirectorySearch(iface
);
1854 struct ldap_search_context
*ldap_ctx
= res
;
1856 TRACE("%p,%p\n", iface
, res
);
1858 if (!res
) return E_ADS_BAD_PARAMETER
;
1861 ldap_search_abandon_page(ldap
->ld
, ldap_ctx
->page
);
1863 ldap_msgfree(ldap_ctx
->res
);
1865 ber_free(ldap_ctx
->ber
, 0);
1871 static const IDirectorySearchVtbl IDirectorySearch_vtbl
=
1873 search_QueryInterface
,
1876 search_SetSearchPreference
,
1877 search_ExecuteSearch
,
1878 search_AbandonSearch
,
1881 search_GetPreviousRow
,
1882 search_GetNextColumnName
,
1885 search_CloseSearchHandle
1888 static inline LDAP_namespace
*impl_from_IDirectoryObject(IDirectoryObject
*iface
)
1890 return CONTAINING_RECORD(iface
, LDAP_namespace
, IDirectoryObject_iface
);
1893 static HRESULT WINAPI
dirobj_QueryInterface(IDirectoryObject
*iface
, REFIID riid
, void **obj
)
1895 LDAP_namespace
*ldap
= impl_from_IDirectoryObject(iface
);
1897 TRACE("%p,%s,%p\n", iface
, debugstr_guid(riid
), obj
);
1899 if (!riid
|| !obj
) return E_INVALIDARG
;
1901 if (IsEqualGUID(riid
, &IID_IDirectoryObject
) ||
1902 IsEqualGUID(riid
, &IID_IUnknown
))
1904 IDirectoryObject_AddRef(iface
);
1909 return IADs_QueryInterface(&ldap
->IADs_iface
, riid
, obj
);
1912 static ULONG WINAPI
dirobj_AddRef(IDirectoryObject
*iface
)
1914 LDAP_namespace
*ldap
= impl_from_IDirectoryObject(iface
);
1915 return IADs_AddRef(&ldap
->IADs_iface
);
1918 static ULONG WINAPI
dirobj_Release(IDirectoryObject
*iface
)
1920 LDAP_namespace
*ldap
= impl_from_IDirectoryObject(iface
);
1921 return IADs_Release(&ldap
->IADs_iface
);
1924 static HRESULT WINAPI
dirobj_GetObjectInformation(IDirectoryObject
*iface
, PADS_OBJECT_INFO
*info
)
1926 FIXME("%p,%p: stub\n", iface
, info
);
1930 static HRESULT WINAPI
dirobj_GetObjectAttributes(IDirectoryObject
*iface
, LPWSTR
*names
,
1931 DWORD count
, PADS_ATTR_INFO
*attrs
, DWORD
*count_returned
)
1933 FIXME("%p,%p,%lu,%p,%p: stub\n", iface
, names
, count
, attrs
, count_returned
);
1937 static HRESULT WINAPI
dirobj_SetObjectAttributes(IDirectoryObject
*iface
, PADS_ATTR_INFO attrs
,
1938 DWORD count
, DWORD
*count_set
)
1940 FIXME("%p,%p,%lu,%p: stub\n", iface
, attrs
, count
, count_set
);
1944 static HRESULT WINAPI
dirobj_CreateDSObject(IDirectoryObject
*iface
, LPWSTR name
,
1945 PADS_ATTR_INFO attrs
, DWORD count
, IDispatch
**obj
)
1947 FIXME("%p,%s,%p,%lu,%p: stub\n", iface
, debugstr_w(name
), attrs
, count
, obj
);
1951 static HRESULT WINAPI
dirobj_DeleteDSObject(IDirectoryObject
*iface
, LPWSTR name
)
1953 FIXME("%p,%s: stub\n", iface
, debugstr_w(name
));
1957 static const IDirectoryObjectVtbl IDirectoryObject_vtbl
=
1959 dirobj_QueryInterface
,
1962 dirobj_GetObjectInformation
,
1963 dirobj_GetObjectAttributes
,
1964 dirobj_SetObjectAttributes
,
1965 dirobj_CreateDSObject
,
1966 dirobj_DeleteDSObject
1969 static HRESULT
LDAPNamespace_create(REFIID riid
, void **obj
)
1971 LDAP_namespace
*ldap
;
1974 ldap
= malloc(sizeof(*ldap
));
1975 if (!ldap
) return E_OUTOFMEMORY
;
1977 ldap
->IADs_iface
.lpVtbl
= &IADs_vtbl
;
1978 ldap
->IADsOpenDSObject_iface
.lpVtbl
= &IADsOpenDSObject_vtbl
;
1979 ldap
->IDirectorySearch_iface
.lpVtbl
= &IDirectorySearch_vtbl
;
1980 ldap
->IDirectoryObject_iface
.lpVtbl
= &IDirectoryObject_vtbl
;
1984 ldap
->object
= NULL
;
1985 ldap
->attrs_count
= 0;
1986 ldap
->attrs_count_allocated
= 0;
1988 ldap
->search
.scope
= ADS_SCOPE_SUBTREE
;
1989 ldap
->search
.pagesize
= 0;
1990 ldap
->search
.size_limit
= 0;
1991 ldap
->search
.cache_results
= TRUE
;
1992 ldap
->search
.attribtypes_only
= FALSE
;
1993 ldap
->search
.tombstone
= FALSE
;
1995 ldap
->at_single_count
= 0;
1996 ldap
->at_multiple_count
= 0;
1998 hr
= IADs_QueryInterface(&ldap
->IADs_iface
, riid
, obj
);
1999 IADs_Release(&ldap
->IADs_iface
);
2004 static const struct class_info
2007 HRESULT (*constructor
)(REFIID
, void **);
2010 { &CLSID_ADSystemInfo
, ADSystemInfo_create
},
2011 { &CLSID_LDAP
, LDAP_create
},
2012 { &CLSID_LDAPNamespace
, LDAPNamespace_create
},
2017 IClassFactory IClassFactory_iface
;
2019 const struct class_info
*info
;
2022 static inline class_factory
*impl_from_IClassFactory(IClassFactory
*iface
)
2024 return CONTAINING_RECORD(iface
, class_factory
, IClassFactory_iface
);
2027 static HRESULT WINAPI
factory_QueryInterface(IClassFactory
*iface
, REFIID riid
, LPVOID
*obj
)
2029 TRACE("%p,%s,%p\n", iface
, debugstr_guid(riid
), obj
);
2031 if (!riid
|| !obj
) return E_INVALIDARG
;
2033 if (IsEqualIID(riid
, &IID_IUnknown
) ||
2034 IsEqualIID(riid
, &IID_IClassFactory
))
2036 IClassFactory_AddRef(iface
);
2042 FIXME("interface %s is not implemented\n", debugstr_guid(riid
));
2043 return E_NOINTERFACE
;
2046 static ULONG WINAPI
factory_AddRef(IClassFactory
*iface
)
2048 class_factory
*factory
= impl_from_IClassFactory(iface
);
2049 ULONG ref
= InterlockedIncrement(&factory
->ref
);
2051 TRACE("(%p) ref %lu\n", iface
, ref
);
2056 static ULONG WINAPI
factory_Release(IClassFactory
*iface
)
2058 class_factory
*factory
= impl_from_IClassFactory(iface
);
2059 ULONG ref
= InterlockedDecrement(&factory
->ref
);
2061 TRACE("(%p) ref %lu\n", iface
, ref
);
2069 static HRESULT WINAPI
factory_CreateInstance(IClassFactory
*iface
, IUnknown
*outer
, REFIID riid
, void **obj
)
2071 class_factory
*factory
= impl_from_IClassFactory(iface
);
2073 TRACE("%p,%s,%p\n", outer
, debugstr_guid(riid
), obj
);
2075 if (!riid
|| !obj
) return E_INVALIDARG
;
2078 if (outer
) return CLASS_E_NOAGGREGATION
;
2080 return factory
->info
->constructor(riid
, obj
);
2083 static HRESULT WINAPI
factory_LockServer(IClassFactory
*iface
, BOOL lock
)
2085 FIXME("%p,%d: stub\n", iface
, lock
);
2089 static const struct IClassFactoryVtbl factory_vtbl
=
2091 factory_QueryInterface
,
2094 factory_CreateInstance
,
2098 static HRESULT
factory_constructor(const struct class_info
*info
, REFIID riid
, void **obj
)
2100 class_factory
*factory
;
2103 factory
= malloc(sizeof(*factory
));
2104 if (!factory
) return E_OUTOFMEMORY
;
2106 factory
->IClassFactory_iface
.lpVtbl
= &factory_vtbl
;
2108 factory
->info
= info
;
2110 hr
= IClassFactory_QueryInterface(&factory
->IClassFactory_iface
, riid
, obj
);
2111 IClassFactory_Release(&factory
->IClassFactory_iface
);
2116 HRESULT WINAPI
DllGetClassObject(REFCLSID clsid
, REFIID iid
, LPVOID
*obj
)
2120 TRACE("%s,%s,%p\n", debugstr_guid(clsid
), debugstr_guid(iid
), obj
);
2122 if (!clsid
|| !iid
|| !obj
) return E_INVALIDARG
;
2126 for (i
= 0; i
< ARRAY_SIZE(class_info
); i
++)
2128 if (IsEqualCLSID(class_info
[i
].clsid
, clsid
))
2129 return factory_constructor(&class_info
[i
], iid
, obj
);
2132 FIXME("class %s/%s is not implemented\n", debugstr_guid(clsid
), debugstr_guid(iid
));
2133 return CLASS_E_CLASSNOTAVAILABLE
;