~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_build.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_build.c
 
37
 *
 
38
 * Abstract:
 
39
 *
 
40
 *        Likewise Security and Authentication Subsystem (LSASS)
 
41
 *
 
42
 *        Active Directory Authentication Provider
 
43
 *
 
44
 * Authors: Danilo Almeida (dalmeida@likewisesoftware.com)
 
45
 *          Wei Fu (wfu@likewisesoftware.com)
 
46
 *
 
47
 */
 
48
 
 
49
#include "adprovider.h"
 
50
#include "batch_build.h"
 
51
 
 
52
typedef DWORD (*LSA_AD_BATCH_BUILDER_GET_ATTR_VALUE_CALLBACK)(
 
53
    IN PVOID pCallbackContext,
 
54
    IN PVOID pItem,
 
55
    OUT PCSTR* ppszValue,
 
56
    OUT PVOID* ppFreeValueContext
 
57
    );
 
58
 
 
59
typedef VOID (*LSA_AD_BATCH_BUILDER_FREE_VALUE_CONTEXT_CALLBACK)(
 
60
    IN PVOID pCallbackContext,
 
61
    IN OUT PVOID* ppFreeValueContext
 
62
    );
 
63
 
 
64
typedef PVOID (*LSA_AD_BATCH_BUILDER_NEXT_ITEM_CALLBACK)(
 
65
    IN PVOID pCallbackContext,
 
66
    IN PVOID pItem
 
67
    );
 
68
 
 
69
static
 
70
DWORD
 
71
LsaAdBatchBuilderAppend(
 
72
    IN OUT PDWORD pdwQueryOffset,
 
73
    IN OUT PSTR pszQuery,
 
74
    IN DWORD dwQuerySize,
 
75
    IN PCSTR pszAppend,
 
76
    IN DWORD dwAppendLength
 
77
    )
 
78
{
 
79
    DWORD dwError = 0;
 
80
    DWORD dwQueryOffset = *pdwQueryOffset;
 
81
    DWORD dwNewQueryOffset = 0;
 
82
 
 
83
    if (dwAppendLength > 0)
 
84
    {
 
85
        dwNewQueryOffset = dwQueryOffset + dwAppendLength;
 
86
        if (dwNewQueryOffset < dwQueryOffset)
 
87
        {
 
88
            // overflow
 
89
            dwError = LW_ERROR_DATA_ERROR;
 
90
            BAIL_ON_LSA_ERROR(dwError);
 
91
        }
 
92
        else if (dwNewQueryOffset - 1 >= dwQuerySize)
 
93
        {
 
94
            // overflow
 
95
            dwError = LW_ERROR_DATA_ERROR;
 
96
            BAIL_ON_LSA_ERROR(dwError);
 
97
        }
 
98
        memcpy(pszQuery + dwQueryOffset, pszAppend, dwAppendLength);
 
99
        pszQuery[dwNewQueryOffset] = 0;
 
100
        *pdwQueryOffset = dwNewQueryOffset;
 
101
    }
 
102
 
 
103
cleanup:
 
104
    return dwError;
 
105
 
 
106
error:
 
107
    goto cleanup;
 
108
}
 
109
 
 
110
static
 
111
DWORD
 
112
LsaAdBatchBuilderCreateQuery(
 
113
    IN PCSTR pszQueryPrefix,
 
114
    IN PCSTR pszQuerySuffix,
 
115
    IN PCSTR pszAttributeName,
 
116
    IN PVOID pFirstItem,
 
117
    IN PVOID pEndItem,
 
118
    OUT PVOID* ppNextItem,
 
119
    IN OPTIONAL PVOID pCallbackContext,
 
120
    IN LSA_AD_BATCH_BUILDER_GET_ATTR_VALUE_CALLBACK pGetAttributeValueCallback,
 
121
    IN OPTIONAL LSA_AD_BATCH_BUILDER_FREE_VALUE_CONTEXT_CALLBACK pFreeValueContextCallback,
 
122
    IN LSA_AD_BATCH_BUILDER_NEXT_ITEM_CALLBACK pNextItemCallback,
 
123
    IN DWORD dwMaxQuerySize,
 
124
    IN DWORD dwMaxQueryCount,
 
125
    OUT PDWORD pdwQueryCount,
 
126
    OUT PSTR* ppszQuery
 
127
    )
 
