~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/dsdb/samdb/ldb_modules/extended_dn_out.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
   ldb database library
 
3
 
 
4
   Copyright (C) Simo Sorce 2005-2008
 
5
   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007-2008
 
6
 
 
7
   This program is free software; you can redistribute it and/or modify
 
8
   it under the terms of the GNU General Public License as published by
 
9
   the Free Software Foundation; either version 3 of the License, or
 
10
   (at your option) any later version.
 
11
   
 
12
   This program is distributed in the hope that it will be useful,
 
13
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
   GNU General Public License for more details.
 
16
   
 
17
   You should have received a copy of the GNU General Public License
 
18
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
19
*/
 
20
 
 
21
/*
 
22
 *  Name: ldb
 
23
 *
 
24
 *  Component: ldb extended dn control module
 
25
 *
 
26
 *  Description: this module builds a special dn for returned search
 
27
 *  results, and fixes some other aspects of the result (returned case issues)
 
28
 *  values.
 
29
 *
 
30
 *  Authors: Simo Sorce
 
31
 *           Andrew Bartlett
 
32
 */
 
33
 
 
34
#include "includes.h"
 
35
#include "ldb/include/ldb.h"
 
36
#include "ldb/include/ldb_errors.h"
 
37
#include "ldb/include/ldb_private.h"
 
38
#include "librpc/gen_ndr/ndr_misc.h"
 
39
#include "librpc/ndr/libndr.h"
 
40
#include "dsdb/samdb/samdb.h"
 
41
 
 
42
struct extended_dn_out_private {
 
43
        bool dereference;
 
44
        bool normalise;
 
45
        struct dsdb_openldap_dereference_control *dereference_control;
 
46
};
 
47
 
 
48
static bool is_attr_in_list(const char * const * attrs, const char *attr)
 
49
{
 
50
        int i;
 
51
 
 
52
        for (i = 0; attrs[i]; i++) {
 
53
                if (ldb_attr_cmp(attrs[i], attr) == 0)
 
54
                        return true;
 
55
        }
 
56
 
 
57
        return false;
 
58
}
 
59
 
 
60
static char **copy_attrs(void *mem_ctx, const char * const * attrs)
 
61
{
 
62
        char **nattrs;
 
63
        int i, num;
 
64
 
 
65
        for (num = 0; attrs[num]; num++);
 
66
 
 
67
        nattrs = talloc_array(mem_ctx, char *, num + 1);
 
68
        if (!nattrs) return NULL;
 
69
 
 
70
        for(i = 0; i < num; i++) {
 
71
                nattrs[i] = talloc_strdup(nattrs, attrs[i]);
 
72
                if (!nattrs[i]) {
 
73
                        talloc_free(nattrs);
 
74
                        return NULL;
 
75
                }
 
76
        }
 
77
        nattrs[i] = NULL;
 
78
 
 
79
        return nattrs;
 
80
}
 
81
 
 
82
static bool add_attrs(void *mem_ctx, char ***attrs, const char *attr)
 
83
{
 
84
        char **nattrs;
 
85
        int num;
 
86
 
 
87
        for (num = 0; (*attrs)[num]; num++);
 
88
 
 
89
        nattrs = talloc_realloc(mem_ctx, *attrs, char *, num + 2);
 
90
        if (!nattrs) return false;
 
91
 
 
92
        *attrs = nattrs;
 
93
 
 
94
        nattrs[num] = talloc_strdup(nattrs, attr);
 
95
        if (!nattrs[num]) return false;
 
96
 
 
97
        nattrs[num + 1] = NULL;
 
98
 
 
99
        return true;
 
100
}
 
101
 
 
102
/* Fix the DN so that the relative attribute names are in upper case so that the DN:
 
103
   cn=Adminstrator,cn=users,dc=samba,dc=example,dc=com becomes
 
104
   CN=Adminstrator,CN=users,DC=samba,DC=example,DC=com
 
105
*/
 
106
 
 
107
 
 
108
static int fix_dn(struct ldb_dn *dn) 
 
