• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/samba-3.5.8/source4/dsdb/samdb/ldb_modules/
1/*
2   ldb database library
3
4   Copyright (C) Andrew Tridgell 2005
5   Copyright (C) Simo Sorce 2006-2008
6   Copyright (C) Matthias Dieter Walln��fer 2009
7
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.
12
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.
17
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/>.
20*/
21
22/*
23  handle operational attributes
24 */
25
26/*
27  createTimestamp: HIDDEN, searchable, ldaptime, alias for whenCreated
28  modifyTimestamp: HIDDEN, searchable, ldaptime, alias for whenChanged
29
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
34
35     we also need to replace these with the whenCreated/whenChanged
36     equivalent in the search expression trees
37
38  whenCreated: not-HIDDEN, CONSTRUCTED, SEARCHABLE
39  whenChanged: not-HIDDEN, CONSTRUCTED, SEARCHABLE
40
41     on init we need to setup attribute handlers for these so
42     comparisons are done correctly. The resolution is 1 second.
43
44     on add we need to add both the above, for current time
45
46     on modify we need to change whenChanged
47
48  structuralObjectClass: HIDDEN, CONSTRUCTED, not-searchable. always same as objectclass?
49
50     for this one we do the search as normal, then if requested ask
51     for objectclass, change the attribute name, and add it
52
53  primaryGroupToken: HIDDEN, CONSTRUCTED, SEARCHABLE
54
55     contains the RID of a certain group object
56
57
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?
64*/
65
66#include "ldb_includes.h"
67#include "ldb_module.h"
68
69#include "includes.h"
70#include "dsdb/samdb/samdb.h"
71
72#ifndef ARRAY_SIZE
73#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
74#endif
75
76/*
77  construct a canonical name from a message
78*/
79static int construct_canonical_name(struct ldb_module *module,
80	struct ldb_message *msg)
81{
82	char *canonicalName;
83	canonicalName = ldb_dn_canonical_string(msg, msg->dn);
84	if (canonicalName == NULL) {
85		return -1;
86	}
87	return ldb_msg_add_steal_string(msg, "canonicalName", canonicalName);
88}
89
90/*
91  construct a primary group token for groups from a message
92*/
93static int construct_primary_group_token(struct ldb_module *module,
94	struct ldb_message *msg)
95{
96	struct ldb_context *ldb;
97	uint32_t primary_group_token;
98
99	ldb = ldb_module_get_ctx(module);
100
101	if (samdb_search_count(ldb, ldb, msg->dn, "(objectclass=group)") == 1) {
102		primary_group_token
103			= samdb_result_rid_from_sid(ldb, msg, "objectSid", 0);
104		return samdb_msg_add_int(ldb, ldb, msg, "primaryGroupToken",
105			primary_group_token);
106	} else {
107		return LDB_SUCCESS;
108	}
109}
110
111
112/*
113  a list of attribute names that should be substituted in the parse
114  tree before the search is done
115*/
116static const struct {
117	const char *attr;
118	const char *replace;
119} parse_tree_sub[] = {
120	{ "createTimestamp", "whenCreated" },
121	{ "modifyTimestamp", "whenChanged" }
122};
123
124
125/*
126  a list of attribute names that are hidden, but can be searched for
127  using another (non-hidden) name to produce the correct result
128*/
129static const struct {
130	const char *attr;
131	const char *replace;
132	int (*constructor)(struct ldb_module *, struct ldb_message *);
133} search_sub[] = {
134	{ "createTimestamp", "whenCreated", NULL },
135	{ "modifyTimestamp", "whenChanged", NULL },
136	{ "structuralObjectClass", "objectClass", NULL },
137	{ "canonicalName", "distinguishedName", construct_canonical_name },
138	{ "primaryGroupToken", "objectSid", construct_primary_group_token }
139};
140
141/*
142  post process a search result record. For any search_sub[] attributes that were
143  asked for, we need to call the appropriate copy routine to copy the result
144  into the message, then remove any attributes that we added to the search but
145  were not asked for by the user
146*/
147static int operational_search_post_process(struct ldb_module *module,
148					   struct ldb_message *msg,
149					   const char * const *attrs)
150{
151	struct ldb_context *ldb;
152	int i, a=0;
153
154	ldb = ldb_module_get_ctx(module);
155
156	for (a=0;attrs && attrs[a];a++) {
157		for (i=0;i<ARRAY_SIZE(search_sub);i++) {
158			if (ldb_attr_cmp(attrs[a], search_sub[i].attr) != 0) {
159				continue;
160			}
161
162			/* construct the new attribute, using either a supplied
163			   constructor or a simple copy */
164			if (search_sub[i].constructor) {
165				if (search_sub[i].constructor(module, msg) != 0) {
166					goto failed;
167				}
168			} else if (ldb_msg_copy_attr(msg,
169						     search_sub[i].replace,
170						     search_sub[i].attr) != 0) {
171				goto failed;
172			}
173
174			/* remove the added search attribute, unless it was
175 			   asked for by the user */
176			if (search_sub[i].replace == NULL ||
177			    ldb_attr_in_list(attrs, search_sub[i].replace) ||
178			    ldb_attr_in_list(attrs, "*")) {
179				continue;
180			}
181
182			ldb_msg_remove_attr(msg, search_sub[i].replace);
183		}
184	}
185
186	return 0;
187
188failed:
189	ldb_debug_set(ldb, LDB_DEBUG_WARNING,
190		      "operational_search_post_process failed for attribute '%s'",
191		      attrs[a]);
192	return -1;
193}
194
195
196/*
197  hook search operations
198*/
199
200struct operational_context {
201	struct ldb_module *module;
202	struct ldb_request *req;
203
204	const char * const *attrs;
205};
206
207static int operational_callback(struct ldb_request *req, struct ldb_reply *ares)
208{
209	struct operational_context *ac;
210	int ret;
211
212	ac = talloc_get_type(req->context, struct operational_context);
213
214	if (!ares) {
215		return ldb_module_done(ac->req, NULL, NULL,
216					LDB_ERR_OPERATIONS_ERROR);
217	}
218	if (ares->error != LDB_SUCCESS) {
219		return ldb_module_done(ac->req, ares->controls,
220					ares->response, ares->error);
221	}
222
223	switch (ares->type) {
224	case LDB_REPLY_ENTRY:
225		/* for each record returned post-process to add any derived
226		   attributes that have been asked for */
227		ret = operational_search_post_process(ac->module,
228							ares->message,
229							ac->attrs);
230		if (ret != 0) {
231			return ldb_module_done(ac->req, NULL, NULL,
232						LDB_ERR_OPERATIONS_ERROR);
233		}
234		return ldb_module_send_entry(ac->req, ares->message, ares->controls);
235
236	case LDB_REPLY_REFERRAL:
237		/* ignore referrals */
238		break;
239
240	case LDB_REPLY_DONE:
241
242		return ldb_module_done(ac->req, ares->controls,
243					ares->response, LDB_SUCCESS);
244	}
245
246	talloc_free(ares);
247	return LDB_SUCCESS;
248}
249
250static int operational_search(struct ldb_module *module, struct ldb_request *req)
251{
252	struct ldb_context *ldb;
253	struct operational_context *ac;
254	struct ldb_request *down_req;
255	const char **search_attrs = NULL;
256	int i, a;
257	int ret;
258
259	ldb = ldb_module_get_ctx(module);
260
261	ac = talloc(req, struct operational_context);
262	if (ac == NULL) {
263		return LDB_ERR_OPERATIONS_ERROR;
264	}
265
266	ac->module = module;
267	ac->req = req;
268	ac->attrs = req->op.search.attrs;
269
270	/*  FIXME: We must copy the tree and keep the original
271	 *  unmodified. SSS */
272	/* replace any attributes in the parse tree that are
273	   searchable, but are stored using a different name in the
274	   backend */
275	for (i=0;i<ARRAY_SIZE(parse_tree_sub);i++) {
276		ldb_parse_tree_attr_replace(req->op.search.tree,
277					    parse_tree_sub[i].attr,
278					    parse_tree_sub[i].replace);
279	}
280
281	/* in the list of attributes we are looking for, rename any
282	   attributes to the alias for any hidden attributes that can
283	   be fetched directly using non-hidden names */
284	for (a=0;ac->attrs && ac->attrs[a];a++) {
285		for (i=0;i<ARRAY_SIZE(search_sub);i++) {
286			if (ldb_attr_cmp(ac->attrs[a], search_sub[i].attr) == 0 &&
287			    search_sub[i].replace) {
288				if (!search_attrs) {
289					search_attrs = ldb_attr_list_copy(req, ac->attrs);
290					if (search_attrs == NULL) {
291						return LDB_ERR_OPERATIONS_ERROR;
292					}
293				}
294				search_attrs[a] = search_sub[i].replace;
295			}
296		}
297	}
298
299	ret = ldb_build_search_req_ex(&down_req, ldb, ac,
300					req->op.search.base,
301					req->op.search.scope,
302					req->op.search.tree,
303					/* use new set of attrs if any */
304					search_attrs == NULL?req->op.search.attrs:search_attrs,
305					req->controls,
306					ac, operational_callback,
307					req);
308	if (ret != LDB_SUCCESS) {
309		return LDB_ERR_OPERATIONS_ERROR;
310	}
311
312	/* perform the search */
313	return ldb_next_request(module, down_req);
314}
315
316static int operational_init(struct ldb_module *ctx)
317{
318	int ret = 0;
319
320	if (ret != 0) {
321		return ret;
322	}
323
324	return ldb_next_init(ctx);
325}
326
327const struct ldb_module_ops ldb_operational_module_ops = {
328	.name              = "operational",
329	.search            = operational_search,
330	.init_context	   = operational_init
331};
332