128
{
 
129
    DWORD dwError = 0;
 
130
    PVOID pCurrentItem = NULL;
 
131
    PSTR pszQuery = NULL;
 
132
    PVOID pLastItem = pFirstItem;
 
133
    const char szOrPrefix[] = "(|";
 
134
    const char szOrSuffix[] = ")";
 
135
    const DWORD dwOrPrefixLength = sizeof(szOrPrefix)-1;
 
136
    const DWORD dwOrSuffixLength = sizeof(szOrSuffix)-1;
 
137
    DWORD dwAttributeNameLength = strlen(pszAttributeName);
 
138
    DWORD dwQuerySize = 0;
 
139
    DWORD dwQueryCount = 0;
 
140
    PVOID pFreeValueContext = NULL;
 
141
    DWORD dwQueryPrefixLength = 0;
 
142
    DWORD dwQuerySuffixLength = 0;
 
143
    DWORD dwQueryOffset = 0;
 
144
    DWORD dwSavedQueryCount = 0;
 
145
 
 
146
    if (pszQueryPrefix)
 
147
    {
 
148
        dwQueryPrefixLength = strlen(pszQueryPrefix);
 
149
    }
 
150
    if (pszQuerySuffix)
 
151
    {
 
152
        dwQuerySuffixLength = strlen(pszQuerySuffix);
 
153
    }
 
154
 
 
155
    // The overhead is:
 
156
    // prefix + orPrefix + <CONTENT> + orSuffix + suffix + NULL
 
157
    dwQuerySize = dwQueryPrefixLength + dwOrPrefixLength + dwOrSuffixLength + dwQuerySuffixLength + 1;
 
158
 
 
159
    pCurrentItem = pFirstItem;
 
160
    while (pCurrentItem != pEndItem)
 
161
    {
 
162
        PCSTR pszAttributeValue = NULL;
 
163
 
 
164
        if (pFreeValueContext)
 
165
        {
 
166
            pFreeValueContextCallback(pCallbackContext, &pFreeValueContext);
 
167
        }
 
168
 
 
169
        dwError = pGetAttributeValueCallback(
 
170
                        pCallbackContext,
 
171
                        pCurrentItem,
 
172
                        &pszAttributeValue,
 
173
                        &pFreeValueContext);
 
174
        BAIL_ON_LSA_ERROR(dwError);
 
175
 
 
176
        if (pszAttributeValue)
 
177
        {
 
178
            // "(" + attributeName + "=" + attributeValue + ")"
 
179
            DWORD dwAttributeValueLength = strlen(pszAttributeValue);
 
180
            DWORD dwItemLength = (1 + dwAttributeNameLength + 1 + dwAttributeValueLength + 1);
 
181
            DWORD dwNewQuerySize = dwQuerySize + dwItemLength;
 
182
            DWORD dwNewQueryCount = dwQueryCount + 1;
 
183
 
 
184
            if (dwNewQuerySize < dwQuerySize)
 
185
            {
 
186
                // overflow
 
187
                dwError = LW_ERROR_DATA_ERROR;
 
188
                BAIL_ON_LSA_ERROR(dwError);
 
189
            }
 
190
            if (dwMaxQuerySize && (dwNewQuerySize > dwMaxQuerySize))
 
191
            {
 
192
                break;
 
193
            }
 
194
            if (dwMaxQueryCount && (dwNewQueryCount > dwMaxQueryCount))
 
195
            {
 
196
                break;
 
197
            }
 
198
            dwQuerySize = dwNewQuerySize;
 
199
            dwQueryCount = dwNewQueryCount;
 
200
        }
 
201
 
 
202
        pCurrentItem = pNextItemCallback(pCallbackContext, pCurrentItem);
 
203
    }
 
204
    pLastItem = pCurrentItem;
 
205
    dwSavedQueryCount = dwQueryCount;
 
206
 
 
207
    if (dwQueryCount < 1)
 
208
    {
 
209
        goto cleanup;
 
210
    }
 
211
 
 
212
    dwError = LwAllocateMemory(dwQuerySize, (PVOID*)&pszQuery);
 
213
    BAIL_ON_LSA_ERROR(dwError);
 
214
 
 
215
    // Set up the query
 
216
    dwQueryOffset = 0;
 
217
 
 
218
    dwError = LsaAdBatchBuilderAppend(&dwQueryOffset, pszQuery, dwQuerySize,
 
219
                                      pszQueryPrefix, dwQueryPrefixLength);
 
220
    BAIL_ON_LSA_ERROR(dwError);
 
221
 
 
222
    dwError = LsaAdBatchBuilderAppend(&dwQueryOffset, pszQuery, dwQuerySize,
 
223
                                      szOrPrefix, dwOrPrefixLength);
 
224
    BAIL_ON_LSA_ERROR(dwError);
 
225
 
 
226
    dwQueryCount = 0;
 
227
    pCurrentItem = pFirstItem;
 
228
    while (pCurrentItem != pLastItem)
 
229
    {
 
230
        PCSTR pszAttributeValue = NULL;
 
231
 
 
232
        if (pFreeValueContext)
 
233
        {
 
234
            pFreeValueContextCallback(pCallbackContext, &pFreeValueContext);
 
235
        }
 
236
 
 
237
        dwError = pGetAttributeValueCallback(
 
238
                        pCallbackContext,
 
239
                        pCurrentItem,
 
240
                        &pszAttributeValue,
 
241
                        &pFreeValueContext);
 
242
        BAIL_ON_LSA_ERROR(dwError);
 
243
 
 
244
        if (pszAttributeValue)
 
245
        {
 
246
            DWORD dwAttributeValueLength = strlen(pszAttributeValue);
 
247
 
 
248
            dwError = LsaAdBatchBuilderAppend(&dwQueryOffset, pszQuery, dwQuerySize,
 
249
                                              "(", 1);
 
250
            BAIL_ON_LSA_ERROR(dwError);
 
251
 
 
252
            dwError = LsaAdBatchBuilderAppend(&dwQueryOffset, pszQuery, dwQuerySize,
 
253
                                              pszAttributeName, dwAttributeNameLength);
 
254
            BAIL_ON_LSA_ERROR(dwError);
 
255
 
 
256
            dwError = LsaAdBatchBuilderAppend(&dwQueryOffset, pszQuery, dwQuerySize,
 
257
                                              "=", 1);
 
258
            BAIL_ON_LSA_ERROR(dwError);
 
259
 
 
260
            dwError = LsaAdBatchBuilderAppend(&dwQueryOffset, pszQuery, dwQuerySize,
 
261
                                              pszAttributeValue, dwAttributeValueLength);
 
262
            BAIL_ON_LSA_ERROR(dwError);
 
263
 
 
264
            dwError = LsaAdBatchBuilderAppend(&dwQueryOffset, pszQuery, dwQuerySize,
 
265
                                              ")", 1);
 
266
            BAIL_ON_LSA_ERROR(dwError);
 
267
 
 
268
            dwQueryCount++;
 
269
        }
 
270
 
 
271
        pCurrentItem = pNextItemCallback(pCallbackContext, pCurrentItem);
 
272
    }
 
273
 
 
274
    dwError = LsaAdBatchBuilderAppend(&dwQueryOffset, pszQuery, dwQuerySize,
 
275
                                      szOrSuffix, dwOrSuffixLength);
 
276
    BAIL_ON_LSA_ERROR(dwError);
 
277
 
 
278
    dwError = LsaAdBatchBuilderAppend(&dwQueryOffset, pszQuery, dwQuerySize,
 
279
                                      pszQuerySuffix, dwQuerySuffixLength);
 
280
    BAIL_ON_LSA_ERROR(dwError);
 
281
 
 
282
    assert(dwQueryOffset + 1 == dwQuerySize);
 
283
    assert(dwSavedQueryCount == dwQueryCount);
 
284
 
 
285
cleanup:
 
286
    // We handle error here instead of error label
 
287
    // because there is a goto cleanup above.
 
288
    if (dwError)
 
289
    {
 
290
        LW_SAFE_FREE_STRING(pszQuery);
 
291
        dwQueryCount = 0;
 
292
        pLastItem = pFirstItem;
 
293
    }
 
294
 
 
295
    if (pFreeValueContext)
 
296
    {
 
297
        pFreeValueContextCallback(pCallbackContext, &pFreeValueContext);
 
298
    }
 
299
 
 
300
    *ppszQuery = pszQuery;
 
301
    *pdwQueryCount = dwQueryCount;
 
302
    *ppNextItem = pLastItem;
 
303
 
 
304
    return dwError;
 
305
 
 
306
error:
 
307
    // Do not actually handle any errors here.
 
308
    goto cleanup;
 
309
}
 
310
 
 
311
typedef struct _LSA_AD_BATCH_BUILDER_BATCH_ITEM_CONTEXT {
 
312
    LSA_AD_BATCH_QUERY_TYPE QueryType;
 
313
    BOOLEAN bIsForRealObject;
 
314
} LSA_AD_BATCH_BUILDER_BATCH_ITEM_CONTEXT, *PLSA_AD_BATCH_BUILDER_BATCH_ITEM_CONTEXT;
 