109
{
 
110
        int i, ret;
 
111
        char *upper_rdn_attr;
 
112
 
 
113
        for (i=0; i < ldb_dn_get_comp_num(dn); i++) {
 
114
                /* We need the attribute name in upper case */
 
115
                upper_rdn_attr = strupper_talloc(dn,
 
116
                                                 ldb_dn_get_component_name(dn, i));
 
117
                if (!upper_rdn_attr) {
 
118
                        return LDB_ERR_OPERATIONS_ERROR;
 
119
                }
 
120
                
 
121
                /* And replace it with CN=foo (we need the attribute in upper case */
 
122
                ret = ldb_dn_set_component(dn, i, upper_rdn_attr,
 
123
                                           *ldb_dn_get_component_val(dn, i));
 
124
                talloc_free(upper_rdn_attr);
 
125
                if (ret != LDB_SUCCESS) {
 
126
                        return ret;
 
127
                }
 
128
        }
 
129
        return LDB_SUCCESS;
 
130
}
 
131
 
 
132
/* Inject the extended DN components, so the DN cn=Adminstrator,cn=users,dc=samba,dc=example,dc=com becomes
 
133
   <GUID=541203ae-f7d6-47ef-8390-bfcf019f9583>;<SID=S-1-5-21-4177067393-1453636373-93818737-500>;cn=Adminstrator,cn=users,dc=samba,dc=example,dc=com */
 
134
 
 
135
static int inject_extended_dn_out(struct ldb_reply *ares,
 
136
                                  struct ldb_context *ldb,
 
137
                                  int type,
 
138
                                  bool remove_guid,
 
139
                                  bool remove_sid)
 
140
{
 
141
        int ret;
 
142
        const DATA_BLOB *guid_blob;
 
143
        const DATA_BLOB *sid_blob;
 
144
 
 
145
        guid_blob = ldb_msg_find_ldb_val(ares->message, "objectGUID");
 
146
        sid_blob = ldb_msg_find_ldb_val(ares->message, "objectSID");
 
147
 
 
148
        if (!guid_blob) {
 
149
                ldb_set_errstring(ldb, "Did not find objectGUID to inject into extended DN");
 
150
                return LDB_ERR_OPERATIONS_ERROR;
 
151
        }
 
152
 
 
153
        ret = ldb_dn_set_extended_component(ares->message->dn, "GUID", guid_blob);
 
154
        if (ret != LDB_SUCCESS) {
 
155
                return ret;
 
156
        }
 
157
        if (sid_blob) {
 
158
                ret = ldb_dn_set_extended_component(ares->message->dn, "SID", sid_blob);
 
159
                if (ret != LDB_SUCCESS) {
 
160
                        return ret;
 
161
                }
 
162
        }
 
163
 
 
164
        if (remove_guid) {
 
165
                ldb_msg_remove_attr(ares->message, "objectGUID");
 
166
        }
 
167
 
 
168
        if (sid_blob && remove_sid) {
 
169
                ldb_msg_remove_attr(ares->message, "objectSID");
 
170
        }
 
171
 
 
172
        return LDB_SUCCESS;
 
173
}
 
174
 
 
175
static int handle_dereference(struct ldb_dn *dn,
 
176
                              struct dsdb_openldap_dereference_result **dereference_attrs, 
 
177
                              const char *attr, const DATA_BLOB *val)
 
