dsdb-acl: add acl_check_access_on_objectclass() helper
[Samba/gebeck_regimport.git] / source4 / dsdb / samdb / ldb_modules / proxy.c
blobc3f12bae3a16dd2d07ee1d19588fcb10121e4331
1 /*
2 samdb proxy module
4 Copyright (C) Andrew Tridgell 2005
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 ldb proxy module. At startup this looks for a record like this:
23 dn=@PROXYINFO
24 url=destination url
25 olddn = basedn to proxy in upstream server
26 newdn = basedn in local server
27 username = username to connect to upstream
28 password = password for upstream
30 NOTE: this module is a complete hack at this stage. I am committing it just
31 so others can know how I am investigating mmc support
35 #include "includes.h"
36 #include "ldb_module.h"
37 #include "auth/credentials/credentials.h"
39 struct proxy_data {
40 struct ldb_context *upstream;
41 struct ldb_dn *olddn;
42 struct ldb_dn *newdn;
43 const char **oldstr;
44 const char **newstr;
47 struct proxy_ctx {
48 struct ldb_module *module;
49 struct ldb_request *req;
51 #ifdef DEBUG_PROXY
52 int count;
53 #endif
57 load the @PROXYINFO record
59 static int load_proxy_info(struct ldb_module *module)
61 struct ldb_context *ldb = ldb_module_get_ctx(module);
62 struct proxy_data *proxy = talloc_get_type(ldb_module_get_private(module), struct proxy_data);
63 struct ldb_dn *dn;
64 struct ldb_result *res = NULL;
65 int ret;
66 const char *olddn, *newdn, *url, *username, *password, *oldstr, *newstr;
67 struct cli_credentials *creds;
69 /* see if we have already loaded it */
70 if (proxy->upstream != NULL) {
71 return LDB_SUCCESS;
74 dn = ldb_dn_new(proxy, ldb, "@PROXYINFO");
75 if (dn == NULL) {
76 goto failed;
78 ret = ldb_search(ldb, proxy, &res, dn, LDB_SCOPE_BASE, NULL, NULL);
79 talloc_free(dn);
80 if (ret != LDB_SUCCESS || res->count != 1) {
81 ldb_debug(ldb, LDB_DEBUG_FATAL, "Can't find @PROXYINFO\n");
82 goto failed;
85 url = ldb_msg_find_attr_as_string(res->msgs[0], "url", NULL);
86 olddn = ldb_msg_find_attr_as_string(res->msgs[0], "olddn", NULL);
87 newdn = ldb_msg_find_attr_as_string(res->msgs[0], "newdn", NULL);
88 username = ldb_msg_find_attr_as_string(res->msgs[0], "username", NULL);
89 password = ldb_msg_find_attr_as_string(res->msgs[0], "password", NULL);
90 oldstr = ldb_msg_find_attr_as_string(res->msgs[0], "oldstr", NULL);
91 newstr = ldb_msg_find_attr_as_string(res->msgs[0], "newstr", NULL);
93 if (url == NULL || olddn == NULL || newdn == NULL || username == NULL || password == NULL) {
94 ldb_debug(ldb, LDB_DEBUG_FATAL, "Need url, olddn, newdn, oldstr, newstr, username and password in @PROXYINFO\n");
95 goto failed;
98 proxy->olddn = ldb_dn_new(proxy, ldb, olddn);
99 if (proxy->olddn == NULL) {
100 ldb_debug(ldb, LDB_DEBUG_FATAL, "Failed to explode olddn '%s'\n", olddn);
101 goto failed;
104 proxy->newdn = ldb_dn_new(proxy, ldb, newdn);
105 if (proxy->newdn == NULL) {
106 ldb_debug(ldb, LDB_DEBUG_FATAL, "Failed to explode newdn '%s'\n", newdn);
107 goto failed;
110 proxy->upstream = ldb_init(proxy, ldb_get_event_context(ldb));
111 if (proxy->upstream == NULL) {
112 ldb_oom(ldb);
113 goto failed;
116 proxy->oldstr = str_list_make(proxy, oldstr, ", ");
117 if (proxy->oldstr == NULL) {
118 ldb_oom(ldb);
119 goto failed;
122 proxy->newstr = str_list_make(proxy, newstr, ", ");
123 if (proxy->newstr == NULL) {
124 ldb_oom(ldb);
125 goto failed;
128 /* setup credentials for connection */
129 creds = cli_credentials_init(proxy->upstream);
130 if (creds == NULL) {
131 ldb_oom(ldb);
132 goto failed;
134 cli_credentials_guess(creds, ldb_get_opaque(ldb, "loadparm"));
135 cli_credentials_set_username(creds, username, CRED_SPECIFIED);
136 cli_credentials_set_password(creds, password, CRED_SPECIFIED);
138 ldb_set_opaque(proxy->upstream, "credentials", creds);
140 ret = ldb_connect(proxy->upstream, url, 0, NULL);
141 if (ret != LDB_SUCCESS) {
142 ldb_debug(ldb, LDB_DEBUG_FATAL, "proxy failed to connect to %s\n", url);
143 goto failed;
146 ldb_debug(ldb, LDB_DEBUG_TRACE, "proxy connected to %s\n", url);
148 talloc_free(res);
150 return LDB_SUCCESS;
152 failed:
153 talloc_free(res);
154 talloc_free(proxy->olddn);
155 talloc_free(proxy->newdn);
156 talloc_free(proxy->upstream);
157 proxy->upstream = NULL;
158 return ldb_operr(ldb);
163 convert a binary blob
165 static void proxy_convert_blob(TALLOC_CTX *mem_ctx, struct ldb_val *v,
166 const char *oldstr, const char *newstr)
168 size_t len1, len2, len3;
169 uint8_t *olddata = v->data;
170 char *p = strcasestr((char *)v->data, oldstr);
172 len1 = (p - (char *)v->data);
173 len2 = strlen(newstr);
174 len3 = v->length - (p+strlen(oldstr) - (char *)v->data);
175 v->length = len1+len2+len3;
176 v->data = talloc_size(mem_ctx, v->length);
177 memcpy(v->data, olddata, len1);
178 memcpy(v->data+len1, newstr, len2);
179 memcpy(v->data+len1+len2, olddata + len1 + strlen(oldstr), len3);
183 convert a returned value
185 static void proxy_convert_value(struct proxy_data *proxy, struct ldb_message *msg, struct ldb_val *v)
187 size_t i;
189 for (i=0;proxy->oldstr[i];i++) {
190 char *p = strcasestr((char *)v->data, proxy->oldstr[i]);
191 if (p == NULL) continue;
192 proxy_convert_blob(msg, v, proxy->oldstr[i], proxy->newstr[i]);
198 convert a returned value
200 static struct ldb_parse_tree *proxy_convert_tree(TALLOC_CTX *mem_ctx,
201 struct proxy_data *proxy,
202 struct ldb_parse_tree *tree)
204 size_t i;
205 char *expression = ldb_filter_from_tree(mem_ctx, tree);
207 for (i=0;proxy->newstr[i];i++) {
208 struct ldb_val v;
209 char *p = strcasestr(expression, proxy->newstr[i]);
210 if (p == NULL) continue;
211 v.data = (uint8_t *)expression;
212 v.length = strlen(expression)+1;
213 proxy_convert_blob(mem_ctx, &v, proxy->newstr[i], proxy->oldstr[i]);
214 return ldb_parse_tree(mem_ctx, (const char *)v.data);
216 return tree;
222 convert a returned record
224 static void proxy_convert_record(struct ldb_context *ldb,
225 struct proxy_data *proxy,
226 struct ldb_message *msg)
228 unsigned int attr, v;
230 /* fix the message DN */
231 if (ldb_dn_compare_base(proxy->olddn, msg->dn) == 0) {
232 ldb_dn_remove_base_components(msg->dn, ldb_dn_get_comp_num(proxy->olddn));
233 ldb_dn_add_base(msg->dn, proxy->newdn);
236 /* fix any attributes */
237 for (attr=0;attr<msg->num_elements;attr++) {
238 for (v=0;v<msg->elements[attr].num_values;v++) {
239 proxy_convert_value(proxy, msg, &msg->elements[attr].values[v]);
243 /* fix any DN components */
244 for (attr=0;attr<msg->num_elements;attr++) {
245 for (v=0;v<msg->elements[attr].num_values;v++) {
246 proxy_convert_value(proxy, msg, &msg->elements[attr].values[v]);
251 static int proxy_search_callback(struct ldb_request *req,
252 struct ldb_reply *ares)
254 struct ldb_context *ldb;
255 struct proxy_data *proxy;
256 struct proxy_ctx *ac;
257 int ret;
259 ac = talloc_get_type(req->context, struct proxy_ctx);
260 ldb = ldb_module_get_ctx(ac->module);
261 proxy = talloc_get_type(ldb_module_get_private(module), struct proxy_data);
263 if (!ares) {
264 return ldb_module_done(ac->req, NULL, NULL,
265 LDB_ERR_OPERATIONS_ERROR);
267 if (ares->error != LDB_SUCCESS) {
268 return ldb_module_done(ac->req, ares->controls,
269 ares->response, ares->error);
272 /* Only entries are interesting, and we only want the olddn */
273 switch (ares->type) {
274 case LDB_REPLY_ENTRY:
276 #ifdef DEBUG_PROXY
277 ac->count++;
278 #endif
279 proxy_convert_record(ldb, proxy, ares->message);
280 ret = ldb_module_send_entry(ac->req, ares->message, ares->controls);
281 break;
283 case LDB_REPLY_REFERRAL:
285 /* ignore remote referrals */
286 break;
288 case LDB_REPLY_DONE:
290 #ifdef DEBUG_PROXY
291 printf("# record %d\n", ac->count+1);
292 #endif
294 return ldb_module_done(ac->req, NULL, NULL, LDB_SUCCESS);
297 talloc_free(ares);
298 return ret;
301 /* search */
302 static int proxy_search_bytree(struct ldb_module *module, struct ldb_request *req)
304 struct ldb_context *ldb;
305 struct proxy_ctx *ac;
306 struct ldb_parse_tree *newtree;
307 struct proxy_data *proxy = talloc_get_type(ldb_module_get_private(module), struct proxy_data);
308 struct ldb_request *newreq;
309 struct ldb_dn *base;
310 unsigned int i;
311 int ret;
313 ldb = ldb_module_get_ctx(module);
315 if (req->op.search.base == NULL ||
316 (req->op.search.base->comp_num == 1 &&
317 req->op.search.base->components[0].name[0] == '@')) {
318 goto passthru;
321 if (load_proxy_info(module) != LDB_SUCCESS) {
322 return ldb_operr(ldb);
325 /* see if the dn is within olddn */
326 if (ldb_dn_compare_base(proxy->newdn, req->op.search.base) != 0) {
327 goto passthru;
330 ac = talloc(req, struct proxy_ctx);
331 if (ac == NULL) {
332 return ldb_oom(ldb);
335 ac->module = module;
336 ac->req = req;
337 #ifdef DEBUG_PROXY
338 ac->count = 0;
339 #endif
341 newtree = proxy_convert_tree(ac, proxy, req->op.search.tree);
342 if (newtree == NULL) {
343 goto failed;
346 /* convert the basedn of this search */
347 base = ldb_dn_copy(ac, req->op.search.base);
348 if (base == NULL) {
349 goto failed;
351 ldb_dn_remove_base_components(base, ldb_dn_get_comp_num(proxy->newdn));
352 ldb_dn_add_base(base, proxy->olddn);
354 ldb_debug(ldb, LDB_DEBUG_FATAL, "proxying: '%s' with dn '%s' \n",
355 ldb_filter_from_tree(ac, newreq->op.search.tree), ldb_dn_get_linearized(newreq->op.search.base));
356 for (i = 0; req->op.search.attrs && req->op.search.attrs[i]; i++) {
357 ldb_debug(ldb, LDB_DEBUG_FATAL, "attr: '%s'\n", req->op.search.attrs[i]);
360 ret = ldb_build_search_req_ex(&newreq, ldb, ac,
361 base, req->op.search.scope,
362 newtree, req->op.search.attrs,
363 req->controls,
364 ac, proxy_search_callback,
365 req);
366 LDB_REQ_SET_LOCATION(newreq);
367 /* FIXME: warning, need a real event system hooked up for this to work properly,
368 * for now this makes the module *not* ASYNC */
369 ret = ldb_request(proxy->upstream, newreq);
370 if (ret != LDB_SUCCESS) {
371 ldb_set_errstring(ldb, ldb_errstring(proxy->upstream));
373 ret = ldb_wait(newreq->handle, LDB_WAIT_ALL);
374 if (ret != LDB_SUCCESS) {
375 ldb_set_errstring(ldb, ldb_errstring(proxy->upstream));
377 return ret;
379 failed:
380 ldb_debug(ldb, LDB_DEBUG_TRACE, "proxy failed for %s\n",
381 ldb_dn_get_linearized(req->op.search.base));
383 passthru:
384 return ldb_next_request(module, req);
387 static int proxy_request(struct ldb_module *module, struct ldb_request *req)
389 switch (req->operation) {
391 case LDB_REQ_SEARCH:
392 return proxy_search_bytree(module, req);
394 default:
395 return ldb_next_request(module, req);
400 static const struct ldb_module_ops ldb_proxy_module_ops = {
401 .name = "proxy",
402 .request = proxy_request
405 int ldb_proxy_module_init(const char *version)
407 LDB_MODULE_CHECK_VERSION(version);
408 return ldb_register_module(&ldb_proxy_module_ops);