315
 
 
316
static
 
317
DWORD
 
318
LsaAdBatchBuilderBatchItemGetAttributeValue(
 
319
    IN PVOID pCallbackContext,
 
320
    IN PVOID pItem,
 
321
    OUT PCSTR* ppszValue,
 
322
    OUT PVOID* ppFreeValueContext
 
323
    )
 
324
{
 
325
    DWORD dwError = 0;
 
326
    PLSA_AD_BATCH_BUILDER_BATCH_ITEM_CONTEXT pContext = (PLSA_AD_BATCH_BUILDER_BATCH_ITEM_CONTEXT)pCallbackContext;
 
327
    LSA_AD_BATCH_QUERY_TYPE QueryType = pContext->QueryType;
 
328
    BOOLEAN bIsForRealObject = pContext->bIsForRealObject;
 
329
    PLSA_LIST_LINKS pLinks = (PLSA_LIST_LINKS)pItem;
 
330
    PLSA_AD_BATCH_ITEM pBatchItem = LW_STRUCT_FROM_FIELD(pLinks, LSA_AD_BATCH_ITEM, BatchItemListLinks);
 
331
    PSTR pszValueToEscape = NULL;
 
332
    PSTR pszValueToHex = NULL;
 
333
    PSTR pszValue = NULL;
 
334
    PVOID pFreeValueContext = NULL;
 
335
    // Free this on error only.
 
336
    PSTR pszMatchTerm = NULL;
 
337
    PSTR pszAllocatedMatchTermValue = NULL;
 
338
    BOOLEAN bHaveReal = IsSetFlag(pBatchItem->Flags, LSA_AD_BATCH_ITEM_FLAG_HAVE_REAL);
 
339
    BOOLEAN bHavePseudo = IsSetFlag(pBatchItem->Flags, LSA_AD_BATCH_ITEM_FLAG_HAVE_PSEUDO);
 
340
 
 
341
    if (IsSetFlag(pBatchItem->Flags, LSA_AD_BATCH_ITEM_FLAG_ALLOCATED_MATCH_TERM))
 
342
    {
 
343
        LW_SAFE_FREE_STRING(pBatchItem->pszQueryMatchTerm);
 
344
        ClearFlag(pBatchItem->Flags, LSA_AD_BATCH_ITEM_FLAG_ALLOCATED_MATCH_TERM);
 
345
    }
 
346
 
 
347
    if ((bIsForRealObject && bHaveReal) ||
 
348
        (!bIsForRealObject && bHavePseudo))
 
349
    {
 
350
        // This can only happen in the linked cells case, but even
 
351
        // that should go away in the future as we just keep an
 
352
        // unresolved batch items list.
 
353
 
 
354
        LSA_ASSERT(!bIsForRealObject && (gpADProviderData->dwDirectoryMode == CELL_MODE));
 
355
        goto cleanup;
 
356
    }
 
357
 
 
358
    switch (QueryType)
 
359
    {
 
360
        case LSA_AD_BATCH_QUERY_TYPE_BY_DN:
 
361
            // Must be looking for real object
 
362
            LSA_ASSERT(bIsForRealObject);
 
363
            LSA_ASSERT(QueryType == pBatchItem->QueryTerm.Type);
 
364
 
 
365
            pszValueToEscape = (PSTR)pBatchItem->QueryTerm.pszString;
 
366
            LSA_ASSERT(pszValueToEscape);
 
367
            break;
 
368
 
 
369
        case LSA_AD_BATCH_QUERY_TYPE_BY_SID:
 
370
            if (pBatchItem->pszSid)
 
371
            {
 
372
                // This is case where we already got the SID by resolving
 
373
                // the pseudo object by id/alias.
 
374
                pszValue = pBatchItem->pszSid;
 
375
            }
 
376
            else if (QueryType == pBatchItem->QueryTerm.Type)
 
377
            {
 
378
                // This is the case where the original query was
 
379
                // a query by SID.
 
380
                pszValue = (PSTR)pBatchItem->QueryTerm.pszString;
 
381
                LSA_ASSERT(pszValue);
 
382
            }
 
383
            // Will be NULL if we cannot find a SID for which to query.
 
384
            // This can happen if this batch item is for an object
 
385
            // that we did not find real but are trying to look up pseudo.
 
386
            // In that case, we have NULL and will just skip it.
 
387
 
 
388
            // If we have a SID string, make sure it looks like a SID.
 
389
            // Note that we must do some sanity checking to make sure
 
390
            // that the string does not need escaping since we are
 
391
            // not setting pszValueToEscape.  (The SID check takes
 
392
            // care of that.)
 
393
            if (pszValue && !LsaAdBatchHasValidCharsForSid(pszValue))
 
394
            {
 
395
                LSA_ASSERT(FALSE);
 
396
                dwError = LW_ERROR_INTERNAL;
 
397
                BAIL_ON_LSA_ERROR(dwError);
 
398
            }
 
399
 
 
400
            if (bIsForRealObject)
 
401
            {
 
402
                // "S-"-style SID string are only handled starting with
 
403
                // Windows 2003.  So an LDAP hex-formatted SID string
 
404
                // is needed to handle Windows 2000.
 
405
 
 
406
                pszValueToHex = pszValue;
 
407
                pszValue = NULL;
 
408
            }
 
409
            break;
 
410
 
 
411
        case LSA_AD_BATCH_QUERY_TYPE_BY_NT4:
 
412
            LSA_ASSERT(bIsForRealObject);
 
413
            if (pBatchItem->pszSamAccountName)
 
414
            {
 
415
                // Unprovisioned id/alias case where id mapper returned
 
416
                // a SAM account name (and domain name) but no SID.
 
417
                pszValueToEscape = pBatchItem->pszSamAccountName;
 
418
                // However, we currently do not have this sort of id mapper
 
419
                // support, so we LSA_ASSERT(FALSE) for now.
 
420
                LSA_ASSERT(FALSE);
 
421
            }
 
422
            else if (QueryType == pBatchItem->QueryTerm.Type)
 
423
            {
 
424
                pszValueToEscape = (PSTR)pBatchItem->QueryTerm.pszString;
 
425
                LSA_ASSERT(pszValueToEscape);
 
426
            }
 
427
            break;
 
428
 
 
429
        case LSA_AD_BATCH_QUERY_TYPE_BY_UID:
 
430
        case LSA_AD_BATCH_QUERY_TYPE_BY_GID:
 
431
            LSA_ASSERT(!bIsForRealObject);
 
432
            LSA_ASSERT(QueryType == pBatchItem->QueryTerm.Type);
 
433
 
 
434
            dwError = LwAllocateStringPrintf(
 
435
                            &pszAllocatedMatchTermValue,
 
436
                            "%u",
 
437
                            (unsigned int)pBatchItem->QueryTerm.dwId);
 
438
            BAIL_ON_LSA_ERROR(dwError);
 
439
            pszValue = pszAllocatedMatchTermValue;
 
440
 
 
441
            // Note: It is ok to set this here because it is ok for
 
442
            // this flag to be set if the match term field in the
 
443
            // batch item is still NULL (i.e., if we fail later in
 
444
            // this function).
 
445
            SetFlag(pBatchItem->Flags, LSA_AD_BATCH_ITEM_FLAG_ALLOCATED_MATCH_TERM);
 
446
 
 
447
            break;
 
448
 
 
449
        case LSA_AD_BATCH_QUERY_TYPE_BY_USER_ALIAS:
 
450
        case LSA_AD_BATCH_QUERY_TYPE_BY_GROUP_ALIAS:
 
451
            LSA_ASSERT(!bIsForRealObject);
 
452
            LSA_ASSERT(QueryType == pBatchItem->QueryTerm.Type);
 
453
 
 
454
            pszValueToEscape = (PSTR)pBatchItem->QueryTerm.pszString;
 
455
            LSA_ASSERT(pszValueToEscape);
 
456
            break;
 
457
 
 
458
        default:
 
459
            dwError = LW_ERROR_INVALID_PARAMETER;
 
460
            BAIL_ON_LSA_ERROR(dwError);
 
461
    }
 
462
 
 
463
    LSA_ASSERT(!pszMatchTerm);
 
464
    LSA_ASSERT(!(pszValueToEscape && pszValueToHex));
 
465
 
 
466
    if (pszValueToEscape)
 
467
    {
 
468
        LSA_ASSERT(!pszValue);
 
469
        dwError = LwLdapEscapeString(&pszValue, pszValueToEscape);
 
470
        BAIL_ON_LSA_ERROR(dwError);
 
471
 
 
472
        pszMatchTerm = pszValueToEscape;
 
473
        pFreeValueContext = pszValue;
 
474
    }
 
475
    else if (pszValueToHex)
 
476
    {
 
477
        LSA_ASSERT(!pszValue);
 
478
        dwError = LsaSidStrToLdapFormatHexStr(pszValueToHex, &pszValue);
 
479
        BAIL_ON_LSA_ERROR(dwError);
 
480
 
 
481
        pszMatchTerm = pszValueToHex;
 
482
        pFreeValueContext = pszValue;
 
483
    }
 
484
    else
 
485
    {
 
486
        pszMatchTerm = pszValue;
 
487
    }
 
488
 
 
489
cleanup:
 
490
    // Note that the match value can be different from the value,
 
491
    // which we may need to escape or hex.
 
492
    pBatchItem->pszQueryMatchTerm = pszMatchTerm;
 
493
    *ppszValue = pszValue;
 
494
    *ppFreeValueContext = pFreeValueContext;
 
495
 
 
496
    return dwError;
 
497
 
 
498
error:
 
499
    // assing output in cleanup in case of goto cleanup in function.
 
500
    pszValueToEscape = NULL;
 
501
    pszValue = NULL;
 
502
    LW_SAFE_FREE_STRING(pFreeValueContext);
 
503
    LW_SAFE_FREE_STRING(pszAllocatedMatchTermValue);
 
504
    goto cleanup;
 
505
}
 
