~ubuntu-branches/ubuntu/oneiric/likewise-open/oneiric

« back to all changes in this revision

Viewing changes to lsass/server/auth-providers/ad-open-provider/batch_enum.c

  • Committer: Bazaar Package Importer
  • Author(s): Scott Salley
  • Date: 2010-11-22 12:06:00 UTC
  • mfrom: (1.1.6 upstream)
  • Revision ID: james.westby@ubuntu.com-20101122120600-8lba1fpceot71wlb
Tags: 6.0.0.53010-1
Likewise Open 6.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Editor Settings: expandtabs and use 4 spaces for indentation
 
2
 * ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: *
 
3
 * -*- mode: c, c-basic-offset: 4 -*- */
 
4
 
 
5
/*
 
6
 * Copyright Likewise Software    2004-2008
 
7
 * All rights reserved.
 
8
 *
 
9
 * This program is free software; you can redistribute it and/or modify
 
10
 * it under the terms of the GNU General Public License as published by
 
11
 * the Free Software Foundation; either version 2 of the License, or (at
 
12
 * your option) any later version.
 
13
 *
 
14
 * This program is distributed in the hope that it will be useful, but
 
15
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 
16
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 
17
 * for more details.  You should have received a copy of the GNU General
 
18
 * Public License along with this program.  If not, see
 
19
 * <http://www.gnu.org/licenses/>.
 
20
 *
 
21
 * LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING
 
22
 * TERMS AS WELL.  IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT
 
23
 * WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE
 
24
 * TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU
 
25
 * GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE.  IF YOU
 
26
 * HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING
 
27
 * TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT
 
28
 * license@likewisesoftware.com
 
29
 */
 
30
 
 
31
/*
 
32
 * Copyright (C) Likewise Software. All rights reserved.
 
33
 *
 
34
 * Module Name:
 
35
 *
 
36
 *        batch_enum.c
 
37
 *
 
38
 * Abstract:
 
39
 *
 
40
 *        Likewise Security and Authentication Subsystem (LSASS)
 
41
 *
 
42
 *        Active Directory Authentication Provider
 
43
 *
 
44
 * Authors: Wei Fu (wfu@likewisesoftware.com)
 
45
 *          Danilo Almeida (dalmeida@likewisesoftware.com)
 
46
 */
 
47
 
 
48
#include "adprovider.h"
 
49
#include "batch_common.h"
 
50
#include "batch_gather.h"
 
51
#include "batch_marshal.h"
 
52
 
 
53
typedef struct __AD_CELL_COOKIE_DATA
 
54
{
 
55
    // Initially, this is set to NULL to indicate that the primary cell
 
56
    // should be searched.
 
57
    const DLINKEDLIST* pCurrentCell;
 
58
    PLSA_DM_LDAP_CONNECTION pLdapConn;
 
59
    LW_SEARCH_COOKIE LdapCookie;
 
60
 
 
61
    // This hash table is used to ensure that the same user/group is not
 
62
    // returned twice through linked cells. It is only allocated if linked
 
63
    // cells are used in the computer's cell.
 
64
    PLSA_HASH_TABLE pEnumeratedSids;
 
65
} AD_CELL_COOKIE_DATA, *PAD_CELL_COOKIE_DATA;
 
66
 
 
67
static
 
68
VOID
 
69
LsaAdBatchFreeCellCookie(
 
70
    IN OUT PVOID pvCookie
 
71
    )
 
72
{
 
73
    PAD_CELL_COOKIE_DATA pData = (PAD_CELL_COOKIE_DATA)pvCookie;
 
74
 
 
75
    if (pData != NULL)
 
76
    {
 
77
        LwFreeCookieContents(&pData->LdapCookie);
 
78
        LsaDmLdapClose(pData->pLdapConn);
 
79
        LsaHashSafeFree(&pData->pEnumeratedSids);
 
80
 
 
81
        LW_SAFE_FREE_MEMORY(pData);
 
82
    }
 
83
}
 
84
 
 
85
static
 
86
DWORD
 
87
LsaAdBatchEnumGetNoMoreError(
 
88
    IN LSA_AD_BATCH_OBJECT_TYPE ObjectType
 
89
    )
 
90
{
 
91
    DWORD dwError = 0;
 
92
 
 
93
    switch (ObjectType)
 
94
    {
 
95
        case LSA_AD_BATCH_OBJECT_TYPE_USER:
 
96
            dwError = LW_ERROR_NO_MORE_USERS;
 
97
            break;
 
98
        case LSA_AD_BATCH_OBJECT_TYPE_GROUP:
 
99
            dwError = LW_ERROR_NO_MORE_GROUPS;
 
100
            break;
 
101
        default:
 
102
            LSA_ASSERT(FALSE);
 
103
            dwError = LW_ERROR_INTERNAL;
 
104
    }
 
105
 
 
106
    return dwError;
 
107
}
 
108
 
 
109
static
 
110
DWORD
 
111
LsaAdBatchEnumGetScopeRoot(
 
112
    IN LSA_AD_BATCH_OBJECT_TYPE ObjectType,
 
113
    IN BOOLEAN bIsByRealObject,
 
114
    IN OPTIONAL PCSTR pszDnsDomainName,
 
115
    IN OPTIONAL PCSTR pszCellDn,
 
116
    OUT PSTR* ppszScopeRoot
 
117
    )
 
