• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/samba-3.5.8/source3/lib/ldb/modules/
1/*
2   ldb database library
3
4   Copyright (C) Andrew Tridgell 2005
5   Copyright (C) Simo Sorce 2006
6
7     ** NOTE! The following LGPL license applies to the ldb
8     ** library. This does NOT imply that all of Samba is released
9     ** under the LGPL
10
11   This library is free software; you can redistribute it and/or
12   modify it under the terms of the GNU Lesser General Public
13   License as published by the Free Software Foundation; either
14   version 3 of the License, or (at your option) any later version.
15
16   This library is distributed in the hope that it will be useful,
17   but WITHOUT ANY WARRANTY; without even the implied warranty of
18   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19   Lesser General Public License for more details.
20
21   You should have received a copy of the GNU Lesser General Public
22   License along with this library; if not, see <http://www.gnu.org/licenses/>.
23*/
24/*
25  handle operational attributes
26 */
27
28/*
29  createTimestamp: HIDDEN, searchable, ldaptime, alias for whenCreated
30  modifyTimestamp: HIDDEN, searchable, ldaptime, alias for whenChanged
31
32     for the above two, we do the search as normal, and if
33     createTimestamp or modifyTimestamp is asked for, then do
34     additional searches for whenCreated and whenChanged and fill in
35     the resulting values
36
37     we also need to replace these with the whenCreated/whenChanged
38     equivalent in the search expression trees
39
40  whenCreated: not-HIDDEN, CONSTRUCTED, SEARCHABLE
41  whenChanged: not-HIDDEN, CONSTRUCTED, SEARCHABLE
42
43     on init we need to setup attribute handlers for these so
44     comparisons are done correctly. The resolution is 1 second.
45
46     on add we need to add both the above, for current time
47
48     on modify we need to change whenChanged
49
50
51  subschemaSubentry: HIDDEN, not-searchable,
52                     points at DN CN=Aggregate,CN=Schema,CN=Configuration,$BASEDN
53
54     for this one we do the search as normal, then add the static
55     value if requested. How do we work out the $BASEDN from inside a
56     module?
57
58
59  structuralObjectClass: HIDDEN, CONSTRUCTED, not-searchable. always same as objectclass?
60
61     for this one we do the search as normal, then if requested ask
62     for objectclass, change the attribute name, and add it
63
64  allowedAttributesEffective: HIDDEN, CONSTRUCTED, not-searchable,
65     list of attributes that can be modified - requires schema lookup
66
67
68  attributeTypes: in schema only
69  objectClasses: in schema only
70  matchingRules: in schema only
71  matchingRuleUse: in schema only
72  creatorsName: not supported by w2k3?
73  modifiersName: not supported by w2k3?
74*/
75
76#include "includes.h"
77#include "ldb/include/includes.h"
78
79/*
80  construct a canonical name from a message
81*/
82static int construct_canonical_name(struct ldb_module *module, struct ldb_message *msg)
83{
84	char *canonicalName;
85	canonicalName = ldb_dn_canonical_string(msg, msg->dn);
86	if (canonicalName == NULL) {
87		return -1;
88	}
89	return ldb_msg_add_steal_string(msg, "canonicalName", canonicalName);
90}
91
92/*
93  a list of attribute names that should be substituted in the parse
94  tree before the search is done
95*/
96static const struct {
97	const char *attr;
98	const char *replace;
99} parse_tree_sub[] = {
100	{ "createTimestamp", "whenCreated" },
101	{ "modifyTimestamp", "whenChanged" }
102};
103
104
105/*
106  a list of attribute names that are hidden, but can be searched for
107  using another (non-hidden) name to produce the correct result
108*/
109static const struct {
110	const char *attr;
111	const char *replace;
112	int (*constructor)(struct ldb_module *, struct ldb_message *);
113} search_sub[] = {
114	{ "createTimestamp", "whenCreated", NULL },
115	{ "modifyTimestamp", "whenChanged", NULL },
116	{ "structuralObjectClass", "objectClass", NULL },
117	{ "canonicalName", "distinguishedName", construct_canonical_name }
118};
119
120/*
121  post process a search result record. For any search_sub[] attributes that were
122  asked for, we need to call the appropriate copy routine to copy the result
123  into the message, then remove any attributes that we added to the search but were
124  not asked for by the user
125*/
126static int operational_search_post_process(struct ldb_module *module,
127					   struct ldb_message *msg,
128					   const char * const *attrs)
129{
130	int i, a=0;
131
132	for (a=0;attrs && attrs[a];a++) {
133		for (i=0;i<ARRAY_SIZE(search_sub);i++) {
134			if (ldb_attr_cmp(attrs[a], search_sub[i].attr) != 0) {
135				continue;
136			}
137
138			/* construct the new attribute, using either a supplied
139			   constructor or a simple copy */
140			if (search_sub[i].constructor) {
141				if (search_sub[i].constructor(module, msg) != 0) {
142					goto failed;
143				}
144			} else if (ldb_msg_copy_attr(msg,
145						     search_sub[i].replace,
146						     search_sub[i].attr) != 0) {
147				goto failed;
148			}
149
150			/* remove the added search attribute, unless it was asked for
151			   by the user */
152			if (search_sub[i].replace == NULL ||
153			    ldb_attr_in_list(attrs, search_sub[i].replace) ||
154			    ldb_attr_in_list(attrs, "*")) {
155				continue;
156			}
157
158			ldb_msg_remove_attr(msg, search_sub[i].replace);
159		}
160	}
161
162	return 0;
163
164failed:
165	ldb_debug_set(module->ldb, LDB_DEBUG_WARNING,
166		      "operational_search_post_process failed for attribute '%s'\n",
167		      attrs[a]);
168	return -1;
169}
170
171
172/*
173  hook search operations
174*/
175
176struct operational_context {
177
178	struct ldb_module *module;
179	void *up_context;
180	int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *);
181
182	const char * const *attrs;
183};
184
185static int operational_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
186{
187	struct operational_context *ac;
188
189	if (!context || !ares) {
190		ldb_set_errstring(ldb, "NULL Context or Result in callback");
191		goto error;
192	}
193
194	ac = talloc_get_type(context, struct operational_context);
195
196	if (ares->type == LDB_REPLY_ENTRY) {
197		/* for each record returned post-process to add any derived
198		   attributes that have been asked for */
199		if (operational_search_post_process(ac->module, ares->message, ac->attrs) != 0) {
200			goto error;
201		}
202	}
203
204	return ac->up_callback(ldb, ac->up_context, ares);
205
206error:
207	talloc_free(ares);
208	return LDB_ERR_OPERATIONS_ERROR;
209}
210
211static int operational_search(struct ldb_module *module, struct ldb_request *req)
212{
213	struct operational_context *ac;
214	struct ldb_request *down_req;
215	const char **search_attrs = NULL;
216	int i, a, ret;
217
218	req->handle = NULL;
219
220	ac = talloc(req, struct operational_context);
221	if (ac == NULL) {
222		return LDB_ERR_OPERATIONS_ERROR;
223	}
224
225	ac->module = module;
226	ac->up_context = req->context;
227	ac->up_callback = req->callback;
228	ac->attrs = req->op.search.attrs;
229
230	down_req = talloc_zero(req, struct ldb_request);
231	if (down_req == NULL) {
232		return LDB_ERR_OPERATIONS_ERROR;
233	}
234
235	down_req->operation = req->operation;
236	down_req->op.search.base = req->op.search.base;
237	down_req->op.search.scope = req->op.search.scope;
238	down_req->op.search.tree = req->op.search.tree;
239
240	/*  FIXME: I hink we should copy the tree and keep the original
241	 *  unmodified. SSS */
242	/* replace any attributes in the parse tree that are
243	   searchable, but are stored using a different name in the
244	   backend */
245	for (i=0;i<ARRAY_SIZE(parse_tree_sub);i++) {
246		ldb_parse_tree_attr_replace(discard_const_p(struct ldb_parse_tree, req->op.search.tree),
247					    parse_tree_sub[i].attr,
248					    parse_tree_sub[i].replace);
249	}
250
251	/* in the list of attributes we are looking for, rename any
252	   attributes to the alias for any hidden attributes that can
253	   be fetched directly using non-hidden names */
254	for (a=0;ac->attrs && ac->attrs[a];a++) {
255		for (i=0;i<ARRAY_SIZE(search_sub);i++) {
256			if (ldb_attr_cmp(ac->attrs[a], search_sub[i].attr) == 0 &&
257			    search_sub[i].replace) {
258				if (!search_attrs) {
259					search_attrs = ldb_attr_list_copy(req, ac->attrs);
260					if (search_attrs == NULL) {
261						return LDB_ERR_OPERATIONS_ERROR;
262					}
263				}
264				search_attrs[a] = search_sub[i].replace;
265			}
266		}
267	}
268
269	/* use new set of attrs if any */
270	if (search_attrs) down_req->op.search.attrs = search_attrs;
271	else down_req->op.search.attrs = req->op.search.attrs;
272
273	down_req->controls = req->controls;
274
275	down_req->context = ac;
276	down_req->callback = operational_callback;
277	ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
278
279	/* perform the search */
280	ret = ldb_next_request(module, down_req);
281
282	/* do not free down_req as the call results may be linked to it,
283	 * it will be freed when the upper level request get freed */
284	if (ret == LDB_SUCCESS) {
285		req->handle = down_req->handle;
286	}
287
288	return ret;
289}
290
291static int operational_init(struct ldb_module *ctx)
292{
293	/* setup some standard attribute handlers */
294	ldb_set_attrib_handler_syntax(ctx->ldb, "whenCreated", LDB_SYNTAX_UTC_TIME);
295	ldb_set_attrib_handler_syntax(ctx->ldb, "whenChanged", LDB_SYNTAX_UTC_TIME);
296	ldb_set_attrib_handler_syntax(ctx->ldb, "subschemaSubentry", LDB_SYNTAX_DN);
297	ldb_set_attrib_handler_syntax(ctx->ldb, "structuralObjectClass", LDB_SYNTAX_OBJECTCLASS);
298
299	return ldb_next_init(ctx);
300}
301
302static const struct ldb_module_ops operational_ops = {
303	.name              = "operational",
304	.search            = operational_search,
305	.init_context	   = operational_init
306};
307
308int ldb_operational_init(void)
309{
310	return ldb_register_module(&operational_ops);
311}
312