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