118
{
 
119
    DWORD dwError = 0;
 
120
    PSTR pszScopeRoot = NULL;
 
121
 
 
122
    if (bIsByRealObject)
 
123
    {
 
124
        dwError = LwLdapConvertDomainToDN(pszDnsDomainName, &pszScopeRoot);
 
125
        BAIL_ON_LSA_ERROR(dwError);
 
126
    }
 
127
    else
 
128
    {
 
129
        PCSTR pszContainer = NULL;
 
130
        switch (ObjectType)
 
131
        {
 
132
            case LSA_AD_BATCH_OBJECT_TYPE_USER:
 
133
                pszContainer = "Users";
 
134
                break;
 
135
            case LSA_AD_BATCH_OBJECT_TYPE_GROUP:
 
136
                pszContainer = "Groups";
 
137
                break;
 
138
            default:
 
139
                LSA_ASSERT(FALSE);
 
140
                dwError = LW_ERROR_INTERNAL;
 
141
                BAIL_ON_LSA_ERROR(dwError);
 
142
        }
 
143
 
 
144
        dwError = LwAllocateStringPrintf(
 
145
                        &pszScopeRoot,
 
146
                        "CN=%s,%s",
 
147
                        pszContainer,
 
148
                        pszCellDn);
 
149
        BAIL_ON_LSA_ERROR(dwError);
 
150
    }
 
151
 
 
152
cleanup:
 
153
    *ppszScopeRoot = pszScopeRoot;
 
154
    return dwError;
 
155
 
 
156
error:
 
157
    LW_SAFE_FREE_STRING(pszScopeRoot);
 
158
    goto cleanup;
 
159
}
 
160
 
 
161
 
 
162
static
 
163
PCSTR
 
164
LsaAdBatchEnumGetRealQuery(
 
165
    IN BOOLEAN bIsSchemaMode,
 
166
    IN LSA_AD_BATCH_OBJECT_TYPE ObjectType
 
167
    )
 
168
{
 
169
    PCSTR pszQuery = NULL;
 
170
 
 
171
    if (bIsSchemaMode)
 
172
    {
 
173
        switch (ObjectType)
 
174
        {
 
175
            case LSA_AD_BATCH_OBJECT_TYPE_USER:
 
176
                pszQuery = "(&(objectClass=User)(!(objectClass=Computer))(sAMAccountName=*)(uidNumber=*))";
 
177
                break;
 
178
            case LSA_AD_BATCH_OBJECT_TYPE_GROUP:
 
179
                pszQuery = "(&(objectClass=Group)(!(objectClass=Computer))(sAMAccountName=*)(gidNumber=*))";
 
180
                break;
 
181
        }
 
182
    }
 
183
    else
 
184
    {
 
185
        switch (ObjectType)
 
186
        {
 
187
            case LSA_AD_BATCH_OBJECT_TYPE_USER:
 
188
                pszQuery = "(&(objectClass=User)(!(objectClass=Computer))(sAMAccountName=*))";
 
189
                break;
 
190
            case LSA_AD_BATCH_OBJECT_TYPE_GROUP:
 
191
                pszQuery = "(&(objectClass=Group)(!(objectClass=Computer))(sAMAccountName=*))";
 
192
                break;
 
193
        }
 
194
    }
 
195
 
 
196
    return pszQuery;
 
197
}
 
198
 
 
199
static
 
200
PCSTR
 
201
LsaAdBatchEnumGetPseudoQuery(
 
202
    IN BOOLEAN bIsSchemaMode,
 
203
    IN LSA_AD_BATCH_OBJECT_TYPE ObjectType
 
204
    )
 
205
{
 
206
    PCSTR pszQuery = NULL;
 
207
 
 
208
    if (bIsSchemaMode)
 
209
    {
 
210
        switch (ObjectType)
 
211
        {
 
212
            case LSA_AD_BATCH_OBJECT_TYPE_USER:
 
213
                pszQuery = "(&(objectClass=posixAccount)(keywords=objectClass=centerisLikewiseUser)(uidNumber=*))";
 
214
                break;
 
215
            case LSA_AD_BATCH_OBJECT_TYPE_GROUP:
 
216
                pszQuery = "(&(objectClass=posixGroup)(keywords=objectClass=centerisLikewiseGroup)(gidNumber=*))";
 
217
                break;
 
218
        }
 
219
    }
 
220
    else
 
221
    {
 
222
        switch (ObjectType)
 
223
        {
 
224
            case LSA_AD_BATCH_OBJECT_TYPE_USER:
 
225
                pszQuery = "(&(objectClass=serviceConnectionPoint)(keywords=objectClass=centerisLikewiseUser)(keywords=uidNumber=*))";
 
226
                break;
 
227
            case LSA_AD_BATCH_OBJECT_TYPE_GROUP:
 
228
                pszQuery = "(&(objectClass=serviceConnectionPoint)(keywords=objectClass=centerisLikewiseGroup)(keywords=gidNumber=*))";
 
229
                break;
 
230
        }
 
231
    }
 
232
 
 
233
    return pszQuery;
 
234
}
 
235
 
 
236
static
 
237
PCSTR
 
238
LsaAdBatchEnumGetQuery(
 
239
    IN BOOLEAN bIsByRealObject,
 
240
    IN BOOLEAN bIsSchemaMode,
 
241
    IN LSA_AD_BATCH_OBJECT_TYPE ObjectType
 
242
    )
 
243
{
 
244
    PCSTR pszQuery = NULL;
 
245
 
 
246
    if (bIsByRealObject)
 
247
    {
 
248
        pszQuery = LsaAdBatchEnumGetRealQuery(bIsSchemaMode, ObjectType);
 
249
    }
 
250
    else
 
251
    {
 
252
        pszQuery = LsaAdBatchEnumGetPseudoQuery(bIsSchemaMode, ObjectType);
 
253
    }
 
254
 
 
255
    return pszQuery;
 
256
}
 
257
 
 
258
static
 
259
DWORD
 