506
 
 
507
static
 
508
VOID
 
509
LsaAdBatchBuilderGenericFreeValueContext(
 
510
    IN PVOID pCallbackContext,
 
511
    IN OUT PVOID* ppFreeValueContext
 
512
    )
 
513
{
 
514
    LW_SAFE_FREE_MEMORY(*ppFreeValueContext);
 
515
}
 
516
 
 
517
static
 
518
PVOID
 
519
LsaAdBatchBuilderBatchItemNextItem(
 
520
    IN PVOID pCallbackContext,
 
521
    IN PVOID pItem
 
522
    )
 
523
{
 
524
    PLSA_LIST_LINKS pLinks = (PLSA_LIST_LINKS)pItem;
 
525
    return pLinks->Next;
 
526
}
 
527
 
 
528
#define AD_LDAP_QUERY_LW_USER  "(keywords=objectClass=" AD_LDAP_CLASS_LW_USER ")"
 
529
#define AD_LDAP_QUERY_LW_GROUP "(keywords=objectClass=" AD_LDAP_CLASS_LW_GROUP ")"
 
530
#define AD_LDAP_QUERY_SCHEMA_USER  "(objectClass=" AD_LDAP_CLASS_SCHEMA_USER ")"
 
531
#define AD_LDAP_QUERY_SCHEMA_GROUP "(objectClass=" AD_LDAP_CLASS_SCHEMA_GROUP ")"
 
532
#define AD_LDAP_QUERY_NON_SCHEMA "(objectClass=" AD_LDAP_CLASS_NON_SCHEMA ")"
 
533
#define AD_LDAP_QUERY_USER "(objectClass=User)"
 
534
#define AD_LDAP_QUERY_GROUP "(objectClass=Group)"
 
535
#define AD_LDAP_QUERY_DEFAULT_SCHEMA_ENABLED_USER "(uidNumber=*)"
 
536
#define AD_LDAP_QUERY_DEFAULT_SCHEMA_ENABLED_GROUP "(gidNumber=*)"
 
537
 
 
538
 
 
539
static
 
540
PCSTR
 
541
LsaAdBatchBuilderGetPseudoQueryPrefixInternal(
 
542
    IN OPTIONAL PDWORD pdwDirectoryMode,
 
543
    IN BOOLEAN bIsSchemaMode,
 
544
    IN LSA_AD_BATCH_QUERY_TYPE QueryType,
 
545
    IN LSA_AD_BATCH_OBJECT_TYPE ObjectType,
 
546
    OUT PCSTR* ppszSuffix
 
547
    )
 
