source: branches/samba-3.3.x/source/lib/ldb/modules/operational.c

Last change on this file was 206, checked in by Herwig Bauernfeind, 16 years ago

Import Samba 3.3 branch at 3.0.0 level (psmedley's port)

File size: 9.0 KB
Line 
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}
Note: See TracBrowser for help on using the repository browser.