260
LsaAdBatchEnumProcessRealMessages(
 
261
    IN PCSTR pszDnsDomainName,
 
262
    IN PCSTR pszNetbiosDomainName,
 
263
    IN DWORD dwDirectoryMode,
 
264
    IN ADConfigurationMode adMode,
 
265
    IN LSA_AD_BATCH_OBJECT_TYPE ObjectType,
 
266
    IN HANDLE hDirectory,
 
267
    IN LDAPMessage* pMessages,
 
268
    IN DWORD dwCount,
 
269
    OUT PDWORD pdwObjectsCount,
 
270
    OUT PLSA_SECURITY_OBJECT** pppObjects
 
271
    )
 
272
{
 
273
    DWORD dwError = 0;
 
274
    LDAPMessage* pCurrentMessage = NULL;
 
275
    LDAP* pLd = LwLdapGetSession(hDirectory);
 
276
    PLSA_SECURITY_OBJECT* ppObjects = NULL;
 
277
    DWORD dwObjectsCount = 0;
 
278
    LSA_AD_BATCH_ITEM batchItem = { { 0 }, 0 };
 
279
 
 
280
    dwError = LwAllocateMemory(
 
281
                    dwCount * sizeof(*ppObjects),
 
282
                    (PVOID*)&ppObjects);
 
283
    BAIL_ON_LSA_ERROR(dwError);
 
284
 
 
285
    pCurrentMessage = ldap_first_entry(pLd, pMessages);
 
286
    while (pCurrentMessage)
 
287
    {
 
288
        dwError = LsaAdBatchGatherRealObjectInternal(
 
289
                        &batchItem,
 
290
                        &dwDirectoryMode,
 
291
                        &adMode,
 
292
                        ObjectType,
 
293
                        NULL,
 
294
                        hDirectory,
 
295
                        pCurrentMessage);
 
296
        BAIL_ON_LSA_ERROR(dwError);
 
297
 
 
298
        //
 
299
        // Need to discard special groups (such as BUILTIN)
 
300
        // that can show up in domain group enumeration.
 
301
        //
 
302
        if (!AdIsSpecialDomainSidPrefix(batchItem.pszSid))
 
303
        {
 
304
            dwError = LsaAdBatchMarshal(
 
305
                            pszDnsDomainName,
 
306
                            pszNetbiosDomainName,
 
307
                            &batchItem,
 
308
                            &ppObjects[dwObjectsCount]);
 
309
            BAIL_ON_LSA_ERROR(dwError);
 
310
 
 
311
            if (ppObjects[dwObjectsCount])
 
312
            {
 
313
                dwObjectsCount++;
 
314
            }
 
315
        }
 
316
 
 
317
        LsaAdBatchDestroyBatchItemContents(&batchItem);
 
318
 
 
319
        pCurrentMessage = ldap_next_entry(pLd, pCurrentMessage);
 
320
    }
 
321
 
 
322
cleanup:
 
323
    LsaAdBatchDestroyBatchItemContents(&batchItem);
 
324
 
 
325
    *pdwObjectsCount = dwObjectsCount;
 
326
    *pppObjects = ppObjects;
 
327
 
 
328
    return dwError;
 
329
 
 
330
error:
 
331
    // set OUT params out cleanup.
 
332
    ADCacheSafeFreeObjectList(dwObjectsCount, &ppObjects);
 
333
    dwObjectsCount = 0;
 
334
 
 
335
    goto cleanup;
 
336
}
 
337
 
 
338
static
 
339
DWORD
 
340
LsaAdBatchEnumProcessPseudoMessages(
 
341
    IN PCSTR pszDnsDomainName,
 
342
    IN PCSTR pszNetbiosDomainName,
 
343
    IN LSA_AD_BATCH_OBJECT_TYPE ObjectType,
 
344
    IN HANDLE hDirectory,
 
345
    IN LDAPMessage* pMessages,
 
346
    IN DWORD dwCount,
 
347
    OUT PDWORD pdwObjectsCount,
 
348
    OUT PLSA_SECURITY_OBJECT** pppObjects
 
349
    )
 
