Fix bug #9098 - winbind does not refresh kerberos tickets.
[Samba.git] / source4 / lib / ldb / modules / asq.c
blob7482de826f0cf088d17d3e63ce30f6b1818e479e
1 /*
2 ldb database library
4 Copyright (C) Simo Sorce 2005-2008
6 ** NOTE! The following LGPL license applies to the ldb
7 ** library. This does NOT imply that all of Samba is released
8 ** under the LGPL
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 3 of the License, or (at your option) any later version.
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, see <http://www.gnu.org/licenses/>.
25 * Name: ldb
27 * Component: ldb attribute scoped query control module
29 * Description: this module searches all the objects pointed by
30 * the DNs contained in the references attribute
32 * Author: Simo Sorce
35 #include "replace.h"
36 #include "system/filesys.h"
37 #include "system/time.h"
38 #include "ldb_module.h"
40 struct asq_context {
42 enum {ASQ_SEARCH_BASE, ASQ_SEARCH_MULTI} step;
44 struct ldb_module *module;
45 struct ldb_request *req;
47 struct ldb_asq_control *asq_ctrl;
49 const char * const *req_attrs;
50 char *req_attribute;
51 enum {
52 ASQ_CTRL_SUCCESS = 0,
53 ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX = 21,
54 ASQ_CTRL_UNWILLING_TO_PERFORM = 53,
55 ASQ_CTRL_AFFECTS_MULTIPLE_DSA = 71
56 } asq_ret;
58 struct ldb_reply *base_res;
60 struct ldb_request **reqs;
61 unsigned int num_reqs;
62 unsigned int cur_req;
64 struct ldb_control **controls;
67 static struct asq_context *asq_context_init(struct ldb_module *module, struct ldb_request *req)
69 struct ldb_context *ldb;
70 struct asq_context *ac;
72 ldb = ldb_module_get_ctx(module);
74 ac = talloc_zero(req, struct asq_context);
75 if (ac == NULL) {
76 ldb_oom(ldb);
77 return NULL;
80 ac->module = module;
81 ac->req = req;
83 return ac;
86 static int asq_search_continue(struct asq_context *ac);
88 static int asq_search_terminate(struct asq_context *ac)
90 struct ldb_asq_control *asq;
91 unsigned int i;
93 if (ac->controls) {
94 for (i = 0; ac->controls[i]; i++) /* count em */ ;
95 } else {
96 i = 0;
99 ac->controls = talloc_realloc(ac, ac->controls, struct ldb_control *, i + 2);
101 if (ac->controls == NULL) {
102 return LDB_ERR_OPERATIONS_ERROR;
105 ac->controls[i] = talloc(ac->controls, struct ldb_control);
106 if (ac->controls[i] == NULL) {
107 return LDB_ERR_OPERATIONS_ERROR;
110 ac->controls[i]->oid = LDB_CONTROL_ASQ_OID;
111 ac->controls[i]->critical = 0;
113 asq = talloc_zero(ac->controls[i], struct ldb_asq_control);
114 if (asq == NULL)
115 return LDB_ERR_OPERATIONS_ERROR;
117 asq->result = ac->asq_ret;
119 ac->controls[i]->data = asq;
121 ac->controls[i + 1] = NULL;
123 return ldb_module_done(ac->req, ac->controls, NULL, LDB_SUCCESS);
126 static int asq_base_callback(struct ldb_request *req, struct ldb_reply *ares)
128 struct asq_context *ac;
129 int ret;
131 ac = talloc_get_type(req->context, struct asq_context);
133 if (!ares) {
134 return ldb_module_done(ac->req, NULL, NULL,
135 LDB_ERR_OPERATIONS_ERROR);
137 if (ares->error != LDB_SUCCESS) {
138 return ldb_module_done(ac->req, ares->controls,
139 ares->response, ares->error);
142 switch (ares->type) {
143 case LDB_REPLY_ENTRY:
144 ac->base_res = talloc_move(ac, &ares);
145 break;
147 case LDB_REPLY_REFERRAL:
148 /* ignore referrals */
149 talloc_free(ares);
150 break;
152 case LDB_REPLY_DONE:
154 talloc_free(ares);
156 /* next step */
157 ret = asq_search_continue(ac);
158 if (ret != LDB_SUCCESS) {
159 return ldb_module_done(ac->req, NULL, NULL, ret);
161 break;
164 return LDB_SUCCESS;
167 static int asq_reqs_callback(struct ldb_request *req, struct ldb_reply *ares)
169 struct asq_context *ac;
170 int ret;
172 ac = talloc_get_type(req->context, struct asq_context);
174 if (!ares) {
175 return ldb_module_done(ac->req, NULL, NULL,
176 LDB_ERR_OPERATIONS_ERROR);
178 if (ares->error != LDB_SUCCESS) {
179 return ldb_module_done(ac->req, ares->controls,
180 ares->response, ares->error);
183 switch (ares->type) {
184 case LDB_REPLY_ENTRY:
185 /* pass the message up to the original callback as we
186 * do not have to elaborate on it any further */
187 ret = ldb_module_send_entry(ac->req, ares->message, ares->controls);
188 if (ret != LDB_SUCCESS) {
189 return ldb_module_done(ac->req, NULL, NULL, ret);
191 talloc_free(ares);
192 break;
194 case LDB_REPLY_REFERRAL:
195 /* ignore referrals */
196 talloc_free(ares);
197 break;
199 case LDB_REPLY_DONE:
201 talloc_free(ares);
203 ret = asq_search_continue(ac);
204 if (ret != LDB_SUCCESS) {
205 return ldb_module_done(ac->req, NULL, NULL, ret);
207 break;
210 return LDB_SUCCESS;
213 static int asq_build_first_request(struct asq_context *ac, struct ldb_request **base_req)
215 struct ldb_context *ldb;
216 const char **base_attrs;
217 int ret;
219 ldb = ldb_module_get_ctx(ac->module);
221 ac->req_attrs = ac->req->op.search.attrs;
222 ac->req_attribute = talloc_strdup(ac, ac->asq_ctrl->source_attribute);
223 if (ac->req_attribute == NULL)
224 return LDB_ERR_OPERATIONS_ERROR;
226 base_attrs = talloc_array(ac, const char *, 2);
227 if (base_attrs == NULL) return LDB_ERR_OPERATIONS_ERROR;
229 base_attrs[0] = talloc_strdup(base_attrs, ac->asq_ctrl->source_attribute);
230 if (base_attrs[0] == NULL) return LDB_ERR_OPERATIONS_ERROR;
232 base_attrs[1] = NULL;
234 ret = ldb_build_search_req(base_req, ldb, ac,
235 ac->req->op.search.base,
236 LDB_SCOPE_BASE,
237 NULL,
238 (const char * const *)base_attrs,
239 NULL,
240 ac, asq_base_callback,
241 ac->req);
242 if (ret != LDB_SUCCESS) {
243 return ret;
246 return LDB_SUCCESS;
249 static int asq_build_multiple_requests(struct asq_context *ac, bool *terminated)
251 struct ldb_context *ldb;
252 struct ldb_control **saved_controls;
253 struct ldb_control *control;
254 struct ldb_dn *dn;
255 struct ldb_message_element *el;
256 unsigned int i;
257 int ret;
259 if (ac->base_res == NULL) {
260 return LDB_ERR_NO_SUCH_OBJECT;
263 ldb = ldb_module_get_ctx(ac->module);
265 el = ldb_msg_find_element(ac->base_res->message, ac->req_attribute);
266 /* no values found */
267 if (el == NULL) {
268 ac->asq_ret = ASQ_CTRL_SUCCESS;
269 *terminated = true;
270 return asq_search_terminate(ac);
273 ac->num_reqs = el->num_values;
274 ac->cur_req = 0;
275 ac->reqs = talloc_array(ac, struct ldb_request *, ac->num_reqs);
276 if (ac->reqs == NULL) {
277 return LDB_ERR_OPERATIONS_ERROR;
280 for (i = 0; i < el->num_values; i++) {
282 dn = ldb_dn_new(ac, ldb,
283 (const char *)el->values[i].data);
284 if ( ! ldb_dn_validate(dn)) {
285 ac->asq_ret = ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX;
286 *terminated = true;
287 return asq_search_terminate(ac);
290 ret = ldb_build_search_req_ex(&ac->reqs[i],
291 ldb, ac,
292 dn, LDB_SCOPE_BASE,
293 ac->req->op.search.tree,
294 ac->req_attrs,
295 ac->req->controls,
296 ac, asq_reqs_callback,
297 ac->req);
298 if (ret != LDB_SUCCESS) {
299 return ret;
302 /* remove the ASQ control itself */
303 control = ldb_request_get_control(ac->req, LDB_CONTROL_ASQ_OID);
304 if (!ldb_save_controls(control, ac->reqs[i], &saved_controls)) {
305 return LDB_ERR_OPERATIONS_ERROR;
309 return LDB_SUCCESS;
312 static int asq_search_continue(struct asq_context *ac)
314 struct ldb_context *ldb;
315 bool terminated = false;
316 int ret;
318 ldb = ldb_module_get_ctx(ac->module);
320 switch (ac->step) {
321 case ASQ_SEARCH_BASE:
323 /* build up the requests call chain */
324 ret = asq_build_multiple_requests(ac, &terminated);
325 if (ret != LDB_SUCCESS || terminated) {
326 return ret;
329 ac->step = ASQ_SEARCH_MULTI;
331 return ldb_request(ldb, ac->reqs[ac->cur_req]);
333 case ASQ_SEARCH_MULTI:
335 ac->cur_req++;
337 if (ac->cur_req == ac->num_reqs) {
338 /* done */
339 return asq_search_terminate(ac);
342 return ldb_request(ldb, ac->reqs[ac->cur_req]);
345 return LDB_ERR_OPERATIONS_ERROR;
348 static int asq_search(struct ldb_module *module, struct ldb_request *req)
350 struct ldb_context *ldb;
351 struct ldb_request *base_req;
352 struct ldb_control *control;
353 struct asq_context *ac;
354 int ret;
356 ldb = ldb_module_get_ctx(module);
358 /* check if there's an ASQ control */
359 control = ldb_request_get_control(req, LDB_CONTROL_ASQ_OID);
360 if (control == NULL) {
361 /* not found go on */
362 return ldb_next_request(module, req);
365 ac = asq_context_init(module, req);
366 if (!ac) {
367 return LDB_ERR_OPERATIONS_ERROR;
370 /* check the search is well formed */
371 if (req->op.search.scope != LDB_SCOPE_BASE) {
372 ac->asq_ret = ASQ_CTRL_UNWILLING_TO_PERFORM;
373 return asq_search_terminate(ac);
376 ac->asq_ctrl = talloc_get_type(control->data, struct ldb_asq_control);
377 if (!ac->asq_ctrl) {
378 return LDB_ERR_PROTOCOL_ERROR;
381 ret = asq_build_first_request(ac, &base_req);
382 if (ret != LDB_SUCCESS) {
383 return ret;
386 ac->step = ASQ_SEARCH_BASE;
388 return ldb_request(ldb, base_req);
391 static int asq_init(struct ldb_module *module)
393 struct ldb_context *ldb;
394 int ret;
396 ldb = ldb_module_get_ctx(module);
398 ret = ldb_mod_register_control(module, LDB_CONTROL_ASQ_OID);
399 if (ret != LDB_SUCCESS) {
400 ldb_debug(ldb, LDB_DEBUG_WARNING, "asq: Unable to register control with rootdse!");
403 return ldb_next_init(module);
406 static const struct ldb_module_ops ldb_asq_module_ops = {
407 .name = "asq",
408 .search = asq_search,
409 .init_context = asq_init
412 int ldb_asq_init(const char *version)
414 LDB_MODULE_CHECK_VERSION(version);
415 return ldb_register_module(&ldb_asq_module_ops);