Merge ldb_search() and ldb_search_exp_fmt() into a simgle function.
[Samba.git] / source4 / dsdb / samdb / ldb_modules / proxy.c
blobd0a315e45a444d59359b157cdc16a0e331224f34
1 /*
2 samdb proxy module
4 Copyright (C) Andrew Tridgell 2005
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 ldb proxy module. At startup this looks for a record like this:
27 dn=@PROXYINFO
28 url=destination url
29 olddn = basedn to proxy in upstream server
30 newdn = basedn in local server
31 username = username to connect to upstream
32 password = password for upstream
34 NOTE: this module is a complete hack at this stage. I am committing it just
35 so others can know how I am investigating mmc support
39 #include "includes.h"
40 #include "ldb/include/ldb.h"
41 #include "ldb/include/ldb_errors.h"
42 #include "ldb/include/ldb_private.h"
43 #include "auth/credentials/credentials.h"
45 struct proxy_data {
46 struct ldb_context *upstream;
47 struct ldb_dn *olddn;
48 struct ldb_dn *newdn;
49 const char **oldstr;
50 const char **newstr;
55 load the @PROXYINFO record
57 static int load_proxy_info(struct ldb_module *module)
59 struct proxy_data *proxy = talloc_get_type(module->private_data, struct proxy_data);
60 struct ldb_dn *dn;
61 struct ldb_result *res = NULL;
62 int ret;
63 const char *olddn, *newdn, *url, *username, *password, *oldstr, *newstr;
64 struct cli_credentials *creds;
67 /* see if we have already loaded it */
68 if (proxy->upstream != NULL) {
69 return 0;
72 dn = ldb_dn_new(proxy, module->ldb, "@PROXYINFO");
73 if (dn == NULL) {
74 goto failed;
76 ret = ldb_search(module->ldb, proxy, &res, dn, LDB_SCOPE_BASE, NULL, NULL);
77 talloc_free(dn);
78 if (ret != LDB_SUCCESS || res->count != 1) {
79 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Can't find @PROXYINFO\n");
80 goto failed;
83 url = ldb_msg_find_attr_as_string(res->msgs[0], "url", NULL);
84 olddn = ldb_msg_find_attr_as_string(res->msgs[0], "olddn", NULL);
85 newdn = ldb_msg_find_attr_as_string(res->msgs[0], "newdn", NULL);
86 username = ldb_msg_find_attr_as_string(res->msgs[0], "username", NULL);
87 password = ldb_msg_find_attr_as_string(res->msgs[0], "password", NULL);
88 oldstr = ldb_msg_find_attr_as_string(res->msgs[0], "oldstr", NULL);
89 newstr = ldb_msg_find_attr_as_string(res->msgs[0], "newstr", NULL);
91 if (url == NULL || olddn == NULL || newdn == NULL || username == NULL || password == NULL) {
92 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Need url, olddn, newdn, oldstr, newstr, username and password in @PROXYINFO\n");
93 goto failed;
96 proxy->olddn = ldb_dn_new(proxy, module->ldb, olddn);
97 if (proxy->olddn == NULL) {
98 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Failed to explode olddn '%s'\n", olddn);
99 goto failed;
102 proxy->newdn = ldb_dn_new(proxy, module->ldb, newdn);
103 if (proxy->newdn == NULL) {
104 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Failed to explode newdn '%s'\n", newdn);
105 goto failed;
108 proxy->upstream = ldb_init(proxy);
109 if (proxy->upstream == NULL) {
110 ldb_oom(module->ldb);
111 goto failed;
114 proxy->oldstr = str_list_make(proxy, oldstr, ", ");
115 if (proxy->oldstr == NULL) {
116 ldb_oom(module->ldb);
117 goto failed;
120 proxy->newstr = str_list_make(proxy, newstr, ", ");
121 if (proxy->newstr == NULL) {
122 ldb_oom(module->ldb);
123 goto failed;
126 /* setup credentials for connection */
127 creds = cli_credentials_init(proxy->upstream);
128 if (creds == NULL) {
129 ldb_oom(module->ldb);
130 goto failed;
132 cli_credentials_guess(creds, ldb_get_opaque(module->ldb, "loadparm"));
133 cli_credentials_set_username(creds, username, CRED_SPECIFIED);
134 cli_credentials_set_password(creds, password, CRED_SPECIFIED);
136 ldb_set_opaque(proxy->upstream, "credentials", creds);
138 ret = ldb_connect(proxy->upstream, url, 0, NULL);
139 if (ret != 0) {
140 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "proxy failed to connect to %s\n", url);
141 goto failed;
144 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "proxy connected to %s\n", url);
146 talloc_free(res);
148 return 0;
150 failed:
151 talloc_free(res);
152 talloc_free(proxy->olddn);
153 talloc_free(proxy->newdn);
154 talloc_free(proxy->upstream);
155 proxy->upstream = NULL;
156 return -1;
161 convert a binary blob
163 static void proxy_convert_blob(TALLOC_CTX *mem_ctx, struct ldb_val *v,
164 const char *oldstr, const char *newstr)
166 int len1, len2, len3;
167 uint8_t *olddata = v->data;
168 char *p = strcasestr((char *)v->data, oldstr);
170 len1 = (p - (char *)v->data);
171 len2 = strlen(newstr);
172 len3 = v->length - (p+strlen(oldstr) - (char *)v->data);
173 v->length = len1+len2+len3;
174 v->data = talloc_size(mem_ctx, v->length);
175 memcpy(v->data, olddata, len1);
176 memcpy(v->data+len1, newstr, len2);
177 memcpy(v->data+len1+len2, olddata + len1 + strlen(oldstr), len3);
181 convert a returned value
183 static void proxy_convert_value(struct ldb_module *module, struct ldb_message *msg, struct ldb_val *v)
185 struct proxy_data *proxy = talloc_get_type(module->private_data, struct proxy_data);
186 int i;
187 for (i=0;proxy->oldstr[i];i++) {
188 char *p = strcasestr((char *)v->data, proxy->oldstr[i]);
189 if (p == NULL) continue;
190 proxy_convert_blob(msg, v, proxy->oldstr[i], proxy->newstr[i]);
196 convert a returned value
198 static struct ldb_parse_tree *proxy_convert_tree(struct ldb_module *module,
199 struct ldb_parse_tree *tree)
201 struct proxy_data *proxy = talloc_get_type(module->private_data, struct proxy_data);
202 int i;
203 char *expression = ldb_filter_from_tree(module, tree);
204 for (i=0;proxy->newstr[i];i++) {
205 struct ldb_val v;
206 char *p = strcasestr(expression, proxy->newstr[i]);
207 if (p == NULL) continue;
208 v.data = (uint8_t *)expression;
209 v.length = strlen(expression)+1;
210 proxy_convert_blob(module, &v, proxy->newstr[i], proxy->oldstr[i]);
211 return ldb_parse_tree(module, (const char *)v.data);
213 return tree;
219 convert a returned record
221 static void proxy_convert_record(struct ldb_module *module, struct ldb_message *msg)
223 struct proxy_data *proxy = talloc_get_type(module->private_data, struct proxy_data);
224 int attr, v;
226 /* fix the message DN */
227 if (ldb_dn_compare_base(module->ldb, proxy->olddn, msg->dn) == 0) {
228 ldb_dn_remove_base_components(msg->dn, ldb_dn_get_comp_num(proxy->olddn));
229 ldb_dn_add_base(msg->dn, proxy->newdn);
232 /* fix any attributes */
233 for (attr=0;attr<msg->num_elements;attr++) {
234 for (v=0;v<msg->elements[attr].num_values;v++) {
235 proxy_convert_value(module, msg, &msg->elements[attr].values[v]);
239 /* fix any DN components */
240 for (attr=0;attr<msg->num_elements;attr++) {
241 for (v=0;v<msg->elements[attr].num_values;v++) {
242 proxy_convert_value(module, msg, &msg->elements[attr].values[v]);
247 /* search */
248 static int proxy_search_bytree(struct ldb_module *module, struct ldb_request *req)
250 struct proxy_data *proxy = talloc_get_type(module->private_data, struct proxy_data);
251 struct ldb_request *newreq;
252 struct ldb_dn *base;
253 int ret, i;
255 if (req->op.search.base == NULL ||
256 (req->op.search.base->comp_num == 1 &&
257 req->op.search.base->components[0].name[0] == '@')) {
258 goto passthru;
261 if (load_proxy_info(module) != 0) {
262 return -1;
265 /* see if the dn is within olddn */
266 if (ldb_dn_compare_base(module->ldb, proxy->newdn, req->op.search.base) != 0) {
267 goto passthru;
270 newreq = talloc(module, struct ldb_request);
271 if (newreq == NULL) {
272 return -1;
275 newreq->op.search.tree = proxy_convert_tree(module, req->op.search.tree);
277 /* convert the basedn of this search */
278 base = ldb_dn_copy(proxy, req->op.search.base);
279 if (base == NULL) {
280 talloc_free(newreq);
281 goto failed;
283 ldb_dn_remove_base_components(base, ldb_dn_get_comp_num(proxy->newdn));
284 ldb_dn_add_base(base, proxy->olddn);
286 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "proxying: '%s' with dn '%s' \n",
287 ldb_filter_from_tree(proxy, newreq->op.search.tree), ldb_dn_get_linearized(newreq->op.search.base));
288 for (i = 0; req->op.search.attrs && req->op.search.attrs[i]; i++) {
289 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "attr: '%s'\n", req->op.search.attrs[i]);
292 newreq->op.search.base = base;
293 newreq->op.search.scope = req->op.search.scope;
294 newreq->op.search.attrs = req->op.search.attrs;
295 newreq->op.search.res = req->op.search.res;
296 newreq->controls = req->controls;
297 ret = ldb_request(proxy->upstream, newreq);
298 if (ret != LDB_SUCCESS) {
299 ldb_set_errstring(module->ldb, ldb_errstring(proxy->upstream));
300 talloc_free(newreq);
301 return -1;
304 for (i = 0; i < newreq->op.search.res->count; i++) {
305 printf("# record %d\n", i+1);
307 proxy_convert_record(module, newreq->op.search.res->msgs[i]);
310 talloc_free(newreq);
311 return ret;
313 failed:
314 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "proxy failed for %s\n",
315 ldb_dn_get_linearized(req->op.search.base));
317 passthru:
318 return ldb_next_request(module, req);
321 static int proxy_request(struct ldb_module *module, struct ldb_request *req)
323 switch (req->operation) {
325 case LDB_REQ_SEARCH:
326 return proxy_search_bytree(module, req);
328 default:
329 return ldb_next_request(module, req);
334 _PUBLIC_ const struct ldb_module_ops ldb_proxy_module_ops = {
335 .name = "proxy",
336 .request = proxy_request