548
{
 
549
    PCSTR pszPrefix = NULL;
 
550
    DWORD dwDirectoryMode = (pdwDirectoryMode == NULL ?
 
551
                             gpADProviderData->dwDirectoryMode :
 
552
                             *pdwDirectoryMode);
 
553
 
 
554
    if ((DEFAULT_MODE == dwDirectoryMode) && bIsSchemaMode)
 
555
    {
 
556
        if (LSA_AD_BATCH_QUERY_TYPE_BY_USER_ALIAS == QueryType ||
 
557
            LSA_AD_BATCH_QUERY_TYPE_BY_GROUP_ALIAS == QueryType)
 
558
        {
 
559
            switch (ObjectType)
 
560
            {
 
561
                case LSA_AD_BATCH_OBJECT_TYPE_USER:
 
562
                    pszPrefix =
 
563
                        "(&"
 
564
                        "(&" AD_LDAP_QUERY_USER AD_LDAP_QUERY_DEFAULT_SCHEMA_ENABLED_USER")"
 
565
                        "";
 
566
                    break;
 
567
                case LSA_AD_BATCH_OBJECT_TYPE_GROUP:
 
568
                    pszPrefix =
 
569
                        "(&"
 
570
                        "(&" AD_LDAP_QUERY_GROUP AD_LDAP_QUERY_DEFAULT_SCHEMA_ENABLED_GROUP")"
 
571
                        "";
 
572
                    break;
 
573
                default:
 
574
                    pszPrefix =
 
575
                        "(&"
 
576
                        "(|"
 
577
                        "(&" AD_LDAP_QUERY_USER AD_LDAP_QUERY_DEFAULT_SCHEMA_ENABLED_USER")"
 
578
                        "(&" AD_LDAP_QUERY_GROUP AD_LDAP_QUERY_DEFAULT_SCHEMA_ENABLED_GROUP")"
 
579
                        ")"
 
580
                        "";
 
581
            }
 
582
        }
 
583
        else
 
584
        {
 
585
            switch (ObjectType)
 
586
            {
 
587
                case LSA_AD_BATCH_OBJECT_TYPE_USER:
 
588
                    pszPrefix =
 
589
                        "(&"
 
590
                        "(&" AD_LDAP_QUERY_USER ")"
 
591
                        "";
 
592
                    break;
 
593
                case LSA_AD_BATCH_OBJECT_TYPE_GROUP:
 
594
                    pszPrefix =
 
595
                        "(&"
 
596
                        "(&" AD_LDAP_QUERY_GROUP ")"
 
597
                        "";
 
598
                    break;
 
599
                default:
 
600
                    pszPrefix =
 
601
                        "(&"
 
602
                        "(|"
 
603
                        "(&" AD_LDAP_QUERY_USER ")"
 
604
                        "(&" AD_LDAP_QUERY_GROUP ")"
 
605
                        ")"
 
606
                        "";
 
607
            }
 
608
        }
 
609
    }
 
610
    else if (bIsSchemaMode)
 
611
    {
 
612
        switch (ObjectType)
 
613
        {
 
614
            case LSA_AD_BATCH_OBJECT_TYPE_USER:
 
615
                pszPrefix =
 
616
                    "(&"
 
617
                    "(&" AD_LDAP_QUERY_SCHEMA_USER AD_LDAP_QUERY_LW_USER ")"
 
618
                    "";
 
619
                break;
 
620
            case LSA_AD_BATCH_OBJECT_TYPE_GROUP:
 
621
                pszPrefix =
 
622
                    "(&"
 
623
                    "(&" AD_LDAP_QUERY_SCHEMA_GROUP AD_LDAP_QUERY_LW_GROUP ")"
 
624
                    "";
 
625
                break;
 
626
            default:
 
627
                pszPrefix =
 
628
                    "(&"
 
629
                    "(|"
 
630
                    "(&" AD_LDAP_QUERY_SCHEMA_USER AD_LDAP_QUERY_LW_USER ")"
 
631
                    "(&" AD_LDAP_QUERY_SCHEMA_GROUP AD_LDAP_QUERY_LW_GROUP ")"
 
632
                    ")"
 
633
                    "";
 
634
        }
 
635
    }
 
636
    else
 
637
    {
 
638
        switch (ObjectType)
 
639
        {
 
640
            case LSA_AD_BATCH_OBJECT_TYPE_USER:
 
641
                pszPrefix =
 
642
                    "(&"
 
643
                    AD_LDAP_QUERY_NON_SCHEMA
 
644
                    AD_LDAP_QUERY_LW_USER
 
645
                    "";
 
646
                break;
 
647
            case LSA_AD_BATCH_OBJECT_TYPE_GROUP:
 
648
                pszPrefix =
 
649
                    "(&"
 
650
                    AD_LDAP_QUERY_NON_SCHEMA
 
651
                    AD_LDAP_QUERY_LW_GROUP
 
652
                    "";
 
653
                break;
 
654
            default:
 
655
                pszPrefix =
 
656
                    "(&"
 
657
                    AD_LDAP_QUERY_NON_SCHEMA
 
658
                    "(|"
 
659
                    AD_LDAP_QUERY_LW_USER
 
660
                    AD_LDAP_QUERY_LW_GROUP
 
661
                    ")"
 
662
                    "";
 
663
        }
 
664
    }
 
665
 
 
666
    *ppszSuffix = pszPrefix ? ")" : NULL;
 
667
    return pszPrefix;
 
668
}
 
669
 
 
670
static
 
671
PCSTR
 
672
LsaAdBatchBuilderGetPseudoQueryAttributeInternal(
 
673
    IN OPTIONAL PDWORD pdwDirectoryMode,
 
674
    IN BOOLEAN bIsSchemaMode,
 
675
    IN LSA_AD_BATCH_QUERY_TYPE QueryType
 
676
    )
 
677
{
 
678
    PCSTR pszAttributeName = NULL;
 
679
 
 
680
    switch (QueryType)
 
681
    {
 
682
        case LSA_AD_BATCH_QUERY_TYPE_BY_SID:
 
683
            if (bIsSchemaMode &&
 
684
                pdwDirectoryMode != NULL && *pdwDirectoryMode == DEFAULT_MODE)
 
685
            {
 
686
                pszAttributeName = AD_LDAP_OBJECTSID_TAG;
 
687
            }
 
688
            else
 
689
            {
 
690
                pszAttributeName = "keywords=" AD_LDAP_BACKLINK_PSEUDO_TAG;
 
691
            }
 
692
            break;
 
693
        case LSA_AD_BATCH_QUERY_TYPE_BY_UID:
 
694
            if (bIsSchemaMode)
 
695
            {
 
696
                pszAttributeName = AD_LDAP_UID_TAG;
 
697
            }
 
698
            else
 
699
            {
 
700
                pszAttributeName = "keywords=" AD_LDAP_UID_TAG;
 
701
            }
 
702
            break;
 
703
        case LSA_AD_BATCH_QUERY_TYPE_BY_GID:
 
704
            if (bIsSchemaMode)
 
705
            {
 
706
                pszAttributeName = AD_LDAP_GID_TAG;
 
707
            }
 
708
            else
 
709
            {
 
710
                pszAttributeName = "keywords=" AD_LDAP_GID_TAG;
 
711
            }
 
712
            break;
 
713
        case LSA_AD_BATCH_QUERY_TYPE_BY_USER_ALIAS:
 
714
            if (bIsSchemaMode)
 
715
            {
 
716
                pszAttributeName = AD_LDAP_ALIAS_TAG;
 
717
            }
 
718
            else
 
719
            {
 
720
                pszAttributeName = "keywords=" AD_LDAP_ALIAS_TAG;
 
721
            }
 
722
            break;
 
723
        case LSA_AD_BATCH_QUERY_TYPE_BY_GROUP_ALIAS:
 
724
            if (bIsSchemaMode)
 
725
            {
 
726
                pszAttributeName = AD_LDAP_DISPLAY_NAME_TAG;
 
727
            }
 
728
            else
 
729
            {
 
730
                pszAttributeName = "keywords=" AD_LDAP_DISPLAY_NAME_TAG;
 
731
            }
 
732
            break;
 
733
    }
 
734
 
 
735
    return pszAttributeName;
 
736
}
 
