r11958: - fixed memory leaks in the ldb_result handling in ldb operations
[mdw/samba.git] / source4 / dsdb / samdb / ldb_modules / proxy.c
1 /* 
2    samdb proxy module
3
4    Copyright (C) Andrew Tridgell 2005
5
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
9    
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 2 of the License, or (at your option) any later version.
14
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.
19
20    You should have received a copy of the GNU Lesser General Public
21    License along with this library; if not, write to the Free Software
22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 */
24
25 /*
26   ldb proxy module. At startup this looks for a record like this:
27
28    dn=@PROXYINFO
29    url=destination url
30    olddn = basedn to proxy in upstream server
31    newdn = basedn in local server
32    username = username to connect to upstream
33    password = password for upstream
34
35    NOTE: this module is a complete hack at this stage. I am committing it just
36    so others can know how I am investigating mmc support
37    
38  */
39
40 #include "includes.h"
41 #include "ldb/include/ldb.h"
42 #include "ldb/include/ldb_errors.h"
43 #include "ldb/include/ldb_private.h"
44 #include "lib/cmdline/popt_common.h"
45
46 struct proxy_data {
47         struct ldb_context *upstream;
48         struct ldb_dn *olddn;
49         struct ldb_dn *newdn;
50         const char **oldstr;
51         const char **newstr;
52 };
53
54
55 /*
56   load the @PROXYINFO record
57 */
58 static int load_proxy_info(struct ldb_module *module)
59 {
60         struct proxy_data *proxy = talloc_get_type(module->private_data, struct proxy_data);
61         struct ldb_dn *dn;
62         struct ldb_result *res;
63         int ret;
64         const char *olddn, *newdn, *url, *username, *password, *oldstr, *newstr;
65         struct cli_credentials *creds;
66         
67
68         /* see if we have already loaded it */
69         if (proxy->upstream != NULL) {
70                 return 0;
71         }
72
73         dn = ldb_dn_explode(proxy, "@PROXYINFO");
74         if (dn == NULL) {
75                 goto failed;
76         }
77         ret = ldb_search(module->ldb, dn, LDB_SCOPE_BASE, NULL, NULL, &res);
78         talloc_free(dn);
79         if (ret != LDB_SUCCESS || res->count != 1) {
80                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Can't find @PROXYINFO\n");
81                 goto failed;
82         }
83
84         url      = ldb_msg_find_string(res->msgs[0], "url", NULL);
85         olddn    = ldb_msg_find_string(res->msgs[0], "olddn", NULL);
86         newdn    = ldb_msg_find_string(res->msgs[0], "newdn", NULL);
87         username = ldb_msg_find_string(res->msgs[0], "username", NULL);
88         password = ldb_msg_find_string(res->msgs[0], "password", NULL);
89         oldstr   = ldb_msg_find_string(res->msgs[0], "oldstr", NULL);
90         newstr   = ldb_msg_find_string(res->msgs[0], "newstr", NULL);
91
92         if (url == NULL || olddn == NULL || newdn == NULL || username == NULL || password == NULL) {
93                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Need url, olddn, newdn, oldstr, newstr, username and password in @PROXYINFO\n");
94                 goto failed;
95         }
96
97         proxy->olddn = ldb_dn_explode(proxy, olddn);
98         if (proxy->olddn == NULL) {
99                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Failed to explode olddn '%s'\n", olddn);
100                 goto failed;
101         }
102         
103         proxy->newdn = ldb_dn_explode(proxy, newdn);
104         if (proxy->newdn == NULL) {
105                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Failed to explode newdn '%s'\n", newdn);
106                 goto failed;
107         }
108
109         proxy->upstream = ldb_init(proxy);
110         if (proxy->upstream == NULL) {
111                 ldb_oom(module->ldb);
112                 goto failed;
113         }
114
115         proxy->oldstr = str_list_make(proxy, oldstr, ", ");
116         if (proxy->oldstr == NULL) {
117                 ldb_oom(module->ldb);
118                 goto failed;
119         }
120
121         proxy->newstr = str_list_make(proxy, newstr, ", ");
122         if (proxy->newstr == NULL) {
123                 ldb_oom(module->ldb);
124                 goto failed;
125         }
126
127         /* setup credentials for connection */
128         creds = cli_credentials_init(proxy->upstream);
129         if (creds == NULL) {
130                 ldb_oom(module->ldb);
131                 goto failed;
132         }
133         cli_credentials_guess(creds);
134         cli_credentials_set_username(creds, username, CRED_SPECIFIED);
135         cli_credentials_set_password(creds, password, CRED_SPECIFIED);
136
137         ldb_set_opaque(proxy->upstream, "credentials", creds);
138
139         ret = ldb_connect(proxy->upstream, url, 0, NULL);
140         if (ret != 0) {
141                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "proxy failed to connect to %s\n", url);
142                 goto failed;
143         }
144
145         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "proxy connected to %s\n", url);
146
147         talloc_free(res);
148
149         return 0;
150
151 failed:
152         talloc_free(res);
153         talloc_free(proxy->olddn);
154         talloc_free(proxy->newdn);
155         talloc_free(proxy->upstream);
156         proxy->upstream = NULL;
157         return -1;
158 }
159
160
161 /*
162   convert a binary blob
163 */
164 static void proxy_convert_blob(TALLOC_CTX *mem_ctx, struct ldb_val *v,
165                                const char *oldstr, const char *newstr)
166 {
167         int len1, len2, len3;
168         uint8_t *olddata = v->data;
169         char *p = strcasestr((char *)v->data, oldstr);
170
171         len1 = (p - (char *)v->data);
172         len2 = strlen(newstr);
173         len3 = v->length - (p+strlen(oldstr) - (char *)v->data);
174         v->length = len1+len2+len3;
175         v->data = talloc_size(mem_ctx, v->length);
176         memcpy(v->data, olddata, len1);
177         memcpy(v->data+len1, newstr, len2);
178         memcpy(v->data+len1+len2, olddata + len1 + strlen(oldstr), len3);
179 }
180
181 /*
182   convert a returned value
183 */
184 static void proxy_convert_value(struct ldb_module *module, struct ldb_message *msg, struct ldb_val *v)
185 {
186         struct proxy_data *proxy = talloc_get_type(module->private_data, struct proxy_data);
187         int i;
188         for (i=0;proxy->oldstr[i];i++) {
189                 char *p = strcasestr((char *)v->data, proxy->oldstr[i]);
190                 if (p == NULL) continue;
191                 proxy_convert_blob(msg, v, proxy->oldstr[i], proxy->newstr[i]);
192         }
193 }
194
195
196 /*
197   convert a returned value
198 */
199 static struct ldb_parse_tree *proxy_convert_tree(struct ldb_module *module, 
200                                                  struct ldb_parse_tree *tree)
201 {
202         struct proxy_data *proxy = talloc_get_type(module->private_data, struct proxy_data);
203         int i;
204         char *expression = ldb_filter_from_tree(module, tree);
205         for (i=0;proxy->newstr[i];i++) {
206                 struct ldb_val v;
207                 char *p = strcasestr(expression, proxy->newstr[i]);
208                 if (p == NULL) continue;
209                 v.data = (uint8_t *)expression;
210                 v.length = strlen(expression)+1;
211                 proxy_convert_blob(module, &v, proxy->newstr[i], proxy->oldstr[i]);
212                 return ldb_parse_tree(module, (const char *)v.data);
213         }
214         return tree;
215 }
216
217
218
219 /*
220   convert a returned record
221 */
222 static void proxy_convert_record(struct ldb_module *module, struct ldb_message *msg)
223 {
224         struct proxy_data *proxy = talloc_get_type(module->private_data, struct proxy_data);
225         int attr, v;
226         
227         /* fix the message DN */
228         if (ldb_dn_compare_base(module->ldb, proxy->olddn, msg->dn) == 0) {
229                 struct ldb_dn *newdn = ldb_dn_copy(msg, msg->dn);
230                 newdn->comp_num -= proxy->olddn->comp_num;
231                 msg->dn = ldb_dn_compose(msg, newdn, proxy->newdn);
232         }
233
234         /* fix any attributes */
235         for (attr=0;attr<msg->num_elements;attr++) {
236                 for (v=0;v<msg->elements[attr].num_values;v++) {
237                         proxy_convert_value(module, msg, &msg->elements[attr].values[v]);
238                 }
239         }
240
241         /* fix any DN components */
242         for (attr=0;attr<msg->num_elements;attr++) {
243                 for (v=0;v<msg->elements[attr].num_values;v++) {
244                         proxy_convert_value(module, msg, &msg->elements[attr].values[v]);
245                 }
246         }
247 }
248
249 /* search */
250 static int proxy_search_bytree(struct ldb_module *module, struct ldb_request *req)
251 {
252         struct proxy_data *proxy = talloc_get_type(module->private_data, struct proxy_data);
253         struct ldb_request newreq;
254         struct ldb_dn *base;
255         int ret, i;
256
257         if (req->op.search.base == NULL ||
258                 (req->op.search.base->comp_num == 1 &&
259                         req->op.search.base->components[0].name[0] == '@')) {
260                 goto passthru;
261         }
262
263         if (load_proxy_info(module) != 0) {
264                 return -1;
265         }
266
267         /* see if the dn is within olddn */
268         if (ldb_dn_compare_base(module->ldb, proxy->newdn, req->op.search.base) != 0) {
269                 goto passthru;
270         }
271
272         newreq.op.search.tree = proxy_convert_tree(module, req->op.search.tree);
273
274         /* convert the basedn of this search */
275         base = ldb_dn_copy(proxy, req->op.search.base);
276         if (base == NULL) {
277                 goto failed;
278         }
279         base->comp_num -= proxy->newdn->comp_num;
280         base = ldb_dn_compose(proxy, newreq.op.search.base, proxy->olddn);
281
282         ldb_debug(module->ldb, LDB_DEBUG_FATAL, "proxying: '%s' with dn '%s' \n", 
283                   ldb_filter_from_tree(proxy, newreq.op.search.tree), ldb_dn_linearize(proxy, newreq.op.search.base));
284         for (i = 0; req->op.search.attrs && req->op.search.attrs[i]; i++) {
285                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "attr: '%s'\n", req->op.search.attrs[i]);
286         }
287
288         newreq.op.search.base = base;
289         newreq.op.search.scope = req->op.search.scope;
290         newreq.op.search.attrs = req->op.search.attrs;
291         newreq.op.search.res = req->op.search.res;
292         ret = ldb_request(proxy->upstream, &newreq);
293         if (ret != LDB_SUCCESS) {
294                 ldb_set_errstring(module, talloc_strdup(module, ldb_errstring(proxy->upstream)));
295                 return -1;
296         }
297
298         for (i = 0; i < newreq.op.search.res->count; i++) {
299                 struct ldb_ldif ldif;
300                 printf("# record %d\n", i+1);
301                 
302                 proxy_convert_record(module, newreq.op.search.res->msgs[i]);
303
304                 ldif.changetype = LDB_CHANGETYPE_NONE;
305                 ldif.msg = newreq.op.search.res->msgs[i];
306         }
307
308         return ret;
309
310 failed:
311         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "proxy failed for %s\n", 
312                   ldb_dn_linearize(proxy, req->op.search.base));
313
314 passthru:
315         return ldb_next_request(module, req); 
316 }
317
318 static int proxy_request(struct ldb_module *module, struct ldb_request *req)
319 {
320         switch (req->operation) {
321
322         case LDB_REQ_SEARCH:
323                 return proxy_search_bytree(module, req);
324
325         default:
326                 return ldb_next_request(module, req);
327
328         }
329 }
330
331 static const struct ldb_module_ops proxy_ops = {
332         .name           = "proxy",
333         .request        = proxy_request
334 };
335
336 #ifdef HAVE_DLOPEN_DISABLED
337 struct ldb_module *init_module(struct ldb_context *ldb, const char *options[])
338 #else
339 struct ldb_module *proxy_module_init(struct ldb_context *ldb, const char *options[])
340 #endif
341 {
342         struct ldb_module *ctx;
343
344         ctx = talloc(ldb, struct ldb_module);
345         if (!ctx)
346                 return NULL;
347
348         ctx->ldb = ldb;
349         ctx->prev = ctx->next = NULL;
350         ctx->ops = &proxy_ops;
351
352         ctx->private_data = talloc_zero(ctx, struct proxy_data);
353         if (ctx->private_data == NULL) {
354                 return NULL;
355         }
356
357         return ctx;
358 }