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