178
{
 
179
        const struct ldb_val *entryUUIDblob, *sid_blob;
 
180
        struct ldb_message fake_msg; /* easier to use routines that expect an ldb_message */
 
181
        int j;
 
182
        
 
183
        fake_msg.num_elements = 0;
 
184
                        
 
185
        /* Look for this attribute in the returned control */
 
186
        for (j = 0; dereference_attrs && dereference_attrs[j]; j++) {
 
187
                struct ldb_val source_dn = data_blob_string_const(dereference_attrs[j]->dereferenced_dn);
 
188
                if (ldb_attr_cmp(dereference_attrs[j]->source_attribute, attr) == 0
 
189
                    && data_blob_cmp(&source_dn, val) == 0) {
 
190
                        fake_msg.num_elements = dereference_attrs[j]->num_attributes;
 
191
                        fake_msg.elements = dereference_attrs[j]->attributes;
 
192
                        break;
 
193
                }
 
194
        }
 
195
        if (!fake_msg.num_elements) {
 
196
                return LDB_SUCCESS;
 
197
        }
 
198
        /* Look for an OpenLDAP entryUUID */
 
199
        
 
200
        entryUUIDblob = ldb_msg_find_ldb_val(&fake_msg, "entryUUID");
 
201
        if (entryUUIDblob) {
 
202
                NTSTATUS status;
 
203
                enum ndr_err_code ndr_err;
 
204
                
 
205
                struct ldb_val guid_blob;
 
206
                struct GUID guid;
 
207
                
 
208
                status = GUID_from_data_blob(entryUUIDblob, &guid);
 
209
                
 
210
                if (!NT_STATUS_IS_OK(status)) {
 
211
                        return LDB_ERR_INVALID_DN_SYNTAX;
 
212
                }
 
213
                ndr_err = ndr_push_struct_blob(&guid_blob, NULL, NULL, &guid,
 
214
                                               (ndr_push_flags_fn_t)ndr_push_GUID);
 
215
                if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 
216
                        return LDB_ERR_INVALID_DN_SYNTAX;
 
217
                }
 
218
                
 
219
                ldb_dn_set_extended_component(dn, "GUID", &guid_blob);
 
220
        }
 
221
        
 
222
        sid_blob = ldb_msg_find_ldb_val(&fake_msg, "objectSID");
 
223
        
 
224
        /* Look for the objectSID */
 
225
        if (sid_blob) {
 
226
                ldb_dn_set_extended_component(dn, "SID", sid_blob);
 
227
        }
 
228
        return LDB_SUCCESS;
 
229
}
 
230
 
 
231
/* search */
 
232
struct extended_search_context {
 
233
        struct ldb_module *module;
 
234
        const struct dsdb_schema *schema;
 
235
        struct ldb_request *req;
 
236
        bool inject;
 
237
        bool remove_guid;
 
238
        bool remove_sid;
 
239
        int extended_type;
 
240
};
 
241
 
 
242
static int extended_callback(struct ldb_request *req, struct ldb_reply *ares)
 
