4 Copyright (C) Andrew Tridgell 2005
5 Copyright (C) Simo Sorce 2006
7 ** NOTE! The following LGPL license applies to the ldb
8 ** library. This does NOT imply that all of Samba is released
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 2 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, write to the Free Software
23 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 handle operational attributes
30 createTimestamp: HIDDEN, searchable, ldaptime, alias for whenCreated
31 modifyTimestamp: HIDDEN, searchable, ldaptime, alias for whenChanged
33 for the above two, we do the search as normal, and if
34 createTimestamp or modifyTimestamp is asked for, then do
35 additional searches for whenCreated and whenChanged and fill in
38 we also need to replace these with the whenCreated/whenChanged
39 equivalent in the search expression trees
41 whenCreated: not-HIDDEN, CONSTRUCTED, SEARCHABLE
42 whenChanged: not-HIDDEN, CONSTRUCTED, SEARCHABLE
44 on init we need to setup attribute handlers for these so
45 comparisons are done correctly. The resolution is 1 second.
47 on add we need to add both the above, for current time
49 on modify we need to change whenChanged
52 subschemaSubentry: HIDDEN, not-searchable,
53 points at DN CN=Aggregate,$SCHEMADN
55 for this one we do the search as normal, then add the static
56 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,
66 list of attributes that can be modified - requires schema lookup
69 attributeTypes: in schema only
70 objectClasses: in schema only
71 matchingRules: in schema only
72 matchingRuleUse: in schema only
73 creatorsName: not supported by w2k3?
74 modifiersName: not supported by w2k3?
78 #include "ldb/include/includes.h"
81 construct a canonical name from a message
83 static int construct_canonical_name(struct ldb_module
*module
, struct ldb_message
*msg
)
86 canonicalName
= ldb_dn_canonical_string(msg
, msg
->dn
);
87 if (canonicalName
== NULL
) {
90 return ldb_msg_add_steal_string(msg
, "canonicalName", canonicalName
);
94 a list of attribute names that should be substituted in the parse
95 tree before the search is done
100 } parse_tree_sub
[] = {
101 { "createTimestamp", "whenCreated" },
102 { "modifyTimestamp", "whenChanged" }
107 a list of attribute names that are hidden, but can be searched for
108 using another (non-hidden) name to produce the correct result
110 static const struct {
113 int (*constructor
)(struct ldb_module
*, struct ldb_message
*);
115 { "createTimestamp", "whenCreated", NULL
},
116 { "modifyTimestamp", "whenChanged", NULL
},
117 { "structuralObjectClass", "objectClass", NULL
},
118 { "canonicalName", "distinguishedName", construct_canonical_name
}
122 post process a search result record. For any search_sub[] attributes that were
123 asked for, we need to call the appropriate copy routine to copy the result
124 into the message, then remove any attributes that we added to the search but were
125 not asked for by the user
127 static int operational_search_post_process(struct ldb_module
*module
,
128 struct ldb_message
*msg
,
129 const char * const *attrs
)
133 for (a
=0;attrs
&& attrs
[a
];a
++) {
134 for (i
=0;i
<ARRAY_SIZE(search_sub
);i
++) {
135 if (ldb_attr_cmp(attrs
[a
], search_sub
[i
].attr
) != 0) {
139 /* construct the new attribute, using either a supplied
140 constructor or a simple copy */
141 if (search_sub
[i
].constructor
) {
142 if (search_sub
[i
].constructor(module
, msg
) != 0) {
145 } else if (ldb_msg_copy_attr(msg
,
146 search_sub
[i
].replace
,
147 search_sub
[i
].attr
) != 0) {
151 /* remove the added search attribute, unless it was asked for
153 if (search_sub
[i
].replace
== NULL
||
154 ldb_attr_in_list(attrs
, search_sub
[i
].replace
) ||
155 ldb_attr_in_list(attrs
, "*")) {
159 ldb_msg_remove_attr(msg
, search_sub
[i
].replace
);
166 ldb_debug_set(module
->ldb
, LDB_DEBUG_WARNING
,
167 "operational_search_post_process failed for attribute '%s'\n",
174 hook search operations
177 struct operational_context
{
179 struct ldb_module
*module
;
181 int (*up_callback
)(struct ldb_context
*, void *, struct ldb_reply
*);
183 const char * const *attrs
;
186 static int operational_callback(struct ldb_context
*ldb
, void *context
, struct ldb_reply
*ares
)
188 struct operational_context
*ac
;
190 if (!context
|| !ares
) {
191 ldb_set_errstring(ldb
, "NULL Context or Result in callback");
195 ac
= talloc_get_type(context
, struct operational_context
);
197 if (ares
->type
== LDB_REPLY_ENTRY
) {
198 /* for each record returned post-process to add any derived
199 attributes that have been asked for */
200 if (operational_search_post_process(ac
->module
, ares
->message
, ac
->attrs
) != 0) {
205 return ac
->up_callback(ldb
, ac
->up_context
, ares
);
209 return LDB_ERR_OPERATIONS_ERROR
;
212 static int operational_search(struct ldb_module
*module
, struct ldb_request
*req
)
214 struct operational_context
*ac
;
215 struct ldb_request
*down_req
;
216 const char **search_attrs
= NULL
;
221 ac
= talloc(req
, struct operational_context
);
223 return LDB_ERR_OPERATIONS_ERROR
;
227 ac
->up_context
= req
->context
;
228 ac
->up_callback
= req
->callback
;
229 ac
->attrs
= req
->op
.search
.attrs
;
231 down_req
= talloc_zero(req
, struct ldb_request
);
232 if (down_req
== NULL
) {
233 return LDB_ERR_OPERATIONS_ERROR
;
236 down_req
->operation
= req
->operation
;
237 down_req
->op
.search
.base
= req
->op
.search
.base
;
238 down_req
->op
.search
.scope
= req
->op
.search
.scope
;
239 down_req
->op
.search
.tree
= req
->op
.search
.tree
;
241 /* FIXME: I hink we should copy the tree and keep the original
243 /* replace any attributes in the parse tree that are
244 searchable, but are stored using a different name in the
246 for (i
=0;i
<ARRAY_SIZE(parse_tree_sub
);i
++) {
247 ldb_parse_tree_attr_replace(req
->op
.search
.tree
,
248 parse_tree_sub
[i
].attr
,
249 parse_tree_sub
[i
].replace
);
252 /* in the list of attributes we are looking for, rename any
253 attributes to the alias for any hidden attributes that can
254 be fetched directly using non-hidden names */
255 for (a
=0;ac
->attrs
&& ac
->attrs
[a
];a
++) {
256 for (i
=0;i
<ARRAY_SIZE(search_sub
);i
++) {
257 if (ldb_attr_cmp(ac
->attrs
[a
], search_sub
[i
].attr
) == 0 &&
258 search_sub
[i
].replace
) {
260 search_attrs
= ldb_attr_list_copy(req
, ac
->attrs
);
261 if (search_attrs
== NULL
) {
262 return LDB_ERR_OPERATIONS_ERROR
;
265 search_attrs
[a
] = search_sub
[i
].replace
;
270 /* use new set of attrs if any */
271 if (search_attrs
) down_req
->op
.search
.attrs
= search_attrs
;
272 else down_req
->op
.search
.attrs
= req
->op
.search
.attrs
;
274 down_req
->controls
= req
->controls
;
276 down_req
->context
= ac
;
277 down_req
->callback
= operational_callback
;
278 ldb_set_timeout_from_prev_req(module
->ldb
, req
, down_req
);
280 /* perform the search */
281 ret
= ldb_next_request(module
, down_req
);
283 /* do not free down_req as the call results may be linked to it,
284 * it will be freed when the upper level request get freed */
285 if (ret
== LDB_SUCCESS
) {
286 req
->handle
= down_req
->handle
;
292 static int operational_init(struct ldb_module
*ctx
)
296 /* setup some standard attribute handlers */
297 ret
|= ldb_schema_attribute_add(ctx
->ldb
, "whenCreated", 0, LDB_SYNTAX_UTC_TIME
);
298 ret
|= ldb_schema_attribute_add(ctx
->ldb
, "whenChanged", 0, LDB_SYNTAX_UTC_TIME
);
299 ret
|= ldb_schema_attribute_add(ctx
->ldb
, "subschemaSubentry", 0, LDB_SYNTAX_DN
);
300 ret
|= ldb_schema_attribute_add(ctx
->ldb
, "structuralObjectClass", 0, LDB_SYNTAX_OBJECTCLASS
);
306 return ldb_next_init(ctx
);
309 static const struct ldb_module_ops operational_ops
= {
310 .name
= "operational",
311 .search
= operational_search
,
312 .init_context
= operational_init
315 int ldb_operational_init(void)
317 return ldb_register_module(&operational_ops
);