4 Copyright (C) Andrew Tridgell 2005
5 Copyright (C) Simo Sorce 2006-2008
6 Copyright (C) Matthias Dieter Wallnöfer 2009
8 ** NOTE! The following LGPL license applies to the ldb
9 ** library. This does NOT imply that all of Samba is released
12 This library is free software; you can redistribute it and/or
13 modify it under the terms of the GNU Lesser General Public
14 License as published by the Free Software Foundation; either
15 version 3 of the License, or (at your option) any later version.
17 This library is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 Lesser General Public License for more details.
22 You should have received a copy of the GNU Lesser General Public
23 License along with this library; if not, see <http://www.gnu.org/licenses/>.
27 handle operational attributes
31 createTimestamp: HIDDEN, searchable, ldaptime, alias for whenCreated
32 modifyTimestamp: HIDDEN, searchable, ldaptime, alias for whenChanged
34 for the above two, we do the search as normal, and if
35 createTimestamp or modifyTimestamp is asked for, then do
36 additional searches for whenCreated and whenChanged and fill in
39 we also need to replace these with the whenCreated/whenChanged
40 equivalent in the search expression trees
42 whenCreated: not-HIDDEN, CONSTRUCTED, SEARCHABLE
43 whenChanged: not-HIDDEN, CONSTRUCTED, SEARCHABLE
45 on init we need to setup attribute handlers for these so
46 comparisons are done correctly. The resolution is 1 second.
48 on add we need to add both the above, for current time
50 on modify we need to change whenChanged
53 subschemaSubentry: HIDDEN, not-searchable,
54 points at DN CN=Aggregate,$SCHEMADN
56 for this one we do the search as normal, then add the static
57 value if requested. How do we work out the $BASEDN from inside a
60 structuralObjectClass: HIDDEN, CONSTRUCTED, not-searchable. always same as objectclass?
62 for this one we do the search as normal, then if requested ask
63 for objectclass, change the attribute name, and add it
65 allowedAttributesEffective: HIDDEN, CONSTRUCTED, not-searchable,
67 list of attributes that can be modified - requires schema lookup
69 primaryGroupToken: HIDDEN, CONSTRUCTED, SEARCHABLE
71 contains the RID of a certain group object
74 attributeTypes: in schema only
75 objectClasses: in schema only
76 matchingRules: in schema only
77 matchingRuleUse: in schema only
78 creatorsName: not supported by w2k3?
79 modifiersName: not supported by w2k3?
82 #include "ldb_includes.h"
83 #include "ldb_module.h"
86 #include "dsdb/samdb/samdb.h"
89 #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
93 construct a canonical name from a message
95 static int construct_canonical_name(struct ldb_module *module,
96 struct ldb_message *msg)
99 canonicalName = ldb_dn_canonical_string(msg, msg->dn);
100 if (canonicalName == NULL) {
103 return ldb_msg_add_steal_string(msg, "canonicalName", canonicalName);
107 construct a primary group token for groups from a message
109 static int construct_primary_group_token(struct ldb_module *module,
110 struct ldb_message *msg)
112 struct ldb_context *ldb;
113 uint32_t primary_group_token;
115 ldb = ldb_module_get_ctx(module);
117 if (samdb_search_count(ldb, ldb, msg->dn, "(objectclass=group)") == 1) {
119 = samdb_result_rid_from_sid(ldb, msg, "objectSid", 0);
120 return samdb_msg_add_int(ldb, ldb, msg, "primaryGroupToken",
121 primary_group_token);
129 a list of attribute names that should be substituted in the parse
130 tree before the search is done
132 static const struct {
135 } parse_tree_sub[] = {
136 { "createTimestamp", "whenCreated" },
137 { "modifyTimestamp", "whenChanged" }
142 a list of attribute names that are hidden, but can be searched for
143 using another (non-hidden) name to produce the correct result
145 static const struct {
148 int (*constructor)(struct ldb_module *, struct ldb_message *);
150 { "createTimestamp", "whenCreated", NULL },
151 { "modifyTimestamp", "whenChanged", NULL },
152 { "structuralObjectClass", "objectClass", NULL },
153 { "canonicalName", "distinguishedName", construct_canonical_name },
154 { "primaryGroupToken", "objectSid", construct_primary_group_token }
158 post process a search result record. For any search_sub[] attributes that were
159 asked for, we need to call the appropriate copy routine to copy the result
160 into the message, then remove any attributes that we added to the search but
161 were not asked for by the user
163 static int operational_search_post_process(struct ldb_module *module,
164 struct ldb_message *msg,
165 const char * const *attrs)
167 struct ldb_context *ldb;
170 ldb = ldb_module_get_ctx(module);
172 for (a=0;attrs && attrs[a];a++) {
173 for (i=0;i<ARRAY_SIZE(search_sub);i++) {
174 if (ldb_attr_cmp(attrs[a], search_sub[i].attr) != 0) {
178 /* construct the new attribute, using either a supplied
179 constructor or a simple copy */
180 if (search_sub[i].constructor) {
181 if (search_sub[i].constructor(module, msg) != 0) {
184 } else if (ldb_msg_copy_attr(msg,
185 search_sub[i].replace,
186 search_sub[i].attr) != 0) {
190 /* remove the added search attribute, unless it was
191 asked for by the user */
192 if (search_sub[i].replace == NULL ||
193 ldb_attr_in_list(attrs, search_sub[i].replace) ||
194 ldb_attr_in_list(attrs, "*")) {
198 ldb_msg_remove_attr(msg, search_sub[i].replace);
205 ldb_debug_set(ldb, LDB_DEBUG_WARNING,
206 "operational_search_post_process failed for attribute '%s'",
213 hook search operations
216 struct operational_context {
217 struct ldb_module *module;
218 struct ldb_request *req;
220 const char * const *attrs;
223 static int operational_callback(struct ldb_request *req, struct ldb_reply *ares)
225 struct operational_context *ac;
228 ac = talloc_get_type(req->context, struct operational_context);
231 return ldb_module_done(ac->req, NULL, NULL,
232 LDB_ERR_OPERATIONS_ERROR);
234 if (ares->error != LDB_SUCCESS) {
235 return ldb_module_done(ac->req, ares->controls,
236 ares->response, ares->error);
239 switch (ares->type) {
240 case LDB_REPLY_ENTRY:
241 /* for each record returned post-process to add any derived
242 attributes that have been asked for */
243 ret = operational_search_post_process(ac->module,
247 return ldb_module_done(ac->req, NULL, NULL,
248 LDB_ERR_OPERATIONS_ERROR);
250 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
252 case LDB_REPLY_REFERRAL:
253 /* ignore referrals */
258 return ldb_module_done(ac->req, ares->controls,
259 ares->response, LDB_SUCCESS);
266 static int operational_search(struct ldb_module *module, struct ldb_request *req)
268 struct ldb_context *ldb;
269 struct operational_context *ac;
270 struct ldb_request *down_req;
271 const char **search_attrs = NULL;
275 ldb = ldb_module_get_ctx(module);
277 ac = talloc(req, struct operational_context);
279 return LDB_ERR_OPERATIONS_ERROR;
284 ac->attrs = req->op.search.attrs;
286 /* FIXME: We must copy the tree and keep the original
288 /* replace any attributes in the parse tree that are
289 searchable, but are stored using a different name in the
291 for (i=0;i<ARRAY_SIZE(parse_tree_sub);i++) {
292 ldb_parse_tree_attr_replace(req->op.search.tree,
293 parse_tree_sub[i].attr,
294 parse_tree_sub[i].replace);
297 /* in the list of attributes we are looking for, rename any
298 attributes to the alias for any hidden attributes that can
299 be fetched directly using non-hidden names */
300 for (a=0;ac->attrs && ac->attrs[a];a++) {
301 for (i=0;i<ARRAY_SIZE(search_sub);i++) {
302 if (ldb_attr_cmp(ac->attrs[a], search_sub[i].attr) == 0 &&
303 search_sub[i].replace) {
305 search_attrs = ldb_attr_list_copy(req, ac->attrs);
306 if (search_attrs == NULL) {
307 return LDB_ERR_OPERATIONS_ERROR;
310 search_attrs[a] = search_sub[i].replace;
315 ret = ldb_build_search_req_ex(&down_req, ldb, ac,
317 req->op.search.scope,
319 /* use new set of attrs if any */
320 search_attrs == NULL?req->op.search.attrs:search_attrs,
322 ac, operational_callback,
324 if (ret != LDB_SUCCESS) {
325 return LDB_ERR_OPERATIONS_ERROR;
328 /* perform the search */
329 return ldb_next_request(module, down_req);
332 static int operational_init(struct ldb_module *ctx)
340 return ldb_next_init(ctx);
343 const struct ldb_module_ops ldb_operational_module_ops = {
344 .name = "operational",
345 .search = operational_search,
346 .init_context = operational_init