243
{
 
244
        struct extended_search_context *ac;
 
245
        struct ldb_control *control;
 
246
        struct dsdb_openldap_dereference_result_control *dereference_control = NULL;
 
247
        int ret, i, j;
 
248
        struct ldb_message *msg = ares->message;
 
249
        struct extended_dn_out_private *p;
 
250
 
 
251
        ac = talloc_get_type(req->context, struct extended_search_context);
 
252
        p = talloc_get_type(ac->module->private_data, struct extended_dn_out_private);
 
253
 
 
254
        if (!ares) {
 
255
                return ldb_module_done(ac->req, NULL, NULL,
 
256
                                        LDB_ERR_OPERATIONS_ERROR);
 
257
        }
 
258
        if (ares->error != LDB_SUCCESS) {
 
259
                return ldb_module_done(ac->req, ares->controls,
 
260
                                        ares->response, ares->error);
 
261
        }
 
262
 
 
263
        switch (ares->type) {
 
264
        case LDB_REPLY_REFERRAL:
 
265
                return ldb_module_send_referral(ac->req, ares->referral);
 
266
 
 
267
        case LDB_REPLY_DONE:
 
268
                return ldb_module_done(ac->req, ares->controls,
 
269
                                        ares->response, LDB_SUCCESS);
 
270
        case LDB_REPLY_ENTRY:
 
271
                break;
 
272
        }
 
273
 
 
274
        if (p && p->normalise) {
 
275
                ret = fix_dn(ares->message->dn);
 
276
                if (ret != LDB_SUCCESS) {
 
277
                        return ldb_module_done(ac->req, NULL, NULL, ret);
 
278
                }
 
279
        }
 
280
                        
 
281
        if (ac->inject) {
 
282
                /* for each record returned post-process to add any derived
 
283
                   attributes that have been asked for */
 
284
                ret = inject_extended_dn_out(ares, ac->module->ldb,
 
285
                                             ac->extended_type, ac->remove_guid,
 
286
                                             ac->remove_sid);
 
287
                if (ret != LDB_SUCCESS) {
 
288
                        return ldb_module_done(ac->req, NULL, NULL, ret);
 
289
                }
 
290
        }
 
291
 
 
292
        if ((p && p->normalise) || ac->inject) {
 
293
                const struct ldb_val *val = ldb_msg_find_ldb_val(ares->message, "distinguishedName");
 
294
                if (val) {
 
295
                        ldb_msg_remove_attr(ares->message, "distinguishedName");
 
296
                        if (ac->inject) {
 
297
                                ret = ldb_msg_add_steal_string(ares->message, "distinguishedName", 
 
298
                                                               ldb_dn_get_extended_linearized(ares->message, ares->message->dn, ac->extended_type));
 
299
                        } else {
 
300
                                ret = ldb_msg_add_string(ares->message, "distinguishedName", 
 
301
                                                         ldb_dn_get_linearized(ares->message->dn));
 
302
                        }
 
303
                        if (ret != LDB_SUCCESS) {
 
304
                                ldb_oom(ac->module->ldb);
 
305
                                return LDB_ERR_OPERATIONS_ERROR;
 
306
                        }
 
307
                }
 
308
        }
 
309
 
 
310
        if (p && p->dereference) {
 
311
                control = ldb_reply_get_control(ares, DSDB_OPENLDAP_DEREFERENCE_CONTROL);
 
312
        
 
313
                if (control && control->data) {
 
314
                        dereference_control = talloc_get_type(control->data, struct dsdb_openldap_dereference_result_control);
 
315
                }
 
316
        }
 
317
 
 
318
        /* Walk the retruned elements (but only if we have a schema to interpret the list with) */
 
319
        for (i = 0; ac->schema && i < msg->num_elements; i++) {
 
320
                const struct dsdb_attribute *attribute;
 
321
                attribute = dsdb_attribute_by_lDAPDisplayName(ac->schema, msg->elements[i].name);
 
322
                if (!attribute) {
 
323
                        continue;
 
324
                }
 
325
 
 
326
                if (p->normalise) {
 
327
                        /* If we are also in 'normalise' mode, then
 
328
                         * fix the attribute names to be in the
 
329
                         * correct case */
 
330
                        msg->elements[i].name = talloc_strdup(msg->elements, attribute->lDAPDisplayName);
 
331
                        if (!msg->elements[i].name) {
 
332
                                ldb_oom(ac->module->ldb);
 
333
                                return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
 
334
                        }
 
335
                }
 
336
 
 
337
                /* distinguishedName has been dealt with above */
 
338
                if (ldb_attr_cmp(msg->elements[i].name, "distinguishedName") == 0) {
 
339
                        continue;
 
340
                }
 
341
 
 
342
                /* Look to see if this attributeSyntax is a DN */
 
343
                if (strcmp(attribute->attributeSyntax_oid, "2.5.5.1") != 0) {
 
344
                        continue;
 
345
                }
 
346
 
 
347
                for (j = 0; j < msg->elements[i].num_values; j++) {
 
348
                        const char *dn_str;
 
349
                        struct ldb_dn *dn = ldb_dn_from_ldb_val(ac, ac->module->ldb, &msg->elements[i].values[j]);
 
350
                        if (!dn || !ldb_dn_validate(dn)) {
 
351
                                return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_INVALID_DN_SYNTAX);
 
352
                        }
 
353
 
 
354
                        if (p->normalise) {
 
355
                                ret = fix_dn(dn);
 
356
                                if (ret != LDB_SUCCESS) {
 
357
                                        return ldb_module_done(ac->req, NULL, NULL, ret);
 
358
                                }
 
359
                        }
 
360
                        
 
361
                        /* If we are running in dereference mode (such
 
362
                         * as against OpenLDAP) then the DN in the msg
 
363
                         * above does not contain the extended values,
 
364
                         * and we need to look in the dereference
 
365
                         * result */
 
366
 
 
367
                        /* Look for this value in the attribute */
 
368
 
 
369
                        if (dereference_control) {
 
370
                                ret = handle_dereference(dn, 
 
371
                                                         dereference_control->attributes,
 
372
                                                         msg->elements[i].name,
 
373
                                                         &msg->elements[i].values[j]);
 
374
                                if (ret != LDB_SUCCESS) {
 
375
                                        return ldb_module_done(ac->req, NULL, NULL, ret);
 
376
                                }
 
377
                        }
 
378
                        
 
379
                        if (!ac->inject) {
 
380
                                dn_str = talloc_steal(msg->elements[i].values, 
 
381
                                                      ldb_dn_get_linearized(dn));
 
382
                        } else {
 
383
                                dn_str = talloc_steal(msg->elements[i].values, 
 
384
                                                      ldb_dn_get_extended_linearized(msg->elements[i].values, 
 
385
                                                                                     dn, ac->extended_type));
 
386
                        }
 
387
                        if (!dn_str) {
 
388
                                ldb_oom(ac->module->ldb);
 
389
                                return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
 
390
                        }
 
391
                        msg->elements[i].values[j] = data_blob_string_const(dn_str);
 
392
                        talloc_free(dn);
 
393
                }
 
394
        }
 
