s4-drs: Synchronous Implementation of generated parentGUID
[Samba/cd1.git] / source4 / dsdb / samdb / ldb_modules / operational.c
blobccfddbe56edf98530856d2a18d2687b709dfd56e
1 /*
2 ldb database library
4 Copyright (C) Andrew Tridgell 2005
5 Copyright (C) Simo Sorce 2006-2008
6 Copyright (C) Matthias Dieter Wallnöfer 2009
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 handle operational attributes
27 createTimestamp: HIDDEN, searchable, ldaptime, alias for whenCreated
28 modifyTimestamp: HIDDEN, searchable, ldaptime, alias for whenChanged
30 for the above two, we do the search as normal, and if
31 createTimestamp or modifyTimestamp is asked for, then do
32 additional searches for whenCreated and whenChanged and fill in
33 the resulting values
35 we also need to replace these with the whenCreated/whenChanged
36 equivalent in the search expression trees
38 whenCreated: not-HIDDEN, CONSTRUCTED, SEARCHABLE
39 whenChanged: not-HIDDEN, CONSTRUCTED, SEARCHABLE
41 on init we need to setup attribute handlers for these so
42 comparisons are done correctly. The resolution is 1 second.
44 on add we need to add both the above, for current time
46 on modify we need to change whenChanged
48 structuralObjectClass: HIDDEN, CONSTRUCTED, not-searchable. always same as objectclass?
50 for this one we do the search as normal, then if requested ask
51 for objectclass, change the attribute name, and add it
53 primaryGroupToken: HIDDEN, CONSTRUCTED, SEARCHABLE
55 contains the RID of a certain group object
58 attributeTypes: in schema only
59 objectClasses: in schema only
60 matchingRules: in schema only
61 matchingRuleUse: in schema only
62 creatorsName: not supported by w2k3?
63 modifiersName: not supported by w2k3?
66 #include "includes.h"
67 #include "ldb_includes.h"
68 #include "ldb_module.h"
70 #include "librpc/gen_ndr/ndr_misc.h"
71 #include "param/param.h"
72 #include "dsdb/samdb/samdb.h"
74 #ifndef ARRAY_SIZE
75 #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
76 #endif
79 construct a canonical name from a message
81 static int construct_canonical_name(struct ldb_module *module,
82 struct ldb_message *msg)
84 char *canonicalName;
85 canonicalName = ldb_dn_canonical_string(msg, msg->dn);
86 if (canonicalName == NULL) {
87 return -1;
89 return ldb_msg_add_steal_string(msg, "canonicalName", canonicalName);
93 construct a primary group token for groups from a message
95 static int construct_primary_group_token(struct ldb_module *module,
96 struct ldb_message *msg)
98 struct ldb_context *ldb;
99 uint32_t primary_group_token;
101 ldb = ldb_module_get_ctx(module);
103 if (samdb_search_count(ldb, ldb, msg->dn, "(objectclass=group)") == 1) {
104 primary_group_token
105 = samdb_result_rid_from_sid(ldb, msg, "objectSid", 0);
106 return samdb_msg_add_int(ldb, ldb, msg, "primaryGroupToken",
107 primary_group_token);
108 } else {
109 return LDB_SUCCESS;
113 static int construct_parent_guid(struct ldb_module *module,
114 struct ldb_message *msg)
116 struct ldb_context *ldb;
117 struct GUID parent_guid;
118 int ret;
120 ldb = ldb_module_get_ctx(module);
122 ret = dsdb_find_parentguid_by_dn(ldb, msg->dn, &parent_guid);
125 if (ret != LDB_SUCCESS){
127 /* if there is no parentGUID for this object, then return */
128 if (ret == LDB_ERR_NO_SUCH_OBJECT){
129 return LDB_SUCCESS;
130 }else{
131 return ret;
136 ret = dsdb_msg_add_guid(msg, &parent_guid, "parentGUID");
138 return ret;
144 a list of attribute names that should be substituted in the parse
145 tree before the search is done
147 static const struct {
148 const char *attr;
149 const char *replace;
150 } parse_tree_sub[] = {
151 { "createTimestamp", "whenCreated" },
152 { "modifyTimestamp", "whenChanged" }
157 a list of attribute names that are hidden, but can be searched for
158 using another (non-hidden) name to produce the correct result
160 static const struct {
161 const char *attr;
162 const char *replace;
163 int (*constructor)(struct ldb_module *, struct ldb_message *);
164 } search_sub[] = {
165 { "createTimestamp", "whenCreated", NULL },
166 { "modifyTimestamp", "whenChanged", NULL },
167 { "structuralObjectClass", "objectClass", NULL },
168 { "canonicalName", "distinguishedName", construct_canonical_name },
169 { "primaryGroupToken", "objectSid", construct_primary_group_token },
170 { "parentGUID", NULL, construct_parent_guid }
174 post process a search result record. For any search_sub[] attributes that were
175 asked for, we need to call the appropriate copy routine to copy the result
176 into the message, then remove any attributes that we added to the search but
177 were not asked for by the user
179 static int operational_search_post_process(struct ldb_module *module,
180 struct ldb_message *msg,
181 const char * const *attrs)
183 struct ldb_context *ldb;
184 int i, a=0;
186 ldb = ldb_module_get_ctx(module);
188 for (a=0;attrs && attrs[a];a++) {
189 for (i=0;i<ARRAY_SIZE(search_sub);i++) {
190 if (ldb_attr_cmp(attrs[a], search_sub[i].attr) != 0) {
191 continue;
194 /* construct the new attribute, using either a supplied
195 constructor or a simple copy */
196 if (search_sub[i].constructor) {
197 if (search_sub[i].constructor(module, msg) != 0) {
198 goto failed;
200 } else if (ldb_msg_copy_attr(msg,
201 search_sub[i].replace,
202 search_sub[i].attr) != 0) {
203 goto failed;
206 /* remove the added search attribute, unless it was
207 asked for by the user */
208 if (search_sub[i].replace == NULL ||
209 ldb_attr_in_list(attrs, search_sub[i].replace) ||
210 ldb_attr_in_list(attrs, "*")) {
211 continue;
214 ldb_msg_remove_attr(msg, search_sub[i].replace);
218 return 0;
220 failed:
221 ldb_debug_set(ldb, LDB_DEBUG_WARNING,
222 "operational_search_post_process failed for attribute '%s'",
223 attrs[a]);
224 return -1;
229 hook search operations
232 struct operational_context {
233 struct ldb_module *module;
234 struct ldb_request *req;
236 const char * const *attrs;
239 static int operational_callback(struct ldb_request *req, struct ldb_reply *ares)
241 struct operational_context *ac;
242 int ret;
244 ac = talloc_get_type(req->context, struct operational_context);
246 if (!ares) {
247 return ldb_module_done(ac->req, NULL, NULL,
248 LDB_ERR_OPERATIONS_ERROR);
250 if (ares->error != LDB_SUCCESS) {
251 return ldb_module_done(ac->req, ares->controls,
252 ares->response, ares->error);
255 switch (ares->type) {
256 case LDB_REPLY_ENTRY:
257 /* for each record returned post-process to add any derived
258 attributes that have been asked for */
259 ret = operational_search_post_process(ac->module,
260 ares->message,
261 ac->attrs);
262 if (ret != 0) {
263 return ldb_module_done(ac->req, NULL, NULL,
264 LDB_ERR_OPERATIONS_ERROR);
266 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
268 case LDB_REPLY_REFERRAL:
269 /* ignore referrals */
270 break;
272 case LDB_REPLY_DONE:
274 return ldb_module_done(ac->req, ares->controls,
275 ares->response, LDB_SUCCESS);
278 talloc_free(ares);
279 return LDB_SUCCESS;
282 static int operational_search(struct ldb_module *module, struct ldb_request *req)
284 struct ldb_context *ldb;
285 struct operational_context *ac;
286 struct ldb_request *down_req;
287 const char **search_attrs = NULL;
288 int i, a;
289 int ret;
291 ldb = ldb_module_get_ctx(module);
293 ac = talloc(req, struct operational_context);
294 if (ac == NULL) {
295 return LDB_ERR_OPERATIONS_ERROR;
298 ac->module = module;
299 ac->req = req;
300 ac->attrs = req->op.search.attrs;
302 /* FIXME: We must copy the tree and keep the original
303 * unmodified. SSS */
304 /* replace any attributes in the parse tree that are
305 searchable, but are stored using a different name in the
306 backend */
307 for (i=0;i<ARRAY_SIZE(parse_tree_sub);i++) {
308 ldb_parse_tree_attr_replace(req->op.search.tree,
309 parse_tree_sub[i].attr,
310 parse_tree_sub[i].replace);
313 /* in the list of attributes we are looking for, rename any
314 attributes to the alias for any hidden attributes that can
315 be fetched directly using non-hidden names */
316 for (a=0;ac->attrs && ac->attrs[a];a++) {
317 for (i=0;i<ARRAY_SIZE(search_sub);i++) {
318 if (ldb_attr_cmp(ac->attrs[a], search_sub[i].attr) == 0 &&
319 search_sub[i].replace) {
320 if (!search_attrs) {
321 search_attrs = ldb_attr_list_copy(req, ac->attrs);
322 if (search_attrs == NULL) {
323 return LDB_ERR_OPERATIONS_ERROR;
326 search_attrs[a] = search_sub[i].replace;
331 ret = ldb_build_search_req_ex(&down_req, ldb, ac,
332 req->op.search.base,
333 req->op.search.scope,
334 req->op.search.tree,
335 /* use new set of attrs if any */
336 search_attrs == NULL?req->op.search.attrs:search_attrs,
337 req->controls,
338 ac, operational_callback,
339 req);
340 if (ret != LDB_SUCCESS) {
341 return LDB_ERR_OPERATIONS_ERROR;
344 /* perform the search */
345 return ldb_next_request(module, down_req);
348 static int operational_init(struct ldb_module *ctx)
350 int ret = 0;
352 if (ret != 0) {
353 return ret;
356 return ldb_next_init(ctx);
359 const struct ldb_module_ops ldb_operational_module_ops = {
360 .name = "operational",
361 .search = operational_search,
362 .init_context = operational_init