/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- construct_canonical_name
- operational_search_post_process
- operational_callback
- operational_search
- operational_init
1 /*
2 ldb database library
3
4 Copyright (C) Andrew Tridgell 2005
5 Copyright (C) Simo Sorce 2006-2008
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,$SCHEMADN
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 "ldb_includes.h"
77 #include "ldb_module.h"
78
79 #ifndef ARRAY_SIZE
80 #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
81 #endif
82
83 /*
84 construct a canonical name from a message
85 */
86 static int construct_canonical_name(struct ldb_module *module, struct ldb_message *msg)
/* [<][>][^][v][top][bottom][index][help] */
87 {
88 char *canonicalName;
89 canonicalName = ldb_dn_canonical_string(msg, msg->dn);
90 if (canonicalName == NULL) {
91 return -1;
92 }
93 return ldb_msg_add_steal_string(msg, "canonicalName", canonicalName);
94 }
95
96 /*
97 a list of attribute names that should be substituted in the parse
98 tree before the search is done
99 */
100 static const struct {
101 const char *attr;
102 const char *replace;
103 } parse_tree_sub[] = {
104 { "createTimestamp", "whenCreated" },
105 { "modifyTimestamp", "whenChanged" }
106 };
107
108
109 /*
110 a list of attribute names that are hidden, but can be searched for
111 using another (non-hidden) name to produce the correct result
112 */
113 static const struct {
114 const char *attr;
115 const char *replace;
116 int (*constructor)(struct ldb_module *, struct ldb_message *);
117 } search_sub[] = {
118 { "createTimestamp", "whenCreated", NULL },
119 { "modifyTimestamp", "whenChanged", NULL },
120 { "structuralObjectClass", "objectClass", NULL },
121 { "canonicalName", "distinguishedName", construct_canonical_name }
122 };
123
124 /*
125 post process a search result record. For any search_sub[] attributes that were
126 asked for, we need to call the appropriate copy routine to copy the result
127 into the message, then remove any attributes that we added to the search but were
128 not asked for by the user
129 */
130 static int operational_search_post_process(struct ldb_module *module,
/* [<][>][^][v][top][bottom][index][help] */
131 struct ldb_message *msg,
132 const char * const *attrs)
133 {
134 struct ldb_context *ldb;
135 int i, a=0;
136
137 ldb = ldb_module_get_ctx(module);
138
139 for (a=0;attrs && attrs[a];a++) {
140 for (i=0;i<ARRAY_SIZE(search_sub);i++) {
141 if (ldb_attr_cmp(attrs[a], search_sub[i].attr) != 0) {
142 continue;
143 }
144
145 /* construct the new attribute, using either a supplied
146 constructor or a simple copy */
147 if (search_sub[i].constructor) {
148 if (search_sub[i].constructor(module, msg) != 0) {
149 goto failed;
150 }
151 } else if (ldb_msg_copy_attr(msg,
152 search_sub[i].replace,
153 search_sub[i].attr) != 0) {
154 goto failed;
155 }
156
157 /* remove the added search attribute, unless it was asked for
158 by the user */
159 if (search_sub[i].replace == NULL ||
160 ldb_attr_in_list(attrs, search_sub[i].replace) ||
161 ldb_attr_in_list(attrs, "*")) {
162 continue;
163 }
164
165 ldb_msg_remove_attr(msg, search_sub[i].replace);
166 }
167 }
168
169 return 0;
170
171 failed:
172 ldb_debug_set(ldb, LDB_DEBUG_WARNING,
173 "operational_search_post_process failed for attribute '%s'\n",
174 attrs[a]);
175 return -1;
176 }
177
178
179 /*
180 hook search operations
181 */
182
183 struct operational_context {
184 struct ldb_module *module;
185 struct ldb_request *req;
186
187 const char * const *attrs;
188 };
189
190 static int operational_callback(struct ldb_request *req, struct ldb_reply *ares)
/* [<][>][^][v][top][bottom][index][help] */
191 {
192 struct operational_context *ac;
193 int ret;
194
195 ac = talloc_get_type(req->context, struct operational_context);
196
197 if (!ares) {
198 return ldb_module_done(ac->req, NULL, NULL,
199 LDB_ERR_OPERATIONS_ERROR);
200 }
201 if (ares->error != LDB_SUCCESS) {
202 return ldb_module_done(ac->req, ares->controls,
203 ares->response, ares->error);
204 }
205
206 switch (ares->type) {
207 case LDB_REPLY_ENTRY:
208 /* for each record returned post-process to add any derived
209 attributes that have been asked for */
210 ret = operational_search_post_process(ac->module,
211 ares->message,
212 ac->attrs);
213 if (ret != 0) {
214 return ldb_module_done(ac->req, NULL, NULL,
215 LDB_ERR_OPERATIONS_ERROR);
216 }
217 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
218
219 case LDB_REPLY_REFERRAL:
220 /* ignore referrals */
221 break;
222
223 case LDB_REPLY_DONE:
224
225 return ldb_module_done(ac->req, ares->controls,
226 ares->response, LDB_SUCCESS);
227 }
228
229 talloc_free(ares);
230 return LDB_SUCCESS;
231 }
232
233 static int operational_search(struct ldb_module *module, struct ldb_request *req)
/* [<][>][^][v][top][bottom][index][help] */
234 {
235 struct ldb_context *ldb;
236 struct operational_context *ac;
237 struct ldb_request *down_req;
238 const char **search_attrs = NULL;
239 int i, a;
240 int ret;
241
242 ldb = ldb_module_get_ctx(module);
243
244 ac = talloc(req, struct operational_context);
245 if (ac == NULL) {
246 return LDB_ERR_OPERATIONS_ERROR;
247 }
248
249 ac->module = module;
250 ac->req = req;
251 ac->attrs = req->op.search.attrs;
252
253 /* FIXME: We must copy the tree and keep the original
254 * unmodified. SSS */
255 /* replace any attributes in the parse tree that are
256 searchable, but are stored using a different name in the
257 backend */
258 for (i=0;i<ARRAY_SIZE(parse_tree_sub);i++) {
259 ldb_parse_tree_attr_replace(req->op.search.tree,
260 parse_tree_sub[i].attr,
261 parse_tree_sub[i].replace);
262 }
263
264 /* in the list of attributes we are looking for, rename any
265 attributes to the alias for any hidden attributes that can
266 be fetched directly using non-hidden names */
267 for (a=0;ac->attrs && ac->attrs[a];a++) {
268 for (i=0;i<ARRAY_SIZE(search_sub);i++) {
269 if (ldb_attr_cmp(ac->attrs[a], search_sub[i].attr) == 0 &&
270 search_sub[i].replace) {
271 if (!search_attrs) {
272 search_attrs = ldb_attr_list_copy(req, ac->attrs);
273 if (search_attrs == NULL) {
274 return LDB_ERR_OPERATIONS_ERROR;
275 }
276 }
277 search_attrs[a] = search_sub[i].replace;
278 }
279 }
280 }
281
282 ret = ldb_build_search_req_ex(&down_req, ldb, ac,
283 req->op.search.base,
284 req->op.search.scope,
285 req->op.search.tree,
286 /* use new set of attrs if any */
287 search_attrs == NULL?req->op.search.attrs:search_attrs,
288 req->controls,
289 ac, operational_callback,
290 req);
291 if (ret != LDB_SUCCESS) {
292 return LDB_ERR_OPERATIONS_ERROR;
293 }
294
295 /* perform the search */
296 return ldb_next_request(module, down_req);
297 }
298
299 static int operational_init(struct ldb_module *ctx)
/* [<][>][^][v][top][bottom][index][help] */
300 {
301 int ret = 0;
302
303 if (ret != 0) {
304 return ret;
305 }
306
307 return ldb_next_init(ctx);
308 }
309
310 const struct ldb_module_ops ldb_operational_module_ops = {
311 .name = "operational",
312 .search = operational_search,
313 .init_context = operational_init
314 };