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