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:
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
36 #include "ldb_module.h"
37 #include "auth/credentials/credentials.h"
40 struct ldb_context
*upstream
;
48 struct ldb_module
*module
;
49 struct ldb_request
*req
;
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
);
64 struct ldb_result
*res
= NULL
;
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
) {
74 dn
= ldb_dn_new(proxy
, ldb
, "@PROXYINFO");
78 ret
= ldb_search(ldb
, proxy
, &res
, dn
, LDB_SCOPE_BASE
, NULL
, NULL
);
80 if (ret
!= LDB_SUCCESS
|| res
->count
!= 1) {
81 ldb_debug(ldb
, LDB_DEBUG_FATAL
, "Can't find @PROXYINFO\n");
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");
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
);
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
);
110 proxy
->upstream
= ldb_init(proxy
, ldb_get_event_context(ldb
));
111 if (proxy
->upstream
== NULL
) {
116 proxy
->oldstr
= str_list_make(proxy
, oldstr
, ", ");
117 if (proxy
->oldstr
== NULL
) {
122 proxy
->newstr
= str_list_make(proxy
, newstr
, ", ");
123 if (proxy
->newstr
== NULL
) {
128 /* setup credentials for connection */
129 creds
= cli_credentials_init(proxy
->upstream
);
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
);
142 ldb_debug(ldb
, LDB_DEBUG_FATAL
, "proxy failed to connect to %s\n", url
);
146 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "proxy connected to %s\n", url
);
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
)
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
)
205 char *expression
= ldb_filter_from_tree(mem_ctx
, tree
);
207 for (i
=0;proxy
->newstr
[i
];i
++) {
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
);
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
;
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
);
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
:
279 proxy_convert_record(ldb
, proxy
, ares
->message
);
280 ret
= ldb_module_send_entry(ac
->req
, ares
->message
, ares
->controls
);
283 case LDB_REPLY_REFERRAL
:
285 /* ignore remote referrals */
291 printf("# record %d\n", ac
->count
+1);
294 return ldb_module_done(ac
->req
, NULL
, NULL
, LDB_SUCCESS
);
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
;
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] == '@')) {
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) {
330 ac
= talloc(req
, struct proxy_ctx
);
341 newtree
= proxy_convert_tree(ac
, proxy
, req
->op
.search
.tree
);
343 /* convert the basedn of this search */
344 base
= ldb_dn_copy(ac
, req
->op
.search
.base
);
348 ldb_dn_remove_base_components(base
, ldb_dn_get_comp_num(proxy
->newdn
));
349 ldb_dn_add_base(base
, proxy
->olddn
);
351 ldb_debug(ldb
, LDB_DEBUG_FATAL
, "proxying: '%s' with dn '%s' \n",
352 ldb_filter_from_tree(ac
, newreq
->op
.search
.tree
), ldb_dn_get_linearized(newreq
->op
.search
.base
));
353 for (i
= 0; req
->op
.search
.attrs
&& req
->op
.search
.attrs
[i
]; i
++) {
354 ldb_debug(ldb
, LDB_DEBUG_FATAL
, "attr: '%s'\n", req
->op
.search
.attrs
[i
]);
357 ret
= ldb_build_search_req_ex(&newreq
, ldb
, ac
,
358 base
, req
->op
.search
.scope
,
359 newtree
, req
->op
.search
.attrs
,
361 ac
, proxy_search_callback
,
363 LDB_REQ_SET_LOCATION(newreq
);
364 /* FIXME: warning, need a real event system hooked up for this to work properly,
365 * for now this makes the module *not* ASYNC */
366 ret
= ldb_request(proxy
->upstream
, newreq
);
367 if (ret
!= LDB_SUCCESS
) {
368 ldb_set_errstring(ldb
, ldb_errstring(proxy
->upstream
));
370 ret
= ldb_wait(newreq
->handle
, LDB_WAIT_ALL
);
371 if (ret
!= LDB_SUCCESS
) {
372 ldb_set_errstring(ldb
, ldb_errstring(proxy
->upstream
));
377 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "proxy failed for %s\n",
378 ldb_dn_get_linearized(req
->op
.search
.base
));
381 return ldb_next_request(module
, req
);
384 static int proxy_request(struct ldb_module
*module
, struct ldb_request
*req
)
386 switch (req
->operation
) {
389 return proxy_search_bytree(module
, req
);
392 return ldb_next_request(module
, req
);
397 static const struct ldb_module_ops ldb_proxy_module_ops
= {
399 .request
= proxy_request
402 int ldb_proxy_module_init(const char *version
)
404 LDB_MODULE_CHECK_VERSION(version
);
405 return ldb_register_module(&ldb_proxy_module_ops
);