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