350
{
 
351
    DWORD dwError = 0;
 
352
    LDAPMessage* pCurrentMessage = NULL;
 
353
    LDAP* pLd = LwLdapGetSession(hDirectory);
 
354
    PSTR* ppszSids = NULL;
 
355
    DWORD dwSidsCount = 0;
 
356
    PLSA_SECURITY_OBJECT* ppObjects = NULL;
 
357
    DWORD dwObjectsCount = 0;
 
358
    PSTR* ppszKeywordValues = NULL;
 
359
    DWORD dwKeywordValuesCount = 0;
 
360
 
 
361
    dwError = LwAllocateMemory(
 
362
                    dwCount * sizeof(*ppszSids),
 
363
                    (PVOID*)&ppszSids);
 
364
    BAIL_ON_LSA_ERROR(dwError);
 
365
 
 
366
    pCurrentMessage = ldap_first_entry(pLd, pMessages);
 
367
    while (pCurrentMessage)
 
368
    {
 
369
        PCSTR pszSidFromKeywords = NULL;
 
370
 
 
371
        dwError = LwLdapGetStrings(
 
372
                        hDirectory,
 
373
                        pCurrentMessage,
 
374
                        AD_LDAP_KEYWORDS_TAG,
 
375
                        &ppszKeywordValues,
 
376
                        &dwKeywordValuesCount);
 
377
        BAIL_ON_LSA_ERROR(dwError);
 
378
 
 
379
        pszSidFromKeywords = LsaAdBatchFindKeywordAttributeStatic(
 
380
                                    dwKeywordValuesCount,
 
381
                                    ppszKeywordValues,
 
382
                                    AD_LDAP_BACKLINK_PSEUDO_TAG);
 
383
        if (LW_IS_NULL_OR_EMPTY_STR(pszSidFromKeywords))
 
384
        {
 
385
            dwError = LW_ERROR_INVALID_SID;
 
386
            BAIL_ON_LSA_ERROR(dwError);
 
387
        }
 
388
 
 
389
        //
 
390
        // There should never be any special groups (such as BUILTIN)
 
391
        // that were provisioned in the domain.
 
392
        //
 
393
        if (!AdIsSpecialDomainSidPrefix(pszSidFromKeywords))
 
394
        {
 
395
            dwError = LwAllocateString(pszSidFromKeywords,
 
396
                                        &ppszSids[dwSidsCount]);
 
397
            BAIL_ON_LSA_ERROR(dwError);
 
398
 
 
399
            dwSidsCount++;
 
400
        }
 
401
        else
 
402
        {
 
403
            LSA_LOG_WARNING("Got unexpected special domain SID in enumeration of pseudo-objects: '%s'", pszSidFromKeywords);
 
404
        }
 
405
 
 
406
        LwFreeStringArray(ppszKeywordValues, dwKeywordValuesCount);
 
407
        ppszKeywordValues = NULL;
 
408
        dwKeywordValuesCount = 0;
 
409
 
 
410
        pCurrentMessage = ldap_next_entry(pLd, pCurrentMessage);
 
411
    }
 
412
 
 
413
    dwError = LsaAdBatchFindObjects(
 
414
                    LSA_AD_BATCH_QUERY_TYPE_BY_SID,
 
415
                    dwSidsCount,
 
416
                    ppszSids,
 
417
                    NULL,
 
418
                    &dwObjectsCount,
 
419
                    &ppObjects);
 
420
    BAIL_ON_LSA_ERROR(dwError);
 
421
 
 
422
    // Ideally, do extra sanity check on object type.
 
423
    // In the future, find should take the object type
 
424
    // and restrict the search based on that.
 
425
    XXX;
 
426
 
 
427
cleanup:
 
428
    LwFreeStringArray(ppszKeywordValues, dwKeywordValuesCount);
 
429
    LwFreeStringArray(ppszSids, dwSidsCount);
 
430
 
 
431
    *pdwObjectsCount = dwObjectsCount;
 
432
    *pppObjects = ppObjects;
 
433
 
 
434
    return dwError;
 
435
 
 
436
error:
 
437
    // set OUT params out cleanup.
 
438
    ADCacheSafeFreeObjectList(dwObjectsCount, &ppObjects);
 
439
    dwObjectsCount = 0;
 
440
 
 
441
    goto cleanup;
 
442
}
 
443
 
 
444
static
 
445
DWORD
 
446
LsaAdBatchEnumProcessMessages(
 
447
    IN PCSTR pszDnsDomainName,
 
448
    IN PCSTR pszNetbiosDomainName,
 
449
    IN LSA_AD_BATCH_OBJECT_TYPE ObjectType,
 
450
    IN DWORD dwDirectoryMode,
 
451
    IN ADConfigurationMode adMode,
 
452
    IN HANDLE hDirectory,
 
453
    IN LDAPMessage* pMessages,
 
454
    IN DWORD dwMaxCount,
 
455
    OUT PDWORD pdwObjectsCount,
 
456
    OUT PLSA_SECURITY_OBJECT** pppObjects
 
457
    )
 
458
{
 
459
    DWORD dwError = 0;
 
460
    DWORD dwCount = 0;
 
461
    LDAP* pLd = LwLdapGetSession(hDirectory);
 
462
    PLSA_SECURITY_OBJECT* ppObjects = NULL;
 
463
    DWORD dwObjectsCount = 0;
 
464
 
 
465
    dwCount = ldap_count_entries(pLd, pMessages);
 
466
    if ((int)dwCount < 0)
 
467
    {
 
468
       dwError = LW_ERROR_LDAP_ERROR;
 
469
       BAIL_ON_LSA_ERROR(dwError);
 
470
    }
 
471
    else if (dwCount == 0)
 
472
    {
 
473
        dwError = LsaAdBatchEnumGetNoMoreError(ObjectType);
 
474
        BAIL_ON_LSA_ERROR(dwError);
 
475
    }
 
476
    else if (dwCount > dwMaxCount)
 
477
    {
 
478
       dwError = LW_ERROR_LDAP_ERROR;
 
479
       BAIL_ON_LSA_ERROR(dwError);
 
480
    }
 
481
 
 
482
    if ((DEFAULT_MODE == dwDirectoryMode && SchemaMode == adMode) ||
 
483
        (UNPROVISIONED_MODE == dwDirectoryMode))
 
484
    {
 
485
        dwError = LsaAdBatchEnumProcessRealMessages(
 
486
                        pszDnsDomainName,
 
487
                        pszNetbiosDomainName,
 
488
                        dwDirectoryMode,
 
489
                        adMode,
 
490
                        ObjectType,
 
491
                        hDirectory,
 
492
                        pMessages,
 
493
                        dwCount,
 
494
                        &dwObjectsCount,
 
495
                        &ppObjects);
 
496
        BAIL_ON_LSA_ERROR(dwError);
 
497
    }
 
498
    else
 
499
    {
 
500
        dwError = LsaAdBatchEnumProcessPseudoMessages(
 
501
                        pszDnsDomainName,
 
502
                        pszNetbiosDomainName,
 
503
                        ObjectType,
 
504
                        hDirectory,
 
505
                        pMessages,
 
506
                        dwCount,
 
507
                        &dwObjectsCount,
 
508
                        &ppObjects);
 
509
        BAIL_ON_LSA_ERROR(dwError);
 
510
    }
 
511
 
 
512
cleanup:
 
513
    *pdwObjectsCount = dwObjectsCount;
 
514
    *pppObjects = ppObjects;
 
515
 
 
516
    return dwError;
 
517
 
 
518
error:
 
519
    // set OUT params out cleanup.
 
520
    ADCacheSafeFreeObjectList(dwObjectsCount, &ppObjects);
 
521
    dwObjectsCount = 0;
 
522
 
 
523
    goto cleanup;
 
524
}
 
