Fix the mess with ldb includes.
[Samba/ekacnet.git] / source4 / lib / ldb / modules / operational.c
blobd862638389ca6302f8c7d4fd4afda52976a336cc
1 /*
2 ldb database library
4 Copyright (C) Andrew Tridgell 2005
5 Copyright (C) Simo Sorce 2006-2008
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
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.
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.
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/>.
25 handle operational attributes
29 createTimestamp: HIDDEN, searchable, ldaptime, alias for whenCreated
30 modifyTimestamp: HIDDEN, searchable, ldaptime, alias for whenChanged
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
37 we also need to replace these with the whenCreated/whenChanged
38 equivalent in the search expression trees
40 whenCreated: not-HIDDEN, CONSTRUCTED, SEARCHABLE
41 whenChanged: not-HIDDEN, CONSTRUCTED, SEARCHABLE
43 on init we need to setup attribute handlers for these so
44 comparisons are done correctly. The resolution is 1 second.
46 on add we need to add both the above, for current time
48 on modify we need to change whenChanged
51 subschemaSubentry: HIDDEN, not-searchable,
52 points at DN CN=Aggregate,$SCHEMADN
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?
59 structuralObjectClass: HIDDEN, CONSTRUCTED, not-searchable. always same as objectclass?
61 for this one we do the search as normal, then if requested ask
62 for objectclass, change the attribute name, and add it
64 allowedAttributesEffective: HIDDEN, CONSTRUCTED, not-searchable,
65 list of attributes that can be modified - requires schema lookup
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?
76 #include "ldb_module.h"
79 construct a canonical name from a message
81 static int construct_canonical_name(struct ldb_module *module, struct ldb_message *msg)
83 char *canonicalName;
84 canonicalName = ldb_dn_canonical_string(msg, msg->dn);
85 if (canonicalName == NULL) {
86 return -1;
88 return ldb_msg_add_steal_string(msg, "canonicalName", canonicalName);
92 a list of attribute names that should be substituted in the parse
93 tree before the search is done
95 static const struct {
96 const char *attr;
97 const char *replace;
98 } parse_tree_sub[] = {
99 { "createTimestamp", "whenCreated" },
100 { "modifyTimestamp", "whenChanged" }
105 a list of attribute names that are hidden, but can be searched for
106 using another (non-hidden) name to produce the correct result
108 static const struct {
109 const char *attr;
110 const char *replace;
111 int (*constructor)(struct ldb_module *, struct ldb_message *);
112 } search_sub[] = {
113 { "createTimestamp", "whenCreated", NULL },
114 { "modifyTimestamp", "whenChanged", NULL },
115 { "structuralObjectClass", "objectClass", NULL },
116 { "canonicalName", "distinguishedName", construct_canonical_name }
120 post process a search result record. For any search_sub[] attributes that were
121 asked for, we need to call the appropriate copy routine to copy the result
122 into the message, then remove any attributes that we added to the search but were
123 not asked for by the user
125 static int operational_search_post_process(struct ldb_module *module,
126 struct ldb_message *msg,
127 const char * const *attrs)
129 struct ldb_context *ldb;
130 int i, a=0;
132 ldb = ldb_module_get_ctx(module);
134 for (a=0;attrs && attrs[a];a++) {
135 for (i=0;i<ARRAY_SIZE(search_sub);i++) {
136 if (ldb_attr_cmp(attrs[a], search_sub[i].attr) != 0) {
137 continue;
140 /* construct the new attribute, using either a supplied
141 constructor or a simple copy */
142 if (search_sub[i].constructor) {
143 if (search_sub[i].constructor(module, msg) != 0) {
144 goto failed;
146 } else if (ldb_msg_copy_attr(msg,
147 search_sub[i].replace,
148 search_sub[i].attr) != 0) {
149 goto failed;
152 /* remove the added search attribute, unless it was asked for
153 by the user */
154 if (search_sub[i].replace == NULL ||
155 ldb_attr_in_list(attrs, search_sub[i].replace) ||
156 ldb_attr_in_list(attrs, "*")) {
157 continue;
160 ldb_msg_remove_attr(msg, search_sub[i].replace);
164 return 0;
166 failed:
167 ldb_debug_set(ldb, LDB_DEBUG_WARNING,
168 "operational_search_post_process failed for attribute '%s'\n",
169 attrs[a]);
170 return -1;
175 hook search operations
178 struct operational_context {
179 struct ldb_module *module;
180 struct ldb_request *req;
182 const char * const *attrs;
185 static int operational_callback(struct ldb_request *req, struct ldb_reply *ares)
187 struct operational_context *ac;
188 int ret;
190 ac = talloc_get_type(req->context, struct operational_context);
192 if (!ares) {
193 return ldb_module_done(ac->req, NULL, NULL,
194 LDB_ERR_OPERATIONS_ERROR);
196 if (ares->error != LDB_SUCCESS) {
197 return ldb_module_done(ac->req, ares->controls,
198 ares->response, ares->error);
201 switch (ares->type) {
202 case LDB_REPLY_ENTRY:
203 /* for each record returned post-process to add any derived
204 attributes that have been asked for */
205 ret = operational_search_post_process(ac->module,
206 ares->message,
207 ac->attrs);
208 if (ret != 0) {
209 return ldb_module_done(ac->req, NULL, NULL,
210 LDB_ERR_OPERATIONS_ERROR);
212 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
214 case LDB_REPLY_REFERRAL:
215 /* ignore referrals */
216 break;
218 case LDB_REPLY_DONE:
220 return ldb_module_done(ac->req, ares->controls,
221 ares->response, LDB_SUCCESS);
224 talloc_free(ares);
225 return LDB_SUCCESS;
228 static int operational_search(struct ldb_module *module, struct ldb_request *req)
230 struct ldb_context *ldb;
231 struct operational_context *ac;
232 struct ldb_request *down_req;
233 const char **search_attrs = NULL;
234 int i, a;
235 int ret;
237 ldb = ldb_module_get_ctx(module);
239 ac = talloc(req, struct operational_context);
240 if (ac == NULL) {
241 return LDB_ERR_OPERATIONS_ERROR;
244 ac->module = module;
245 ac->req = req;
246 ac->attrs = req->op.search.attrs;
248 /* FIXME: We must copy the tree and keep the original
249 * unmodified. SSS */
250 /* replace any attributes in the parse tree that are
251 searchable, but are stored using a different name in the
252 backend */
253 for (i=0;i<ARRAY_SIZE(parse_tree_sub);i++) {
254 ldb_parse_tree_attr_replace(req->op.search.tree,
255 parse_tree_sub[i].attr,
256 parse_tree_sub[i].replace);
259 /* in the list of attributes we are looking for, rename any
260 attributes to the alias for any hidden attributes that can
261 be fetched directly using non-hidden names */
262 for (a=0;ac->attrs && ac->attrs[a];a++) {
263 for (i=0;i<ARRAY_SIZE(search_sub);i++) {
264 if (ldb_attr_cmp(ac->attrs[a], search_sub[i].attr) == 0 &&
265 search_sub[i].replace) {
266 if (!search_attrs) {
267 search_attrs = ldb_attr_list_copy(req, ac->attrs);
268 if (search_attrs == NULL) {
269 return LDB_ERR_OPERATIONS_ERROR;
272 search_attrs[a] = search_sub[i].replace;
277 ret = ldb_build_search_req_ex(&down_req, ldb, ac,
278 req->op.search.base,
279 req->op.search.scope,
280 req->op.search.tree,
281 /* use new set of attrs if any */
282 search_attrs == NULL?req->op.search.attrs:search_attrs,
283 req->controls,
284 ac, operational_callback,
285 req);
286 if (ret != LDB_SUCCESS) {
287 return LDB_ERR_OPERATIONS_ERROR;
290 /* perform the search */
291 return ldb_next_request(module, down_req);
294 static int operational_init(struct ldb_module *ctx)
296 int ret = 0;
298 if (ret != 0) {
299 return ret;
302 return ldb_next_init(ctx);
305 const struct ldb_module_ops ldb_operational_module_ops = {
306 .name = "operational",
307 .search = operational_search,
308 .init_context = operational_init