r12658: Couple of fixes related to shared module builds.
[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
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;
51 };
52
53
54 /*
55   load the @PROXYINFO record
56 */
57 static int load_proxy_info(struct ldb_module *module)
58 {
59         struct proxy_data *proxy = talloc_get_type(module->private_data, struct proxy_data);
60         struct ldb_dn *dn;
61         struct ldb_result *res;
62         int ret;
63         const char *olddn, *newdn, *url, *username, *password, *oldstr, *newstr;
64         struct cli_credentials *creds;
65         
66
67         /* see if we have already loaded it */
68         if (proxy->upstream != NULL) {
69                 return 0;
70         }
71
72         dn = ldb_dn_explode(proxy, "@PROXYINFO");
73         if (dn == NULL) {
74                 goto failed;
75         }
76         ret = ldb_search(module->ldb, dn, LDB_SCOPE_BASE, NULL, NULL, &res);
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;
81         }
82
83         url      = ldb_msg_find_string(res->msgs[0], "url", NULL);
84         olddn    = ldb_msg_find_string(res->msgs[0], "olddn", NULL);
85         newdn    = ldb_msg_find_string(res->msgs[0], "newdn", NULL);
86         username = ldb_msg_find_string(res->msgs[0], "username", NULL);
87         password = ldb_msg_find_string(res->msgs[0], "password", NULL);
88         oldstr   = ldb_msg_find_string(res->msgs[0], "oldstr", NULL);
89         newstr   = ldb_msg_find_string(res->msgs[0], "newstr", NULL);
90
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;
94         }
95
96         proxy->olddn = ldb_dn_explode(proxy, olddn);
97         if (proxy->olddn == NULL) {
98                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Failed to explode olddn '%s'\n", olddn);
99                 goto failed;
100         }
101         
102         proxy->newdn = ldb_dn_explode(proxy, newdn);
103         if (proxy->newdn == NULL) {
104                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Failed to explode newdn '%s'\n", newdn);
105                 goto failed;
106         }
107
108         proxy->upstream = ldb_init(proxy);
109         if (proxy->upstream == NULL) {
110                 ldb_oom(module->ldb);
111                 goto failed;
112         }
113
114         proxy->oldstr = str_list_make(proxy, oldstr, ", ");
115         if (proxy->oldstr == NULL) {
116                 ldb_oom(module->ldb);
117                 goto failed;
118         }
119
120         proxy->newstr = str_list_make(proxy, newstr, ", ");
121         if (proxy->newstr == NULL) {
122                 ldb_oom(module->ldb);
123                 goto failed;
124         }
125
126         /* setup credentials for connection */
127         creds = cli_credentials_init(proxy->upstream);
128         if (creds == NULL) {
129                 ldb_oom(module->ldb);
130                 goto failed;
131         }
132         cli_credentials_guess(creds);
133         cli_credentials_set_username(creds, username, CRED_SPECIFIED);
134         cli_credentials_set_password(creds, password, CRED_SPECIFIED);
135
136         ldb_set_opaque(proxy->upstream, "credentials", creds);
137
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;
142         }
143
144         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "proxy connected to %s\n", url);
145
146         talloc_free(res);
147
148         return 0;
149
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;
157 }
158
159
160 /*
161   convert a binary blob
162 */
163 static void proxy_convert_blob(TALLOC_CTX *mem_ctx, struct ldb_val *v,
164                                const char *oldstr, const char *newstr)
165 {
166         int len1, len2, len3;
167         uint8_t *olddata = v->data;
168         char *p = strcasestr((char *)v->data, oldstr);
169
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);
178 }
179
180 /*
181   convert a returned value
182 */
183 static void proxy_convert_value(struct ldb_module *module, struct ldb_message *msg, struct ldb_val *v)
184 {
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]);
191         }
192 }
193
194
195 /*
196   convert a returned value
197 */
198 static struct ldb_parse_tree *proxy_convert_tree(struct ldb_module *module, 
199                                                  struct ldb_parse_tree *tree)
200 {
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);
212         }
213         return tree;
214 }
215
216
217
218 /*
219   convert a returned record
220 */
221 static void proxy_convert_record(struct ldb_module *module, struct ldb_message *msg)
222 {
223         struct proxy_data *proxy = talloc_get_type(module->private_data, struct proxy_data);
224         int attr, v;
225         
226         /* fix the message DN */
227         if (ldb_dn_compare_base(module->ldb, proxy->olddn, msg->dn) == 0) {
228                 struct ldb_dn *newdn = ldb_dn_copy(msg, msg->dn);
229                 newdn->comp_num -= proxy->olddn->comp_num;
230                 msg->dn = ldb_dn_compose(msg, newdn, proxy->newdn);
231         }
232
233         /* fix any attributes */
234         for (attr=0;attr<msg->num_elements;attr++) {
235                 for (v=0;v<msg->elements[attr].num_values;v++) {
236                         proxy_convert_value(module, msg, &msg->elements[attr].values[v]);
237                 }
238         }
239
240         /* fix any DN components */
241         for (attr=0;attr<msg->num_elements;attr++) {
242                 for (v=0;v<msg->elements[attr].num_values;v++) {
243                         proxy_convert_value(module, msg, &msg->elements[attr].values[v]);
244                 }
245         }
246 }
247
248 /* search */
249 static int proxy_search_bytree(struct ldb_module *module, struct ldb_request *req)
250 {
251         struct proxy_data *proxy = talloc_get_type(module->private_data, struct proxy_data);
252         struct ldb_request newreq;
253         struct ldb_dn *base;
254         int ret, i;
255
256         if (req->op.search.base == NULL ||
257                 (req->op.search.base->comp_num == 1 &&
258                         req->op.search.base->components[0].name[0] == '@')) {
259                 goto passthru;
260         }
261
262         if (load_proxy_info(module) != 0) {
263                 return -1;
264         }
265
266         /* see if the dn is within olddn */
267         if (ldb_dn_compare_base(module->ldb, proxy->newdn, req->op.search.base) != 0) {
268                 goto passthru;
269         }
270
271         newreq.op.search.tree = proxy_convert_tree(module, req->op.search.tree);
272
273         /* convert the basedn of this search */
274         base = ldb_dn_copy(proxy, req->op.search.base);
275         if (base == NULL) {
276                 goto failed;
277         }
278         base->comp_num -= proxy->newdn->comp_num;
279         base = ldb_dn_compose(proxy, newreq.op.search.base, proxy->olddn);
280
281         ldb_debug(module->ldb, LDB_DEBUG_FATAL, "proxying: '%s' with dn '%s' \n", 
282                   ldb_filter_from_tree(proxy, newreq.op.search.tree), ldb_dn_linearize(proxy, newreq.op.search.base));
283         for (i = 0; req->op.search.attrs && req->op.search.attrs[i]; i++) {
284                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "attr: '%s'\n", req->op.search.attrs[i]);
285         }
286
287         newreq.op.search.base = base;
288         newreq.op.search.scope = req->op.search.scope;
289         newreq.op.search.attrs = req->op.search.attrs;
290         newreq.op.search.res = req->op.search.res;
291         ret = ldb_request(proxy->upstream, &newreq);
292         if (ret != LDB_SUCCESS) {
293                 ldb_set_errstring(module, talloc_strdup(module, ldb_errstring(proxy->upstream)));
294                 return -1;
295         }
296
297         for (i = 0; i < newreq.op.search.res->count; i++) {
298                 struct ldb_ldif ldif;
299                 printf("# record %d\n", i+1);
300                 
301                 proxy_convert_record(module, newreq.op.search.res->msgs[i]);
302
303                 ldif.changetype = LDB_CHANGETYPE_NONE;
304                 ldif.msg = newreq.op.search.res->msgs[i];
305         }
306
307         return ret;
308
309 failed:
310         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "proxy failed for %s\n", 
311                   ldb_dn_linearize(proxy, req->op.search.base));
312
313 passthru:
314         return ldb_next_request(module, req); 
315 }
316
317 static int proxy_request(struct ldb_module *module, struct ldb_request *req)
318 {
319         switch (req->operation) {
320
321         case LDB_REQ_SEARCH:
322                 return proxy_search_bytree(module, req);
323
324         default:
325                 return ldb_next_request(module, req);
326
327         }
328 }
329
330 static const struct ldb_module_ops proxy_ops = {
331         .name           = "proxy",
332         .request        = proxy_request
333 };
334
335 struct ldb_module *proxy_module_init(struct ldb_context *ldb, const char *options[])
336 {
337         struct ldb_module *ctx;
338
339         ctx = talloc(ldb, struct ldb_module);
340         if (!ctx)
341                 return NULL;
342
343         ctx->ldb = ldb;
344         ctx->prev = ctx->next = NULL;
345         ctx->ops = &proxy_ops;
346
347         ctx->private_data = talloc_zero(ctx, struct proxy_data);
348         if (ctx->private_data == NULL) {
349                 return NULL;
350         }
351
352         return ctx;
353 }