525
 
 
526
// If this function returns with an error, the position stored in pCookie will
 
527
// be advanced, even though no results are returned. pCookie will still need
 
528
// to be freed outside of this function, even if this function returns with an
 
529
// error.
 
530
static
 
531
DWORD
 
532
LsaAdBatchEnumObjectsInCell(
 
533
    IN PLSA_DM_LDAP_CONNECTION pConn,
 
534
    IN OUT PLW_SEARCH_COOKIE pCookie,
 
535
    IN LSA_AD_BATCH_OBJECT_TYPE ObjectType,
 
536
    IN DWORD dwDirectoryMode,
 
537
    IN ADConfigurationMode adMode,
 
538
    IN OPTIONAL PCSTR pszDnsDomainName,
 
539
    IN OPTIONAL PCSTR pszCellDn,
 
540
    IN DWORD dwMaxObjectsCount,
 
541
    OUT PDWORD pdwObjectsCount,
 
542
    OUT PLSA_SECURITY_OBJECT** pppObjects
 
543
    )
 
544
{
 
545
    DWORD dwError = 0;
 
546
    DWORD dwRemainingObjectsWanted = dwMaxObjectsCount;
 
547
    PSTR szBacklinkAttributeList[] =
 
548
    {
 
549
        AD_LDAP_KEYWORDS_TAG,
 
550
        NULL
 
551
    };
 
552
    PSTR szRealAttributeList[] =
 
553
    {
 
554
        // AD attributes:
 
555
        // - common:
 
556
        AD_LDAP_OBJECTCLASS_TAG,
 
557
        AD_LDAP_OBJECTSID_TAG,
 
558
        AD_LDAP_SAM_NAME_TAG,
 
559
        AD_LDAP_DN_TAG,
 
560
        // - user-specific:
 
561
        AD_LDAP_PRIMEGID_TAG,
 
562
        AD_LDAP_UPN_TAG,
 
563
        AD_LDAP_USER_CTRL_TAG,
 
564
        AD_LDAP_ACCOUT_EXP_TAG,
 
565
        AD_LDAP_PWD_LASTSET_TAG,
 
566
        // schema mode:
 
567
        // - (group alias) or (user gecos in unprovisioned mode):
 
568
        AD_LDAP_DISPLAY_NAME_TAG,
 
569
        // - unix properties (alias is just user alias):
 
570
        AD_LDAP_ALIAS_TAG,
 
571
        AD_LDAP_UID_TAG,
 
572
        AD_LDAP_GID_TAG,
 
573
        AD_LDAP_PASSWD_TAG,
 
574
        AD_LDAP_GECOS_TAG,
 
575
        AD_LDAP_HOMEDIR_TAG,
 
576
        AD_LDAP_SHELL_TAG,
 
577
        NULL
 
578
    };
 
579
    PSTR* pszAttributeList = NULL;
 
580
    PSTR pszScopeRoot = NULL;
 
581
    PCSTR pszQuery = NULL;
 
582
    PSTR pszNetbiosDomainName = NULL;
 
583
    LDAPMessage* pMessage = NULL;
 
584
    PLSA_SECURITY_OBJECT* ppObjects = NULL;
 
585
    DWORD dwObjectsCount = 0;
 
586
    PLSA_SECURITY_OBJECT* ppTotalObjects = NULL;
 
587
    DWORD dwTotalObjectsCount = 0;
 
588
    HANDLE hDirectory = NULL;
 
589
    BOOLEAN bIsByRealObject = FALSE;
 
590
    BOOLEAN bIsSchemaMode = SchemaMode == adMode;
 
591
 
 
592
    if (pCookie->bSearchFinished)
 
593
    {
 
594
        // Client programs cannot directly call this function, so typically
 
595
        // this function will not get called after the search is finished.
 
596
        // However, if this function failed in a previous invocation, the
 
597
        // bSearchFinished would be set to true, but the caller would bail out
 
598
        // before moving to the next cell.
 
599
        dwError = LsaAdBatchEnumGetNoMoreError(ObjectType);
 
600
        BAIL_ON_LSA_ERROR(dwError);
 
601
    }
 
602
 
 
603
    if ((DEFAULT_MODE == dwDirectoryMode && SchemaMode == adMode) ||
 
604
        (UNPROVISIONED_MODE == dwDirectoryMode))
 
605
    {
 
606
        bIsByRealObject = TRUE;
 
607
    }
 
608
 
 
609
    pszAttributeList = bIsByRealObject ? szRealAttributeList : szBacklinkAttributeList;
 
610
 
 
611
    dwError = LsaAdBatchEnumGetScopeRoot(
 
612
                    ObjectType,
 
613
                    bIsByRealObject,
 
614
                    pszDnsDomainName,
 
615
                    pszCellDn,
 
616
                    &pszScopeRoot);
 
617
    BAIL_ON_LSA_ERROR(dwError);
 
618
 
 
619
    pszQuery = LsaAdBatchEnumGetQuery(bIsByRealObject, bIsSchemaMode, ObjectType);
 
620
    LSA_ASSERT(pszQuery);
 
621
 
 
622
    dwError = LsaDmWrapGetDomainName(pszDnsDomainName, NULL,
 
623
                                     &pszNetbiosDomainName);
 
624
    BAIL_ON_LSA_ERROR(dwError);
 
625
 
 
626
    while (!pCookie->bSearchFinished && dwRemainingObjectsWanted)
 
627
    {
 
628
        dwError = LsaDmLdapDirectoryOnePagedSearch(
 
629
                        pConn,
 
630
                        pszScopeRoot,
 
631
                        pszQuery,
 
632
                        pszAttributeList,
 
633
                        dwRemainingObjectsWanted,
 
634
                        pCookie,
 
635
                        bIsByRealObject ? LDAP_SCOPE_SUBTREE : LDAP_SCOPE_ONELEVEL,
 
636
                        &hDirectory,
 
637
                        &pMessage);
 
638
        BAIL_ON_LSA_ERROR(dwError);
 
639
 
 
640
        dwError = LsaAdBatchEnumProcessMessages(
 
641
                        pszDnsDomainName,
 
642
                        pszNetbiosDomainName,
 
643
                        ObjectType,
 
644
                        dwDirectoryMode,
 
645
                        adMode,
 
646
                        hDirectory,
 
647
                        pMessage,
 
648
                        dwRemainingObjectsWanted,
 
649
                        &dwObjectsCount,
 
650
                        &ppObjects);
 
651
        if (dwError == LW_ERROR_NO_MORE_USERS || dwError == LW_ERROR_NO_MORE_GROUPS)
 
652
        {
 
653
            dwError = 0;
 
654
        }
 
655
        BAIL_ON_LSA_ERROR(dwError);
 
656
 
 
657
        ldap_msgfree(pMessage);
 
658
        pMessage = NULL;
 
659
 
 
660
        dwRemainingObjectsWanted -= dwObjectsCount;
 
661
 
 
662
        dwError = LsaAppendAndFreePtrs(
 
663
                        &dwTotalObjectsCount,
 
664
                        (PVOID**)&ppTotalObjects,
 
665
                        &dwObjectsCount,
 
666
                        (PVOID**)&ppObjects);
 
667
        BAIL_ON_LSA_ERROR(dwError);
 
668
    }
 
669
 
 
670
cleanup:
 
671
    LW_SAFE_FREE_STRING(pszScopeRoot);
 
672
    LW_SAFE_FREE_STRING(pszNetbiosDomainName);
 
673
    if (pMessage)
 
674
    {
 
675
        ldap_msgfree(pMessage);
 
676
    }
 
677
    ADCacheSafeFreeObjectList(dwObjectsCount, &ppObjects);
 
678
 
 
679
    *pdwObjectsCount = dwTotalObjectsCount;
 
680
    *pppObjects = ppTotalObjects;
 
681
 
 
682
    return dwError;
 
683
 
 
684
error:
 
685
    // set OUT params in cleanup.
 
686
    ADCacheSafeFreeObjectList(dwTotalObjectsCount, &ppTotalObjects);
 
687
    dwTotalObjectsCount = 0;
 
688
 
 
689
    goto cleanup;
 
690
}
 