395
        return ldb_module_send_entry(ac->req, msg, ares->controls);
 
396
}
 
397
 
 
398
 
 
399
static int extended_dn_out_search(struct ldb_module *module, struct ldb_request *req)
 
400
{
 
401
        struct ldb_control *control;
 
402
        struct ldb_control *storage_format_control;
 
403
        struct ldb_extended_dn_control *extended_ctrl = NULL;
 
404
        struct ldb_control **saved_controls;
 
405
        struct extended_search_context *ac;
 
406
        struct ldb_request *down_req;
 
407
        char **new_attrs;
 
408
        const char * const *const_attrs;
 
409
        int ret;
 
410
 
 
411
        struct extended_dn_out_private *p = talloc_get_type(module->private_data, struct extended_dn_out_private);
 
412
 
 
413
        /* check if there's an extended dn control */
 
414
        control = ldb_request_get_control(req, LDB_CONTROL_EXTENDED_DN_OID);
 
415
        if (control && control->data) {
 
416
                extended_ctrl = talloc_get_type(control->data, struct ldb_extended_dn_control);
 
417
                if (!extended_ctrl) {
 
418
                        return LDB_ERR_PROTOCOL_ERROR;
 
419
                }
 
420
        }
 
421
 
 
422
        /* Look to see if, as we are in 'store DN+GUID+SID' mode, the
 
423
         * client is after the storage format (to fill in linked
 
424
         * attributes) */
 
425
        storage_format_control = ldb_request_get_control(req, DSDB_CONTROL_DN_STORAGE_FORMAT_OID);
 
426
        if (!control && storage_format_control && storage_format_control->data) {
 
427
                extended_ctrl = talloc_get_type(storage_format_control->data, struct ldb_extended_dn_control);
 
428
                if (!extended_ctrl) {
 
429
                        ldb_set_errstring(module->ldb, "extended_dn_out: extended_ctrl was of the wrong data type");
 
430
                        return LDB_ERR_PROTOCOL_ERROR;
 
431
                }
 
432
        }
 
433
 
 
434
        ac = talloc_zero(req, struct extended_search_context);
 
435
        if (ac == NULL) {
 
436
                ldb_oom(module->ldb);
 
437
                return LDB_ERR_OPERATIONS_ERROR;
 
438
        }
 
439
 
 
440
        ac->module = module;
 
441
        ac->schema = dsdb_get_schema(module->ldb);
 
442
        ac->req = req;
 
443
        ac->inject = false;
 
444
        ac->remove_guid = false;
 
445
        ac->remove_sid = false;
 
446
        
 
447
        const_attrs = req->op.search.attrs;
 
448
 
 
449
        /* We only need to do special processing if we were asked for
 
450
         * the extended DN, or we are 'store DN+GUID+SID'
 
451
         * (!dereference) mode.  (This is the normal mode for LDB on
 
452
         * tdb). */
 
453
        if (control || (storage_format_control && p && !p->dereference)) {
 
454
                ac->inject = true;
 
455
                if (extended_ctrl) {
 
456
                        ac->extended_type = extended_ctrl->type;
 
457
                } else {
 
458
                        ac->extended_type = 0;
 
459
                }
 
460
 
 
461
                /* check if attrs only is specified, in that case check wether we need to modify them */
 
462
                if (req->op.search.attrs && !is_attr_in_list(req->op.search.attrs, "*")) {
 
463
                        if (! is_attr_in_list(req->op.search.attrs, "objectGUID")) {
 
464
                                ac->remove_guid = true;
 
465
                        }
 
466
                        if (! is_attr_in_list(req->op.search.attrs, "objectSID")) {
 
467
                                ac->remove_sid = true;
 
468
                        }
 
469
                        if (ac->remove_guid || ac->remove_sid) {
 
470
                                new_attrs = copy_attrs(ac, req->op.search.attrs);
 
471
                                if (new_attrs == NULL) {
 
472
                                        ldb_oom(module->ldb);
 
473
                                        return LDB_ERR_OPERATIONS_ERROR;
 
474
                                }
 
475
 
 
476
                                if (ac->remove_guid) {
 
477
                                        if (!add_attrs(ac, &new_attrs, "objectGUID"))
 
478
                                                return LDB_ERR_OPERATIONS_ERROR;
 
479
                                }
 
480
                                if (ac->remove_sid) {
 
481
                                        if (!add_attrs(ac, &new_attrs, "objectSID"))
 
482
                                                return LDB_ERR_OPERATIONS_ERROR;
 
483
                                }
 
484
                                const_attrs = (const char * const *)new_attrs;
 
485
                        }
 
486
                }
 
487
        }
 
488
 
 
489
        ret = ldb_build_search_req_ex(&down_req,
 
490
                                      module->ldb, ac,
 
491
                                      req->op.search.base,
 
492
                                      req->op.search.scope,
 
493
                                      req->op.search.tree,
 
494
                                      const_attrs,
 
495
                                      req->controls,
 
496
                                      ac, extended_callback,
 
497
                                      req);
 
498
        if (ret != LDB_SUCCESS) {
 
499
                return ret;
 
500
        }
 
501
 
 
502
        /* Remove extended DN and storage format controls */
 
503
 
 
504
        if (control) {
 
505
                /* save it locally and remove it from the list */
 
506
                /* we do not need to replace them later as we
 
507
                 * are keeping the original req intact */
 
508
                if (!save_controls(control, down_req, &saved_controls)) {
 
509
                        return LDB_ERR_OPERATIONS_ERROR;
 
510
                }
 
511
        }
 
512
 
 
513
        if (storage_format_control) {
 
514
                /* save it locally and remove it from the list */
 
515
                /* we do not need to replace them later as we
 
516
                 * are keeping the original req intact */
 
517
                if (!save_controls(storage_format_control, down_req, &saved_controls)) {
 
518
                        return LDB_ERR_OPERATIONS_ERROR;
 
519
                }
 
520
        }
 
521
 
 
522
        /* Add in dereference control, if we were asked to, we are
 
523
         * using the 'dereference' mode (such as with an OpenLDAP
 
524
         * backend) and have the control prepared */
 
525
        if (control && p && p->dereference && p->dereference_control) {
 
526
                ret = ldb_request_add_control(down_req,
 
527
                                              DSDB_OPENLDAP_DEREFERENCE_CONTROL,
 
528
                                              false, p->dereference_control);
 
529
                if (ret != LDB_SUCCESS) {
 
530
                        return ret;
 
531
                }
 
532
        }
 
533
 
 
534
        /* perform the search */
 
535
        return ldb_next_request(module, down_req);
 
536
}
 
