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
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:
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
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"
46 struct ldb_context
*upstream
;
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
);
61 struct ldb_result
*res
= NULL
;
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
) {
72 dn
= ldb_dn_new(proxy
, module
->ldb
, "@PROXYINFO");
76 ret
= ldb_search(module
->ldb
, proxy
, &res
, dn
, LDB_SCOPE_BASE
, NULL
, NULL
);
78 if (ret
!= LDB_SUCCESS
|| res
->count
!= 1) {
79 ldb_debug(module
->ldb
, LDB_DEBUG_FATAL
, "Can't find @PROXYINFO\n");
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");
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
);
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
);
108 proxy
->upstream
= ldb_init(proxy
);
109 if (proxy
->upstream
== NULL
) {
110 ldb_oom(module
->ldb
);
114 proxy
->oldstr
= str_list_make(proxy
, oldstr
, ", ");
115 if (proxy
->oldstr
== NULL
) {
116 ldb_oom(module
->ldb
);
120 proxy
->newstr
= str_list_make(proxy
, newstr
, ", ");
121 if (proxy
->newstr
== NULL
) {
122 ldb_oom(module
->ldb
);
126 /* setup credentials for connection */
127 creds
= cli_credentials_init(proxy
->upstream
);
129 ldb_oom(module
->ldb
);
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
);
140 ldb_debug(module
->ldb
, LDB_DEBUG_FATAL
, "proxy failed to connect to %s\n", url
);
144 ldb_debug(module
->ldb
, LDB_DEBUG_TRACE
, "proxy connected to %s\n", url
);
152 talloc_free(proxy
->olddn
);
153 talloc_free(proxy
->newdn
);
154 talloc_free(proxy
->upstream
);
155 proxy
->upstream
= NULL
;
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
);
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
);
203 char *expression
= ldb_filter_from_tree(module
, tree
);
204 for (i
=0;proxy
->newstr
[i
];i
++) {
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
);
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
);
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
]);
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
;
255 if (req
->op
.search
.base
== NULL
||
256 (req
->op
.search
.base
->comp_num
== 1 &&
257 req
->op
.search
.base
->components
[0].name
[0] == '@')) {
261 if (load_proxy_info(module
) != 0) {
265 /* see if the dn is within olddn */
266 if (ldb_dn_compare_base(module
->ldb
, proxy
->newdn
, req
->op
.search
.base
) != 0) {
270 newreq
= talloc(module
, struct ldb_request
);
271 if (newreq
== NULL
) {
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
);
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
));
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
]);
314 ldb_debug(module
->ldb
, LDB_DEBUG_TRACE
, "proxy failed for %s\n",
315 ldb_dn_get_linearized(req
->op
.search
.base
));
318 return ldb_next_request(module
, req
);
321 static int proxy_request(struct ldb_module
*module
, struct ldb_request
*req
)
323 switch (req
->operation
) {
326 return proxy_search_bytree(module
, req
);
329 return ldb_next_request(module
, req
);
334 _PUBLIC_
const struct ldb_module_ops ldb_proxy_module_ops
= {
336 .request
= proxy_request