737
 
 
738
DWORD
 
739
LsaAdBatchBuildQueryForRpc(
 
740
    IN PCSTR pszNetbiosDomainName,
 
741
    IN LSA_AD_BATCH_QUERY_TYPE QueryType,
 
742
    // List of PLSA_AD_BATCH_ITEM
 
743
    IN PLSA_LIST_LINKS pFirstLinks,
 
744
    IN PLSA_LIST_LINKS pEndLinks,
 
745
    OUT PLSA_LIST_LINKS* ppNextLinks,
 
746
    IN DWORD dwMaxQueryCount,
 
747
    OUT PDWORD pdwQueryCount,
 
748
    OUT PSTR** pppszQueryList
 
749
    )
 
750
{
 
751
    DWORD dwError = 0;
 
752
    PLSA_LIST_LINKS pLinks = NULL;
 
753
    PSTR* ppszQueryList = NULL;
 
754
    PLSA_LIST_LINKS pLastLinks = pFirstLinks;
 
755
    DWORD dwQueryCount = 0;
 
756
    DWORD dwSavedQueryCount = 0;
 
757
 
 
758
    pLinks = pFirstLinks;
 
759
    for (pLinks = pFirstLinks; pLinks != pEndLinks; pLinks = pLinks->Next)
 
760
    {
 
761
        PLSA_AD_BATCH_ITEM pBatchItem = LW_STRUCT_FROM_FIELD(pLinks, LSA_AD_BATCH_ITEM, BatchItemListLinks);
 
762
        PCSTR pszQueryTerm = NULL;
 
763
 
 
764
        switch (QueryType)
 
765
        {
 
766
            case LSA_AD_BATCH_QUERY_TYPE_BY_SID:
 
767
            {
 
768
                if (pBatchItem->pszSid)
 
769
                {
 
770
                    pszQueryTerm = pBatchItem->pszSid;
 
771
                }
 
772
                else if (QueryType == pBatchItem->QueryTerm.Type)
 
773
                {
 
774
                    pszQueryTerm = pBatchItem->QueryTerm.pszString;
 
775
                }
 
776
                break;
 
777
            }
 
778
            case LSA_AD_BATCH_QUERY_TYPE_BY_NT4:
 
779
            {
 
780
                if (pBatchItem->pszSamAccountName)
 
781
                {
 
782
                    pszQueryTerm = pBatchItem->pszSamAccountName;
 
783
                }
 
784
                else if (QueryType == pBatchItem->QueryTerm.Type)
 
785
                {
 
786
                    pszQueryTerm = pBatchItem->QueryTerm.pszString;
 
787
                }
 
788
                break;
 
789
            }
 
790
            default:
 
791
                LSA_ASSERT(FALSE);
 
792
                dwError = LW_ERROR_INTERNAL;
 
793
                BAIL_ON_LSA_ERROR(dwError);
 
794
        }
 
795
 
 
796
        if (!LW_IS_NULL_OR_EMPTY_STR(pszQueryTerm))
 
797
        {
 
798
            DWORD dwNewQueryCount = dwQueryCount + 1;
 
799
 
 
800
            if (dwMaxQueryCount && (dwNewQueryCount > dwMaxQueryCount))
 
801
            {
 
802
                break;
 
803
            }
 
804
            dwQueryCount = dwNewQueryCount;
 
805
        }
 
806
    }
 
807
    pLastLinks = pLinks;
 
808
    dwSavedQueryCount = dwQueryCount;
 
809
 
 
810
    if (dwQueryCount < 1)
 
811
    {
 
812
        goto cleanup;
 
813
    }
 
814
 
 
815
    dwError = LwAllocateMemory(dwQueryCount*sizeof(*ppszQueryList), (PVOID*)&ppszQueryList);
 
816
    BAIL_ON_LSA_ERROR(dwError);
 
817
 
 
818
    dwQueryCount = 0;
 
819
    // Loop until we reach last links.
 
820
    for (pLinks = pFirstLinks; pLinks != pLastLinks; pLinks = pLinks->Next)
 
821
    {
 
822
        PLSA_AD_BATCH_ITEM pBatchItem = LW_STRUCT_FROM_FIELD(pLinks, LSA_AD_BATCH_ITEM, BatchItemListLinks);
 
823
 
 
824
        if (IsSetFlag(pBatchItem->Flags, LSA_AD_BATCH_ITEM_FLAG_ALLOCATED_MATCH_TERM))
 
825
        {
 
826
            LW_SAFE_FREE_STRING(pBatchItem->pszQueryMatchTerm);
 
827
            ClearFlag(pBatchItem->Flags, LSA_AD_BATCH_ITEM_FLAG_ALLOCATED_MATCH_TERM);
 
828
        }
 
829
 
 
830
        switch (QueryType)
 
831
        {
 
832
            case LSA_AD_BATCH_QUERY_TYPE_BY_SID:
 
833
            {
 
834
                PCSTR pszUseSid = NULL;
 
835
                if (pBatchItem->pszSid)
 
836
                {
 
837
                    pszUseSid = pBatchItem->pszSid;
 
838
                }
 
839
                else if (QueryType == pBatchItem->QueryTerm.Type)
 
840
                {
 
841
                    pszUseSid = pBatchItem->QueryTerm.pszString;
 
842
                }
 
843
                // We might not have a SID if we failed to find a pseudo.
 
844
                if (pszUseSid)
 
845
                {
 
846
                    dwError = LwAllocateString(pszUseSid,
 
847
                                                &ppszQueryList[dwQueryCount++]);
 
848
                    BAIL_ON_LSA_ERROR(dwError);
 
849
                    pBatchItem->pszQueryMatchTerm = (PSTR)pszUseSid;
 
850
                }
 
851
                break;
 
852
            }
 
853
 
 
854
            case LSA_AD_BATCH_QUERY_TYPE_BY_NT4:
 
855
            {
 
856
                PCSTR pszUseSamAccountName = NULL;
 
857
                if (pBatchItem->pszSamAccountName)
 
858
                {
 
859
                    pszUseSamAccountName = pBatchItem->pszSamAccountName;
 
860
                }
 
861
                else if (QueryType == pBatchItem->QueryTerm.Type)
 
862
                {
 
863
                    pszUseSamAccountName = pBatchItem->QueryTerm.pszString;
 
864
                }
 
865
                if (pszUseSamAccountName)
 
866
                {
 
867
                    dwError = LwAllocateStringPrintf(
 
868
                                    &ppszQueryList[dwQueryCount++],
 
869
                                    "%s\\%s",
 
870
                                    pszNetbiosDomainName,
 
871
                                    pszUseSamAccountName);
 
872
                    BAIL_ON_LSA_ERROR(dwError);
 
873
                    pBatchItem->pszQueryMatchTerm = (PSTR)pszUseSamAccountName;
 
874
                }
 
875
                break;
 
876
            }
 
877
            default:
 
878
                LSA_ASSERT(FALSE);
 
879
                dwError = LW_ERROR_INTERNAL;
 
880
                BAIL_ON_LSA_ERROR(dwError);
 
881
        }
 
882
    }
 
883
 
 
884
    assert(dwSavedQueryCount == dwQueryCount);
 
885
 
 
886
cleanup:
 
887
    // We handle error here instead of error label
 
888
    // because there is a goto cleanup above.
 
889
    if (dwError)
 
890
    {
 
891
        LwFreeStringArray(ppszQueryList, dwSavedQueryCount);
 
892
        dwQueryCount = 0;
 
893
        dwSavedQueryCount = 0;
 
894
        pLastLinks = pFirstLinks;
 
895
    }
 
896
 
 
897
    *pppszQueryList = ppszQueryList;
 
898
    *pdwQueryCount = dwQueryCount;
 
899
    *ppNextLinks = pLastLinks;
 
900
 
 
901
    return dwError;
 
902
 
 
903
error:
 
904
    // Do not actually handle any errors here.
 
905
    goto cleanup;
 
906
}
 
