]> git.sur5r.net Git - openldap/blob - servers/slapd/back-meta/bind.c
Change dn->bv_val to op->o_req_dn.bv_val in LDAP_LOG() (from rev 1.24 change).
[openldap] / servers / slapd / back-meta / bind.c
1 /*
2  * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
3  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
4  *
5  * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
6  *
7  * This work has been developed to fulfill the requirements
8  * of SysNet s.n.c. <http:www.sys-net.it> and it has been donated
9  * to the OpenLDAP Foundation in the hope that it may be useful
10  * to the Open Source community, but WITHOUT ANY WARRANTY.
11  *
12  * Permission is granted to anyone to use this software for any purpose
13  * on any computer system, and to alter it and redistribute it, subject
14  * to the following restrictions:
15  *
16  * 1. The author and SysNet s.n.c. are not responsible for the consequences
17  *    of use of this software, no matter how awful, even if they arise from 
18  *    flaws in it.
19  *
20  * 2. The origin of this software must not be misrepresented, either by
21  *    explicit claim or by omission.  Since few users ever read sources,
22  *    credits should appear in the documentation.
23  *
24  * 3. Altered versions must be plainly marked as such, and must not be
25  *    misrepresented as being the original software.  Since few users
26  *    ever read sources, credits should appear in the documentation.
27  *    SysNet s.n.c. cannot be responsible for the consequences of the
28  *    alterations.
29  *
30  * 4. This notice may not be removed or altered.
31  *
32  *
33  * This software is based on the backend back-ldap, implemented
34  * by Howard Chu <hyc@highlandsun.com>, and modified by Mark Valence
35  * <kurash@sassafras.com>, Pierangelo Masarati <ando@sys-net.it> and other
36  * contributors. The contribution of the original software to the present
37  * implementation is acknowledged in this copyright statement.
38  *
39  * A special acknowledgement goes to Howard for the overall architecture
40  * (and for borrowing large pieces of code), and to Mark, who implemented
41  * from scratch the attribute/objectclass mapping.
42  *
43  * The original copyright statement follows.
44  *
45  * Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
46  *
47  * Permission is granted to anyone to use this software for any purpose
48  * on any computer system, and to alter it and redistribute it, subject
49  * to the following restrictions:
50  *
51  * 1. The author is not responsible for the consequences of use of this
52  *    software, no matter how awful, even if they arise from flaws in it.
53  *
54  * 2. The origin of this software must not be misrepresented, either by
55  *    explicit claim or by omission.  Since few users ever read sources,
56  *    credits should appear in the documentation.
57  *
58  * 3. Altered versions must be plainly marked as such, and must not be
59  *    misrepresented as being the original software.  Since few users
60  *    ever read sources, credits should appear in the
61  *    documentation.
62  *
63  * 4. This notice may not be removed or altered.
64  *
65  */
66
67 #include "portable.h"
68
69 #include <stdio.h>
70
71 #include <ac/socket.h>
72 #include <ac/string.h>
73
74
75 #define AVL_INTERNAL
76 #include "slap.h"
77 #include "../back-ldap/back-ldap.h"
78 #include "back-meta.h"
79
80 static LDAP_REBIND_PROC meta_back_rebind;
81
82 static int
83 meta_back_do_single_bind(
84                 struct metaconn         *lc,
85                 Operation               *op,
86                 SlapReply               *rs,
87                 int                     candidate
88 );
89
90 int
91 meta_back_bind( Operation *op, SlapReply *rs )
92 {
93         struct metainfo *li = ( struct metainfo * )op->o_bd->be_private;
94         struct metaconn *lc;
95
96         int rc = -1, i, gotit = 0, ndnlen, isroot = 0;
97         int op_type = META_OP_ALLOW_MULTIPLE;
98
99         rs->sr_err = LDAP_SUCCESS;
100
101 #ifdef NEW_LOGGING
102         LDAP_LOG( BACK_META, ENTRY, "meta_back_bind: dn: %s.\n",
103                         op->o_req_dn.bv_val, 0, 0 );
104 #else /* !NEW_LOGGING */
105         Debug( LDAP_DEBUG_ARGS, "meta_back_bind: dn: %s.\n%s%s",
106                         op->o_req_dn.bv_val, "", "" );
107 #endif /* !NEW_LOGGING */
108
109         if ( op->oq_bind.rb_method == LDAP_AUTH_SIMPLE && be_isroot_pw( op ) ) {
110                 isroot = 1;
111                 ber_dupbv( &op->oq_bind.rb_edn, be_root_dn( op->o_bd ) );
112                 op_type = META_OP_REQUIRE_ALL;
113         }
114         lc = meta_back_getconn( op, rs, op_type,
115                         &op->o_req_ndn, NULL );
116         if ( !lc ) {
117 #ifdef NEW_LOGGING
118                 LDAP_LOG( BACK_META, NOTICE,
119                                 "meta_back_bind: no target for dn %s.\n",
120                                 op->o_req_dn.bv_val, 0, 0 );
121 #else /* !NEW_LOGGING */
122                 Debug( LDAP_DEBUG_ANY,
123                                 "meta_back_bind: no target for dn %s.\n%s%s",
124                                 op->o_req_dn.bv_val, "", "");
125 #endif /* !NEW_LOGGING */
126
127                 send_ldap_result( op, rs );
128                 return -1;
129         }
130
131         /*
132          * Each target is scanned ...
133          */
134         lc->bound_target = META_BOUND_NONE;
135         ndnlen = op->o_req_ndn.bv_len;
136         for ( i = 0; i < li->ntargets; i++ ) {
137                 int             lerr;
138                 struct berval   orig_dn = op->o_req_dn;
139                 struct berval   orig_ndn = op->o_req_ndn;
140                 struct berval   orig_cred = op->oq_bind.rb_cred;
141                 int             orig_method = op->oq_bind.rb_method;
142                 
143
144                 /*
145                  * Skip non-candidates
146                  */
147                 if ( lc->conns[ i ].candidate != META_CANDIDATE ) {
148                         continue;
149                 }
150
151                 if ( gotit == 0 ) {
152                         gotit = 1;
153                 } else {
154                         /*
155                          * A bind operation is expected to have
156                          * ONE CANDIDATE ONLY!
157                          */
158 #ifdef NEW_LOGGING
159                         LDAP_LOG( BACK_META, WARNING,
160                                         "==>meta_back_bind: more than one"
161                                         " candidate is attempting to bind"
162                                         " ...\n" , 0, 0, 0 );
163 #else /* !NEW_LOGGING */
164                         Debug( LDAP_DEBUG_ANY,
165                                         "==>meta_back_bind: more than one"
166                                         " candidate is attempting to bind"
167                                         " ...\n%s%s%s", 
168                                         "", "", "" );
169 #endif /* !NEW_LOGGING */
170                 }
171
172                 if ( isroot && li->targets[ i ]->pseudorootdn.bv_val != NULL ) {
173                         op->o_req_dn = li->targets[ i ]->pseudorootdn;
174                         op->o_req_ndn = li->targets[ i ]->pseudorootdn;
175                         op->oq_bind.rb_cred = li->targets[ i ]->pseudorootpw;
176                         op->oq_bind.rb_method = LDAP_AUTH_SIMPLE;
177                 }
178                 
179                 lerr = meta_back_do_single_bind( lc, op, rs, i );
180                 if ( lerr != LDAP_SUCCESS ) {
181                         rs->sr_err = lerr;
182                         ( void )meta_clear_one_candidate( &lc->conns[ i ], 1 );
183                 } else {
184                         rc = LDAP_SUCCESS;
185                 }
186
187                 op->o_req_dn = orig_dn;
188                 op->o_req_ndn = orig_ndn;
189                 op->oq_bind.rb_cred = orig_cred;
190                 op->oq_bind.rb_method = orig_method;
191         }
192
193         if ( isroot ) {
194                 lc->bound_target = META_BOUND_ALL;
195         }
196
197         /*
198          * rc is LDAP_SUCCESS if at least one bind succeeded,
199          * err is the last error that occurred during a bind;
200          * if at least (and at most?) one bind succeedes, fine.
201          */
202         if ( rc != LDAP_SUCCESS /* && rs->sr_err != LDAP_SUCCESS */ ) {
203                 
204                 /*
205                  * deal with bind failure ...
206                  */
207
208                 /*
209                  * no target was found within the naming context, 
210                  * so bind must fail with invalid credentials
211                  */
212                 if ( rs->sr_err == LDAP_SUCCESS && gotit == 0 ) {
213                         rs->sr_err = LDAP_INVALID_CREDENTIALS;
214                 }
215
216                 rs->sr_err = ldap_back_map_result( rs );
217                 send_ldap_result( op, rs );
218                 return -1;
219         }
220
221         return 0;
222 }
223
224 /*
225  * meta_back_do_single_bind
226  *
227  * attempts to perform a bind with creds
228  */
229 static int
230 meta_back_do_single_bind(
231                 struct metaconn         *lc,
232                 Operation               *op,
233                 SlapReply               *rs,
234                 int                     candidate
235 )
236 {
237         struct metainfo *li = ( struct metainfo * )op->o_bd->be_private;
238         struct berval   mdn = { 0, NULL };
239         ber_int_t       msgid;
240         dncookie        dc;
241         struct metasingleconn   *lsc = &lc->conns[ candidate ];
242         
243         /*
244          * Rewrite the bind dn if needed
245          */
246         dc.rwmap = &li->targets[ candidate ]->rwmap;
247         dc.conn = op->o_conn;
248         dc.rs = rs;
249         dc.ctx = "bindDn";
250
251         if ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
252                 send_ldap_result( op, rs );
253                 return -1;
254         }
255
256         if ( op->o_ctrls ) {
257                 rs->sr_err = ldap_set_option( lsc->ld, 
258                                 LDAP_OPT_SERVER_CONTROLS, op->o_ctrls );
259                 if ( rs->sr_err != LDAP_SUCCESS ) {
260                         rs->sr_err = ldap_back_map_result( rs );
261                         goto return_results;
262                 }
263         }
264         
265         rs->sr_err = ldap_sasl_bind(lsc->ld, mdn.bv_val,
266                         LDAP_SASL_SIMPLE, &op->oq_bind.rb_cred,
267                         op->o_ctrls, NULL, &msgid);
268         if ( rs->sr_err != LDAP_SUCCESS ) {
269                 rs->sr_err = ldap_back_map_result( rs );
270
271         } else {
272                 /*
273                  * FIXME: handle response!!!
274                  */
275                 if ( lsc->bound_dn.bv_val != NULL ) {
276                         ber_memfree( lsc->bound_dn.bv_val );
277                 }
278                 ber_dupbv( &lsc->bound_dn, &op->o_req_dn );
279                 lsc->bound = META_BOUND;
280                 lc->bound_target = candidate;
281
282                 if ( li->savecred ) {
283                         if ( lsc->cred.bv_val ) {
284                                 memset( lsc->cred.bv_val, 0, lsc->cred.bv_len );
285                                 ber_memfree( lsc->cred.bv_val );
286                         }
287                         ber_dupbv( &lsc->cred, &op->oq_bind.rb_cred );
288                         ldap_set_rebind_proc( lsc->ld, meta_back_rebind, lsc );
289                 }
290
291                 if ( li->cache.ttl != META_DNCACHE_DISABLED
292                                 && op->o_req_ndn.bv_len != 0 ) {
293                         ( void )meta_dncache_update_entry( &li->cache,
294                                         &op->o_req_ndn, candidate );
295                 }
296         }
297
298 return_results:;
299         
300         if ( mdn.bv_val != op->o_req_dn.bv_val ) {
301                 free( mdn.bv_val );
302         }
303
304         return rs->sr_err;
305 }
306
307 /*
308  * meta_back_dobind
309  */
310 int
311 meta_back_dobind( struct metaconn *lc, Operation *op )
312 {
313         struct metasingleconn *lsc;
314         int bound = 0, i;
315
316         /*
317          * all the targets are bound as pseudoroot
318          */
319         if ( lc->bound_target == META_BOUND_ALL ) {
320                 return 1;
321         }
322
323         for ( i = 0, lsc = lc->conns; !META_LAST(lsc); ++i, ++lsc ) {
324                 int rc;
325
326                 /*
327                  * Not a candidate or something wrong with this target ...
328                  */
329                 if ( lsc->ld == NULL ) {
330                         continue;
331                 }
332
333                 /*
334                  * If required, set controls
335                  */
336                 if ( op->o_ctrls ) {
337                         if ( ldap_set_option( lsc->ld, LDAP_OPT_SERVER_CONTROLS,
338                                         op->o_ctrls ) != LDAP_SUCCESS ) {
339                                 ( void )meta_clear_one_candidate( lsc, 1 );
340                                 continue;
341                         }
342                 }
343         
344                 /*
345                  * If the target is already bound it is skipped
346                  */
347                 if ( lsc->bound == META_BOUND && lc->bound_target == i ) {
348                         ++bound;
349                         continue;
350                 }
351
352                 /*
353                  * Otherwise an anonymous bind is performed
354                  * (note: if the target was already bound, the anonymous
355                  * bind clears the previous bind).
356                  */
357                 if ( lsc->bound_dn.bv_val ) {
358                         ber_memfree( lsc->bound_dn.bv_val );
359                         lsc->bound_dn.bv_val = NULL;
360                         lsc->bound_dn.bv_len = 0;
361                 }
362                 
363                 if ( /* FIXME: need li ... li->savecred && */ 
364                                 lsc->cred.bv_val ) {
365                         memset( lsc->cred.bv_val, 0, lsc->cred.bv_len );
366                         ber_memfree( lsc->cred.bv_val );
367                         lsc->cred.bv_val = NULL;
368                         lsc->cred.bv_len = 0;
369                 }
370
371                 rc = ldap_bind_s( lsc->ld, 0, NULL, LDAP_AUTH_SIMPLE );
372                 if ( rc != LDAP_SUCCESS ) {
373                         
374 #ifdef NEW_LOGGING
375                         LDAP_LOG( BACK_META, WARNING,
376                                         "meta_back_dobind: (anonymous)"
377                                         " bind failed"
378                                         " with error %d (%s)\n",
379                                         rc, ldap_err2string( rc ), 0 );
380 #else /* !NEW_LOGGING */
381                         Debug( LDAP_DEBUG_ANY,
382                                         "==>meta_back_dobind: (anonymous)"
383                                         " bind failed"
384                                         " with error %d (%s)\n",
385                                         rc, ldap_err2string( rc ), 0 );
386 #endif /* !NEW_LOGGING */
387
388                         /*
389                          * null cred bind should always succeed
390                          * as anonymous, so a failure means
391                          * the target is no longer candidate possibly
392                          * due to technical reasons (remote host down?)
393                          * so better clear the handle
394                          */
395                         ( void )meta_clear_one_candidate( lsc, 1 );
396                         continue;
397                 } /* else */
398                 
399                 lsc->bound = META_ANONYMOUS;
400                 ++bound;
401         }
402
403         return( bound > 0 );
404 }
405
406 /*
407  *
408  */
409 int
410 meta_back_is_valid( struct metaconn *lc, int candidate )
411 {
412         struct metasingleconn   *lsc;
413         int                     i;
414
415         assert( lc );
416
417         if ( candidate < 0 ) {
418                 return 0;
419         }
420
421         for ( i = 0, lsc = lc->conns; !META_LAST(lsc) && i < candidate; 
422                         ++i, ++lsc );
423         
424         if ( !META_LAST(lsc) ) {
425                 return( lsc->ld != NULL );
426         }
427
428         return 0;
429 }
430
431 /*
432  * meta_back_rebind
433  *
434  * This is a callback used for chasing referrals using the same
435  * credentials as the original user on this session.
436  */
437 static int 
438 meta_back_rebind( LDAP *ld, LDAP_CONST char *url, ber_tag_t request,
439         ber_int_t msgid, void *params )
440 {
441         struct metasingleconn *lc = params;
442
443         return ldap_bind_s( ld, lc->bound_dn.bv_val, lc->cred.bv_val,
444                         LDAP_AUTH_SIMPLE );
445 }
446
447 /*
448  * FIXME: error return must be handled in a cleaner way ...
449  */
450 int
451 meta_back_op_result( struct metaconn *lc, Operation *op, SlapReply *rs )
452 {
453         int i, rerr = LDAP_SUCCESS;
454         struct metasingleconn *lsc;
455         char *rmsg = NULL;
456         char *rmatch = NULL;
457
458         for ( i = 0, lsc = lc->conns; !META_LAST(lsc); ++i, ++lsc ) {
459                 char *msg = NULL;
460                 char *match = NULL;
461
462                 rs->sr_err = LDAP_SUCCESS;
463
464                 ldap_get_option( lsc->ld, LDAP_OPT_ERROR_NUMBER, &rs->sr_err );
465                 if ( rs->sr_err != LDAP_SUCCESS ) {
466                         /*
467                          * better check the type of error. In some cases
468                          * (search ?) it might be better to return a
469                          * success if at least one of the targets gave
470                          * positive result ...
471                          */
472                         ldap_get_option( lsc->ld,
473                                         LDAP_OPT_ERROR_STRING, &msg );
474                         ldap_get_option( lsc->ld,
475                                         LDAP_OPT_MATCHED_DN, &match );
476                         rs->sr_err = ldap_back_map_result( rs );
477
478 #ifdef NEW_LOGGING
479                         LDAP_LOG( BACK_META, RESULTS,
480                                         "meta_back_op_result: target"
481                                         " <%d> sending msg \"%s\""
482                                         " (matched \"%s\")\n",
483                                         i, ( msg ? msg : "" ),
484                                         ( match ? match : "" ) );
485 #else /* !NEW_LOGGING */
486                         Debug(LDAP_DEBUG_ANY,
487                                         "==> meta_back_op_result: target"
488                                         " <%d> sending msg \"%s\""
489                                         " (matched \"%s\")\n", 
490                                         i, ( msg ? msg : "" ),
491                                         ( match ? match : "" ) );
492 #endif /* !NEW_LOGGING */
493
494                         /*
495                          * FIXME: need to rewrite "match" (need rwinfo)
496                          */
497                         switch ( rs->sr_err ) {
498                         default:
499                                 rerr = rs->sr_err;
500                                 rmsg = msg;
501                                 msg = NULL;
502                                 rmatch = match;
503                                 match = NULL;
504                                 break;
505                         }
506
507                         /* better test the pointers before freeing? */
508                         if ( match ) {
509                                 free( match );
510                         }
511                         if ( msg ) {
512                                 free( msg );
513                         }
514                 }
515         }
516
517         rs->sr_err = rerr;
518         rs->sr_text = rmsg;
519         rs->sr_matched = rmatch;
520         send_ldap_result( op, rs );
521         rs->sr_text = NULL;
522         rs->sr_matched = NULL;
523
524         return ( ( rerr == LDAP_SUCCESS ) ? 0 : -1 );
525 }
526