Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/dlls/adsldp/adsldp.c
4388 views
1
/*
2
* Active Directory services LDAP Provider
3
*
4
* Copyright 2018 Dmitry Timoshkov
5
*
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.
10
*
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.
15
*
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
19
*/
20
21
#include <stdarg.h>
22
23
#define COBJMACROS
24
#include "windef.h"
25
#include "winbase.h"
26
#include "initguid.h"
27
#include "objbase.h"
28
#include "rpcproxy.h"
29
#include "rpc.h"
30
#include "iads.h"
31
#include "adshlp.h"
32
#include "adserr.h"
33
#define SECURITY_WIN32
34
#include "security.h"
35
#include "dsgetdc.h"
36
#include "lmcons.h"
37
#include "lmapibuf.h"
38
#include "winldap.h"
39
#include "winber.h"
40
41
#include "adsldp_private.h"
42
43
#include "wine/debug.h"
44
45
WINE_DEFAULT_DEBUG_CHANNEL(adsldp);
46
47
#ifndef LDAP_OPT_SERVER_CONTROLS
48
#define LDAP_OPT_SERVER_CONTROLS 0x0012
49
#endif
50
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);
53
54
static HRESULT LDAPNamespace_create(REFIID riid, void **obj);
55
56
typedef struct
57
{
58
IParseDisplayName IParseDisplayName_iface;
59
LONG ref;
60
} LDAP_PARSE;
61
62
static inline LDAP_PARSE *impl_from_IParseDisplayName(IParseDisplayName *iface)
63
{
64
return CONTAINING_RECORD(iface, LDAP_PARSE, IParseDisplayName_iface);
65
}
66
67
static HRESULT WINAPI ldap_QueryInterface(IParseDisplayName *iface, REFIID riid, void **obj)
68
{
69
TRACE("%p,%s,%p\n", iface, debugstr_guid(riid), obj);
70
71
if (!riid || !obj) return E_INVALIDARG;
72
73
if (IsEqualGUID(riid, &IID_IUnknown) ||
74
IsEqualGUID(riid, &IID_IParseDisplayName))
75
{
76
IParseDisplayName_AddRef(iface);
77
*obj = iface;
78
return S_OK;
79
}
80
81
*obj = NULL;
82
FIXME("interface %s is not implemented\n", debugstr_guid(riid));
83
return E_NOINTERFACE;
84
}
85
86
static ULONG WINAPI ldap_AddRef(IParseDisplayName *iface)
87
{
88
LDAP_PARSE *ldap = impl_from_IParseDisplayName(iface);
89
return InterlockedIncrement(&ldap->ref);
90
}
91
92
static ULONG WINAPI ldap_Release(IParseDisplayName *iface)
93
{
94
LDAP_PARSE *ldap = impl_from_IParseDisplayName(iface);
95
LONG ref = InterlockedDecrement(&ldap->ref);
96
97
if (!ref)
98
{
99
TRACE("destroying %p\n", iface);
100
free(ldap);
101
}
102
103
return ref;
104
}
105
106
static HRESULT WINAPI ldap_ParseDisplayName(IParseDisplayName *iface, IBindCtx *bc,
107
LPOLESTR name, ULONG *eaten, IMoniker **mk)
108
{
109
HRESULT hr;
110
IADsOpenDSObject *ads_open;
111
IDispatch *disp;
112
113
TRACE("%p,%p,%s,%p,%p\n", iface, bc, debugstr_w(name), eaten, mk);
114
115
hr = LDAPNamespace_create(&IID_IADsOpenDSObject, (void **)&ads_open);
116
if (hr != S_OK) return hr;
117
118
hr = IADsOpenDSObject_OpenDSObject(ads_open, name, NULL, NULL, ADS_SECURE_AUTHENTICATION, &disp);
119
if (hr != S_OK)
120
hr = IADsOpenDSObject_OpenDSObject(ads_open, name, NULL, NULL, 0, &disp);
121
if (hr == S_OK)
122
{
123
hr = CreatePointerMoniker((IUnknown *)disp, mk);
124
if (hr == S_OK)
125
*eaten = wcslen(name);
126
127
IDispatch_Release(disp);
128
}
129
130
IADsOpenDSObject_Release(ads_open);
131
132
return hr;
133
}
134
135
static const IParseDisplayNameVtbl LDAP_PARSE_vtbl =
136
{
137
ldap_QueryInterface,
138
ldap_AddRef,
139
ldap_Release,
140
ldap_ParseDisplayName
141
};
142
143
static HRESULT LDAP_create(REFIID riid, void **obj)
144
{
145
LDAP_PARSE *ldap;
146
HRESULT hr;
147
148
ldap = malloc(sizeof(*ldap));
149
if (!ldap) return E_OUTOFMEMORY;
150
151
ldap->IParseDisplayName_iface.lpVtbl = &LDAP_PARSE_vtbl;
152
ldap->ref = 1;
153
154
hr = IParseDisplayName_QueryInterface(&ldap->IParseDisplayName_iface, riid, obj);
155
IParseDisplayName_Release(&ldap->IParseDisplayName_iface);
156
157
return hr;
158
}
159
160
typedef struct
161
{
162
IADsADSystemInfo IADsADSystemInfo_iface;
163
LONG ref;
164
} AD_sysinfo;
165
166
static inline AD_sysinfo *impl_from_IADsADSystemInfo(IADsADSystemInfo *iface)
167
{
168
return CONTAINING_RECORD(iface, AD_sysinfo, IADsADSystemInfo_iface);
169
}
170
171
static HRESULT WINAPI sysinfo_QueryInterface(IADsADSystemInfo *iface, REFIID riid, void **obj)
172
{
173
TRACE("%p,%s,%p\n", iface, debugstr_guid(riid), obj);
174
175
if (!riid || !obj) return E_INVALIDARG;
176
177
if (IsEqualGUID(riid, &IID_IADsADSystemInfo) ||
178
IsEqualGUID(riid, &IID_IDispatch) ||
179
IsEqualGUID(riid, &IID_IUnknown))
180
{
181
IADsADSystemInfo_AddRef(iface);
182
*obj = iface;
183
return S_OK;
184
}
185
186
*obj = NULL;
187
FIXME("interface %s is not implemented\n", debugstr_guid(riid));
188
return E_NOINTERFACE;
189
}
190
191
static ULONG WINAPI sysinfo_AddRef(IADsADSystemInfo *iface)
192
{
193
AD_sysinfo *sysinfo = impl_from_IADsADSystemInfo(iface);
194
return InterlockedIncrement(&sysinfo->ref);
195
}
196
197
static ULONG WINAPI sysinfo_Release(IADsADSystemInfo *iface)
198
{
199
AD_sysinfo *sysinfo = impl_from_IADsADSystemInfo(iface);
200
LONG ref = InterlockedDecrement(&sysinfo->ref);
201
202
if (!ref)
203
{
204
TRACE("destroying %p\n", iface);
205
free(sysinfo);
206
}
207
208
return ref;
209
}
210
211
static HRESULT WINAPI sysinfo_GetTypeInfoCount(IADsADSystemInfo *iface, UINT *count)
212
{
213
FIXME("%p,%p: stub\n", iface, count);
214
return E_NOTIMPL;
215
}
216
217
static HRESULT WINAPI sysinfo_GetTypeInfo(IADsADSystemInfo *iface, UINT index, LCID lcid, ITypeInfo **info)
218
{
219
FIXME("%p,%u,%#lx,%p: stub\n", iface, index, lcid, info);
220
return E_NOTIMPL;
221
}
222
223
static HRESULT WINAPI sysinfo_GetIDsOfNames(IADsADSystemInfo *iface, REFIID riid, LPOLESTR *names,
224
UINT count, LCID lcid, DISPID *dispid)
225
{
226
FIXME("%p,%s,%p,%u,%lu,%p: stub\n", iface, debugstr_guid(riid), names, count, lcid, dispid);
227
return E_NOTIMPL;
228
}
229
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)
232
{
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);
235
return E_NOTIMPL;
236
}
237
238
static HRESULT WINAPI sysinfo_get_UserName(IADsADSystemInfo *iface, BSTR *retval)
239
{
240
FIXME("%p,%p: stub\n", iface, retval);
241
return E_NOTIMPL;
242
}
243
244
static HRESULT WINAPI sysinfo_get_ComputerName(IADsADSystemInfo *iface, BSTR *retval)
245
{
246
ULONG size;
247
WCHAR *name;
248
249
TRACE("%p,%p\n", iface, retval);
250
251
size = 0;
252
GetComputerObjectNameW(NameFullyQualifiedDN, NULL, &size);
253
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
254
return HRESULT_FROM_WIN32(GetLastError());
255
256
name = SysAllocStringLen(NULL, size);
257
if (!name) return E_OUTOFMEMORY;
258
259
if (!GetComputerObjectNameW(NameFullyQualifiedDN, name, &size))
260
{
261
SysFreeString(name);
262
return HRESULT_FROM_WIN32(GetLastError());
263
}
264
265
*retval = name;
266
return S_OK;
267
}
268
269
static HRESULT WINAPI sysinfo_get_SiteName(IADsADSystemInfo *iface, BSTR *retval)
270
{
271
FIXME("%p,%p: stub\n", iface, retval);
272
return E_NOTIMPL;
273
}
274
275
static HRESULT WINAPI sysinfo_get_DomainShortName(IADsADSystemInfo *iface, BSTR *retval)
276
{
277
FIXME("%p,%p: stub\n", iface, retval);
278
return E_NOTIMPL;
279
}
280
281
static HRESULT WINAPI sysinfo_get_DomainDNSName(IADsADSystemInfo *iface, BSTR *retval)
282
{
283
FIXME("%p,%p: stub\n", iface, retval);
284
return E_NOTIMPL;
285
}
286
287
static HRESULT WINAPI sysinfo_get_ForestDNSName(IADsADSystemInfo *iface, BSTR *retval)
288
{
289
FIXME("%p,%p: stub\n", iface, retval);
290
return E_NOTIMPL;
291
}
292
293
static HRESULT WINAPI sysinfo_get_PDCRoleOwner(IADsADSystemInfo *iface, BSTR *retval)
294
{
295
FIXME("%p,%p: stub\n", iface, retval);
296
return E_NOTIMPL;
297
}
298
299
static HRESULT WINAPI sysinfo_get_SchemaRoleOwner(IADsADSystemInfo *iface, BSTR *retval)
300
{
301
FIXME("%p,%p: stub\n", iface, retval);
302
return E_NOTIMPL;
303
}
304
305
static HRESULT WINAPI sysinfo_get_IsNativeMode(IADsADSystemInfo *iface, VARIANT_BOOL *retval)
306
{
307
FIXME("%p,%p: stub\n", iface, retval);
308
return E_NOTIMPL;
309
}
310
311
static HRESULT WINAPI sysinfo_GetAnyDCName(IADsADSystemInfo *iface, BSTR *retval)
312
{
313
FIXME("%p,%p: stub\n", iface, retval);
314
return E_NOTIMPL;
315
}
316
317
static HRESULT WINAPI sysinfo_GetDCSiteName(IADsADSystemInfo *iface, BSTR server, BSTR *retval)
318
{
319
FIXME("%p,%s,%p: stub\n", iface, debugstr_w(server), retval);
320
return E_NOTIMPL;
321
}
322
323
static HRESULT WINAPI sysinfo_RefreshSchemaCache(IADsADSystemInfo *iface)
324
{
325
FIXME("%p: stub\n", iface);
326
return E_NOTIMPL;
327
}
328
329
static HRESULT WINAPI sysinfo_GetTrees(IADsADSystemInfo *iface, VARIANT *retval)
330
{
331
FIXME("%p,%p: stub\n", iface, retval);
332
return E_NOTIMPL;
333
}
334
335
static const IADsADSystemInfoVtbl IADsADSystemInfo_vtbl =
336
{
337
sysinfo_QueryInterface,
338
sysinfo_AddRef,
339
sysinfo_Release,
340
sysinfo_GetTypeInfoCount,
341
sysinfo_GetTypeInfo,
342
sysinfo_GetIDsOfNames,
343
sysinfo_Invoke,
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,
356
sysinfo_GetTrees
357
};
358
359
static HRESULT ADSystemInfo_create(REFIID riid, void **obj)
360
{
361
AD_sysinfo *sysinfo;
362
HRESULT hr;
363
364
sysinfo = malloc(sizeof(*sysinfo));
365
if (!sysinfo) return E_OUTOFMEMORY;
366
367
sysinfo->IADsADSystemInfo_iface.lpVtbl = &IADsADSystemInfo_vtbl;
368
sysinfo->ref = 1;
369
370
hr = IADsADSystemInfo_QueryInterface(&sysinfo->IADsADSystemInfo_iface, riid, obj);
371
IADsADSystemInfo_Release(&sysinfo->IADsADSystemInfo_iface);
372
373
return hr;
374
}
375
376
struct ldap_attribute
377
{
378
WCHAR *name;
379
WCHAR **values;
380
};
381
382
typedef struct
383
{
384
IADs IADs_iface;
385
IADsOpenDSObject IADsOpenDSObject_iface;
386
IDirectorySearch IDirectorySearch_iface;
387
IDirectoryObject IDirectoryObject_iface;
388
LONG ref;
389
LDAP *ld;
390
BSTR host;
391
BSTR object;
392
ULONG port;
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;
397
struct
398
{
399
ADS_SCOPEENUM scope;
400
int pagesize;
401
int size_limit;
402
BOOL cache_results;
403
BOOL attribtypes_only;
404
BOOL tombstone;
405
} search;
406
} LDAP_namespace;
407
408
struct ldap_search_context
409
{
410
LDAPSearch *page;
411
LDAPMessage *res, *entry;
412
BerElement *ber;
413
ULONG count, pos;
414
BOOL add_ADsPath;
415
};
416
417
static inline LDAP_namespace *impl_from_IADs(IADs *iface)
418
{
419
return CONTAINING_RECORD(iface, LDAP_namespace, IADs_iface);
420
}
421
422
static HRESULT WINAPI ldapns_QueryInterface(IADs *iface, REFIID riid, void **obj)
423
{
424
LDAP_namespace *ldap = impl_from_IADs(iface);
425
426
TRACE("%p,%s,%p\n", iface, debugstr_guid(riid), obj);
427
428
if (!riid || !obj) return E_INVALIDARG;
429
430
if (IsEqualGUID(riid, &IID_IUnknown) ||
431
IsEqualGUID(riid, &IID_IDispatch) ||
432
IsEqualGUID(riid, &IID_IADs))
433
{
434
IADs_AddRef(iface);
435
*obj = iface;
436
return S_OK;
437
}
438
439
if (IsEqualGUID(riid, &IID_IADsOpenDSObject))
440
{
441
IADs_AddRef(iface);
442
*obj = &ldap->IADsOpenDSObject_iface;
443
return S_OK;
444
}
445
446
if (IsEqualGUID(riid, &IID_IDirectorySearch))
447
{
448
if (!ldap->ld || (ldap->object && !wcsicmp(ldap->object, L"rootDSE")))
449
return E_NOINTERFACE;
450
451
IADs_AddRef(iface);
452
*obj = &ldap->IDirectorySearch_iface;
453
return S_OK;
454
}
455
456
if (IsEqualGUID(riid, &IID_IDirectoryObject))
457
{
458
IADs_AddRef(iface);
459
*obj = &ldap->IDirectoryObject_iface;
460
return S_OK;
461
}
462
463
FIXME("interface %s is not implemented\n", debugstr_guid(riid));
464
return E_NOINTERFACE;
465
}
466
467
static ULONG WINAPI ldapns_AddRef(IADs *iface)
468
{
469
LDAP_namespace *ldap = impl_from_IADs(iface);
470
return InterlockedIncrement(&ldap->ref);
471
}
472
473
static void free_attributes(LDAP_namespace *ldap)
474
{
475
ULONG i;
476
477
if (!ldap->attrs) return;
478
479
for (i = 0; i < ldap->attrs_count; i++)
480
{
481
ldap_memfreeW(ldap->attrs[i].name);
482
ldap_value_freeW(ldap->attrs[i].values);
483
}
484
485
free(ldap->attrs);
486
ldap->attrs = NULL;
487
ldap->attrs_count = 0;
488
}
489
490
static ULONG WINAPI ldapns_Release(IADs *iface)
491
{
492
LDAP_namespace *ldap = impl_from_IADs(iface);
493
LONG ref = InterlockedDecrement(&ldap->ref);
494
495
if (!ref)
496
{
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);
503
free(ldap);
504
}
505
506
return ref;
507
}
508
509
static HRESULT WINAPI ldapns_GetTypeInfoCount(IADs *iface, UINT *count)
510
{
511
FIXME("%p,%p: stub\n", iface, count);
512
return E_NOTIMPL;
513
}
514
515
static HRESULT WINAPI ldapns_GetTypeInfo(IADs *iface, UINT index, LCID lcid, ITypeInfo **info)
516
{
517
FIXME("%p,%u,%#lx,%p: stub\n", iface, index, lcid, info);
518
return E_NOTIMPL;
519
}
520
521
static HRESULT WINAPI ldapns_GetIDsOfNames(IADs *iface, REFIID riid, LPOLESTR *names,
522
UINT count, LCID lcid, DISPID *dispid)
523
{
524
FIXME("%p,%s,%p,%u,%lu,%p: stub\n", iface, debugstr_guid(riid), names, count, lcid, dispid);
525
return E_NOTIMPL;
526
}
527
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)
530
{
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);
533
return E_NOTIMPL;
534
}
535
536
static HRESULT WINAPI ldapns_get_Name(IADs *iface, BSTR *retval)
537
{
538
FIXME("%p,%p: stub\n", iface, retval);
539
return E_NOTIMPL;
540
}
541
542
static HRESULT WINAPI ldapns_get_Class(IADs *iface, BSTR *retval)
543
{
544
FIXME("%p,%p: stub\n", iface, retval);
545
return E_NOTIMPL;
546
}
547
548
static HRESULT WINAPI ldapns_get_GUID(IADs *iface, BSTR *retval)
549
{
550
FIXME("%p,%p: stub\n", iface, retval);
551
return E_NOTIMPL;
552
}
553
554
static HRESULT WINAPI ldapns_get_ADsPath(IADs *iface, BSTR *retval)
555
{
556
FIXME("%p,%p: stub\n", iface, retval);
557
return E_NOTIMPL;
558
}
559
560
static HRESULT WINAPI ldapns_get_Parent(IADs *iface, BSTR *retval)
561
{
562
FIXME("%p,%p: stub\n", iface, retval);
563
return E_NOTIMPL;
564
}
565
566
static HRESULT WINAPI ldapns_get_Schema(IADs *iface, BSTR *retval)
567
{
568
FIXME("%p,%p: stub\n", iface, retval);
569
return E_NOTIMPL;
570
}
571
572
static HRESULT WINAPI ldapns_GetInfo(IADs *iface)
573
{
574
HRESULT hr;
575
VARIANT var;
576
577
TRACE("%p\n", iface);
578
579
hr = ADsBuildVarArrayStr(NULL, 0, &var);
580
if (hr == S_OK)
581
{
582
hr = IADs_GetInfoEx(iface, var, 0);
583
VariantClear(&var);
584
}
585
return hr;
586
}
587
588
static HRESULT WINAPI ldapns_SetInfo(IADs *iface)
589
{
590
FIXME("%p: stub\n", iface);
591
return E_NOTIMPL;
592
}
593
594
static HRESULT WINAPI ldapns_Get(IADs *iface, BSTR name, VARIANT *prop)
595
{
596
LDAP_namespace *ldap = impl_from_IADs(iface);
597
HRESULT hr;
598
ULONG i;
599
600
TRACE("%p,%s,%p\n", iface, debugstr_w(name), prop);
601
602
if (!name || !prop) return E_ADS_BAD_PARAMETER;
603
604
if (!ldap->attrs_count)
605
{
606
hr = IADs_GetInfo(iface);
607
if (hr != S_OK) return hr;
608
}
609
610
for (i = 0; i < ldap->attrs_count; i++)
611
{
612
if (!wcsicmp(name, ldap->attrs[i].name))
613
{
614
LONG count = ldap_count_valuesW(ldap->attrs[i].values);
615
if (!count)
616
{
617
V_BSTR(prop) = NULL;
618
V_VT(prop) = VT_BSTR;
619
return S_OK;
620
}
621
622
if (count > 1)
623
{
624
SAFEARRAY *sa;
625
VARIANT item;
626
LONG idx;
627
628
TRACE("attr %s has %lu values\n", debugstr_w(ldap->attrs[i].name), count);
629
630
sa = SafeArrayCreateVector(VT_VARIANT, 0, count);
631
if (!sa) return E_OUTOFMEMORY;
632
633
for (idx = 0; idx < count; idx++)
634
{
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]);
638
if (!V_BSTR(&item))
639
{
640
hr = E_OUTOFMEMORY;
641
goto fail;
642
}
643
644
hr = SafeArrayPutElement(sa, &idx, &item);
645
SysFreeString(V_BSTR(&item));
646
if (hr != S_OK) goto fail;
647
}
648
649
V_VT(prop) = VT_ARRAY | VT_VARIANT;
650
V_ARRAY(prop) = sa;
651
return S_OK;
652
fail:
653
SafeArrayDestroy(sa);
654
return hr;
655
}
656
else
657
{
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;
662
return S_OK;
663
}
664
}
665
}
666
667
return E_ADS_PROPERTY_NOT_FOUND;
668
}
669
670
static HRESULT WINAPI ldapns_Put(IADs *iface, BSTR name, VARIANT prop)
671
{
672
FIXME("%p,%s,%s: stub\n", iface, debugstr_w(name), wine_dbgstr_variant(&prop));
673
return E_NOTIMPL;
674
}
675
676
static HRESULT WINAPI ldapns_GetEx(IADs *iface, BSTR name, VARIANT *prop)
677
{
678
FIXME("%p,%s,%p: stub\n", iface, debugstr_w(name), prop);
679
return E_NOTIMPL;
680
}
681
682
static HRESULT WINAPI ldapns_PutEx(IADs *iface, LONG code, BSTR name, VARIANT prop)
683
{
684
FIXME("%p,%ld,%s,%s: stub\n", iface, code, debugstr_w(name), wine_dbgstr_variant(&prop));
685
return E_NOTIMPL;
686
}
687
688
static HRESULT add_attribute(LDAP_namespace *ldap, WCHAR *name, WCHAR **values)
689
{
690
struct ldap_attribute *new_attrs;
691
692
if (!ldap->attrs)
693
{
694
ldap->attrs = malloc(256 * sizeof(ldap->attrs[0]));
695
if (!ldap->attrs) return E_OUTOFMEMORY;
696
ldap->attrs_count_allocated = 256;
697
}
698
else if (ldap->attrs_count_allocated < ldap->attrs_count + 1)
699
{
700
new_attrs = realloc(ldap->attrs, (ldap->attrs_count_allocated * 2) * sizeof(*new_attrs));
701
if (!new_attrs) return E_OUTOFMEMORY;
702
703
ldap->attrs_count_allocated *= 2;
704
ldap->attrs = new_attrs;
705
}
706
707
ldap->attrs[ldap->attrs_count].name = name;
708
ldap->attrs[ldap->attrs_count].values = values;
709
ldap->attrs_count++;
710
711
return S_OK;
712
}
713
714
static HRESULT WINAPI ldapns_GetInfoEx(IADs *iface, VARIANT prop, LONG reserved)
715
{
716
LDAP_namespace *ldap = impl_from_IADs(iface);
717
HRESULT hr;
718
SAFEARRAY *sa;
719
VARIANT *item;
720
WCHAR **props = NULL, *attr, **values;
721
DWORD i, count, err;
722
LDAPMessage *res = NULL, *entry;
723
BerElement *ber;
724
725
TRACE("%p,%s,%ld\n", iface, wine_dbgstr_variant(&prop), reserved);
726
727
free_attributes(ldap);
728
729
if (!ldap->ld) return E_NOTIMPL;
730
731
if (V_VT(&prop) != (VT_ARRAY | VT_VARIANT))
732
return E_ADS_BAD_PARAMETER;
733
734
sa = V_ARRAY(&prop);
735
if (sa->cDims != 1)
736
return E_ADS_BAD_PARAMETER;
737
738
hr = SafeArrayAccessData(sa, (void *)&item);
739
if (hr != S_OK) return hr;
740
741
count = sa->rgsabound[0].cElements;
742
if (count)
743
{
744
props = malloc((count + 1) * sizeof(props[0]));
745
if (!props)
746
{
747
hr = E_OUTOFMEMORY;
748
goto exit;
749
}
750
751
for (i = 0; i < count; i++)
752
{
753
if (V_VT(&item[i]) != VT_BSTR)
754
{
755
hr = E_ADS_BAD_PARAMETER;
756
goto exit;
757
}
758
props[i] = V_BSTR(&item[i]);
759
}
760
props[sa->rgsabound[0].cElements] = NULL;
761
}
762
763
err = ldap_search_sW(ldap->ld, NULL, LDAP_SCOPE_BASE, (WCHAR *)L"(objectClass=*)", props, FALSE, &res);
764
if (err != LDAP_SUCCESS)
765
{
766
TRACE("ldap_search_sW error %#lx\n", err);
767
hr = HRESULT_FROM_WIN32(map_ldap_error(err));
768
goto exit;
769
}
770
771
entry = ldap_first_entry(ldap->ld, res);
772
while (entry)
773
{
774
attr = ldap_first_attributeW(ldap->ld, entry, &ber);
775
while (attr)
776
{
777
TRACE("attr: %s\n", debugstr_w(attr));
778
779
values = ldap_get_valuesW(ldap->ld, entry, attr);
780
781
hr = add_attribute(ldap, attr, values);
782
if (hr != S_OK)
783
{
784
ldap_value_freeW(values);
785
ldap_memfreeW(attr);
786
ber_free(ber, 0);
787
goto exit;
788
}
789
790
attr = ldap_next_attributeW(ldap->ld, entry, ber);
791
}
792
793
ber_free(ber, 0);
794
entry = ldap_next_entry(ldap->ld, res);
795
}
796
797
exit:
798
if (res) ldap_msgfree(res);
799
free(props);
800
SafeArrayUnaccessData(sa);
801
return hr;
802
}
803
804
static const IADsVtbl IADs_vtbl =
805
{
806
ldapns_QueryInterface,
807
ldapns_AddRef,
808
ldapns_Release,
809
ldapns_GetTypeInfoCount,
810
ldapns_GetTypeInfo,
811
ldapns_GetIDsOfNames,
812
ldapns_Invoke,
813
ldapns_get_Name,
814
ldapns_get_Class,
815
ldapns_get_GUID,
816
ldapns_get_ADsPath,
817
ldapns_get_Parent,
818
ldapns_get_Schema,
819
ldapns_GetInfo,
820
ldapns_SetInfo,
821
ldapns_Get,
822
ldapns_Put,
823
ldapns_GetEx,
824
ldapns_PutEx,
825
ldapns_GetInfoEx
826
};
827
828
static inline LDAP_namespace *impl_from_IADsOpenDSObject(IADsOpenDSObject *iface)
829
{
830
return CONTAINING_RECORD(iface, LDAP_namespace, IADsOpenDSObject_iface);
831
}
832
833
static HRESULT WINAPI openobj_QueryInterface(IADsOpenDSObject *iface, REFIID riid, void **obj)
834
{
835
TRACE("%p,%s,%p\n", iface, debugstr_guid(riid), obj);
836
837
if (!riid || !obj) return E_INVALIDARG;
838
839
if (IsEqualGUID(riid, &IID_IADsOpenDSObject) ||
840
IsEqualGUID(riid, &IID_IDispatch) ||
841
IsEqualGUID(riid, &IID_IUnknown))
842
{
843
IADsOpenDSObject_AddRef(iface);
844
*obj = iface;
845
return S_OK;
846
}
847
848
FIXME("interface %s is not implemented\n", debugstr_guid(riid));
849
return E_NOINTERFACE;
850
}
851
852
static ULONG WINAPI openobj_AddRef(IADsOpenDSObject *iface)
853
{
854
LDAP_namespace *ldap = impl_from_IADsOpenDSObject(iface);
855
return IADs_AddRef(&ldap->IADs_iface);
856
}
857
858
static ULONG WINAPI openobj_Release(IADsOpenDSObject *iface)
859
{
860
LDAP_namespace *ldap = impl_from_IADsOpenDSObject(iface);
861
return IADs_Release(&ldap->IADs_iface);
862
}
863
864
static HRESULT WINAPI openobj_GetTypeInfoCount(IADsOpenDSObject *iface, UINT *count)
865
{
866
FIXME("%p,%p: stub\n", iface, count);
867
return E_NOTIMPL;
868
}
869
870
static HRESULT WINAPI openobj_GetTypeInfo(IADsOpenDSObject *iface, UINT index, LCID lcid, ITypeInfo **info)
871
{
872
FIXME("%p,%u,%#lx,%p: stub\n", iface, index, lcid, info);
873
return E_NOTIMPL;
874
}
875
876
static HRESULT WINAPI openobj_GetIDsOfNames(IADsOpenDSObject *iface, REFIID riid, LPOLESTR *names,
877
UINT count, LCID lcid, DISPID *dispid)
878
{
879
FIXME("%p,%s,%p,%u,%lu,%p: stub\n", iface, debugstr_guid(riid), names, count, lcid, dispid);
880
return E_NOTIMPL;
881
}
882
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)
885
{
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);
888
return E_NOTIMPL;
889
}
890
891
static HRESULT parse_path(WCHAR *path, BSTR *host, ULONG *port, BSTR *object)
892
{
893
WCHAR *p, *p_host;
894
int host_len;
895
896
if (host) *host = NULL;
897
if (port) *port = 0;
898
if (object) *object = NULL;
899
900
if (wcsnicmp(path, L"LDAP:", 5) != 0)
901
return E_ADS_BAD_PATHNAME;
902
903
p = path + 5;
904
if (!*p) return S_OK;
905
906
if (*p++ != '/' || *p++ != '/' || !*p)
907
return E_ADS_BAD_PATHNAME;
908
909
p_host = p;
910
host_len = 0;
911
while (*p && *p != '/')
912
{
913
if (*p == ':')
914
{
915
ULONG dummy;
916
if (!port) port = &dummy;
917
*port = wcstol(p + 1, &p, 10);
918
if (*p && *p != '/') return E_ADS_BAD_PATHNAME;
919
}
920
else
921
{
922
p++;
923
host_len++;
924
}
925
}
926
if (host_len == 0) return E_ADS_BAD_PATHNAME;
927
928
if (host)
929
{
930
*host = SysAllocStringLen(p_host, host_len);
931
if (!*host) return E_OUTOFMEMORY;
932
}
933
934
if (!*p) return S_OK;
935
936
if (*p++ != '/' || !*p)
937
{
938
SysFreeString(*host);
939
return E_ADS_BAD_PATHNAME;
940
}
941
942
if (object)
943
{
944
*object = SysAllocString(p);
945
if (!*object)
946
{
947
SysFreeString(*host);
948
return E_OUTOFMEMORY;
949
}
950
}
951
952
return S_OK;
953
}
954
955
static HRESULT WINAPI openobj_OpenDSObject(IADsOpenDSObject *iface, BSTR path, BSTR user, BSTR password,
956
LONG flags, IDispatch **obj)
957
{
958
BSTR host, object;
959
ULONG port;
960
IADs *ads;
961
LDAP *ld = NULL;
962
HRESULT hr;
963
ULONG err, at_single_count = 0, at_multiple_count = 0;
964
struct attribute_type *at = NULL;
965
966
TRACE("%p,%s,%s,%p,%08lx,%p\n", iface, debugstr_w(path), debugstr_w(user), password, flags, obj);
967
968
hr = parse_path(path, &host, &port, &object);
969
if (hr != S_OK) return hr;
970
971
TRACE("host %s, port %lu, object %s\n", debugstr_w(host), port, debugstr_w(object));
972
973
if (host)
974
{
975
int version;
976
977
if (!wcsicmp(host, L"rootDSE"))
978
{
979
DOMAIN_CONTROLLER_INFOW *dcinfo;
980
981
if (object)
982
{
983
hr = E_ADS_BAD_PATHNAME;
984
goto fail;
985
}
986
987
object = host;
988
989
err = DsGetDcNameW(NULL, NULL, NULL, NULL, DS_RETURN_DNS_NAME, &dcinfo);
990
if (err != ERROR_SUCCESS)
991
{
992
hr = HRESULT_FROM_WIN32(err);
993
goto fail;
994
}
995
996
host = SysAllocString(dcinfo->DomainName);
997
NetApiBufferFree(dcinfo);
998
999
if (!host)
1000
{
1001
hr = E_OUTOFMEMORY;
1002
goto fail;
1003
}
1004
}
1005
1006
ld = ldap_initW(host, port);
1007
if (!ld)
1008
{
1009
hr = HRESULT_FROM_WIN32(LdapGetLastError());
1010
goto fail;
1011
}
1012
1013
version = LDAP_VERSION3;
1014
err = ldap_set_optionW(ld, LDAP_OPT_PROTOCOL_VERSION, &version);
1015
if (err != LDAP_SUCCESS)
1016
{
1017
hr = HRESULT_FROM_WIN32(map_ldap_error(err));
1018
ldap_unbind(ld);
1019
goto fail;
1020
}
1021
1022
err = ldap_connect(ld, NULL);
1023
if (err != LDAP_SUCCESS)
1024
{
1025
hr = HRESULT_FROM_WIN32(map_ldap_error(err));
1026
ldap_unbind(ld);
1027
goto fail;
1028
}
1029
1030
if (flags & ADS_SECURE_AUTHENTICATION)
1031
{
1032
SEC_WINNT_AUTH_IDENTITY_W id;
1033
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;
1041
1042
err = ldap_bind_sW(ld, NULL, (WCHAR *)&id, LDAP_AUTH_NEGOTIATE);
1043
if (err != LDAP_SUCCESS)
1044
{
1045
TRACE("ldap_bind_sW error %#lx\n", err);
1046
hr = HRESULT_FROM_WIN32(map_ldap_error(err));
1047
ldap_unbind(ld);
1048
goto fail;
1049
}
1050
}
1051
else
1052
{
1053
err = ldap_simple_bind_sW(ld, user, password);
1054
if (err != LDAP_SUCCESS)
1055
{
1056
TRACE("ldap_simple_bind_sW error %#lx\n", err);
1057
hr = HRESULT_FROM_WIN32(map_ldap_error(err));
1058
ldap_unbind(ld);
1059
goto fail;
1060
}
1061
}
1062
1063
at = load_schema(ld, &at_single_count, &at_multiple_count);
1064
}
1065
1066
hr = LDAPNamespace_create(&IID_IADs, (void **)&ads);
1067
if (hr == S_OK)
1068
{
1069
LDAP_namespace *ldap = impl_from_IADs(ads);
1070
ldap->ld = ld;
1071
ldap->host = host;
1072
ldap->port = port;
1073
ldap->object = object;
1074
ldap->at = at;
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);
1078
IADs_Release(ads);
1079
return hr;
1080
}
1081
1082
fail:
1083
SysFreeString(host);
1084
SysFreeString(object);
1085
1086
return hr;
1087
}
1088
1089
static const IADsOpenDSObjectVtbl IADsOpenDSObject_vtbl =
1090
{
1091
openobj_QueryInterface,
1092
openobj_AddRef,
1093
openobj_Release,
1094
openobj_GetTypeInfoCount,
1095
openobj_GetTypeInfo,
1096
openobj_GetIDsOfNames,
1097
openobj_Invoke,
1098
openobj_OpenDSObject
1099
};
1100
1101
static inline LDAP_namespace *impl_from_IDirectorySearch(IDirectorySearch *iface)
1102
{
1103
return CONTAINING_RECORD(iface, LDAP_namespace, IDirectorySearch_iface);
1104
}
1105
1106
static HRESULT WINAPI search_QueryInterface(IDirectorySearch *iface, REFIID riid, void **obj)
1107
{
1108
TRACE("%p,%s,%p\n", iface, debugstr_guid(riid), obj);
1109
1110
if (!riid || !obj) return E_INVALIDARG;
1111
1112
if (IsEqualGUID(riid, &IID_IDirectorySearch) ||
1113
IsEqualGUID(riid, &IID_IUnknown))
1114
{
1115
IDirectorySearch_AddRef(iface);
1116
*obj = iface;
1117
return S_OK;
1118
}
1119
1120
FIXME("interface %s is not implemented\n", debugstr_guid(riid));
1121
return E_NOINTERFACE;
1122
}
1123
1124
static ULONG WINAPI search_AddRef(IDirectorySearch *iface)
1125
{
1126
LDAP_namespace *ldap = impl_from_IDirectorySearch(iface);
1127
return IADs_AddRef(&ldap->IADs_iface);
1128
}
1129
1130
static ULONG WINAPI search_Release(IDirectorySearch *iface)
1131
{
1132
LDAP_namespace *ldap = impl_from_IDirectorySearch(iface);
1133
return IADs_Release(&ldap->IADs_iface);
1134
}
1135
1136
static HRESULT WINAPI search_SetSearchPreference(IDirectorySearch *iface, PADS_SEARCHPREF_INFO prefs, DWORD count)
1137
{
1138
LDAP_namespace *ldap = impl_from_IDirectorySearch(iface);
1139
HRESULT hr = S_OK;
1140
DWORD i;
1141
1142
TRACE("%p,%p,%lu\n", iface, prefs, count);
1143
1144
for (i = 0; i < count; i++)
1145
{
1146
switch (prefs[i].dwSearchPref)
1147
{
1148
case ADS_SEARCHPREF_SEARCH_SCOPE:
1149
if (prefs[i].vValue.dwType != ADSTYPE_INTEGER)
1150
{
1151
FIXME("ADS_SEARCHPREF_SEARCH_SCOPE: unsupported dwType %d\n", prefs[i].vValue.dwType);
1152
prefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
1153
break;
1154
}
1155
1156
switch (prefs[i].vValue.Integer)
1157
{
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;
1164
break;
1165
1166
default:
1167
prefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
1168
break;
1169
}
1170
break;
1171
1172
case ADS_SEARCHPREF_SECURITY_MASK:
1173
{
1174
int security_mask;
1175
ULONG err;
1176
BerElement *ber;
1177
struct berval *berval;
1178
LDAPControlW *ctrls[2], mask;
1179
1180
if (prefs[i].vValue.dwType != ADSTYPE_INTEGER)
1181
{
1182
FIXME("ADS_SEARCHPREF_SECURITY_MASK: not supported dwType %d\n", prefs[i].vValue.dwType);
1183
prefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
1184
break;
1185
}
1186
1187
TRACE("SECURITY_MASK: %08lx\n", prefs[i].vValue.Integer);
1188
security_mask = prefs[i].vValue.Integer;
1189
if (!security_mask)
1190
security_mask = ADS_SECURITY_INFO_OWNER;
1191
1192
ber = ber_alloc_t(LBER_USE_DER);
1193
if (!ber || ber_printf(ber, (char *)"{i}", security_mask) == -1 || ber_flatten(ber, &berval) == -1)
1194
{
1195
ber_free(ber, 1);
1196
prefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREF;
1197
break;
1198
}
1199
TRACE("ber: %s\n", debugstr_an(berval->bv_val, berval->bv_len));
1200
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;
1205
ctrls[0] = &mask;
1206
ctrls[1] = NULL;
1207
err = ldap_set_optionW(ldap->ld, LDAP_OPT_SERVER_CONTROLS, ctrls);
1208
if (err != LDAP_SUCCESS)
1209
{
1210
TRACE("ldap_set_option error %#lx\n", err);
1211
prefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREF;
1212
hr = S_ADS_ERRORSOCCURRED;
1213
}
1214
else
1215
prefs[i].dwStatus = ADS_STATUS_S_OK;
1216
1217
ber_bvfree(berval);
1218
ber_free(ber, 1);
1219
break;
1220
}
1221
1222
case ADS_SEARCHPREF_PAGESIZE:
1223
if (prefs[i].vValue.dwType != ADSTYPE_INTEGER)
1224
{
1225
FIXME("ADS_SEARCHPREF_PAGESIZE: unsupported dwType %d\n", prefs[i].vValue.dwType);
1226
prefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
1227
break;
1228
}
1229
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;
1233
break;
1234
1235
case ADS_SEARCHPREF_CACHE_RESULTS:
1236
if (prefs[i].vValue.dwType != ADSTYPE_BOOLEAN)
1237
{
1238
FIXME("ADS_SEARCHPREF_CACHE_RESULTS: unsupported dwType %d\n", prefs[i].vValue.dwType);
1239
prefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
1240
break;
1241
}
1242
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;
1246
break;
1247
1248
case ADS_SEARCHPREF_ATTRIBTYPES_ONLY:
1249
if (prefs[i].vValue.dwType != ADSTYPE_BOOLEAN)
1250
{
1251
FIXME("ADS_SEARCHPREF_ATTRIBTYPES_ONLY: unsupported dwType %d\n", prefs[i].vValue.dwType);
1252
prefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
1253
break;
1254
}
1255
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;
1259
break;
1260
1261
case ADS_SEARCHPREF_TOMBSTONE:
1262
if (prefs[i].vValue.dwType != ADSTYPE_BOOLEAN)
1263
{
1264
FIXME("ADS_SEARCHPREF_TOMBSTONE: unsupported dwType %d\n", prefs[i].vValue.dwType);
1265
prefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
1266
break;
1267
}
1268
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;
1272
break;
1273
1274
case ADS_SEARCHPREF_SIZE_LIMIT:
1275
if (prefs[i].vValue.dwType != ADSTYPE_INTEGER)
1276
{
1277
FIXME("ADS_SEARCHPREF_SIZE_LIMIT: unsupported dwType %d\n", prefs[i].vValue.dwType);
1278
prefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
1279
break;
1280
}
1281
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;
1285
break;
1286
1287
default:
1288
FIXME("pref %d, type %u: stub\n", prefs[i].dwSearchPref, prefs[i].vValue.dwType);
1289
prefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREF;
1290
break;
1291
}
1292
}
1293
1294
return hr;
1295
}
1296
1297
static HRESULT WINAPI search_ExecuteSearch(IDirectorySearch *iface, LPWSTR filter, LPWSTR *names,
1298
DWORD count, PADS_SEARCH_HANDLE res)
1299
{
1300
LDAP_namespace *ldap = impl_from_IDirectorySearch(iface);
1301
ULONG err, i;
1302
WCHAR **props;
1303
LDAPControlW **ctrls = NULL, *ctrls_a[2], tombstone;
1304
struct ldap_search_context *ldap_ctx;
1305
1306
TRACE("%p,%s,%p,%lu,%p\n", iface, debugstr_w(filter), names, count, res);
1307
1308
if (!res) return E_ADS_BAD_PARAMETER;
1309
1310
ldap_ctx = calloc(1, sizeof(*ldap_ctx));
1311
if (!ldap_ctx) return E_OUTOFMEMORY;
1312
1313
if (count == 0xffffffff)
1314
props = NULL;
1315
else
1316
{
1317
if (count && !names)
1318
{
1319
free(ldap_ctx);
1320
return E_ADS_BAD_PARAMETER;
1321
}
1322
1323
props = malloc((count + 1) * sizeof(props[0]));
1324
if (!props)
1325
{
1326
free(ldap_ctx);
1327
return E_OUTOFMEMORY;
1328
}
1329
1330
for (i = 0; i < count; i++)
1331
{
1332
TRACE("=> %s\n", debugstr_w(names[i]));
1333
props[i] = names[i];
1334
}
1335
1336
props[count] = NULL;
1337
}
1338
1339
if (ldap->search.tombstone)
1340
{
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;
1346
ctrls_a[1] = NULL;
1347
ctrls = ctrls_a;
1348
}
1349
1350
if (ldap->search.pagesize)
1351
{
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);
1355
if (ldap_ctx->page)
1356
err = ldap_get_next_page_s(ldap->ld, ldap_ctx->page, NULL,
1357
ldap->search.pagesize, &count, &ldap_ctx->res);
1358
else
1359
err = LDAP_NO_MEMORY;
1360
}
1361
else
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,
1364
&ldap_ctx->res);
1365
free(props);
1366
if (err != LDAP_SUCCESS)
1367
{
1368
TRACE("ldap_search_sW error %#lx\n", err);
1369
if (ldap_ctx->res)
1370
ldap_msgfree(ldap_ctx->res);
1371
if (ldap_ctx->page)
1372
ldap_search_abandon_page(ldap->ld, ldap_ctx->page);
1373
free(ldap_ctx);
1374
return HRESULT_FROM_WIN32(map_ldap_error(err));
1375
}
1376
1377
*res = ldap_ctx;
1378
return S_OK;
1379
}
1380
1381
static HRESULT WINAPI search_AbandonSearch(IDirectorySearch *iface, ADS_SEARCH_HANDLE res)
1382
{
1383
FIXME("%p,%p: stub\n", iface, res);
1384
return E_NOTIMPL;
1385
}
1386
1387
static HRESULT WINAPI search_GetFirstRow(IDirectorySearch *iface, ADS_SEARCH_HANDLE res)
1388
{
1389
struct ldap_search_context *ldap_ctx = res;
1390
1391
TRACE("%p,%p\n", iface, res);
1392
1393
if (!res) return E_ADS_BAD_PARAMETER;
1394
1395
ldap_ctx->entry = NULL;
1396
1397
return IDirectorySearch_GetNextRow(iface, res);
1398
}
1399
1400
static HRESULT WINAPI search_GetNextRow(IDirectorySearch *iface, ADS_SEARCH_HANDLE res)
1401
{
1402
LDAP_namespace *ldap = impl_from_IDirectorySearch(iface);
1403
struct ldap_search_context *ldap_ctx = res;
1404
1405
TRACE("%p,%p\n", iface, res);
1406
1407
if (!res) return E_ADS_BAD_PARAMETER;
1408
1409
if (!ldap_ctx->entry)
1410
{
1411
ldap_ctx->count = ldap_count_entries(ldap->ld, ldap_ctx->res);
1412
ldap_ctx->pos = 0;
1413
1414
if (ldap_ctx->pos >= ldap_ctx->count)
1415
return S_ADS_NOMORE_ROWS;
1416
1417
ldap_ctx->entry = ldap_first_entry(ldap->ld, ldap_ctx->res);
1418
}
1419
else
1420
{
1421
if (ldap_ctx->pos >= ldap_ctx->count)
1422
{
1423
if (ldap_ctx->page)
1424
{
1425
ULONG err, count;
1426
1427
ldap_msgfree(ldap_ctx->res);
1428
ldap_ctx->res = NULL;
1429
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)
1432
{
1433
ldap_ctx->count = ldap_count_entries(ldap->ld, ldap_ctx->res);
1434
ldap_ctx->pos = 0;
1435
1436
if (ldap_ctx->pos >= ldap_ctx->count)
1437
return S_ADS_NOMORE_ROWS;
1438
1439
ldap_ctx->entry = ldap_first_entry(ldap->ld, ldap_ctx->res);
1440
goto exit;
1441
}
1442
1443
if (err != LDAP_NO_RESULTS_RETURNED)
1444
{
1445
TRACE("ldap_get_next_page_s error %#lx\n", err);
1446
return HRESULT_FROM_WIN32(map_ldap_error(err));
1447
}
1448
/* fall through */
1449
}
1450
1451
return S_ADS_NOMORE_ROWS;
1452
}
1453
1454
ldap_ctx->entry = ldap_next_entry(ldap->ld, ldap_ctx->entry);
1455
}
1456
1457
exit:
1458
if (!ldap_ctx->entry)
1459
return S_ADS_NOMORE_ROWS;
1460
1461
ldap_ctx->pos++;
1462
if (ldap_ctx->ber) ber_free(ldap_ctx->ber, 0);
1463
ldap_ctx->ber = NULL;
1464
1465
return S_OK;
1466
}
1467
1468
static HRESULT WINAPI search_GetPreviousRow(IDirectorySearch *iface, ADS_SEARCH_HANDLE res)
1469
{
1470
FIXME("%p,%p: stub\n", iface, res);
1471
return E_NOTIMPL;
1472
}
1473
1474
static HRESULT WINAPI search_GetNextColumnName(IDirectorySearch *iface, ADS_SEARCH_HANDLE res, LPWSTR *name)
1475
{
1476
LDAP_namespace *ldap = impl_from_IDirectorySearch(iface);
1477
struct ldap_search_context *ldap_ctx = res;
1478
WCHAR *attr;
1479
1480
TRACE("%p,%p,%p\n", iface, res, name);
1481
1482
if (!name || !ldap_ctx || !ldap_ctx->entry) return E_ADS_BAD_PARAMETER;
1483
1484
if (!ldap_ctx->ber)
1485
{
1486
attr = ldap_first_attributeW(ldap->ld, ldap_ctx->entry, &ldap_ctx->ber);
1487
ldap_ctx->add_ADsPath = TRUE;
1488
}
1489
else
1490
attr = ldap_next_attributeW(ldap->ld, ldap_ctx->entry, ldap_ctx->ber);
1491
1492
if (attr)
1493
{
1494
TRACE("=> %s\n", debugstr_w(attr));
1495
*name = AllocADsStr(attr);
1496
ldap_memfreeW(attr);
1497
return *name ? S_OK : E_OUTOFMEMORY;
1498
}
1499
else if (ldap_ctx->add_ADsPath)
1500
{
1501
ldap_ctx->add_ADsPath = FALSE;
1502
*name = AllocADsStr((WCHAR *)L"ADsPath");
1503
TRACE("=> %s\n", debugstr_w(*name));
1504
return *name ? S_OK : E_OUTOFMEMORY;
1505
}
1506
1507
*name = NULL;
1508
return S_ADS_NOMORE_COLUMNS;
1509
}
1510
1511
static HRESULT add_column_values(LDAP_namespace *ldap, struct ldap_search_context *ldap_ctx,
1512
LPWSTR name, ADS_SEARCH_COLUMN *col)
1513
{
1514
ADSTYPEENUM type;
1515
DWORD i, count;
1516
1517
type = get_schema_type(name, ldap->at, ldap->at_single_count, ldap->at_multiple_count);
1518
TRACE("%s => type %d\n", debugstr_w(name), type);
1519
1520
switch (type)
1521
{
1522
default:
1523
FIXME("no special handling for type %d\n", type);
1524
/* fall through */
1525
case ADSTYPE_DN_STRING:
1526
case ADSTYPE_CASE_EXACT_STRING:
1527
case ADSTYPE_CASE_IGNORE_STRING:
1528
case ADSTYPE_PRINTABLE_STRING:
1529
{
1530
WCHAR **values = ldap_get_valuesW(ldap->ld, ldap_ctx->entry, name);
1531
if (!values)
1532
return E_ADS_COLUMN_NOT_SET;
1533
count = ldap_count_valuesW(values);
1534
1535
col->pADsValues = calloc(count, sizeof(col->pADsValues[0]));
1536
if (!col->pADsValues)
1537
{
1538
ldap_value_freeW(values);
1539
return E_OUTOFMEMORY;
1540
}
1541
1542
for (i = 0; i < count; i++)
1543
{
1544
TRACE("=> %s\n", debugstr_w(values[i]));
1545
col->pADsValues[i].dwType = type;
1546
col->pADsValues[i].CaseIgnoreString = values[i];
1547
}
1548
1549
col->hReserved = values;
1550
break;
1551
}
1552
1553
case ADSTYPE_BOOLEAN:
1554
{
1555
WCHAR **values = ldap_get_valuesW(ldap->ld, ldap_ctx->entry, name);
1556
if (!values)
1557
return E_ADS_COLUMN_NOT_SET;
1558
count = ldap_count_valuesW(values);
1559
1560
col->pADsValues = calloc(count, sizeof(col->pADsValues[0]));
1561
if (!col->pADsValues)
1562
{
1563
ldap_value_freeW(values);
1564
return E_OUTOFMEMORY;
1565
}
1566
1567
for (i = 0; i < count; i++)
1568
{
1569
col->pADsValues[i].dwType = type;
1570
1571
if (!wcsicmp(values[i], L"TRUE"))
1572
col->pADsValues[i].Boolean = 1;
1573
else if (!wcsicmp(values[i], L"FALSE"))
1574
col->pADsValues[i].Boolean = 0;
1575
else
1576
{
1577
FIXME("not recognized boolean value %s\n", debugstr_w(values[i]));
1578
col->pADsValues[i].Boolean = 0;
1579
}
1580
TRACE("%s => %ld\n", debugstr_w(values[i]), col->pADsValues[i].Boolean);
1581
}
1582
1583
ldap_value_freeW(values);
1584
col->hReserved = NULL;
1585
break;
1586
}
1587
1588
case ADSTYPE_INTEGER:
1589
case ADSTYPE_LARGE_INTEGER:
1590
{
1591
struct berval **values = ldap_get_values_lenW(ldap->ld, ldap_ctx->entry, name);
1592
if (!values)
1593
return E_ADS_COLUMN_NOT_SET;
1594
count = ldap_count_values_len(values);
1595
1596
col->pADsValues = calloc(count, sizeof(col->pADsValues[0]));
1597
if (!col->pADsValues)
1598
{
1599
ldap_value_free_len(values);
1600
return E_OUTOFMEMORY;
1601
}
1602
1603
for (i = 0; i < count; i++)
1604
{
1605
col->pADsValues[i].dwType = type;
1606
1607
if (type == ADSTYPE_LARGE_INTEGER)
1608
{
1609
col->pADsValues[i].LargeInteger.QuadPart = _atoi64(values[i]->bv_val);
1610
TRACE("%s => %s\n", debugstr_an(values[i]->bv_val, values[i]->bv_len), wine_dbgstr_longlong(col->pADsValues[i].LargeInteger.QuadPart));
1611
}
1612
else
1613
{
1614
col->pADsValues[i].Integer = atol(values[i]->bv_val);
1615
TRACE("%s => %ld\n", debugstr_an(values[i]->bv_val, values[i]->bv_len), col->pADsValues[i].Integer);
1616
}
1617
}
1618
1619
ldap_value_free_len(values);
1620
col->hReserved = NULL;
1621
break;
1622
}
1623
1624
case ADSTYPE_OCTET_STRING:
1625
case ADSTYPE_NT_SECURITY_DESCRIPTOR:
1626
{
1627
struct berval **values = ldap_get_values_lenW(ldap->ld, ldap_ctx->entry, name);
1628
if (!values)
1629
return E_ADS_COLUMN_NOT_SET;
1630
count = ldap_count_values_len(values);
1631
1632
col->pADsValues = calloc(count, sizeof(col->pADsValues[0]));
1633
if (!col->pADsValues)
1634
{
1635
ldap_value_free_len(values);
1636
return E_OUTOFMEMORY;
1637
}
1638
1639
for (i = 0; i < count; i++)
1640
{
1641
TRACE("=> %s\n", debugstr_an(values[i]->bv_val, values[i]->bv_len));
1642
col->pADsValues[i].dwType = type;
1643
col->pADsValues[i].OctetString.dwLength = values[i]->bv_len;
1644
col->pADsValues[i].OctetString.lpValue = (BYTE *)values[i]->bv_val;
1645
}
1646
1647
col->hReserved = values;
1648
break;
1649
}
1650
1651
case ADSTYPE_UTC_TIME:
1652
{
1653
struct berval **values = ldap_get_values_lenW(ldap->ld, ldap_ctx->entry, name);
1654
if (!values)
1655
return E_ADS_COLUMN_NOT_SET;
1656
count = ldap_count_values_len(values);
1657
1658
col->pADsValues = calloc(count, sizeof(col->pADsValues[0]));
1659
if (!col->pADsValues)
1660
{
1661
ldap_value_free_len(values);
1662
return E_OUTOFMEMORY;
1663
}
1664
1665
for (i = 0; i < count; i++)
1666
{
1667
col->pADsValues[i].dwType = type;
1668
if (values[i]->bv_len < 14 ||
1669
_snscanf_l(values[i]->bv_val, values[i]->bv_len, "%04hu%02hu%02hu%02hu%02hu%02hu", NULL,
1670
&col->pADsValues[i].UTCTime.wYear, &col->pADsValues[i].UTCTime.wMonth,
1671
&col->pADsValues[i].UTCTime.wDay, &col->pADsValues[i].UTCTime.wHour,
1672
&col->pADsValues[i].UTCTime.wMinute, &col->pADsValues[i].UTCTime.wSecond) != 6)
1673
{
1674
FIXME("not recognized UTCTime: %s\n", debugstr_an(values[i]->bv_val, values[i]->bv_len));
1675
memset(&col->pADsValues[i].UTCTime, 0, sizeof(col->pADsValues[i].UTCTime));
1676
continue;
1677
}
1678
1679
if ((values[i]->bv_val[14] != '.' && values[i]->bv_val[14] != ',') ||
1680
values[i]->bv_val[15] != '0' || values[i]->bv_val[16] != 'Z')
1681
FIXME("not handled time zone: %s\n", debugstr_an(values[i]->bv_val + 14, values[i]->bv_len - 14));
1682
1683
TRACE("%s => %02u.%02u.%04u %02u:%02u:%02u\n", debugstr_an(values[i]->bv_val, values[i]->bv_len),
1684
col->pADsValues[i].UTCTime.wDay, col->pADsValues[i].UTCTime.wMonth,
1685
col->pADsValues[i].UTCTime.wYear, col->pADsValues[i].UTCTime.wHour,
1686
col->pADsValues[i].UTCTime.wMinute, col->pADsValues[i].UTCTime.wSecond);
1687
}
1688
1689
ldap_value_free_len(values);
1690
col->hReserved = NULL;
1691
break;
1692
}
1693
1694
case ADSTYPE_DN_WITH_BINARY:
1695
{
1696
static const BYTE hex2bin[] =
1697
{
1698
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x00 */
1699
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x10 */
1700
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x20 */
1701
0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, /* 0x30 */
1702
0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0, /* 0x40 */
1703
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x50 */
1704
0,10,11,12,13,14,15 /* 0x60 */
1705
};
1706
ADS_DN_WITH_BINARY *dnb;
1707
WCHAR **values = ldap_get_valuesW(ldap->ld, ldap_ctx->entry, name);
1708
if (!values)
1709
return E_ADS_COLUMN_NOT_SET;
1710
count = ldap_count_valuesW(values);
1711
1712
col->pADsValues = calloc(count, sizeof(col->pADsValues[0]) + sizeof(col->pADsValues[0].pDNWithBinary[0]));
1713
if (!col->pADsValues)
1714
{
1715
ldap_value_freeW(values);
1716
return E_OUTOFMEMORY;
1717
}
1718
1719
dnb = (ADS_DN_WITH_BINARY *)(col->pADsValues + count);
1720
1721
for (i = 0; i < count; i++)
1722
{
1723
WCHAR *p = values[i];
1724
DWORD n;
1725
1726
col->pADsValues[i].dwType = type;
1727
col->pADsValues[i].pDNWithBinary = dnb++;
1728
1729
if ((p[0] != 'b' && p[0] != 'B') || p[1] != ':')
1730
FIXME("wrong DN with binary tag '%c%c'\n", p[0], p[1]);
1731
p += 2;
1732
1733
col->pADsValues[i].pDNWithBinary->dwLength = wcstol(p, &p, 10) / 2;
1734
if (*p != ':')
1735
FIXME("wrong DN with binary separator '%c'\n", *p);
1736
p++;
1737
col->pADsValues[i].pDNWithBinary->lpBinaryValue = (BYTE *)p;
1738
/* decode values in-place */
1739
for (n = 0; n < col->pADsValues[i].pDNWithBinary->dwLength; n++, p += 2)
1740
{
1741
BYTE b;
1742
1743
if (p[0] > 'f' || (p[0] != '0' && !hex2bin[p[0]]) ||
1744
p[1] > 'f' || (p[1] != '0' && !hex2bin[p[1]]))
1745
{
1746
FIXME("bad hex encoding at %s\n", debugstr_w(p));
1747
continue;
1748
}
1749
1750
b = (hex2bin[p[0]] << 4) | hex2bin[p[1]];
1751
col->pADsValues[i].pDNWithBinary->lpBinaryValue[n] = b;
1752
}
1753
if (*p != ':')
1754
FIXME("wrong DN with binary separator '%c'\n", *p);
1755
col->pADsValues[i].pDNWithBinary->pszDNString = p + 1;
1756
1757
TRACE("%s => %lu,%s,%s\n", debugstr_w(values[i]),
1758
col->pADsValues[i].pDNWithBinary->dwLength,
1759
debugstr_an((char *)col->pADsValues[i].pDNWithBinary->lpBinaryValue, col->pADsValues[i].pDNWithBinary->dwLength),
1760
debugstr_w(col->pADsValues[i].pDNWithBinary->pszDNString));
1761
}
1762
1763
col->hReserved = values;
1764
break;
1765
}
1766
}
1767
1768
col->dwADsType = type;
1769
col->dwNumValues = count;
1770
col->pszAttrName = wcsdup(name);
1771
1772
return S_OK;
1773
}
1774
1775
static HRESULT WINAPI search_GetColumn(IDirectorySearch *iface, ADS_SEARCH_HANDLE res,
1776
LPWSTR name, PADS_SEARCH_COLUMN col)
1777
{
1778
LDAP_namespace *ldap = impl_from_IDirectorySearch(iface);
1779
struct ldap_search_context *ldap_ctx = res;
1780
HRESULT hr;
1781
ULONG count;
1782
1783
TRACE("%p,%p,%s,%p\n", iface, res, debugstr_w(name), col);
1784
1785
if (!res || !name || !ldap_ctx->entry) return E_ADS_BAD_PARAMETER;
1786
1787
memset(col, 0, sizeof(*col));
1788
1789
if (!wcsicmp(name, L"ADsPath"))
1790
{
1791
WCHAR *dn = ldap_get_dnW(ldap->ld, ldap_ctx->entry);
1792
1793
col->pADsValues = malloc(sizeof(col->pADsValues[0]));
1794
if (!col->pADsValues)
1795
{
1796
hr = E_OUTOFMEMORY;
1797
goto exit;
1798
}
1799
1800
count = sizeof(L"LDAP://") + (wcslen(ldap->host) + 1 /* '/' */) * sizeof(WCHAR);
1801
if (dn) count += wcslen(dn) * sizeof(WCHAR);
1802
1803
col->pADsValues[0].CaseIgnoreString = malloc(count);
1804
if (!col->pADsValues[0].CaseIgnoreString)
1805
{
1806
hr = E_OUTOFMEMORY;
1807
goto exit;
1808
}
1809
1810
wcscpy(col->pADsValues[0].CaseIgnoreString, L"LDAP://");
1811
wcscat(col->pADsValues[0].CaseIgnoreString, ldap->host);
1812
wcscat(col->pADsValues[0].CaseIgnoreString, L"/");
1813
if (dn) wcscat(col->pADsValues[0].CaseIgnoreString, dn);
1814
col->pADsValues[0].dwType = ADSTYPE_CASE_IGNORE_STRING;
1815
col->dwADsType = ADSTYPE_CASE_IGNORE_STRING;
1816
col->dwNumValues = 1;
1817
col->pszAttrName = wcsdup(name);
1818
col->hReserved = NULL;
1819
1820
TRACE("=> %s\n", debugstr_w(col->pADsValues[0].CaseIgnoreString));
1821
hr = S_OK;
1822
exit:
1823
ldap_memfreeW(dn);
1824
return hr;
1825
}
1826
1827
return add_column_values(ldap, ldap_ctx, name, col);
1828
}
1829
1830
static HRESULT WINAPI search_FreeColumn(IDirectorySearch *iface, PADS_SEARCH_COLUMN col)
1831
{
1832
TRACE("%p,%p\n", iface, col);
1833
1834
if (!col) return E_ADS_BAD_PARAMETER;
1835
1836
if (!wcsicmp(col->pszAttrName, L"ADsPath"))
1837
free(col->pADsValues[0].CaseIgnoreString);
1838
free(col->pADsValues);
1839
free(col->pszAttrName);
1840
1841
if (col->hReserved)
1842
{
1843
if (col->dwADsType == ADSTYPE_OCTET_STRING || col->dwADsType == ADSTYPE_NT_SECURITY_DESCRIPTOR)
1844
ldap_value_free_len(col->hReserved);
1845
else
1846
ldap_value_freeW(col->hReserved);
1847
}
1848
1849
return S_OK;
1850
}
1851
1852
static HRESULT WINAPI search_CloseSearchHandle(IDirectorySearch *iface, ADS_SEARCH_HANDLE res)
1853
{
1854
LDAP_namespace *ldap = impl_from_IDirectorySearch(iface);
1855
struct ldap_search_context *ldap_ctx = res;
1856
1857
TRACE("%p,%p\n", iface, res);
1858
1859
if (!res) return E_ADS_BAD_PARAMETER;
1860
1861
if (ldap_ctx->page)
1862
ldap_search_abandon_page(ldap->ld, ldap_ctx->page);
1863
if (ldap_ctx->res)
1864
ldap_msgfree(ldap_ctx->res);
1865
if (ldap_ctx->ber)
1866
ber_free(ldap_ctx->ber, 0);
1867
free(ldap_ctx);
1868
1869
return S_OK;
1870
}
1871
1872
static const IDirectorySearchVtbl IDirectorySearch_vtbl =
1873
{
1874
search_QueryInterface,
1875
search_AddRef,
1876
search_Release,
1877
search_SetSearchPreference,
1878
search_ExecuteSearch,
1879
search_AbandonSearch,
1880
search_GetFirstRow,
1881
search_GetNextRow,
1882
search_GetPreviousRow,
1883
search_GetNextColumnName,
1884
search_GetColumn,
1885
search_FreeColumn,
1886
search_CloseSearchHandle
1887
};
1888
1889
static inline LDAP_namespace *impl_from_IDirectoryObject(IDirectoryObject *iface)
1890
{
1891
return CONTAINING_RECORD(iface, LDAP_namespace, IDirectoryObject_iface);
1892
}
1893
1894
static HRESULT WINAPI dirobj_QueryInterface(IDirectoryObject *iface, REFIID riid, void **obj)
1895
{
1896
LDAP_namespace *ldap = impl_from_IDirectoryObject(iface);
1897
1898
TRACE("%p,%s,%p\n", iface, debugstr_guid(riid), obj);
1899
1900
if (!riid || !obj) return E_INVALIDARG;
1901
1902
if (IsEqualGUID(riid, &IID_IDirectoryObject) ||
1903
IsEqualGUID(riid, &IID_IUnknown))
1904
{
1905
IDirectoryObject_AddRef(iface);
1906
*obj = iface;
1907
return S_OK;
1908
}
1909
1910
return IADs_QueryInterface(&ldap->IADs_iface, riid, obj);
1911
}
1912
1913
static ULONG WINAPI dirobj_AddRef(IDirectoryObject *iface)
1914
{
1915
LDAP_namespace *ldap = impl_from_IDirectoryObject(iface);
1916
return IADs_AddRef(&ldap->IADs_iface);
1917
}
1918
1919
static ULONG WINAPI dirobj_Release(IDirectoryObject *iface)
1920
{
1921
LDAP_namespace *ldap = impl_from_IDirectoryObject(iface);
1922
return IADs_Release(&ldap->IADs_iface);
1923
}
1924
1925
static HRESULT WINAPI dirobj_GetObjectInformation(IDirectoryObject *iface, PADS_OBJECT_INFO *info)
1926
{
1927
FIXME("%p,%p: stub\n", iface, info);
1928
return E_NOTIMPL;
1929
}
1930
1931
static HRESULT WINAPI dirobj_GetObjectAttributes(IDirectoryObject *iface, LPWSTR *names,
1932
DWORD count, PADS_ATTR_INFO *attrs, DWORD *count_returned)
1933
{
1934
FIXME("%p,%p,%lu,%p,%p: stub\n", iface, names, count, attrs, count_returned);
1935
return E_NOTIMPL;
1936
}
1937
1938
static HRESULT WINAPI dirobj_SetObjectAttributes(IDirectoryObject *iface, PADS_ATTR_INFO attrs,
1939
DWORD count, DWORD *count_set)
1940
{
1941
FIXME("%p,%p,%lu,%p: stub\n", iface, attrs, count, count_set);
1942
return E_NOTIMPL;
1943
}
1944
1945
static HRESULT WINAPI dirobj_CreateDSObject(IDirectoryObject *iface, LPWSTR name,
1946
PADS_ATTR_INFO attrs, DWORD count, IDispatch **obj)
1947
{
1948
FIXME("%p,%s,%p,%lu,%p: stub\n", iface, debugstr_w(name), attrs, count, obj);
1949
return E_NOTIMPL;
1950
}
1951
1952
static HRESULT WINAPI dirobj_DeleteDSObject(IDirectoryObject *iface, LPWSTR name)
1953
{
1954
FIXME("%p,%s: stub\n", iface, debugstr_w(name));
1955
return E_NOTIMPL;
1956
}
1957
1958
static const IDirectoryObjectVtbl IDirectoryObject_vtbl =
1959
{
1960
dirobj_QueryInterface,
1961
dirobj_AddRef,
1962
dirobj_Release,
1963
dirobj_GetObjectInformation,
1964
dirobj_GetObjectAttributes,
1965
dirobj_SetObjectAttributes,
1966
dirobj_CreateDSObject,
1967
dirobj_DeleteDSObject
1968
};
1969
1970
static HRESULT LDAPNamespace_create(REFIID riid, void **obj)
1971
{
1972
LDAP_namespace *ldap;
1973
HRESULT hr;
1974
1975
ldap = malloc(sizeof(*ldap));
1976
if (!ldap) return E_OUTOFMEMORY;
1977
1978
ldap->IADs_iface.lpVtbl = &IADs_vtbl;
1979
ldap->IADsOpenDSObject_iface.lpVtbl = &IADsOpenDSObject_vtbl;
1980
ldap->IDirectorySearch_iface.lpVtbl = &IDirectorySearch_vtbl;
1981
ldap->IDirectoryObject_iface.lpVtbl = &IDirectoryObject_vtbl;
1982
ldap->ref = 1;
1983
ldap->ld = NULL;
1984
ldap->host = NULL;
1985
ldap->object = NULL;
1986
ldap->attrs_count = 0;
1987
ldap->attrs_count_allocated = 0;
1988
ldap->attrs = NULL;
1989
ldap->search.scope = ADS_SCOPE_SUBTREE;
1990
ldap->search.pagesize = 0;
1991
ldap->search.size_limit = 0;
1992
ldap->search.cache_results = TRUE;
1993
ldap->search.attribtypes_only = FALSE;
1994
ldap->search.tombstone = FALSE;
1995
ldap->at = NULL;
1996
ldap->at_single_count = 0;
1997
ldap->at_multiple_count = 0;
1998
1999
hr = IADs_QueryInterface(&ldap->IADs_iface, riid, obj);
2000
IADs_Release(&ldap->IADs_iface);
2001
2002
return hr;
2003
}
2004
2005
static const struct class_info
2006
{
2007
const CLSID *clsid;
2008
HRESULT (*constructor)(REFIID, void **);
2009
} class_info[] =
2010
{
2011
{ &CLSID_ADSystemInfo, ADSystemInfo_create },
2012
{ &CLSID_LDAP, LDAP_create },
2013
{ &CLSID_LDAPNamespace, LDAPNamespace_create },
2014
};
2015
2016
typedef struct
2017
{
2018
IClassFactory IClassFactory_iface;
2019
LONG ref;
2020
const struct class_info *info;
2021
} class_factory;
2022
2023
static inline class_factory *impl_from_IClassFactory(IClassFactory *iface)
2024
{
2025
return CONTAINING_RECORD(iface, class_factory, IClassFactory_iface);
2026
}
2027
2028
static HRESULT WINAPI factory_QueryInterface(IClassFactory *iface, REFIID riid, LPVOID *obj)
2029
{
2030
TRACE("%p,%s,%p\n", iface, debugstr_guid(riid), obj);
2031
2032
if (!riid || !obj) return E_INVALIDARG;
2033
2034
if (IsEqualIID(riid, &IID_IUnknown) ||
2035
IsEqualIID(riid, &IID_IClassFactory))
2036
{
2037
IClassFactory_AddRef(iface);
2038
*obj = iface;
2039
return S_OK;
2040
}
2041
2042
*obj = NULL;
2043
FIXME("interface %s is not implemented\n", debugstr_guid(riid));
2044
return E_NOINTERFACE;
2045
}
2046
2047
static ULONG WINAPI factory_AddRef(IClassFactory *iface)
2048
{
2049
class_factory *factory = impl_from_IClassFactory(iface);
2050
ULONG ref = InterlockedIncrement(&factory->ref);
2051
2052
TRACE("(%p) ref %lu\n", iface, ref);
2053
2054
return ref;
2055
}
2056
2057
static ULONG WINAPI factory_Release(IClassFactory *iface)
2058
{
2059
class_factory *factory = impl_from_IClassFactory(iface);
2060
ULONG ref = InterlockedDecrement(&factory->ref);
2061
2062
TRACE("(%p) ref %lu\n", iface, ref);
2063
2064
if (!ref)
2065
free(factory);
2066
2067
return ref;
2068
}
2069
2070
static HRESULT WINAPI factory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **obj)
2071
{
2072
class_factory *factory = impl_from_IClassFactory(iface);
2073
2074
TRACE("%p,%s,%p\n", outer, debugstr_guid(riid), obj);
2075
2076
if (!riid || !obj) return E_INVALIDARG;
2077
2078
*obj = NULL;
2079
if (outer) return CLASS_E_NOAGGREGATION;
2080
2081
return factory->info->constructor(riid, obj);
2082
}
2083
2084
static HRESULT WINAPI factory_LockServer(IClassFactory *iface, BOOL lock)
2085
{
2086
FIXME("%p,%d: stub\n", iface, lock);
2087
return S_OK;
2088
}
2089
2090
static const struct IClassFactoryVtbl factory_vtbl =
2091
{
2092
factory_QueryInterface,
2093
factory_AddRef,
2094
factory_Release,
2095
factory_CreateInstance,
2096
factory_LockServer
2097
};
2098
2099
static HRESULT factory_constructor(const struct class_info *info, REFIID riid, void **obj)
2100
{
2101
class_factory *factory;
2102
HRESULT hr;
2103
2104
factory = malloc(sizeof(*factory));
2105
if (!factory) return E_OUTOFMEMORY;
2106
2107
factory->IClassFactory_iface.lpVtbl = &factory_vtbl;
2108
factory->ref = 1;
2109
factory->info = info;
2110
2111
hr = IClassFactory_QueryInterface(&factory->IClassFactory_iface, riid, obj);
2112
IClassFactory_Release(&factory->IClassFactory_iface);
2113
2114
return hr;
2115
}
2116
2117
HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID iid, LPVOID *obj)
2118
{
2119
int i;
2120
2121
TRACE("%s,%s,%p\n", debugstr_guid(clsid), debugstr_guid(iid), obj);
2122
2123
if (!clsid || !iid || !obj) return E_INVALIDARG;
2124
2125
*obj = NULL;
2126
2127
for (i = 0; i < ARRAY_SIZE(class_info); i++)
2128
{
2129
if (IsEqualCLSID(class_info[i].clsid, clsid))
2130
return factory_constructor(&class_info[i], iid, obj);
2131
}
2132
2133
FIXME("class %s/%s is not implemented\n", debugstr_guid(clsid), debugstr_guid(iid));
2134
return CLASS_E_CLASSNOTAVAILABLE;
2135
}
2136
2137