907
 
 
908
DWORD
 
909
LsaAdBatchBuildQueryForReal(
 
910
    IN LSA_AD_BATCH_QUERY_TYPE QueryType,
 
911
    // List of PLSA_AD_BATCH_ITEM
 
912
    IN PLSA_LIST_LINKS pFirstLinks,
 
913
    IN PLSA_LIST_LINKS pEndLinks,
 
914
    OUT PLSA_LIST_LINKS* ppNextLinks,
 
915
    IN DWORD dwMaxQuerySize,
 
916
    IN DWORD dwMaxQueryCount,
 
917
    OUT PDWORD pdwQueryCount,
 
918
    OUT PSTR* ppszQuery
 
919
    )
 
920
{
 
921
    DWORD dwError = 0;
 
922
    PLSA_LIST_LINKS pNextLinks = NULL;
 
923
    DWORD dwQueryCount = 0;
 
924
    PSTR pszQuery = NULL;
 
925
    PCSTR pszAttributeName = NULL;
 
926
    PCSTR pszPrefix = NULL;
 
927
    LSA_AD_BATCH_BUILDER_BATCH_ITEM_CONTEXT context = { 0 };
 
928
 
 
929
    switch (QueryType)
 
930
    {
 
931
        case LSA_AD_BATCH_QUERY_TYPE_BY_DN:
 
932
            pszAttributeName = AD_LDAP_DN_TAG;
 
933
            break;
 
934
        case LSA_AD_BATCH_QUERY_TYPE_BY_SID:
 
935
            pszAttributeName = AD_LDAP_OBJECTSID_TAG;
 
936
            break;
 
937
        case LSA_AD_BATCH_QUERY_TYPE_BY_NT4:
 
938
            pszAttributeName = AD_LDAP_SAM_NAME_TAG;
 
939
            break;
 
940
        default:
 
941
            dwError = LW_ERROR_INVALID_PARAMETER;
 
942
            BAIL_ON_LSA_ERROR(dwError);
 
943
    }
 
944
 
 
945
    // In Default/schema case, filter out disabled users
 
946
    // when querying real objects.
 
947
    if ((gpADProviderData->dwDirectoryMode == DEFAULT_MODE) &&
 
948
        (gpADProviderData->adConfigurationMode == SchemaMode))
 
949
    {
 
950
        pszPrefix = "(&(|(&(objectClass=user)(uidNumber=*))(objectClass=group))(!(objectClass=computer))";
 
951
    }
 
952
    else
 
953
    {
 
954
#if 0
 
955
        pszPrefix = "(&(|(objectClass=user)(objectClass=group))(!(objectClass=computer))";
 
956
#else
 
957
        /* Enable machine accounts in the unprovisioned provider.
 
958
           This is needed for the srv driver in lwio.  Clients frequently
 
959
           connect using their machine account credentials for dfs referrals,
 
960
           querying server capabilities, etc....  -- gcarter@likewise.com */
 
961
 
 
962
        pszPrefix = "(&(|(objectClass=user)(&(objectClass=group)(groupType<=0)))";
 
963
#endif
 
964
    }
 
965
 
 
966
    context.QueryType = QueryType;
 
967
    context.bIsForRealObject = TRUE;
 
968
 
 
969
    dwError = LsaAdBatchBuilderCreateQuery(
 
970
                    pszPrefix,
 
971
                    ")",
 
972
                    pszAttributeName,
 
973
                    pFirstLinks,
 
974
                    pEndLinks,
 
975
                    (PVOID*)&pNextLinks,
 
976
                    &context,
 
977
                    LsaAdBatchBuilderBatchItemGetAttributeValue,
 
978
                    LsaAdBatchBuilderGenericFreeValueContext,
 
979
                    LsaAdBatchBuilderBatchItemNextItem,
 
980
                    dwMaxQuerySize,
 
981
                    dwMaxQueryCount,
 
982
                    &dwQueryCount,
 
983
                    &pszQuery);
 
984
    BAIL_ON_LSA_ERROR(dwError);
 
985
 
 
986
cleanup:
 
987
    *ppNextLinks = pNextLinks;
 
988
    *pdwQueryCount = dwQueryCount;
 
989
    *ppszQuery = pszQuery;
 
990
    return dwError;
 
991
 
 
992
error:
 
993
    // set output on cleanup
 
994
    pNextLinks = pFirstLinks;
 
995
    dwQueryCount = 0;
 
996
    LW_SAFE_FREE_STRING(pszQuery);
 
997
    goto cleanup;
 
998
}
 
999
 
 
1000
static
 
1001
DWORD
 
