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 -*- */
6
* Copyright Likewise Software 2004-2008
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.
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/>.
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
32
* Copyright (C) Likewise Software. All rights reserved.
40
* Likewise Security and Authentication Subsystem (LSASS)
42
* Active Directory Authentication Provider
44
* Authors: Wei Fu (wfu@likewisesoftware.com)
45
* Danilo Almeida (dalmeida@likewisesoftware.com)
48
#include "adprovider.h"
49
#include "batch_common.h"
50
#include "batch_gather.h"
51
#include "batch_marshal.h"
53
typedef struct __AD_CELL_COOKIE_DATA
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;
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;
69
LsaAdBatchFreeCellCookie(
73
PAD_CELL_COOKIE_DATA pData = (PAD_CELL_COOKIE_DATA)pvCookie;
77
LwFreeCookieContents(&pData->LdapCookie);
78
LsaDmLdapClose(pData->pLdapConn);
79
LsaHashSafeFree(&pData->pEnumeratedSids);
81
LW_SAFE_FREE_MEMORY(pData);
87
LsaAdBatchEnumGetNoMoreError(
88
IN LSA_AD_BATCH_OBJECT_TYPE ObjectType
95
case LSA_AD_BATCH_OBJECT_TYPE_USER:
96
dwError = LW_ERROR_NO_MORE_USERS;
98
case LSA_AD_BATCH_OBJECT_TYPE_GROUP:
99
dwError = LW_ERROR_NO_MORE_GROUPS;
103
dwError = LW_ERROR_INTERNAL;
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
120
PSTR pszScopeRoot = NULL;
124
dwError = LwLdapConvertDomainToDN(pszDnsDomainName, &pszScopeRoot);
125
BAIL_ON_LSA_ERROR(dwError);
129
PCSTR pszContainer = NULL;
132
case LSA_AD_BATCH_OBJECT_TYPE_USER:
133
pszContainer = "Users";
135
case LSA_AD_BATCH_OBJECT_TYPE_GROUP:
136
pszContainer = "Groups";
140
dwError = LW_ERROR_INTERNAL;
141
BAIL_ON_LSA_ERROR(dwError);
144
dwError = LwAllocateStringPrintf(
149
BAIL_ON_LSA_ERROR(dwError);
153
*ppszScopeRoot = pszScopeRoot;
157
LW_SAFE_FREE_STRING(pszScopeRoot);
164
LsaAdBatchEnumGetRealQuery(
165
IN BOOLEAN bIsSchemaMode,
166
IN LSA_AD_BATCH_OBJECT_TYPE ObjectType
169
PCSTR pszQuery = NULL;
175
case LSA_AD_BATCH_OBJECT_TYPE_USER:
176
pszQuery = "(&(objectClass=User)(!(objectClass=Computer))(sAMAccountName=*)(uidNumber=*))";
178
case LSA_AD_BATCH_OBJECT_TYPE_GROUP:
179
pszQuery = "(&(objectClass=Group)(!(objectClass=Computer))(sAMAccountName=*)(gidNumber=*))";
187
case LSA_AD_BATCH_OBJECT_TYPE_USER:
188
pszQuery = "(&(objectClass=User)(!(objectClass=Computer))(sAMAccountName=*))";
190
case LSA_AD_BATCH_OBJECT_TYPE_GROUP:
191
pszQuery = "(&(objectClass=Group)(!(objectClass=Computer))(sAMAccountName=*))";
201
LsaAdBatchEnumGetPseudoQuery(
202
IN BOOLEAN bIsSchemaMode,
203
IN LSA_AD_BATCH_OBJECT_TYPE ObjectType
206
PCSTR pszQuery = NULL;
212
case LSA_AD_BATCH_OBJECT_TYPE_USER:
213
pszQuery = "(&(objectClass=posixAccount)(keywords=objectClass=centerisLikewiseUser)(uidNumber=*))";
215
case LSA_AD_BATCH_OBJECT_TYPE_GROUP:
216
pszQuery = "(&(objectClass=posixGroup)(keywords=objectClass=centerisLikewiseGroup)(gidNumber=*))";
224
case LSA_AD_BATCH_OBJECT_TYPE_USER:
225
pszQuery = "(&(objectClass=serviceConnectionPoint)(keywords=objectClass=centerisLikewiseUser)(keywords=uidNumber=*))";
227
case LSA_AD_BATCH_OBJECT_TYPE_GROUP:
228
pszQuery = "(&(objectClass=serviceConnectionPoint)(keywords=objectClass=centerisLikewiseGroup)(keywords=gidNumber=*))";
238
LsaAdBatchEnumGetQuery(
239
IN BOOLEAN bIsByRealObject,
240
IN BOOLEAN bIsSchemaMode,
241
IN LSA_AD_BATCH_OBJECT_TYPE ObjectType
244
PCSTR pszQuery = NULL;
248
pszQuery = LsaAdBatchEnumGetRealQuery(bIsSchemaMode, ObjectType);
252
pszQuery = LsaAdBatchEnumGetPseudoQuery(bIsSchemaMode, ObjectType);
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,
269
OUT PDWORD pdwObjectsCount,
270
OUT PLSA_SECURITY_OBJECT** pppObjects
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 };
280
dwError = LwAllocateMemory(
281
dwCount * sizeof(*ppObjects),
283
BAIL_ON_LSA_ERROR(dwError);
285
pCurrentMessage = ldap_first_entry(pLd, pMessages);
286
while (pCurrentMessage)
288
dwError = LsaAdBatchGatherRealObjectInternal(
296
BAIL_ON_LSA_ERROR(dwError);
299
// Need to discard special groups (such as BUILTIN)
300
// that can show up in domain group enumeration.
302
if (!AdIsSpecialDomainSidPrefix(batchItem.pszSid))
304
dwError = LsaAdBatchMarshal(
306
pszNetbiosDomainName,
308
&ppObjects[dwObjectsCount]);
309
BAIL_ON_LSA_ERROR(dwError);
311
if (ppObjects[dwObjectsCount])
317
LsaAdBatchDestroyBatchItemContents(&batchItem);
319
pCurrentMessage = ldap_next_entry(pLd, pCurrentMessage);
323
LsaAdBatchDestroyBatchItemContents(&batchItem);
325
*pdwObjectsCount = dwObjectsCount;
326
*pppObjects = ppObjects;
331
// set OUT params out cleanup.
332
ADCacheSafeFreeObjectList(dwObjectsCount, &ppObjects);
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,
347
OUT PDWORD pdwObjectsCount,
348
OUT PLSA_SECURITY_OBJECT** pppObjects
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;
361
dwError = LwAllocateMemory(
362
dwCount * sizeof(*ppszSids),
364
BAIL_ON_LSA_ERROR(dwError);
366
pCurrentMessage = ldap_first_entry(pLd, pMessages);
367
while (pCurrentMessage)
369
PCSTR pszSidFromKeywords = NULL;
371
dwError = LwLdapGetStrings(
374
AD_LDAP_KEYWORDS_TAG,
376
&dwKeywordValuesCount);
377
BAIL_ON_LSA_ERROR(dwError);
379
pszSidFromKeywords = LsaAdBatchFindKeywordAttributeStatic(
380
dwKeywordValuesCount,
382
AD_LDAP_BACKLINK_PSEUDO_TAG);
383
if (LW_IS_NULL_OR_EMPTY_STR(pszSidFromKeywords))
385
dwError = LW_ERROR_INVALID_SID;
386
BAIL_ON_LSA_ERROR(dwError);
390
// There should never be any special groups (such as BUILTIN)
391
// that were provisioned in the domain.
393
if (!AdIsSpecialDomainSidPrefix(pszSidFromKeywords))
395
dwError = LwAllocateString(pszSidFromKeywords,
396
&ppszSids[dwSidsCount]);
397
BAIL_ON_LSA_ERROR(dwError);
403
LSA_LOG_WARNING("Got unexpected special domain SID in enumeration of pseudo-objects: '%s'", pszSidFromKeywords);
406
LwFreeStringArray(ppszKeywordValues, dwKeywordValuesCount);
407
ppszKeywordValues = NULL;
408
dwKeywordValuesCount = 0;
410
pCurrentMessage = ldap_next_entry(pLd, pCurrentMessage);
413
dwError = LsaAdBatchFindObjects(
414
LSA_AD_BATCH_QUERY_TYPE_BY_SID,
420
BAIL_ON_LSA_ERROR(dwError);
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.
428
LwFreeStringArray(ppszKeywordValues, dwKeywordValuesCount);
429
LwFreeStringArray(ppszSids, dwSidsCount);
431
*pdwObjectsCount = dwObjectsCount;
432
*pppObjects = ppObjects;
437
// set OUT params out cleanup.
438
ADCacheSafeFreeObjectList(dwObjectsCount, &ppObjects);
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,
455
OUT PDWORD pdwObjectsCount,
456
OUT PLSA_SECURITY_OBJECT** pppObjects
461
LDAP* pLd = LwLdapGetSession(hDirectory);
462
PLSA_SECURITY_OBJECT* ppObjects = NULL;
463
DWORD dwObjectsCount = 0;
465
dwCount = ldap_count_entries(pLd, pMessages);
466
if ((int)dwCount < 0)
468
dwError = LW_ERROR_LDAP_ERROR;
469
BAIL_ON_LSA_ERROR(dwError);
471
else if (dwCount == 0)
473
dwError = LsaAdBatchEnumGetNoMoreError(ObjectType);
474
BAIL_ON_LSA_ERROR(dwError);
476
else if (dwCount > dwMaxCount)
478
dwError = LW_ERROR_LDAP_ERROR;
479
BAIL_ON_LSA_ERROR(dwError);
482
if ((DEFAULT_MODE == dwDirectoryMode && SchemaMode == adMode) ||
483
(UNPROVISIONED_MODE == dwDirectoryMode))
485
dwError = LsaAdBatchEnumProcessRealMessages(
487
pszNetbiosDomainName,
496
BAIL_ON_LSA_ERROR(dwError);
500
dwError = LsaAdBatchEnumProcessPseudoMessages(
502
pszNetbiosDomainName,
509
BAIL_ON_LSA_ERROR(dwError);
513
*pdwObjectsCount = dwObjectsCount;
514
*pppObjects = ppObjects;
519
// set OUT params out cleanup.
520
ADCacheSafeFreeObjectList(dwObjectsCount, &ppObjects);
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
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
546
DWORD dwRemainingObjectsWanted = dwMaxObjectsCount;
547
PSTR szBacklinkAttributeList[] =
549
AD_LDAP_KEYWORDS_TAG,
552
PSTR szRealAttributeList[] =
556
AD_LDAP_OBJECTCLASS_TAG,
557
AD_LDAP_OBJECTSID_TAG,
558
AD_LDAP_SAM_NAME_TAG,
561
AD_LDAP_PRIMEGID_TAG,
563
AD_LDAP_USER_CTRL_TAG,
564
AD_LDAP_ACCOUT_EXP_TAG,
565
AD_LDAP_PWD_LASTSET_TAG,
567
// - (group alias) or (user gecos in unprovisioned mode):
568
AD_LDAP_DISPLAY_NAME_TAG,
569
// - unix properties (alias is just user alias):
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;
592
if (pCookie->bSearchFinished)
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);
603
if ((DEFAULT_MODE == dwDirectoryMode && SchemaMode == adMode) ||
604
(UNPROVISIONED_MODE == dwDirectoryMode))
606
bIsByRealObject = TRUE;
609
pszAttributeList = bIsByRealObject ? szRealAttributeList : szBacklinkAttributeList;
611
dwError = LsaAdBatchEnumGetScopeRoot(
617
BAIL_ON_LSA_ERROR(dwError);
619
pszQuery = LsaAdBatchEnumGetQuery(bIsByRealObject, bIsSchemaMode, ObjectType);
620
LSA_ASSERT(pszQuery);
622
dwError = LsaDmWrapGetDomainName(pszDnsDomainName, NULL,
623
&pszNetbiosDomainName);
624
BAIL_ON_LSA_ERROR(dwError);
626
while (!pCookie->bSearchFinished && dwRemainingObjectsWanted)
628
dwError = LsaDmLdapDirectoryOnePagedSearch(
633
dwRemainingObjectsWanted,
635
bIsByRealObject ? LDAP_SCOPE_SUBTREE : LDAP_SCOPE_ONELEVEL,
638
BAIL_ON_LSA_ERROR(dwError);
640
dwError = LsaAdBatchEnumProcessMessages(
642
pszNetbiosDomainName,
648
dwRemainingObjectsWanted,
651
if (dwError == LW_ERROR_NO_MORE_USERS || dwError == LW_ERROR_NO_MORE_GROUPS)
655
BAIL_ON_LSA_ERROR(dwError);
657
ldap_msgfree(pMessage);
660
dwRemainingObjectsWanted -= dwObjectsCount;
662
dwError = LsaAppendAndFreePtrs(
663
&dwTotalObjectsCount,
664
(PVOID**)&ppTotalObjects,
666
(PVOID**)&ppObjects);
667
BAIL_ON_LSA_ERROR(dwError);
671
LW_SAFE_FREE_STRING(pszScopeRoot);
672
LW_SAFE_FREE_STRING(pszNetbiosDomainName);
675
ldap_msgfree(pMessage);
677
ADCacheSafeFreeObjectList(dwObjectsCount, &ppObjects);
679
*pdwObjectsCount = dwTotalObjectsCount;
680
*pppObjects = ppTotalObjects;
685
// set OUT params in cleanup.
686
ADCacheSafeFreeObjectList(dwTotalObjectsCount, &ppTotalObjects);
687
dwTotalObjectsCount = 0;
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
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
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;
715
LSA_ASSERT(pCookie->pfnFree == LsaAdBatchFreeCellCookie);
716
pCookieData = (PAD_CELL_COOKIE_DATA)pCookie->pvData;
718
while (dwObjectsCount < dwMaxObjectsCount && pCookieData->pCurrentCell)
720
PAD_LINKED_CELL_INFO pCellInfo = (PAD_LINKED_CELL_INFO)
721
pCookieData->pCurrentCell->pItem;
723
if (pCookieData->pLdapConn == NULL)
725
dwError = LsaDmLdapOpenDc(
726
pCellInfo->pszDomain,
727
&pCookieData->pLdapConn);
728
BAIL_ON_LSA_ERROR(dwError);
731
// determine schema/non-schema mode in the current cell
732
dwError = LsaAdBatchQueryCellConfigurationMode(
733
gpADProviderData->szDomain,
734
pCellInfo->pszCellDN,
736
BAIL_ON_LSA_ERROR(dwError);
738
dwError = LsaAdBatchIsDefaultCell(pCellInfo->pszCellDN,
740
BAIL_ON_LSA_ERROR(dwError);
742
dwError = LsaAdBatchEnumObjectsInCell(
743
pCookieData->pLdapConn,
744
&pCookieData->LdapCookie,
746
bIsDefaultCell ? DEFAULT_MODE : CELL_MODE,
748
pCellInfo->pszDomain,
749
pCellInfo->pszCellDN,
750
dwMaxObjectsCount - dwObjectsCount,
751
&dwObjectsCountInOneCell,
752
&ppObjectsInOneCell);
753
BAIL_ON_LSA_ERROR(dwError);
755
dwError = LsaAppendAndFreePtrs(
758
&dwObjectsCountInOneCell,
759
(PVOID**)&ppObjectsInOneCell);
760
BAIL_ON_LSA_ERROR(dwError);
762
if (pCookieData->LdapCookie.bSearchFinished)
764
pCookieData->pCurrentCell = pCookieData->pCurrentCell->pNext;
765
LwFreeCookieContents(&pCookieData->LdapCookie);
766
LsaDmLdapClose(pCookieData->pLdapConn);
767
pCookieData->pLdapConn = NULL;
771
if (!pCookieData->pCurrentCell)
773
pCookie->bSearchFinished = TRUE;
777
*pdwObjectsCount = dwObjectsCount;
778
*pppObjects = ppObjects;
780
ADCacheSafeFreeObjectList(dwObjectsCountInOneCell, &ppObjectsInOneCell);
785
// set OUT params in cleanup...
786
ADCacheSafeFreeObjectList(dwObjectsCount, &ppObjects);
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
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
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;
814
PSTR pszCopiedSid = NULL;
816
objectType = LsaAdBatchGetObjectTypeFromAccountType(AccountType);
817
if (!LsaAdBatchIsUserOrGroupObjectType(objectType))
819
// We found something else.
820
LSA_LOG_DEBUG("Requested non-user/non-group object type %d",
822
dwError = LW_ERROR_INVALID_PARAMETER;
823
BAIL_ON_LSA_ERROR(dwError);
826
if (pCookie->bSearchFinished)
828
dwError = LsaAdBatchEnumGetNoMoreError(objectType);
829
BAIL_ON_LSA_ERROR(dwError);
832
if (pCookie->pfnFree == NULL)
834
dwError = LwAllocateMemory(
835
sizeof(AD_CELL_COOKIE_DATA),
837
BAIL_ON_LSA_ERROR(dwError);
839
pCookieData = (PAD_CELL_COOKIE_DATA)pCookie->pvData;
840
if (gpADProviderData->pCellList != NULL)
842
// There are linked cells, so we need to keep track of which
843
// sids have been enumerated.
844
dwError = LsaHashCreate(
846
LsaHashCaselessStringCompare,
847
LsaHashCaselessStringHash,
848
LsaHashFreeStringKey,
850
&pCookieData->pEnumeratedSids);
851
BAIL_ON_LSA_ERROR(dwError);
854
pCookie->pfnFree = LsaAdBatchFreeCellCookie;
858
LSA_ASSERT(pCookie->pfnFree == LsaAdBatchFreeCellCookie);
859
pCookieData = (PAD_CELL_COOKIE_DATA)pCookie->pvData;
862
while (dwTotalObjectsCount < dwMaxObjectsCount &&
863
!pCookie->bSearchFinished)
865
if (pCookieData->pCurrentCell == NULL)
867
if (pCookieData->pLdapConn == NULL)
869
dwError = LsaDmLdapOpenDc(
870
gpADProviderData->szDomain,
871
&pCookieData->pLdapConn);
872
BAIL_ON_LSA_ERROR(dwError);
875
// First get the objects from the primary cell
876
dwError = LsaAdBatchEnumObjectsInCell(
877
pCookieData->pLdapConn,
878
&pCookieData->LdapCookie,
880
gpADProviderData->dwDirectoryMode,
881
gpADProviderData->adConfigurationMode,
882
gpADProviderData->szDomain,
883
gpADProviderData->cell.szCellDN,
884
dwMaxObjectsCount - dwTotalObjectsCount,
887
BAIL_ON_LSA_ERROR(dwError);
889
dwError = LsaAppendAndFreePtrs(
890
&dwTotalObjectsCount,
891
(PVOID**)&ppTotalObjects,
893
(PVOID**)&ppObjects);
894
BAIL_ON_LSA_ERROR(dwError);
896
if (pCookieData->LdapCookie.bSearchFinished)
898
LwFreeCookieContents(&pCookieData->LdapCookie);
899
LsaDmLdapClose(pCookieData->pLdapConn);
900
pCookieData->pLdapConn = NULL;
901
pCookieData->pCurrentCell = gpADProviderData->pCellList;
902
if (pCookieData->pCurrentCell == NULL)
904
pCookie->bSearchFinished = TRUE;
910
dwError = LsaAdBatchEnumObjectsInLinkedCells(
913
dwMaxObjectsCount - dwTotalObjectsCount,
916
BAIL_ON_LSA_ERROR(dwError);
918
dwError = LsaAppendAndFreePtrs(
919
&dwTotalObjectsCount,
920
(PVOID**)&ppTotalObjects,
922
(PVOID**)&ppObjects);
923
BAIL_ON_LSA_ERROR(dwError);
926
// Remove any sids that have already been enumerated
927
if (pCookieData->pEnumeratedSids != NULL)
929
for (; dwInput < dwTotalObjectsCount; dwInput++)
931
dwError = LsaHashGetValue(
932
pCookieData->pEnumeratedSids,
933
ppTotalObjects[dwInput]->pszObjectSid,
935
if (dwError == LW_ERROR_SUCCESS)
937
// The object is already in the hash
938
ADCacheSafeFreeObject(&ppTotalObjects[dwInput]);
940
else if (dwError == ERROR_NOT_FOUND)
942
// This is a new entry; let's track it in the hash
944
if (pCookieData->pEnumeratedSids->sCount * 2 >
945
pCookieData->pEnumeratedSids->sTableSize)
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);
954
dwError = LwAllocateString(
955
ppTotalObjects[dwInput]->pszObjectSid,
957
BAIL_ON_LSA_ERROR(dwError);
959
dwError = LsaHashSetValue(
960
pCookieData->pEnumeratedSids,
963
BAIL_ON_LSA_ERROR(dwError);
965
// This is now owned by the hash table
968
ppTotalObjects[dwOutput++] = ppTotalObjects[dwInput];
972
BAIL_ON_LSA_ERROR(dwError);
975
// The array is now smaller since duplicates have been removed
976
dwTotalObjectsCount = dwOutput;
982
*pdwObjectsCount = dwTotalObjectsCount;
983
*pppObjects = ppTotalObjects;
984
LW_SAFE_FREE_STRING(pszCopiedSid);
989
// set OUT params in cleanup...
990
ADCacheSafeFreeObjectList(dwObjectsCount, &ppObjects);
992
ADCacheSafeFreeObjectList(dwTotalObjectsCount, &ppTotalObjects);
993
dwTotalObjectsCount = 0;