691
 
 
692
// If this function returns with an error, the position stored in pCookie will
 
693
// be advanced, even though no results are returned. pCookie will still need
 
694
// to be freed outside of this function, even if this function returns with an
 
695
// error.
 
696
static
 
697
DWORD
 
698
LsaAdBatchEnumObjectsInLinkedCells(
 
699
    IN OUT PLW_SEARCH_COOKIE pCookie,
 
700
    IN LSA_AD_BATCH_OBJECT_TYPE ObjectType,
 
701
    IN DWORD dwMaxObjectsCount,
 
702
    OUT PDWORD pdwObjectsCount,
 
703
    OUT PLSA_SECURITY_OBJECT** pppObjects
 
704
    )
 
705
{
 
706
    DWORD dwError = 0;
 
707
    PLSA_SECURITY_OBJECT* ppObjectsInOneCell = NULL;
 
708
    DWORD dwObjectsCountInOneCell = 0;
 
709
    PLSA_SECURITY_OBJECT* ppObjects = *pppObjects;
 
710
    DWORD dwObjectsCount = *pdwObjectsCount;
 
711
    PAD_CELL_COOKIE_DATA pCookieData = NULL;
 
712
    ADConfigurationMode adMode = gpADProviderData->adConfigurationMode;
 
713
    BOOLEAN bIsDefaultCell = gpADProviderData->dwDirectoryMode == DEFAULT_MODE;
 
714
 
 
715
    LSA_ASSERT(pCookie->pfnFree == LsaAdBatchFreeCellCookie);
 
716
    pCookieData = (PAD_CELL_COOKIE_DATA)pCookie->pvData;
 
717
 
 
718
    while (dwObjectsCount < dwMaxObjectsCount && pCookieData->pCurrentCell)
 
719
    {
 
720
        PAD_LINKED_CELL_INFO pCellInfo = (PAD_LINKED_CELL_INFO)
 
721
            pCookieData->pCurrentCell->pItem;
 
722
 
 
723
        if (pCookieData->pLdapConn == NULL)
 
724
        {
 
725
            dwError = LsaDmLdapOpenDc(
 
726
                            pCellInfo->pszDomain,
 
727
                            &pCookieData->pLdapConn);
 
728
            BAIL_ON_LSA_ERROR(dwError);
 
729
        }
 
730
 
 
731
        // determine schema/non-schema mode in the current cell
 
732
        dwError = LsaAdBatchQueryCellConfigurationMode(
 
733
                       gpADProviderData->szDomain,
 
734
                       pCellInfo->pszCellDN,
 
735
                       &adMode);
 
736
        BAIL_ON_LSA_ERROR(dwError);
 
737
 
 
738
        dwError = LsaAdBatchIsDefaultCell(pCellInfo->pszCellDN,
 
739
                                          &bIsDefaultCell);
 
740
        BAIL_ON_LSA_ERROR(dwError);
 
741
 
 
742
        dwError = LsaAdBatchEnumObjectsInCell(
 
743
                        pCookieData->pLdapConn,
 
744
                        &pCookieData->LdapCookie,
 
745
                        ObjectType,
 
746
                        bIsDefaultCell ? DEFAULT_MODE : CELL_MODE,
 
747
                        adMode,
 
748
                        pCellInfo->pszDomain,
 
749
                        pCellInfo->pszCellDN,
 
750
                        dwMaxObjectsCount - dwObjectsCount,
 
751
                        &dwObjectsCountInOneCell,
 
752
                        &ppObjectsInOneCell);
 
753
        BAIL_ON_LSA_ERROR(dwError);
 
754
 
 
755
        dwError = LsaAppendAndFreePtrs(
 
756
                        &dwObjectsCount,
 
757
                        (PVOID**)&ppObjects,
 
758
                        &dwObjectsCountInOneCell,
 
759
                        (PVOID**)&ppObjectsInOneCell);
 
760
        BAIL_ON_LSA_ERROR(dwError);
 
761
 
 
762
        if (pCookieData->LdapCookie.bSearchFinished)
 
763
        {
 
764
            pCookieData->pCurrentCell = pCookieData->pCurrentCell->pNext;
 
765
            LwFreeCookieContents(&pCookieData->LdapCookie);
 
766
            LsaDmLdapClose(pCookieData->pLdapConn);
 
767
            pCookieData->pLdapConn = NULL;
 
768
        }
 
769
    }
 
770
 
 
771
    if (!pCookieData->pCurrentCell)
 
772
    {
 
773
        pCookie->bSearchFinished = TRUE;
 
774
    }
 
775
 
 
776
cleanup:
 
777
    *pdwObjectsCount = dwObjectsCount;
 
778
    *pppObjects = ppObjects;
 
779
 
 
780
    ADCacheSafeFreeObjectList(dwObjectsCountInOneCell, &ppObjectsInOneCell);
 
781
 
 
782
    return dwError;
 
783
 
 
784
error:
 
785
   // set OUT params in cleanup...
 
786
   ADCacheSafeFreeObjectList(dwObjectsCount, &ppObjects);
 
787
   dwObjectsCount = 0;
 
788
 
 
789
   goto cleanup;
 
790
}
 