1002
LsaAdBatchBuildQueryForPseudoInternal(
 
1003
    IN BOOLEAN bIsSchemaMode,
 
1004
    IN OPTIONAL PDWORD pdwDirectoryMode,
 
1005
    IN LSA_AD_BATCH_QUERY_TYPE QueryType,
 
1006
    // List of PLSA_AD_BATCH_ITEM
 
1007
    IN PLSA_LIST_LINKS pFirstLinks,
 
1008
    IN PLSA_LIST_LINKS pEndLinks,
 
1009
    OUT PLSA_LIST_LINKS* ppNextLinks,
 
1010
    IN DWORD dwMaxQuerySize,
 
1011
    IN DWORD dwMaxQueryCount,
 
1012
    OUT PDWORD pdwQueryCount,
 
1013
    OUT PSTR* ppszQuery
 
1014
    )
 
1015
{
 
1016
    DWORD dwError = 0;
 
1017
    PLSA_LIST_LINKS pNextLinks = NULL;
 
1018
    DWORD dwQueryCount = 0;
 
1019
    PSTR pszQuery = NULL;
 
1020
    PCSTR pszAttributeName = NULL;
 
1021
    PCSTR pszPrefix = NULL;
 
1022
    PCSTR pszSuffix = NULL;
 
1023
    LSA_AD_BATCH_BUILDER_BATCH_ITEM_CONTEXT context = { 0 };
 
1024
 
 
1025
    pszAttributeName = LsaAdBatchBuilderGetPseudoQueryAttributeInternal(
 
1026
                            pdwDirectoryMode,
 
1027
                            bIsSchemaMode,
 
1028
                            QueryType);
 
1029
    if (!pszAttributeName)
 
1030
    {
 
1031
        LSA_ASSERT(FALSE);
 
1032
        dwError = LW_ERROR_INVALID_PARAMETER;
 
1033
        BAIL_ON_LSA_ERROR(dwError);
 
1034
    }
 
1035
 
 
1036
    pszPrefix = LsaAdBatchBuilderGetPseudoQueryPrefixInternal(
 
1037
                        pdwDirectoryMode,
 
1038
                        bIsSchemaMode,
 
1039
                        QueryType,
 
1040
                        LsaAdBatchGetObjectTypeFromQueryType(QueryType),
 
1041
                        &pszSuffix);
 
1042
 
 
1043
    if (!pszPrefix || !pszSuffix)
 
1044
    {
 
1045
        LSA_ASSERT(FALSE);
 
1046
        dwError = LW_ERROR_INVALID_PARAMETER;
 
1047
        BAIL_ON_LSA_ERROR(dwError);
 
1048
    }
 
1049
 
 
1050
    context.QueryType = QueryType;
 
1051
    context.bIsForRealObject = FALSE;
 
1052
 
 
1053
    dwError = LsaAdBatchBuilderCreateQuery(
 
1054
                    pszPrefix,
 
1055
                    pszSuffix,
 
1056
                    pszAttributeName,
 
1057
                    pFirstLinks,
 
1058
                    pEndLinks,
 
1059
                    (PVOID*)&pNextLinks,
 
1060
                    &context,
 
1061
                    LsaAdBatchBuilderBatchItemGetAttributeValue,
 
1062
                    LsaAdBatchBuilderGenericFreeValueContext,
 
1063
                    LsaAdBatchBuilderBatchItemNextItem,
 
1064
                    dwMaxQuerySize,
 
1065
                    dwMaxQueryCount,
 
1066
                    &dwQueryCount,
 
1067
                    &pszQuery);
 
1068
    BAIL_ON_LSA_ERROR(dwError);
 
1069
 
 
1070
cleanup:
 
1071
    *ppNextLinks = pNextLinks;
 
1072
    *pdwQueryCount = dwQueryCount;
 
1073
    *ppszQuery = pszQuery;
 
1074
    return dwError;
 
1075
 
 
1076
error:
 
1077
    // set output on cleanup
 
1078
    pNextLinks = pFirstLinks;
 
1079
    dwQueryCount = 0;
 
1080
    LW_SAFE_FREE_STRING(pszQuery);
 
1081
    goto cleanup;
 
1082
}
 
1083
 
 
1084
DWORD
 
1085
LsaAdBatchBuildQueryForPseudo(
 
1086
    IN BOOLEAN bIsSchemaMode,
 
1087
    IN LSA_AD_BATCH_QUERY_TYPE QueryType,
 
1088
    // List of PLSA_AD_BATCH_ITEM
 
1089
    IN PLSA_LIST_LINKS pFirstLinks,
 
1090
    IN PLSA_LIST_LINKS pEndLinks,
 
1091
    OUT PLSA_LIST_LINKS* ppNextLinks,
 
1092
    IN DWORD dwMaxQuerySize,
 
1093
    IN DWORD dwMaxQueryCount,
 
1094
    OUT PDWORD pdwQueryCount,
 
1095
    OUT PSTR* ppszQuery
 
1096
    )
 
1097
{
 
1098
    return  LsaAdBatchBuildQueryForPseudoInternal(
 
1099
                    bIsSchemaMode,
 
1100
                    NULL,
 
1101
                    QueryType,
 
1102
                    pFirstLinks,
 
1103
                    pEndLinks,
 
1104
                    ppNextLinks,
 
1105
                    dwMaxQuerySize,
 
1106
                    dwMaxQueryCount,
 
1107
                    pdwQueryCount,
 
1108
                    ppszQuery);
 
1109
}
 
1110
 
 
1111
DWORD
 
1112
LsaAdBatchBuildQueryForPseudoDefaultSchema(
 
1113
    IN LSA_AD_BATCH_QUERY_TYPE QueryType,
 
1114
    // List of PLSA_AD_BATCH_ITEM
 
1115
    IN PLSA_LIST_LINKS pFirstLinks,
 
1116
    IN PLSA_LIST_LINKS pEndLinks,
 
1117
    OUT PLSA_LIST_LINKS* ppNextLinks,
 
1118
    IN DWORD dwMaxQuerySize,
 
1119
    IN DWORD dwMaxQueryCount,
 
1120
    OUT PDWORD pdwQueryCount,
 
1121
    OUT PSTR* ppszQuery
 
1122
    )
 
1123
{
 
1124
    DWORD dwDirectoryMode = DEFAULT_MODE;
 
1125
 
 
1126
    return LsaAdBatchBuildQueryForPseudoInternal(
 
1127
                    TRUE,
 
1128
                    &dwDirectoryMode,
 
1129
                    QueryType,
 
1130
                    pFirstLinks,
 
1131
                    pEndLinks,
 
1132
                    ppNextLinks,
 
1133
                    dwMaxQuerySize,
 
1134
                    dwMaxQueryCount,
 
1135
                    pdwQueryCount,
 
1136
                    ppszQuery);
 
1137
}