]> git.sur5r.net Git - openldap/blob - servers/slapd/overlays/chain.c
declare oc_bvfind_undef()
[openldap] / servers / slapd / overlays / chain.c
1 /* chain.c - chain LDAP operations */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2003-2004 The OpenLDAP Foundation.
6  * Portions Copyright 2003 Howard Chu.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in the file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* ACKNOWLEDGEMENTS:
18  * This work was initially developed by the Howard Chu for inclusion
19  * in OpenLDAP Software.
20  */
21
22 #include "portable.h"
23
24 #if defined(SLAPD_LDAP) 
25
26 #ifdef SLAPD_OVER_CHAIN
27
28 #include <stdio.h>
29
30 #include <ac/string.h>
31 #include <ac/socket.h>
32
33 #include "slap.h"
34 #include "../back-ldap/back-ldap.h"
35
36 static BackendInfo *lback;
37
38 static int
39 ldap_chain_chk_referrals( Operation *op, SlapReply *rs )
40 {
41         return LDAP_SUCCESS;
42 }
43
44 static int
45 ldap_chain_response( Operation *op, SlapReply *rs )
46 {
47         slap_overinst   *on = (slap_overinst *) op->o_bd->bd_info;
48         void            *private = op->o_bd->be_private;
49         slap_callback   *sc = op->o_callback;
50         LDAPControl     **prev = op->o_ctrls;
51         LDAPControl     **ctrls = NULL, authz;
52         int             i, nctrls, rc = 0;
53         int             cache = op->o_do_not_cache;
54         char            *authzid = NULL;
55         BerVarray       ref;
56         struct berval   ndn = op->o_ndn;
57
58         struct ldapinfo li, *lip = (struct ldapinfo *)on->on_bi.bi_private;
59
60         if ( rs->sr_err != LDAP_REFERRAL && rs->sr_type != REP_SEARCHREF )
61                 return SLAP_CB_CONTINUE;
62
63         ref = rs->sr_ref;
64         rs->sr_ref = NULL;
65
66         op->o_callback = NULL;
67
68         if ( lip->url == NULL ) {
69                 li = *lip;
70                 op->o_bd->be_private = &li;
71
72                 if ( rs->sr_type != REP_SEARCHREF ) {
73                         LDAPURLDesc     *srv;
74                         char            *save_dn;
75
76                         /* parse reference and use proto://[host][:port]/ only */
77                         rc = ldap_url_parse_ext( ref[0].bv_val, &srv );
78                         if ( rc != LDAP_SUCCESS) {
79                                 /* error */
80                                 return 1;
81                         }
82
83                         /* remove DN essentially because later on 
84                          * ldap_initialize() will parse the URL 
85                          * as a comma-separated URL list */
86                         save_dn = srv->lud_dn;
87                         srv->lud_dn = "";
88                         li.url = ldap_url_desc2str( srv );
89                         if ( li.url == NULL ) {
90                                 /* error */
91                                 srv->lud_dn = save_dn;
92                                 ldap_free_urldesc( srv );
93                                 return 1;
94                         }
95
96                         srv->lud_dn = save_dn;
97                         ldap_free_urldesc( srv );
98                 }
99
100         } else {
101                 op->o_bd->be_private = on->on_bi.bi_private;
102         }
103
104         /* Chaining is performed by a privileged user on behalf
105          * of a normal user, using the ProxyAuthz control. However,
106          * Binds are done separately, on an anonymous session.
107          */
108         if ( op->o_tag != LDAP_REQ_BIND ) {
109                 for (i=0; prev && prev[i]; i++);
110                 nctrls = i;
111
112                 /* Add an extra NULL slot */
113                 if (!prev) i++;
114
115                 ctrls = op->o_tmpalloc((i+1)*sizeof(LDAPControl *),
116                         op->o_tmpmemctx);
117                 for (i=0; i <nctrls; i++)
118                         ctrls[i] = prev[i];
119                 ctrls[nctrls] = &authz;
120                 ctrls[nctrls+1] = NULL;
121                 authz.ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
122                 authz.ldctl_iscritical = 1;
123                 authz.ldctl_value = op->o_dn;
124                 if ( op->o_dn.bv_len ) {
125                         authzid = op->o_tmpalloc( op->o_dn.bv_len + sizeof("dn:") - 1,
126                                 op->o_tmpmemctx );
127                         strcpy(authzid, "dn:");
128                         strcpy(authzid + sizeof("dn:") - 1, op->o_dn.bv_val);
129                         authz.ldctl_value.bv_len = op->o_dn.bv_len + sizeof("dn:") - 1;
130                         authz.ldctl_value.bv_val = authzid;
131                 }
132                 op->o_ctrls = ctrls;
133                 op->o_ndn = op->o_bd->be_rootndn;
134         }
135
136         switch( op->o_tag ) {
137         case LDAP_REQ_BIND: {
138                 struct berval   rndn = op->o_req_ndn;
139                 Connection      *conn = op->o_conn;
140
141                 op->o_req_ndn = slap_empty_bv;
142
143                 op->o_conn = NULL;
144                 rc = lback->bi_op_bind( op, rs );
145                 op->o_req_ndn = rndn;
146                 op->o_conn = conn;
147                 }
148                 break;
149         case LDAP_REQ_ADD:
150                 rc = lback->bi_op_add( op, rs );
151                 break;
152         case LDAP_REQ_DELETE:
153                 rc = lback->bi_op_delete( op, rs );
154                 break;
155         case LDAP_REQ_MODRDN:
156                 rc = lback->bi_op_modrdn( op, rs );
157                 break;
158         case LDAP_REQ_MODIFY:
159                 rc = lback->bi_op_modify( op, rs );
160                 break;
161         case LDAP_REQ_COMPARE:
162                 rc = lback->bi_op_compare( op, rs );
163                 break;
164         case LDAP_REQ_SEARCH:
165                 if ( rs->sr_type == REP_SEARCHREF ) {
166                         struct berval   *curr = ref,
167                                         odn = op->o_req_dn,
168                                         ondn = op->o_req_ndn;
169
170                         rs->sr_type = REP_SEARCH;
171
172                         /* copy the private info because we need to modify it */
173                         for ( ; curr[0].bv_val; curr++ ) {
174                                 LDAPURLDesc     *srv;
175
176                                 /* parse reference and use proto://[host][:port]/ only */
177                                 rc = ldap_url_parse_ext( curr[0].bv_val, &srv );
178                                 if ( rc != LDAP_SUCCESS) {
179                                         /* error */
180                                         rc = 1;
181                                         goto end_of_searchref;
182                                 }
183
184                                 ber_str2bv(srv->lud_dn, 0, 0, &op->o_req_dn);
185                                 op->o_req_ndn = op->o_req_dn;
186
187                                 /* remove DN essentially because later on 
188                                  * ldap_initialize() will parse the URL 
189                                  * as a comma-separated URL list */
190                                 srv->lud_dn = "";
191                                 li.url = ldap_url_desc2str( srv );
192                                 if ( li.url == NULL ) {
193                                         /* error */
194                                         srv->lud_dn = op->o_req_dn.bv_val;
195                                         ldap_free_urldesc( srv );
196                                         rc = 1;
197                                         goto end_of_searchref;
198                                 }
199
200                                 /* FIXME: should we also copy filter and scope?
201                                  * according to RFC3296, no */
202
203                                 rc = lback->bi_op_search( op, rs );
204
205                                 ldap_memfree( li.url );
206                                 li.url = NULL;
207
208                                 srv->lud_dn = op->o_req_dn.bv_val;
209                                 ldap_free_urldesc( srv );
210
211                                 if ( rc ) {
212                                         /* error */
213                                         rc = 1;
214                                         goto end_of_searchref;
215                                 }
216                         }
217
218 end_of_searchref:;
219                         op->o_req_dn = odn;
220                         op->o_req_ndn = ondn;
221                         rs->sr_type = REP_SEARCHREF;
222                         
223                 } else {
224                         rc = lback->bi_op_search( op, rs );
225                 }
226                 break;
227         case LDAP_REQ_EXTENDED:
228                 rc = lback->bi_extended( op, rs );
229                 break;
230         default:
231                 rc = SLAP_CB_CONTINUE;
232                 break;
233         }
234         op->o_do_not_cache = cache;
235         op->o_ctrls = prev;
236         op->o_bd->be_private = private;
237         op->o_callback = sc;
238         op->o_ndn = ndn;
239         if ( ctrls ) op->o_tmpfree( ctrls, op->o_tmpmemctx );
240         if ( authzid ) op->o_tmpfree( authzid, op->o_tmpmemctx );
241         rs->sr_ref = ref;
242         if ( lip->url == NULL && li.url ) {
243                 ldap_memfree( li.url );
244         }
245
246         return rc;
247 }
248
249 static int ldap_chain_config(
250     BackendDB   *be,
251     const char  *fname,
252     int         lineno,
253     int         argc,
254     char        **argv
255 )
256 {
257         slap_overinst   *on = (slap_overinst *) be->bd_info;
258         void            *private = be->be_private;
259         char            *argv0 = NULL;
260         int             rc;
261
262         be->be_private = on->on_bi.bi_private;
263         if ( strncasecmp( argv[ 0 ], "chain-", sizeof( "chain-" ) - 1 ) == 0 ) {
264                 argv0 = argv[ 0 ];
265                 argv[ 0 ] = &argv[ 0 ][ sizeof( "chain-" ) - 1 ];
266         }
267         rc = lback->bi_db_config( be, fname, lineno, argc, argv );
268         if ( argv0 ) {
269                 argv[ 0 ] = argv0;
270         }
271         
272         be->be_private = private;
273         return rc;
274 }
275
276 static int ldap_chain_init(
277         BackendDB *be
278 )
279 {
280         slap_overinst *on = (slap_overinst *) be->bd_info;
281         void *private = be->be_private;
282         int rc;
283
284         be->be_private = NULL;
285         rc = lback->bi_db_init( be );
286         on->on_bi.bi_private = be->be_private;
287         be->be_private = private;
288
289         return rc;
290 }
291
292 static int ldap_chain_destroy(
293         BackendDB *be
294 )
295 {
296         slap_overinst *on = (slap_overinst *) be->bd_info;
297         void *private = be->be_private;
298         int rc;
299
300         be->be_private = on->on_bi.bi_private;
301         rc = lback->bi_db_destroy( be );
302         on->on_bi.bi_private = be->be_private;
303         be->be_private = private;
304         return rc;
305 }
306
307 static slap_overinst ldapchain;
308
309 int chain_init()
310 {
311         lback = backend_info("ldap");
312
313         if ( !lback ) return -1;
314
315         ldapchain.on_bi.bi_type = "chain";
316         ldapchain.on_bi.bi_db_init = ldap_chain_init;
317         ldapchain.on_bi.bi_db_config = ldap_chain_config;
318         ldapchain.on_bi.bi_db_destroy = ldap_chain_destroy;
319         ldapchain.on_response = ldap_chain_response;
320
321         ldapchain.on_bi.bi_chk_referrals = ldap_chain_chk_referrals;
322
323         return overlay_register( &ldapchain );
324 }
325
326 #if SLAPD_OVER_CHAIN == SLAPD_MOD_DYNAMIC
327 int init_module(int argc, char *argv[]) {
328         return chain_init();
329 }
330 #endif /* SLAPD_OVER_CHAIN == SLAPD_MOD_DYNAMIC */
331
332 #endif /* SLAPD_OVER_CHAIN */
333
334 #endif /* ! defined(SLAPD_LDAP) */