4
Copyright (C) Simo Sorce 2005-2008
5
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007-2008
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.
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.
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/>.
24
* Component: ldb extended dn control module
26
* Description: this module interprets DNs of the form <SID=S-1-2-4456> into normal DNs.
33
#include "ldb/include/ldb.h"
34
#include "ldb/include/ldb_errors.h"
35
#include "ldb/include/ldb_private.h"
38
struct extended_search_context {
39
struct ldb_module *module;
40
struct ldb_request *req;
41
struct ldb_dn *basedn;
42
char *wellknown_object;
46
/* An extra layer of indirection because LDB does not allow the original request to be altered */
48
static int extended_final_callback(struct ldb_request *req, struct ldb_reply *ares)
50
int ret = LDB_ERR_OPERATIONS_ERROR;
51
struct extended_search_context *ac;
52
ac = talloc_get_type(req->context, struct extended_search_context);
54
if (ares->error != LDB_SUCCESS) {
55
ret = ldb_module_done(ac->req, ares->controls,
56
ares->response, ares->error);
61
ret = ldb_module_send_entry(ac->req, ares->message, ares->controls);
63
case LDB_REPLY_REFERRAL:
65
ret = ldb_module_send_referral(ac->req, ares->referral);
69
ret = ldb_module_done(ac->req, ares->controls,
70
ares->response, ares->error);
77
static int extended_base_callback(struct ldb_request *req, struct ldb_reply *ares)
79
struct extended_search_context *ac;
80
struct ldb_request *down_req;
81
struct ldb_message_element *el;
86
const char *found = NULL;
88
ac = talloc_get_type(req->context, struct extended_search_context);
91
return ldb_module_done(ac->req, NULL, NULL,
92
LDB_ERR_OPERATIONS_ERROR);
94
if (ares->error != LDB_SUCCESS) {
95
return ldb_module_done(ac->req, ares->controls,
96
ares->response, ares->error);
100
case LDB_REPLY_ENTRY:
101
if (!ac->wellknown_object) {
102
ac->basedn = talloc_steal(ac, ares->message->dn);
106
wkn_len = strlen(ac->wellknown_object);
108
el = ldb_msg_find_element(ares->message, "wellKnownObjects");
114
for (i=0; i < el->num_values; i++) {
115
valstr = talloc_strndup(ac,
116
(const char *)el->values[i].data,
117
el->values[i].length);
119
ldb_oom(ac->module->ldb);
120
return ldb_module_done(ac->req, NULL, NULL,
121
LDB_ERR_OPERATIONS_ERROR);
124
if (strncasecmp(valstr, ac->wellknown_object, wkn_len) != 0) {
129
found = &valstr[wkn_len];
137
ac->basedn = ldb_dn_new(ac, ac->module->ldb, found);
140
ldb_oom(ac->module->ldb);
141
return ldb_module_done(ac->req, NULL, NULL,
142
LDB_ERR_OPERATIONS_ERROR);
147
case LDB_REPLY_REFERRAL:
153
const char *str = talloc_asprintf(req, "Base-DN '%s' not found",
154
ldb_dn_get_linearized(ac->req->op.search.base));
155
ldb_set_errstring(ac->module->ldb, str);
156
return ldb_module_done(ac->req, NULL, NULL,
157
LDB_ERR_NO_SUCH_OBJECT);
160
switch (ac->req->operation) {
162
ret = ldb_build_search_req_ex(&down_req,
163
ac->module->ldb, ac->req,
165
ac->req->op.search.scope,
166
ac->req->op.search.tree,
167
ac->req->op.search.attrs,
169
ac, extended_final_callback,
174
struct ldb_message *add_msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
176
ldb_oom(ac->module->ldb);
177
return ldb_module_done(ac->req, NULL, NULL,
178
LDB_ERR_OPERATIONS_ERROR);
181
add_msg->dn = ac->basedn;
183
ret = ldb_build_add_req(&down_req,
184
ac->module->ldb, ac->req,
187
ac, extended_final_callback,
193
struct ldb_message *mod_msg = ldb_msg_copy_shallow(ac, ac->req->op.mod.message);
195
ldb_oom(ac->module->ldb);
196
return ldb_module_done(ac->req, NULL, NULL,
197
LDB_ERR_OPERATIONS_ERROR);
200
mod_msg->dn = ac->basedn;
202
ret = ldb_build_mod_req(&down_req,
203
ac->module->ldb, ac->req,
206
ac, extended_final_callback,
211
ret = ldb_build_del_req(&down_req,
212
ac->module->ldb, ac->req,
215
ac, extended_final_callback,
219
ret = ldb_build_rename_req(&down_req,
220
ac->module->ldb, ac->req,
222
ac->req->op.rename.newdn,
224
ac, extended_final_callback,
228
return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
231
if (ret != LDB_SUCCESS) {
232
return ldb_module_done(ac->req, NULL, NULL, ret);
235
return ldb_next_request(ac->module, down_req);
241
static int extended_dn_in_fix(struct ldb_module *module, struct ldb_request *req, struct ldb_dn *dn)
243
struct extended_search_context *ac;
244
struct ldb_request *down_req;
246
struct ldb_dn *base_dn = NULL;
247
enum ldb_scope base_dn_scope = LDB_SCOPE_BASE;
248
const char *base_dn_filter = NULL;
249
const char * const *base_dn_attrs = NULL;
250
char *wellknown_object = NULL;
251
static const char *no_attr[] = {
254
static const char *wkattr[] = {
259
if (!ldb_dn_has_extended(dn)) {
260
/* Move along there isn't anything to see here */
261
return ldb_next_request(module, req);
263
/* It looks like we need to map the DN */
264
const struct ldb_val *sid_val, *guid_val, *wkguid_val;
266
sid_val = ldb_dn_get_extended_component(dn, "SID");
267
guid_val = ldb_dn_get_extended_component(dn, "GUID");
268
wkguid_val = ldb_dn_get_extended_component(dn, "WKGUID");
271
/* TODO: do a search over all partitions */
272
base_dn = ldb_get_default_basedn(module->ldb);
273
base_dn_filter = talloc_asprintf(req, "(objectSid=%s)",
274
ldb_binary_encode(req, *sid_val));
275
if (!base_dn_filter) {
276
ldb_oom(module->ldb);
277
return LDB_ERR_OPERATIONS_ERROR;
279
base_dn_scope = LDB_SCOPE_SUBTREE;
280
base_dn_attrs = no_attr;
282
} else if (guid_val) {
284
/* TODO: do a search over all partitions */
285
base_dn = ldb_get_default_basedn(module->ldb);
286
base_dn_filter = talloc_asprintf(req, "(objectGUID=%s)",
287
ldb_binary_encode(req, *guid_val));
288
if (!base_dn_filter) {
289
ldb_oom(module->ldb);
290
return LDB_ERR_OPERATIONS_ERROR;
292
base_dn_scope = LDB_SCOPE_SUBTREE;
293
base_dn_attrs = no_attr;
296
} else if (wkguid_val) {
301
wkguid_dup = talloc_strndup(req, (char *)wkguid_val->data, wkguid_val->length);
303
p = strchr(wkguid_dup, ',');
305
return LDB_ERR_INVALID_DN_SYNTAX;
311
wellknown_object = talloc_asprintf(req, "B:32:%s:", wkguid_dup);
312
if (!wellknown_object) {
313
ldb_oom(module->ldb);
314
return LDB_ERR_OPERATIONS_ERROR;
319
base_dn = ldb_dn_new(req, module->ldb, tail_str);
320
talloc_free(wkguid_dup);
322
ldb_oom(module->ldb);
323
return LDB_ERR_OPERATIONS_ERROR;
325
base_dn_filter = talloc_strdup(req, "(objectClass=*)");
326
if (!base_dn_filter) {
327
ldb_oom(module->ldb);
328
return LDB_ERR_OPERATIONS_ERROR;
330
base_dn_scope = LDB_SCOPE_BASE;
331
base_dn_attrs = wkattr;
333
return LDB_ERR_INVALID_DN_SYNTAX;
336
ac = talloc_zero(req, struct extended_search_context);
338
ldb_oom(module->ldb);
339
return LDB_ERR_OPERATIONS_ERROR;
344
ac->basedn = NULL; /* Filled in if the search finds the DN by SID/GUID etc */
345
ac->wellknown_object = wellknown_object;
347
/* If the base DN was an extended DN (perhaps a well known
348
* GUID) then search for that, so we can proceed with the original operation */
350
ret = ldb_build_search_req(&down_req,
357
ac, extended_base_callback,
359
if (ret != LDB_SUCCESS) {
360
return LDB_ERR_OPERATIONS_ERROR;
363
/* perform the search */
364
return ldb_next_request(module, down_req);
368
static int extended_dn_in_search(struct ldb_module *module, struct ldb_request *req)
370
return extended_dn_in_fix(module, req, req->op.search.base);
373
static int extended_dn_in_modify(struct ldb_module *module, struct ldb_request *req)
375
return extended_dn_in_fix(module, req, req->op.mod.message->dn);
378
static int extended_dn_in_del(struct ldb_module *module, struct ldb_request *req)
380
return extended_dn_in_fix(module, req, req->op.del.dn);
383
static int extended_dn_in_rename(struct ldb_module *module, struct ldb_request *req)
385
return extended_dn_in_fix(module, req, req->op.rename.olddn);
388
_PUBLIC_ const struct ldb_module_ops ldb_extended_dn_in_module_ops = {
389
.name = "extended_dn_in",
390
.search = extended_dn_in_search,
391
.modify = extended_dn_in_modify,
392
.del = extended_dn_in_del,
393
.rename = extended_dn_in_rename,