r17514: Simplify the way to set ldb errors and add another
[ira/wip.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 "auth/credentials/credentials.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 = NULL;
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 = talloc(module, struct ldb_request);
273         if (newreq == NULL) {
274                 return -1;
275         }
276
277         newreq->op.search.tree = proxy_convert_tree(module, req->op.search.tree);
278
279         /* convert the basedn of this search */
280         base = ldb_dn_copy(proxy, req->op.search.base);
281         if (base == NULL) {
282                 talloc_free(newreq);
283                 goto failed;
284         }
285         base->comp_num -= proxy->newdn->comp_num;
286         base = ldb_dn_compose(proxy, newreq->op.search.base, proxy->olddn);
287
288         ldb_debug(module->ldb, LDB_DEBUG_FATAL, "proxying: '%s' with dn '%s' \n", 
289                   ldb_filter_from_tree(proxy, newreq->op.search.tree), ldb_dn_linearize(proxy, newreq->op.search.base));
290         for (i = 0; req->op.search.attrs && req->op.search.attrs[i]; i++) {
291                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "attr: '%s'\n", req->op.search.attrs[i]);
292         }
293
294         newreq->op.search.base = base;
295         newreq->op.search.scope = req->op.search.scope;
296         newreq->op.search.attrs = req->op.search.attrs;
297         newreq->op.search.res = req->op.search.res;
298         newreq->controls = req->controls;
299         ret = ldb_request(proxy->upstream, newreq);
300         if (ret != LDB_SUCCESS) {
301                 ldb_set_errstring(module->ldb, ldb_errstring(proxy->upstream));
302                 talloc_free(newreq);
303                 return -1;
304         }
305
306         for (i = 0; i < newreq->op.search.res->count; i++) {
307                 printf("# record %d\n", i+1);
308                 
309                 proxy_convert_record(module, newreq->op.search.res->msgs[i]);
310         }
311
312         talloc_free(newreq);
313         return ret;
314
315 failed:
316         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "proxy failed for %s\n", 
317                   ldb_dn_linearize(proxy, req->op.search.base));
318
319 passthru:
320         return ldb_next_request(module, req); 
321 }
322
323 static int proxy_request(struct ldb_module *module, struct ldb_request *req)
324 {
325         switch (req->operation) {
326
327         case LDB_REQ_SEARCH:
328                 return proxy_search_bytree(module, req);
329
330         default:
331                 return ldb_next_request(module, req);
332
333         }
334 }
335
336 static const struct ldb_module_ops proxy_ops = {
337         .name           = "proxy",
338         .request        = proxy_request
339 };
340
341 int proxy_module_init(void)
342 {
343         return ldb_register_module(&proxy_ops);
344 }