791
 
 
792
// If this function returns with an error, the position stored in pCookie will
 
793
// be advanced, even though no results are returned. pCookie will still need
 
794
// to be freed outside of this function, even if this function returns with an
 
795
// error.
 
796
DWORD
 
797
LsaAdBatchEnumObjects(
 
798
    IN OUT PLW_SEARCH_COOKIE pCookie,
 
799
    IN LSA_OBJECT_TYPE AccountType,
 
800
    IN DWORD dwMaxObjectsCount,
 
801
    OUT PDWORD pdwObjectsCount,
 
802
    OUT PLSA_SECURITY_OBJECT** pppObjects
 
803
    )
 
804
{
 
805
    DWORD dwError = 0;
 
806
    LSA_AD_BATCH_OBJECT_TYPE objectType = 0;
 
807
    DWORD dwObjectsCount = 0;
 
808
    PLSA_SECURITY_OBJECT* ppObjects = NULL;
 
809
    PAD_CELL_COOKIE_DATA pCookieData = NULL;
 
810
    DWORD dwTotalObjectsCount = 0;
 
811
    PLSA_SECURITY_OBJECT* ppTotalObjects = NULL;
 
812
    DWORD dwInput = 0;
 
813
    DWORD dwOutput = 0;
 
814
    PSTR pszCopiedSid = NULL;
 
815
 
 
816
    objectType = LsaAdBatchGetObjectTypeFromAccountType(AccountType);
 
817
    if (!LsaAdBatchIsUserOrGroupObjectType(objectType))
 
818
    {
 
819
        // We found something else.
 
820
        LSA_LOG_DEBUG("Requested non-user/non-group object type %d",
 
821
                      AccountType);
 
822
        dwError = LW_ERROR_INVALID_PARAMETER;
 
823
        BAIL_ON_LSA_ERROR(dwError);
 
824
    }
 
825
 
 
826
    if (pCookie->bSearchFinished)
 
827
    {
 
828
        dwError = LsaAdBatchEnumGetNoMoreError(objectType);
 
829
        BAIL_ON_LSA_ERROR(dwError);
 
830
    }
 
831
 
 
832
    if (pCookie->pfnFree == NULL)
 
833
    {
 
834
        dwError = LwAllocateMemory(
 
835
                        sizeof(AD_CELL_COOKIE_DATA),
 
836
                        &pCookie->pvData);
 
837
        BAIL_ON_LSA_ERROR(dwError);
 
838
 
 
839
        pCookieData = (PAD_CELL_COOKIE_DATA)pCookie->pvData;
 
840
        if (gpADProviderData->pCellList != NULL)
 
841
        {
 
842
            // There are linked cells, so we need to keep track of which
 
843
            // sids have been enumerated.
 
844
            dwError = LsaHashCreate(
 
845
                            10 * 1024,
 
846
                            LsaHashCaselessStringCompare,
 
847
                            LsaHashCaselessStringHash,
 
848
                            LsaHashFreeStringKey,
 
849
                            NULL,
 
850
                            &pCookieData->pEnumeratedSids);
 
851
            BAIL_ON_LSA_ERROR(dwError);
 
852
        }
 
853
 
 
854
        pCookie->pfnFree = LsaAdBatchFreeCellCookie;
 
855
    }
 
856
    else
 
857
    {
 
858
        LSA_ASSERT(pCookie->pfnFree == LsaAdBatchFreeCellCookie);
 
859
        pCookieData = (PAD_CELL_COOKIE_DATA)pCookie->pvData;
 
860
    }
 
861
 
 
862
    while (dwTotalObjectsCount < dwMaxObjectsCount &&
 
863
            !pCookie->bSearchFinished)
 
864
    {
 
865
        if (pCookieData->pCurrentCell == NULL)
 
866
        {
 
867
            if (pCookieData->pLdapConn == NULL)
 
868
            {
 
869
                dwError = LsaDmLdapOpenDc(
 
870
                                gpADProviderData->szDomain,
 
871
                                &pCookieData->pLdapConn);
 
872
                BAIL_ON_LSA_ERROR(dwError);
 
873
            }
 
874
 
 
875
            // First get the objects from the primary cell
 
876
            dwError = LsaAdBatchEnumObjectsInCell(
 
877
                            pCookieData->pLdapConn,
 
878
                            &pCookieData->LdapCookie,
 
879
                            objectType,
 
880
                            gpADProviderData->dwDirectoryMode,
 
881
                            gpADProviderData->adConfigurationMode,
 
882
                            gpADProviderData->szDomain,
 
883
                            gpADProviderData->cell.szCellDN,
 
884
                            dwMaxObjectsCount - dwTotalObjectsCount,
 
885
                            &dwObjectsCount,
 
886
                            &ppObjects);
 
887
            BAIL_ON_LSA_ERROR(dwError);
 
888
 
 
889
            dwError = LsaAppendAndFreePtrs(
 
890
                            &dwTotalObjectsCount,
 
891
                            (PVOID**)&ppTotalObjects,
 
892
                            &dwObjectsCount,
 
893
                            (PVOID**)&ppObjects);
 
894
            BAIL_ON_LSA_ERROR(dwError);
 
895
 
 
896
            if (pCookieData->LdapCookie.bSearchFinished)
 
897
            {
 
898
                LwFreeCookieContents(&pCookieData->LdapCookie);
 
899
                LsaDmLdapClose(pCookieData->pLdapConn);
 
900
                pCookieData->pLdapConn = NULL;
 
901
                pCookieData->pCurrentCell = gpADProviderData->pCellList;
 
902
                if (pCookieData->pCurrentCell == NULL)
 
903
                {
 
904
                    pCookie->bSearchFinished = TRUE;
 
905
                }
 
906
            }
 
907
        }
 
908
        else
 
909
        {
 
910
            dwError = LsaAdBatchEnumObjectsInLinkedCells(
 
911
                         pCookie,
 
912
                         objectType,
 
913
                         dwMaxObjectsCount - dwTotalObjectsCount,
 
914
                         &dwObjectsCount,
 
915
                         &ppObjects);
 
916
            BAIL_ON_LSA_ERROR(dwError);
 
917
 
 
918
            dwError = LsaAppendAndFreePtrs(
 
919
                            &dwTotalObjectsCount,
 
920
                            (PVOID**)&ppTotalObjects,
 
921
                            &dwObjectsCount,
 
922
                            (PVOID**)&ppObjects);
 
923
            BAIL_ON_LSA_ERROR(dwError);
 
924
        }
 
925
 
 
926
        // Remove any sids that have already been enumerated
 
927
        if (pCookieData->pEnumeratedSids != NULL)
 
928
        {
 
929
            for (; dwInput < dwTotalObjectsCount; dwInput++)
 
930
            {
 
931
                dwError = LsaHashGetValue(
 
932
                            pCookieData->pEnumeratedSids,
 
933
                            ppTotalObjects[dwInput]->pszObjectSid,
 
934
                            NULL);
 
935
                if (dwError == LW_ERROR_SUCCESS)
 
936
                {
 
937
                    // The object is already in the hash
 
938
                    ADCacheSafeFreeObject(&ppTotalObjects[dwInput]);
 
939
                }
 
940
                else if (dwError == ERROR_NOT_FOUND)
 
941
                {
 
942
                    // This is a new entry; let's track it in the hash
 
943
 
 
944
                    if (pCookieData->pEnumeratedSids->sCount * 2 >
 
945
                        pCookieData->pEnumeratedSids->sTableSize)
 
946
                    {
 
947
                        // Enlarge the hash table to avoid collisions
 
948
                        dwError = LsaHashResize(
 
949
                                    pCookieData->pEnumeratedSids,
 
950
                                    pCookieData->pEnumeratedSids->sCount * 4);
 
951
                        BAIL_ON_LSA_ERROR(dwError);
 
952
                    }
 
953
 
 
954
                    dwError = LwAllocateString(
 
955
                                    ppTotalObjects[dwInput]->pszObjectSid,
 
956
                                    &pszCopiedSid);
 
957
                    BAIL_ON_LSA_ERROR(dwError);
 
958
 
 
959
                    dwError = LsaHashSetValue(
 
960
                                pCookieData->pEnumeratedSids,
 
961
                                pszCopiedSid,
 
962
                                NULL);
 
963
                    BAIL_ON_LSA_ERROR(dwError);
 
964
 
 
965
                    // This is now owned by the hash table
 
966
                    pszCopiedSid = NULL;
 
967
 
 
968
                    ppTotalObjects[dwOutput++] = ppTotalObjects[dwInput];
 
969
                }
 
970
                else
 
971
                {
 
972
                    BAIL_ON_LSA_ERROR(dwError);
 
973
                }
 
974
            }
 
975
            // The array is now smaller since duplicates have been removed
 
976
            dwTotalObjectsCount = dwOutput;
 
977
            dwInput = dwOutput;
 
978
        }
 
979
    }
 
980
 
 
981
cleanup:
 
982
    *pdwObjectsCount = dwTotalObjectsCount;
 
983
    *pppObjects = ppTotalObjects;
 
984
    LW_SAFE_FREE_STRING(pszCopiedSid);
 
985
 
 
986
    return dwError;
 
987
 
 
988
error:
 
989
    // set OUT params in cleanup...
 
990
    ADCacheSafeFreeObjectList(dwObjectsCount, &ppObjects);
 
991
    dwObjectsCount = 0;
 
992
    ADCacheSafeFreeObjectList(dwTotalObjectsCount, &ppTotalObjects);
 
993
    dwTotalObjectsCount = 0;
 
994
    goto cleanup;
 
995
}