537
 
 
538
static int extended_dn_out_ldb_init(struct ldb_module *module)
 
539
{
 
540
        int ret;
 
541
 
 
542
        struct extended_dn_out_private *p = talloc(module, struct extended_dn_out_private);
 
543
 
 
544
        module->private_data = p;
 
545
 
 
546
        if (!p) {
 
547
                ldb_oom(module->ldb);
 
548
                return LDB_ERR_OPERATIONS_ERROR;
 
549
        }
 
550
 
 
551
        p->dereference = false;
 
552
        p->normalise = false;
 
553
 
 
554
        ret = ldb_mod_register_control(module, LDB_CONTROL_EXTENDED_DN_OID);
 
555
        if (ret != LDB_SUCCESS) {
 
556
                ldb_debug(module->ldb, LDB_DEBUG_ERROR,
 
557
                        "extended_dn_out: Unable to register control with rootdse!\n");
 
558
                return LDB_ERR_OPERATIONS_ERROR;
 
559
        }
 
560
 
 
561
        return ldb_next_init(module);
 
562
}
 
563
 
 
564
static int extended_dn_out_dereference_init(struct ldb_module *module)
 
565
{
 
566
        int ret, i = 0;
 
567
        struct extended_dn_out_private *p;
 
568
        struct dsdb_openldap_dereference_control *dereference_control;
 
569
        struct dsdb_attribute *cur;
 
570
 
 
571
        struct dsdb_schema *schema;
 
572
 
 
573
        module->private_data = p = talloc_zero(module, struct extended_dn_out_private);
 
574
 
 
575
        if (!p) {
 
576
                ldb_oom(module->ldb);
 
577
                return LDB_ERR_OPERATIONS_ERROR;
 
578
        }
 
579
 
 
580
        p->dereference = true;
 
581
 
 
582
        /* At the moment, servers that need dereference also need the
 
583
         * DN and attribute names to be normalised */
 
584
        p->normalise = true;
 
585
 
 
586
        ret = ldb_mod_register_control(module, LDB_CONTROL_EXTENDED_DN_OID);
 
587
        if (ret != LDB_SUCCESS) {
 
588
                ldb_debug(module->ldb, LDB_DEBUG_ERROR,
 
589
                        "extended_dn_out: Unable to register control with rootdse!\n");
 
590
                return LDB_ERR_OPERATIONS_ERROR;
 
591
        }
 
592
 
 
593
        ret = ldb_next_init(module);
 
594
 
 
595
        if (ret != LDB_SUCCESS) {
 
596
                return ret;
 
597
        }
 
598
 
 
599
        schema = dsdb_get_schema(module->ldb);
 
600
        if (!schema) {
 
601
                /* No schema on this DB (yet) */
 
602
                return LDB_SUCCESS;
 
603
        }
 
604
 
 
605
        p->dereference_control = dereference_control
 
606
                = talloc_zero(p, struct dsdb_openldap_dereference_control);
 
607
 
 
608
        if (!p->dereference_control) {
 
609
                ldb_oom(module->ldb);
 
610
                return LDB_ERR_OPERATIONS_ERROR;
 
611
        }
 
612
        
 
613
        for (cur = schema->attributes; cur; cur = cur->next) {
 
614
                static const char *attrs[] = {
 
615
                        "entryUUID",
 
616
                        "objectSID",
 
617
                        NULL
 
618
                };
 
619
 
 
620
                if (strcmp(cur->syntax->attributeSyntax_oid, "2.5.5.1") != 0) {
 
621
                        continue;
 
622
                }
 
623
                dereference_control->dereference
 
624
                        = talloc_realloc(p, dereference_control->dereference,
 
625
                                         struct dsdb_openldap_dereference *, i + 2);
 
626
                if (!dereference_control) {
 
627
                        ldb_oom(module->ldb);
 
628
                        return LDB_ERR_OPERATIONS_ERROR;
 
629
                }
 
630
                dereference_control->dereference[i] = talloc(dereference_control->dereference,  
 
631
                                         struct dsdb_openldap_dereference);
 
632
                if (!dereference_control->dereference[i]) {
 
633
                        ldb_oom(module->ldb);
 
634
                        return LDB_ERR_OPERATIONS_ERROR;
 
635
                }
 
636
                dereference_control->dereference[i]->source_attribute = cur->lDAPDisplayName;
 
637
                dereference_control->dereference[i]->dereference_attribute = attrs;
 
638
                i++;
 
639
                dereference_control->dereference[i] = NULL;
 
640
        }
 
641
        return LDB_SUCCESS;
 
642
}
 
643
 
 
644
_PUBLIC_ const struct ldb_module_ops ldb_extended_dn_out_ldb_module_ops = {
 
645
        .name              = "extended_dn_out_ldb",
 
646
        .search            = extended_dn_out_search,
 
647
        .init_context      = extended_dn_out_ldb_init,
 
648
};
 
649
 
 
650
 
 
651
_PUBLIC_ const struct ldb_module_ops ldb_extended_dn_out_dereference_module_ops = {
 
652
        .name              = "extended_dn_out_dereference",
 
653
        .search            = extended_dn_out_search,
 
654
        .init_context      = extended_dn_out_dereference_init,
 
655
};