]> git.sur5r.net Git - openldap/blob - servers/slapd/back-meta/bind.c
d990ffb98f944ee8cab2016fb65a5a0d070a5895
[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", dn->bv_val, 0, 0 );
120 #else /* !NEW_LOGGING */
121                 Debug( LDAP_DEBUG_ANY,
122                                 "meta_back_bind: no target for dn %s.\n%s%s",
123                                 op->o_req_dn.bv_val, "", "");
124 #endif /* !NEW_LOGGING */
125
126                 send_ldap_result( op, rs );
127                 return -1;
128         }
129
130         /*
131          * Each target is scanned ...
132          */
133         lc->bound_target = META_BOUND_NONE;
134         ndnlen = op->o_req_ndn.bv_len;
135         for ( i = 0; i < li->ntargets; i++ ) {
136                 int             lerr;
137                 struct berval   orig_dn = op->o_req_dn;
138                 struct berval   orig_ndn = op->o_req_ndn;
139                 struct berval   orig_cred = op->oq_bind.rb_cred;
140                 int             orig_method = op->oq_bind.rb_method;
141                 
142
143                 /*
144                  * Skip non-candidates
145                  */
146                 if ( lc->conns[ i ].candidate != META_CANDIDATE ) {
147                         continue;
148                 }
149
150                 if ( gotit == 0 ) {
151                         gotit = 1;
152                 } else {
153                         /*
154                          * A bind operation is expected to have
155                          * ONE CANDIDATE ONLY!
156                          */
157 #ifdef NEW_LOGGING
158                         LDAP_LOG( BACK_META, WARNING,
159                                         "==>meta_back_bind: more than one"
160                                         " candidate is attempting to bind"
161                                         " ...\n" , 0, 0, 0 );
162 #else /* !NEW_LOGGING */
163                         Debug( LDAP_DEBUG_ANY,
164                                         "==>meta_back_bind: more than one"
165                                         " candidate is attempting to bind"
166                                         " ...\n%s%s%s", 
167                                         "", "", "" );
168 #endif /* !NEW_LOGGING */
169                 }
170
171                 if ( isroot && li->targets[ i ]->pseudorootdn.bv_val != NULL ) {
172                         op->o_req_dn = li->targets[ i ]->pseudorootdn;
173                         op->o_req_ndn = li->targets[ i ]->pseudorootdn;
174                         op->oq_bind.rb_cred = li->targets[ i ]->pseudorootpw;
175                         op->oq_bind.rb_method = LDAP_AUTH_SIMPLE;
176                 }
177                 
178                 lerr = meta_back_do_single_bind( lc, op, rs, i );
179                 if ( lerr != LDAP_SUCCESS ) {
180                         rs->sr_err = lerr;
181                         ( void )meta_clear_one_candidate( &lc->conns[ i ], 1 );
182                 } else {
183                         rc = LDAP_SUCCESS;
184                 }
185
186                 op->o_req_dn = orig_dn;
187                 op->o_req_ndn = orig_ndn;
188                 op->oq_bind.rb_cred = orig_cred;
189                 op->oq_bind.rb_method = orig_method;
190         }
191
192         if ( isroot ) {
193                 lc->bound_target = META_BOUND_ALL;
194         }
195
196         /*
197          * rc is LDAP_SUCCESS if at least one bind succeeded,
198          * err is the last error that occurred during a bind;
199          * if at least (and at most?) one bind succeedes, fine.
200          */
201         if ( rc != LDAP_SUCCESS /* && rs->sr_err != LDAP_SUCCESS */ ) {
202                 
203                 /*
204                  * deal with bind failure ...
205                  */
206
207                 /*
208                  * no target was found within the naming context, 
209                  * so bind must fail with invalid credentials
210                  */
211                 if ( rs->sr_err == LDAP_SUCCESS && gotit == 0 ) {
212                         rs->sr_err = LDAP_INVALID_CREDENTIALS;
213                 }
214
215                 rs->sr_err = ldap_back_map_result( rs );
216                 send_ldap_result( op, rs );
217                 return -1;
218         }
219
220         return 0;
221 }
222
223 /*
224  * meta_back_do_single_bind
225  *
226  * attempts to perform a bind with creds
227  */
228 static int
229 meta_back_do_single_bind(
230                 struct metaconn         *lc,
231                 Operation               *op,
232                 SlapReply               *rs,
233                 int                     candidate
234 )
235 {
236         struct metainfo *li = ( struct metainfo * )op->o_bd->be_private;
237         struct berval   mdn = { 0, NULL };
238         ber_int_t       msgid;
239         
240         /*
241          * Rewrite the bind dn if needed
242          */
243         switch ( rewrite_session( li->targets[ candidate ]->rwinfo,
244                                 "bindDn", op->o_req_dn.bv_val,
245                                 lc->conn, &mdn.bv_val ) ) {
246         case REWRITE_REGEXEC_OK:
247                 if ( mdn.bv_val == NULL ) {
248                         mdn = op->o_req_dn;
249                 } else {
250                         mdn.bv_len = strlen( mdn.bv_val );
251                 }
252 #ifdef NEW_LOGGING
253                 LDAP_LOG( BACK_META, DETAIL1,
254                                 "[rw] bindDn: \"%s\" -> \"%s\"\n",
255                                 op->o_req_dn.bv_val, mdn.bv_val, 0 );
256 #else /* !NEW_LOGGING */
257                 Debug( LDAP_DEBUG_ARGS,
258                                 "rw> bindDn: \"%s\" -> \"%s\"\n%s",
259                                 op->o_req_dn.bv_val, mdn.bv_val, "" );
260 #endif /* !NEW_LOGGING */
261                 break;
262                 
263         case REWRITE_REGEXEC_UNWILLING:
264                 return LDAP_UNWILLING_TO_PERFORM;
265
266         case REWRITE_REGEXEC_ERR:
267                 return LDAP_OTHER;
268         }
269
270         if ( op->o_ctrls ) {
271                 rs->sr_err = ldap_set_option( lc->conns[ candidate ].ld, 
272                                 LDAP_OPT_SERVER_CONTROLS, op->o_ctrls );
273                 if ( rs->sr_err != LDAP_SUCCESS ) {
274                         rs->sr_err = ldap_back_map_result( rs );
275                         goto return_results;
276                 }
277         }
278         
279         rs->sr_err = ldap_sasl_bind(lc->conns[ candidate ].ld, mdn.bv_val,
280                         LDAP_SASL_SIMPLE, &op->oq_bind.rb_cred,
281                         op->o_ctrls, NULL, &msgid);
282         if ( rs->sr_err != LDAP_SUCCESS ) {
283                 rs->sr_err = ldap_back_map_result( rs );
284
285         } else {
286                 /*
287                  * FIXME: handle response!!!
288                  */
289                 ber_dupbv( &lc->conns[ candidate ].bound_dn, &op->o_req_dn );
290                 lc->conns[ candidate ].bound = META_BOUND;
291                 lc->bound_target = candidate;
292
293                 if ( li->savecred ) {
294                         if ( lc->conns[ candidate ].cred.bv_val )
295                                 ch_free( lc->conns[ candidate ].cred.bv_val );
296                         ber_dupbv( &lc->conns[ candidate ].cred,
297                                         &op->oq_bind.rb_cred );
298                         ldap_set_rebind_proc( lc->conns[ candidate ].ld, 
299                                         meta_back_rebind, 
300                                         &lc->conns[ candidate ] );
301                 }
302
303                 if ( li->cache.ttl != META_DNCACHE_DISABLED
304                                 && op->o_req_ndn.bv_len != 0 ) {
305                         ( void )meta_dncache_update_entry( &li->cache,
306                                         &op->o_req_ndn, candidate );
307                 }
308         }
309
310 return_results:;
311         
312         if ( mdn.bv_val != op->o_req_dn.bv_val ) {
313                 free( mdn.bv_val );
314         }
315
316         return rs->sr_err;
317 }
318
319 /*
320  * meta_back_dobind
321  */
322 int
323 meta_back_dobind( struct metaconn *lc, Operation *op )
324 {
325         struct metasingleconn *lsc;
326         int bound = 0, i;
327
328         /*
329          * all the targets are bound as pseudoroot
330          */
331         if ( lc->bound_target == META_BOUND_ALL ) {
332                 return 1;
333         }
334
335         for ( i = 0, lsc = lc->conns; !META_LAST(lsc); ++i, ++lsc ) {
336                 int rc;
337
338                 /*
339                  * Not a candidate or something wrong with this target ...
340                  */
341                 if ( lsc->ld == NULL ) {
342                         continue;
343                 }
344
345                 /*
346                  * If required, set controls
347                  */
348                 if ( op->o_ctrls ) {
349                         if ( ldap_set_option( lsc->ld, LDAP_OPT_SERVER_CONTROLS,
350                                         op->o_ctrls ) != LDAP_SUCCESS ) {
351                                 ( void )meta_clear_one_candidate( lsc, 1 );
352                                 continue;
353                         }
354                 }
355         
356                 /*
357                  * If the target is already bound it is skipped
358                  */
359                 if ( lsc->bound == META_BOUND && lc->bound_target == i ) {
360                         ++bound;
361                         continue;
362                 }
363
364                 /*
365                  * Otherwise an anonymous bind is performed
366                  * (note: if the target was already bound, the anonymous
367                  * bind clears the previous bind).
368                  */
369                 if ( lsc->bound_dn.bv_val ) {
370                         ch_free( lsc->bound_dn.bv_val );
371                         lsc->bound_dn.bv_val = NULL;
372                         lsc->bound_dn.bv_len = 0;
373                 }
374                 
375
376                 rc = ldap_bind_s( lsc->ld, 0, NULL, LDAP_AUTH_SIMPLE );
377                 if ( rc != LDAP_SUCCESS ) {
378                         
379 #ifdef NEW_LOGGING
380                         LDAP_LOG( BACK_META, WARNING,
381                                         "meta_back_dobind: (anonymous)"
382                                         " bind failed"
383                                         " with error %d (%s)\n",
384                                         rc, ldap_err2string( rc ), 0 );
385 #else /* !NEW_LOGGING */
386                         Debug( LDAP_DEBUG_ANY,
387                                         "==>meta_back_dobind: (anonymous)"
388                                         " bind failed"
389                                         " with error %d (%s)\n",
390                                         rc, ldap_err2string( rc ), 0 );
391 #endif /* !NEW_LOGGING */
392
393                         /*
394                          * null cred bind should always succeed
395                          * as anonymous, so a failure means
396                          * the target is no longer candidate possibly
397                          * due to technical reasons (remote host down?)
398                          * so better clear the handle
399                          */
400                         ( void )meta_clear_one_candidate( lsc, 1 );
401                         continue;
402                 } /* else */
403                 
404                 lsc->bound = META_ANONYMOUS;
405                 ++bound;
406         }
407
408         return( bound > 0 );
409 }
410
411 /*
412  *
413  */
414 int
415 meta_back_is_valid( struct metaconn *lc, int candidate )
416 {
417         struct metasingleconn   *lsc;
418         int                     i;
419
420         assert( lc );
421
422         if ( candidate < 0 ) {
423                 return 0;
424         }
425
426         for ( i = 0, lsc = lc->conns; !META_LAST(lsc) && i < candidate; 
427                         ++i, ++lsc );
428         
429         if ( !META_LAST(lsc) ) {
430                 return( lsc->ld != NULL );
431         }
432
433         return 0;
434 }
435
436 /*
437  * meta_back_rebind
438  *
439  * This is a callback used for chasing referrals using the same
440  * credentials as the original user on this session.
441  */
442 static int 
443 meta_back_rebind( LDAP *ld, LDAP_CONST char *url, ber_tag_t request,
444         ber_int_t msgid, void *params )
445 {
446         struct metasingleconn *lc = params;
447
448         return ldap_bind_s( ld, lc->bound_dn.bv_val, lc->cred.bv_val,
449                         LDAP_AUTH_SIMPLE );
450 }
451
452 /*
453  * FIXME: error return must be handled in a cleaner way ...
454  */
455 int
456 meta_back_op_result( struct metaconn *lc, Operation *op, SlapReply *rs )
457 {
458         int i, rerr = LDAP_SUCCESS;
459         struct metasingleconn *lsc;
460         char *rmsg = NULL;
461         char *rmatch = NULL;
462
463         for ( i = 0, lsc = lc->conns; !META_LAST(lsc); ++i, ++lsc ) {
464                 char *msg = NULL;
465                 char *match = NULL;
466
467                 rs->sr_err = LDAP_SUCCESS;
468
469                 ldap_get_option( lsc->ld, LDAP_OPT_ERROR_NUMBER, &rs->sr_err );
470                 if ( rs->sr_err != LDAP_SUCCESS ) {
471                         /*
472                          * better check the type of error. In some cases
473                          * (search ?) it might be better to return a
474                          * success if at least one of the targets gave
475                          * positive result ...
476                          */
477                         ldap_get_option( lsc->ld,
478                                         LDAP_OPT_ERROR_STRING, &msg );
479                         ldap_get_option( lsc->ld,
480                                         LDAP_OPT_MATCHED_DN, &match );
481                         rs->sr_err = ldap_back_map_result( rs );
482
483 #ifdef NEW_LOGGING
484                         LDAP_LOG( BACK_META, RESULTS,
485                                         "meta_back_op_result: target"
486                                         " <%d> sending msg \"%s\""
487                                         " (matched \"%s\")\n",
488                                         i, ( msg ? msg : "" ),
489                                         ( match ? match : "" ) );
490 #else /* !NEW_LOGGING */
491                         Debug(LDAP_DEBUG_ANY,
492                                         "==> meta_back_op_result: target"
493                                         " <%d> sending msg \"%s\""
494                                         " (matched \"%s\")\n", 
495                                         i, ( msg ? msg : "" ),
496                                         ( match ? match : "" ) );
497 #endif /* !NEW_LOGGING */
498
499                         /*
500                          * FIXME: need to rewrite "match" (need rwinfo)
501                          */
502                         switch ( rs->sr_err ) {
503                         default:
504                                 rerr = rs->sr_err;
505                                 rmsg = msg;
506                                 msg = NULL;
507                                 rmatch = match;
508                                 match = NULL;
509                                 break;
510                         }
511
512                         /* better test the pointers before freeing? */
513                         if ( match ) {
514                                 free( match );
515                         }
516                         if ( msg ) {
517                                 free( msg );
518                         }
519                 }
520         }
521
522         rs->sr_err = rerr;
523         rs->sr_text = rmsg;
524         rs->sr_matched = rmatch;
525         send_ldap_result( op, rs );
526         rs->sr_text = NULL;
527         rs->sr_matched = NULL;
528
529         return ( ( rerr == LDAP_SUCCESS ) ? 0 : -1 );
530 }
531