]> git.sur5r.net Git - openldap/blob - servers/slurpd/ldap_op.c
happy new year
[openldap] / servers / slurpd / ldap_op.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2007 The OpenLDAP Foundation.
5  * Portions Copyright 2003 Mark Benson.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16 /* Portions Copyright (c) 1996 Regents of the University of Michigan.
17  * All rights reserved.
18  *
19  * Redistribution and use in source and binary forms are permitted
20  * provided that this notice is preserved and that due credit is given
21  * to the University of Michigan at Ann Arbor. The name of the University
22  * may not be used to endorse or promote products derived from this
23  * software without specific prior written permission. This software
24  * is provided ``as is'' without express or implied warranty.
25  */
26 /* ACKNOWLEDGEMENTS:
27  * This work was originally developed by the University of Michigan
28  * (as part of U-MICH LDAP).  Additional significant contributors
29  * include:
30  *     Mark Benson
31  */
32
33 /*
34  * ldap_op.c - routines to perform LDAP operations
35  */
36
37 #include "portable.h"
38
39 #include <stdio.h>
40
41 #include <ac/stdlib.h>
42
43 #include <ac/errno.h>
44 #include <ac/string.h>
45 #include <ac/ctype.h>
46 #include <ac/time.h>
47 #include <ac/unistd.h>
48
49 #define LDAP_DEPRECATED 1
50 #include <ldap.h>
51 #include "lutil_ldap.h"
52 #include "slurp.h"
53
54 /* Forward references */
55 static struct berval **make_singlevalued_berval LDAP_P(( char   *, int ));
56 static int op_ldap_add LDAP_P(( Ri *, Re *, char **, int * ));
57 static int op_ldap_modify LDAP_P(( Ri *, Re *, char **, int * ));
58 static int op_ldap_delete LDAP_P(( Ri *, Re *, char **, int * ));
59 static int op_ldap_modrdn LDAP_P(( Ri *, Re *, char **, int * ));
60 static LDAPMod *alloc_ldapmod LDAP_P(( void ));
61 static void free_ldapmod LDAP_P(( LDAPMod * ));
62 static void free_ldmarr LDAP_P(( LDAPMod ** ));
63 static int getmodtype LDAP_P(( char * ));
64 #ifdef SLAPD_UNUSED
65 static void dump_ldm_array LDAP_P(( LDAPMod ** ));
66 #endif
67 static int do_bind LDAP_P(( Ri *, int * ));
68 static int do_unbind LDAP_P(( Ri * ));
69
70
71 /*
72  * Determine the type of ldap operation being performed and call the
73  * appropriate routine.
74  * - If successful, returns DO_LDAP_OK
75  * - If a retryable error occurs, ERR_DO_LDAP_RETRYABLE is returned.
76  *   The caller should wait a while and retry the operation.
77  * - If a fatal error occurs, ERR_DO_LDAP_FATAL is returned.  The caller
78  *   should reject the operation and continue with the next replication
79  *   entry.
80  */
81 int
82 do_ldap(
83         Ri              *ri,
84         Re              *re,
85         char    **errmsg,
86         int     *errfree
87 )
88 {
89         int     retry = 2;
90         *errmsg = NULL;
91         *errfree = 0;
92
93         do {
94                 int lderr;
95                 if ( ri->ri_ldp == NULL ) {
96                         lderr = do_bind( ri, &lderr );
97
98                         if ( lderr != BIND_OK ) {
99                                 return DO_LDAP_ERR_RETRYABLE;
100                         }
101                 }
102
103                 switch ( re->re_changetype ) {
104                 case T_ADDCT:
105                         lderr = op_ldap_add( ri, re, errmsg, errfree );
106                         if ( lderr != LDAP_SUCCESS ) {
107                                 Debug( LDAP_DEBUG_ANY,
108                                         "Error: ldap_add_s failed adding DN \"%s\": %s\n",
109                                         re->re_dn, *errmsg && (*errmsg)[0] ?
110                                         *errmsg : ldap_err2string( lderr ), 0 );
111                         }
112                         break;
113
114                 case T_MODIFYCT:
115                         lderr = op_ldap_modify( ri, re, errmsg, errfree );
116                         if ( lderr != LDAP_SUCCESS ) {
117                                 Debug( LDAP_DEBUG_ANY,
118                                         "Error: ldap_modify_s failed modifying DN \"%s\": %s\n",
119                                         re->re_dn, *errmsg && (*errmsg)[0] ?
120                                         *errmsg : ldap_err2string( lderr ), 0 );
121                         }
122                         break;
123
124                 case T_DELETECT:
125                         lderr = op_ldap_delete( ri, re, errmsg, errfree );
126                         if ( lderr != LDAP_SUCCESS ) {
127                                 Debug( LDAP_DEBUG_ANY,
128                                         "Error: ldap_delete_s failed deleting DN \"%s\": %s\n",
129                                         re->re_dn, *errmsg && (*errmsg)[0] ?
130                                         *errmsg : ldap_err2string( lderr ), 0 );
131                         }
132                         break;
133
134                 case T_MODRDNCT:
135                         lderr = op_ldap_modrdn( ri, re, errmsg, errfree );
136                         if ( lderr != LDAP_SUCCESS ) {
137                                 Debug( LDAP_DEBUG_ANY,
138                                         "Error: ldap_modrdn_s failed modifying DN \"%s\": %s\n",
139                                         re->re_dn, *errmsg && (*errmsg)[0] ?
140                                         *errmsg : ldap_err2string( lderr ), 0 );
141                         }
142                         break;
143
144                 default:
145                         Debug( LDAP_DEBUG_ANY,
146                                 "Error: do_ldap: bad op \"%d\", DN \"%s\"\n",
147                                 re->re_changetype, re->re_dn, 0 );
148                         return DO_LDAP_ERR_FATAL;
149                 }
150
151                 /*
152                  * Analyze return code. If ok, just return. If LDAP_SERVER_DOWN,
153                  * we may have been idle long enough that the remote slapd timed
154                  * us out. Rebind and try again.
155                  */
156                 switch( lderr ) {
157                 case LDAP_SUCCESS:
158                         return DO_LDAP_OK;
159         
160                 default:
161                         return DO_LDAP_ERR_FATAL;
162
163                 case LDAP_SERVER_DOWN: /* server went down */
164                         (void) do_unbind( ri );
165                         retry--;
166                 }
167         } while ( retry > 0 );
168
169         return DO_LDAP_ERR_RETRYABLE;
170 }
171
172
173
174 /*
175  * Perform an ldap add operation.
176  */
177 static int
178 op_ldap_add(
179     Ri          *ri,
180     Re          *re,
181     char        **errmsg,
182     int         *errfree
183 )
184 {
185     Mi          *mi;
186     int         nattrs, rc = 0, i;
187     LDAPMod     *ldm, **ldmarr;
188     int         lderr = 0;
189
190     nattrs = i = 0;
191     ldmarr = NULL;
192
193     /*
194      * Construct a null-terminated array of LDAPMod structs.
195      */
196     mi = re->re_mods;
197     while ( mi[ i ].mi_type != NULL ) {
198         ldm = alloc_ldapmod();
199         ldmarr = ( LDAPMod ** ) ch_realloc( ldmarr,
200                 ( nattrs + 2 ) * sizeof( LDAPMod * ));
201         ldmarr[ nattrs ] = ldm;
202         ldm->mod_op = LDAP_MOD_BVALUES;
203         ldm->mod_type = mi[ i ].mi_type;
204         ldm->mod_bvalues =
205                 make_singlevalued_berval( mi[ i ].mi_val, mi[ i ].mi_len );
206         i++;
207         nattrs++;
208     }
209
210     if ( ldmarr != NULL ) {
211         ldmarr[ nattrs ] = NULL;
212
213         /* Perform the operation */
214         Debug( LDAP_DEBUG_ARGS, "replica %s:%d - add dn \"%s\"\n",
215                 ri->ri_hostname, ri->ri_port, re->re_dn );
216         rc = ldap_add_s( ri->ri_ldp, re->re_dn, ldmarr );
217
218         ldap_get_option( ri->ri_ldp, LDAP_OPT_RESULT_CODE, &lderr);
219         ldap_get_option( ri->ri_ldp, LDAP_OPT_DIAGNOSTIC_MESSAGE, errmsg);
220         *errfree = 1;
221
222     } else {
223         *errmsg = "No modifications to do";
224         Debug( LDAP_DEBUG_ANY,
225                "Error: op_ldap_add: no mods to do (%s)!\n", re->re_dn, 0, 0 );
226     }
227     free_ldmarr( ldmarr );
228     return( lderr ); 
229 }
230
231
232
233
234 /*
235  * Perform an ldap modify operation.
236  */
237 #define AWAITING_OP -1
238 static int
239 op_ldap_modify(
240     Ri          *ri,
241     Re          *re,
242     char        **errmsg,
243     int         *errfree
244 )
245 {
246     Mi          *mi;
247     int         state;  /* This code is a simple-minded state machine */
248     int         nvals;  /* Number of values we're modifying */
249     int         nops;   /* Number of LDAPMod structs in ldmarr */
250     LDAPMod     *ldm = NULL, **ldmarr;
251     int         i, len;
252     char        *type, *value;
253     int         rc = 0;
254
255     state = AWAITING_OP;
256     nvals = 0;
257     nops = 0;
258     ldmarr = NULL;
259
260     if ( re->re_mods == NULL ) {
261         *errmsg = "No arguments given";
262         Debug( LDAP_DEBUG_ANY, "Error: op_ldap_modify: no arguments\n",
263                 0, 0, 0 );
264             return -1;
265     }
266
267     /*
268      * Construct a null-terminated array of LDAPMod structs.
269      */
270     for ( mi = re->re_mods, i = 0; mi[ i ].mi_type != NULL; i++ ) {
271         type = mi[ i ].mi_type;
272         value = mi[ i ].mi_val;
273         len = mi[ i ].mi_len;
274         switch ( getmodtype( type )) {
275         case T_MODSEP:
276             state = T_MODSEP; /* Got a separator line "-\n" */
277             continue;
278         case T_MODOPADD:
279             state = T_MODOPADD;
280             ldmarr = ( LDAPMod ** )
281                     ch_realloc(ldmarr, (( nops + 2 ) * ( sizeof( LDAPMod * ))));
282             ldmarr[ nops ] = ldm = alloc_ldapmod();
283             ldm->mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
284             ldm->mod_type = value;
285             nvals = 0;
286             nops++;
287             break;
288         case T_MODOPREPLACE:
289             state = T_MODOPREPLACE;
290             ldmarr = ( LDAPMod ** )
291                     ch_realloc(ldmarr, (( nops + 2 ) * ( sizeof( LDAPMod * ))));
292             ldmarr[ nops ] = ldm = alloc_ldapmod();
293             ldm->mod_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
294             ldm->mod_type = value;
295             nvals = 0;
296             nops++;
297             break;
298         case T_MODOPDELETE:
299             state = T_MODOPDELETE;
300             ldmarr = ( LDAPMod ** )
301                     ch_realloc(ldmarr, (( nops + 2 ) * ( sizeof( LDAPMod * ))));
302             ldmarr[ nops ] = ldm = alloc_ldapmod();
303             ldm->mod_op = LDAP_MOD_DELETE | LDAP_MOD_BVALUES;
304             ldm->mod_type = value;
305             nvals = 0;
306             nops++;
307             break;
308         case T_MODOPINCREMENT:
309             state = T_MODOPINCREMENT;
310             ldmarr = ( LDAPMod ** )
311                     ch_realloc(ldmarr, (( nops + 2 ) * ( sizeof( LDAPMod * ))));
312             ldmarr[ nops ] = ldm = alloc_ldapmod();
313             ldm->mod_op = LDAP_MOD_INCREMENT | LDAP_MOD_BVALUES;
314             ldm->mod_type = value;
315             nvals = 0;
316             nops++;
317             break;
318         default:
319             if ( state == AWAITING_OP ) {
320                 Debug( LDAP_DEBUG_ANY,
321                         "Error: op_ldap_modify: unknown mod type \"%s\"\n",
322                         type, 0, 0 );
323                 continue;
324             }
325
326             assert( ldm != NULL );
327
328             /*
329              * We should have an attribute: value pair here.
330              * Construct the mod_bvalues part of the ldapmod struct.
331              */
332             if ( strcasecmp( type, ldm->mod_type )) {
333                 Debug( LDAP_DEBUG_ANY,
334                         "Error: malformed modify op, %s: %s (expecting %s:)\n",
335                         type, value, ldm->mod_type );
336                 continue;
337             }
338             ldm->mod_bvalues = ( struct berval ** )
339                     ch_realloc( ldm->mod_bvalues,
340                     ( nvals + 2 ) * sizeof( struct berval * ));
341             ldm->mod_bvalues[ nvals + 1 ] = NULL;
342             ldm->mod_bvalues[ nvals ] = ( struct berval * )
343                     ch_malloc( sizeof( struct berval ));
344             ldm->mod_bvalues[ nvals ]->bv_val = value;
345             ldm->mod_bvalues[ nvals ]->bv_len = len;
346             nvals++;
347         }
348     }
349     ldmarr[ nops ] = NULL;
350
351     if ( nops > 0 ) {
352         /* Actually perform the LDAP operation */
353         Debug( LDAP_DEBUG_ARGS, "replica %s:%d - modify dn \"%s\"\n",
354                 ri->ri_hostname, ri->ri_port, re->re_dn );
355         rc = ldap_modify_s( ri->ri_ldp, re->re_dn, ldmarr );
356         ldap_get_option( ri->ri_ldp, LDAP_OPT_DIAGNOSTIC_MESSAGE, errmsg);
357         *errfree = 1;
358     }
359     free_ldmarr( ldmarr );
360     return( rc );
361 }
362
363
364
365
366 /*
367  * Perform an ldap delete operation.
368  */
369 static int
370 op_ldap_delete(
371     Ri          *ri,
372     Re          *re,
373     char        **errmsg,
374     int         *errfree
375 )
376 {
377     int         rc;
378
379     Debug( LDAP_DEBUG_ARGS, "replica %s:%d - delete dn \"%s\"\n",
380             ri->ri_hostname, ri->ri_port, re->re_dn );
381     rc = ldap_delete_s( ri->ri_ldp, re->re_dn );
382     ldap_get_option( ri->ri_ldp, LDAP_OPT_DIAGNOSTIC_MESSAGE, errmsg);
383     *errfree = 1;
384
385     return( rc );
386 }
387
388
389
390
391 /*
392  * Perform an ldap modrdn operation.
393  */
394 #define GOT_NEWRDN              0x1
395 #define GOT_DELOLDRDN   0x2
396 #define GOT_NEWSUP              0x4
397
398 #define GOT_MODDN_REQ   (GOT_NEWRDN|GOT_DELOLDRDN)
399 #define GOT_ALL_MODDN(f)        (((f) & GOT_MODDN_REQ) == GOT_MODDN_REQ)
400 static int
401 op_ldap_modrdn(
402     Ri          *ri,
403     Re          *re,
404     char        **errmsg,
405     int         *errfree
406 )
407 {
408     int         rc = 0;
409     Mi          *mi;
410     int         i;
411         int             lderr = 0;
412     int         state = 0;
413     int         drdnflag = -1;
414     char        *newrdn = NULL;
415         char    *newsup = NULL;
416
417     if ( re->re_mods == NULL ) {
418         *errmsg = "No arguments given";
419         Debug( LDAP_DEBUG_ANY, "Error: op_ldap_modrdn: no arguments\n",
420                 0, 0, 0 );
421             return -1;
422     }
423
424     /*
425      * Get the arguments: should see newrdn: and deleteoldrdn: args.
426      */
427     for ( mi = re->re_mods, i = 0; mi[ i ].mi_type != NULL; i++ ) {
428         if ( !strcmp( mi[ i ].mi_type, T_NEWRDNSTR )) {
429                 if( state & GOT_NEWRDN ) {
430                 Debug( LDAP_DEBUG_ANY,
431                         "Error: op_ldap_modrdn: multiple newrdn arg \"%s\"\n",
432                         mi[ i ].mi_val, 0, 0 );
433                 *errmsg = "Multiple newrdn argument";
434                 return -1;
435                 }
436
437             newrdn = mi[ i ].mi_val;
438             state |= GOT_NEWRDN;
439
440         } else if ( !strcmp( mi[ i ].mi_type, T_DELOLDRDNSTR )) {
441                 if( state & GOT_DELOLDRDN ) {
442                 Debug( LDAP_DEBUG_ANY,
443                         "Error: op_ldap_modrdn: multiple deleteoldrdn arg \"%s\"\n",
444                         mi[ i ].mi_val, 0, 0 );
445                 *errmsg = "Multiple newrdn argument";
446                 return -1;
447                 }
448
449             state |= GOT_DELOLDRDN;
450             if ( !strcmp( mi[ i ].mi_val, "0" )) {
451                 drdnflag = 0;
452             } else if ( !strcmp( mi[ i ].mi_val, "1" )) {
453                 drdnflag = 1;
454             } else {
455                 Debug( LDAP_DEBUG_ANY,
456                         "Error: op_ldap_modrdn: bad deleteoldrdn arg \"%s\"\n",
457                         mi[ i ].mi_val, 0, 0 );
458                 *errmsg = "Incorrect argument to deleteoldrdn";
459                 return -1;
460             }
461
462         } else if ( !strcmp( mi[ i ].mi_type, T_NEWSUPSTR )) {
463                 if( state & GOT_NEWSUP ) {
464                 Debug( LDAP_DEBUG_ANY,
465                         "Error: op_ldap_modrdn: multiple newsuperior arg \"%s\"\n",
466                         mi[ i ].mi_val, 0, 0 );
467                 *errmsg = "Multiple newsuperior argument";
468                 return -1;
469                 }
470
471                 newsup = mi[ i ].mi_val;
472             state |= GOT_NEWSUP;
473
474         } else {
475             Debug( LDAP_DEBUG_ANY, "Error: op_ldap_modrdn: bad type \"%s\"\n",
476                     mi[ i ].mi_type, 0, 0 );
477             *errmsg = "Bad value in replication log entry";
478             return -1;
479         }
480     }
481
482     /*
483      * Punt if we don't have all the args.
484      */
485     if ( !GOT_ALL_MODDN(state) ) {
486         Debug( LDAP_DEBUG_ANY, "Error: op_ldap_modrdn: missing arguments\n",
487                 0, 0, 0 );
488         *errmsg = "Missing argument: requires \"newrdn\" and \"deleteoldrdn\"";
489         return -1;
490     }
491
492 #ifdef LDAP_DEBUG
493     if ( ldap_debug & LDAP_DEBUG_ARGS ) {
494         char buf[ 256 ];
495         char *buf2;
496         int buf2len = strlen( re->re_dn ) + strlen( mi->mi_val ) + 11;
497
498         snprintf( buf, sizeof(buf), "%s:%d", ri->ri_hostname, ri->ri_port );
499
500         buf2 = (char *) ch_malloc( buf2len );
501         snprintf( buf2, buf2len, "(\"%s\" -> \"%s\")", re->re_dn, mi->mi_val );
502
503         Debug( LDAP_DEBUG_ARGS,
504                 "replica %s - modify rdn %s (flag: %d)\n",
505                 buf, buf2, drdnflag );
506         free( buf2 );
507     }
508 #endif /* LDAP_DEBUG */
509
510     assert( newrdn != NULL );
511
512     /* Do the modrdn */
513     rc = ldap_rename2_s( ri->ri_ldp, re->re_dn, newrdn, newsup, drdnflag );
514
515         ldap_get_option( ri->ri_ldp, LDAP_OPT_RESULT_CODE, &lderr);
516         ldap_get_option( ri->ri_ldp, LDAP_OPT_DIAGNOSTIC_MESSAGE, errmsg);
517         *errfree = 1;
518     return( lderr );
519 }
520
521
522
523 /*
524  * Allocate and initialize an ldapmod struct.
525  */
526 static LDAPMod *
527 alloc_ldapmod( void )
528 {
529     LDAPMod     *ldm;
530
531     ldm = ( struct ldapmod * ) ch_malloc( sizeof ( struct ldapmod ));
532     ldm->mod_type = NULL;
533     ldm->mod_bvalues = ( struct berval ** ) NULL;
534     return( ldm );
535 }
536
537
538
539 /*
540  * Free an ldapmod struct associated mod_bvalues.  NOTE - it is assumed
541  * that mod_bvalues and mod_type contain pointers to the same block of memory
542  * pointed to by the repl struct.  Therefore, it's not freed here.
543  */
544 static void
545 free_ldapmod(
546 LDAPMod *ldm )
547 {
548     int         i;
549
550     if ( ldm == NULL ) {
551         return;
552     }
553     if ( ldm->mod_bvalues != NULL ) {
554         for ( i = 0; ldm->mod_bvalues[ i ] != NULL; i++ ) {
555             free( ldm->mod_bvalues[ i ] );
556         }
557         free( ldm->mod_bvalues );
558     }
559     free( ldm );
560     return;
561 }
562
563
564 /*
565  * Free an an array of LDAPMod pointers and the LDAPMod structs they point
566  * to.
567  */
568 static void
569 free_ldmarr(
570 LDAPMod **ldmarr )
571 {
572     int i;
573
574     for ( i = 0; ldmarr[ i ] != NULL; i++ ) {
575         free_ldapmod( ldmarr[ i ] );
576     }
577     free( ldmarr );
578 }
579
580
581 /*
582  * Create a berval with a single value. 
583  */
584 static struct berval **
585 make_singlevalued_berval( 
586 char    *value,
587 int     len )
588 {
589     struct berval **p;
590
591     p = ( struct berval ** ) ch_malloc( 2 * sizeof( struct berval * ));
592     p[ 0 ] = ( struct berval * ) ch_malloc( sizeof( struct berval ));
593     p[ 1 ] = NULL;
594     p[ 0 ]->bv_val = value;
595     p[ 0 ]->bv_len = len;
596     return( p );
597 }
598
599
600 /*
601  * Given a modification type (string), return an enumerated type.
602  * Avoids ugly copy in op_ldap_modify - lets us use a switch statement
603  * there.
604  */
605 static int
606 getmodtype( 
607 char *type )
608 {
609     if ( !strcmp( type, T_MODSEPSTR )) {
610         return( T_MODSEP );
611     }
612     if ( !strcmp( type, T_MODOPADDSTR )) {
613         return( T_MODOPADD );
614     }
615     if ( !strcmp( type, T_MODOPREPLACESTR )) {
616         return( T_MODOPREPLACE );
617     }
618     if ( !strcmp( type, T_MODOPDELETESTR )) {
619         return( T_MODOPDELETE );
620     }
621     if ( !strcmp( type, T_MODOPINCREMENTSTR )) {
622         return( T_MODOPINCREMENT );
623     }
624     return( T_ERR );
625 }
626
627
628 /*
629  * Perform an LDAP unbind operation.  If replica is NULL, or the
630  * repl_ldp is NULL, just return LDAP_SUCCESS.  Otherwise, unbind,
631  * set the ldp to NULL, and return the result of the unbind call.
632  */
633 static int
634 do_unbind(
635     Ri  *ri
636 )
637 {
638     int         rc = LDAP_SUCCESS;
639
640     if (( ri != NULL ) && ( ri->ri_ldp != NULL )) {
641         rc = ldap_unbind( ri->ri_ldp );
642         if ( rc != LDAP_SUCCESS ) {
643             Debug( LDAP_DEBUG_ANY,
644                     "Error: do_unbind: ldap_unbind failed for %s:%d: %s\n",
645                     ri->ri_hostname, ri->ri_port, ldap_err2string( rc ) );
646         }
647         ri->ri_ldp = NULL;
648     }
649     return rc;
650 }
651
652
653
654 /*
655  * Perform an LDAP bind operation to the replication site given
656  * by replica.  If replica->repl_ldp is non-NULL, then we unbind
657  * from the replica before rebinding.  It should be safe to call
658  * this to re-connect if the replica's connection goes away
659  * for some reason.
660  *
661  * Returns 0 on success, -1 if an LDAP error occurred, and a return
662  * code > 0 if some other error occurred, e.g. invalid bind method.
663  * If an LDAP error occurs, the LDAP error is returned in lderr.
664  */
665 static int
666 do_bind( 
667     Ri  *ri,
668     int *lderr
669 )
670 {
671     int         ldrc;
672     int         do_tls;
673
674     *lderr = 0;
675
676     if ( ri == NULL ) {
677         Debug( LDAP_DEBUG_ANY, "Error: do_bind: null ri ptr\n", 0, 0, 0 );
678         return( BIND_ERR_BADRI );
679     }
680
681     do_tls = ri->ri_tls;
682
683 retry:
684     if ( ri->ri_ldp != NULL ) {
685         ldrc = ldap_unbind( ri->ri_ldp );
686         if ( ldrc != LDAP_SUCCESS ) {
687             Debug( LDAP_DEBUG_ANY,
688                     "Error: do_bind: ldap_unbind failed: %s\n",
689                     ldap_err2string( ldrc ), 0, 0 );
690         }
691         ri->ri_ldp = NULL;
692     }
693     
694         if ( ri->ri_uri != NULL ) { /* new URI style */
695             Debug( LDAP_DEBUG_ARGS, "Initializing session to %s\n",
696                     ri->ri_uri, 0, 0 );
697
698                 ldrc = ldap_initialize( &(ri->ri_ldp), ri->ri_uri);
699
700                 if (ldrc != LDAP_SUCCESS) {
701                 Debug( LDAP_DEBUG_ANY, "Error: ldap_initialize(0, %s) failed: %s\n",
702                         ri->ri_uri, ldap_err2string(ldrc), 0 );
703                 return( BIND_ERR_OPEN );                
704                 }
705         } else { /* old HOST style */
706     Debug( LDAP_DEBUG_ARGS, "Initializing session to %s:%d\n",
707             ri->ri_hostname, ri->ri_port, 0 );
708
709     ri->ri_ldp = ldap_init( ri->ri_hostname, ri->ri_port );
710     if ( ri->ri_ldp == NULL ) {
711                 Debug( LDAP_DEBUG_ANY, "Error: ldap_init(%s, %d) failed: %s\n",
712                         ri->ri_hostname, ri->ri_port, sys_errlist[ errno ] );
713                 return( BIND_ERR_OPEN );
714     }
715     }
716
717         {       /* set version 3 */
718                 int err, version = LDAP_VERSION3;
719                 err = ldap_set_option(ri->ri_ldp,
720                         LDAP_OPT_PROTOCOL_VERSION, &version);
721
722                 if( err != LDAP_OPT_SUCCESS ) {
723                         Debug( LDAP_DEBUG_ANY,
724                                 "Error: ldap_set_option(%s, LDAP_OPT_VERSION, 3) failed!\n",
725                                 ri->ri_hostname, NULL, NULL );
726
727                         ldap_unbind( ri->ri_ldp );
728                         ri->ri_ldp = NULL;
729                         return BIND_ERR_VERSION;
730                 }
731         }
732
733     /*
734      * Set ldap library options to (1) not follow referrals, and 
735      * (2) restart the select() system call.
736      */
737         {
738                 int err;
739                 err = ldap_set_option(ri->ri_ldp, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
740
741                 if( err != LDAP_OPT_SUCCESS ) {
742                         Debug( LDAP_DEBUG_ANY,
743                                 "Error: ldap_set_option(%s,REFERRALS, OFF) failed!\n",
744                                 ri->ri_hostname, NULL, NULL );
745                         ldap_unbind( ri->ri_ldp );
746                         ri->ri_ldp = NULL;
747                         return BIND_ERR_REFERRALS;
748                 }
749         }
750         ldap_set_option(ri->ri_ldp, LDAP_OPT_RESTART, LDAP_OPT_ON);
751
752         if( do_tls ) {
753                 int err = ldap_start_tls_s(ri->ri_ldp, NULL, NULL);
754
755                 if( err != LDAP_SUCCESS ) {
756                         Debug( LDAP_DEBUG_ANY,
757                                 "%s: ldap_start_tls failed: %s (%d)\n",
758                                 ri->ri_tls == TLS_CRITICAL ? "Error" : "Warning",
759                                 ldap_err2string( err ), err );
760
761                         if( ri->ri_tls == TLS_CRITICAL ) {
762                                 *lderr = err;
763                                 ldap_unbind( ri->ri_ldp );
764                                 ri->ri_ldp = NULL;
765                                 return BIND_ERR_TLS_FAILED;
766                         }
767                         do_tls = TLS_OFF;
768                         goto retry;
769                 }
770         }
771
772     switch ( ri->ri_bind_method ) {
773     case LDAP_AUTH_SIMPLE:
774         /*
775          * Bind with a plaintext password.
776          */
777         Debug( LDAP_DEBUG_ARGS, "bind to %s:%d as %s (simple)\n",
778                 ri->ri_hostname, ri->ri_port, ri->ri_bind_dn );
779         ldrc = ldap_simple_bind_s( ri->ri_ldp, ri->ri_bind_dn,
780                 ri->ri_password );
781         if ( ldrc != LDAP_SUCCESS ) {
782             Debug( LDAP_DEBUG_ANY,
783                     "Error: ldap_simple_bind_s for %s:%d failed: %s\n",
784                     ri->ri_hostname, ri->ri_port, ldap_err2string( ldrc ));
785             *lderr = ldrc;
786                 ldap_unbind( ri->ri_ldp );
787                 ri->ri_ldp = NULL;
788             return( BIND_ERR_SIMPLE_FAILED );
789         }
790         break;
791
792         case LDAP_AUTH_SASL:
793         Debug( LDAP_DEBUG_ARGS, "bind to %s as %s via %s (SASL)\n",
794                 ri->ri_hostname,
795                 ri->ri_authcId ? ri->ri_authcId : "-",
796                 ri->ri_saslmech );
797
798 #ifdef HAVE_CYRUS_SASL
799         if( ri->ri_secprops != NULL ) {
800                 int err = ldap_set_option(ri->ri_ldp,
801                         LDAP_OPT_X_SASL_SECPROPS, ri->ri_secprops);
802
803                 if( err != LDAP_OPT_SUCCESS ) {
804                         Debug( LDAP_DEBUG_ANY,
805                                 "Error: ldap_set_option(%s,SECPROPS,\"%s\") failed!\n",
806                                 ri->ri_hostname, ri->ri_secprops, NULL );
807                         ldap_unbind( ri->ri_ldp );
808                         ri->ri_ldp = NULL;
809                         return BIND_ERR_SASL_FAILED;
810                 }
811         }
812
813         {
814                 void *defaults = lutil_sasl_defaults( ri->ri_ldp, ri->ri_saslmech,
815                     ri->ri_realm, ri->ri_authcId, ri->ri_password, ri->ri_authzId );
816
817                 ldrc = ldap_sasl_interactive_bind_s( ri->ri_ldp, ri->ri_bind_dn,
818                     ri->ri_saslmech, NULL, NULL,
819                     LDAP_SASL_QUIET, lutil_sasl_interact, defaults );
820
821                 lutil_sasl_freedefs( defaults );
822                 if ( ldrc != LDAP_SUCCESS ) {
823                         Debug( LDAP_DEBUG_ANY, "Error: LDAP SASL for %s:%d failed: %s\n",
824                             ri->ri_hostname, ri->ri_port, ldap_err2string( ldrc ));
825                         *lderr = ldrc;
826                         ldap_unbind( ri->ri_ldp );
827                         ri->ri_ldp = NULL;
828                         return( BIND_ERR_SASL_FAILED );
829                 }
830         }
831         break;
832 #else
833         Debug( LDAP_DEBUG_ANY,
834                 "Error: do_bind: SASL not supported %s:%d\n",
835                  ri->ri_hostname, ri->ri_port, NULL );
836         ldap_unbind( ri->ri_ldp );
837         ri->ri_ldp = NULL;
838         return( BIND_ERR_BAD_ATYPE );
839 #endif
840
841     default:
842         Debug(  LDAP_DEBUG_ANY,
843                 "Error: do_bind: unknown auth type \"%d\" for %s:%d\n",
844                 ri->ri_bind_method, ri->ri_hostname, ri->ri_port );
845         ldap_unbind( ri->ri_ldp );
846         ri->ri_ldp = NULL;
847         return( BIND_ERR_BAD_ATYPE );
848     }
849
850         {
851                 int err;
852                 LDAPControl c;
853                 LDAPControl *ctrls[2];
854                 ctrls[0] = &c;
855                 ctrls[1] = NULL;
856
857                 c.ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
858                 c.ldctl_value.bv_val = NULL;
859                 c.ldctl_value.bv_len = 0;
860                 c.ldctl_iscritical = 0;
861
862                 err = ldap_set_option(ri->ri_ldp, LDAP_OPT_SERVER_CONTROLS, &ctrls);
863
864                 if( err != LDAP_OPT_SUCCESS ) {
865                         Debug( LDAP_DEBUG_ANY, "Error: "
866                                 "ldap_set_option(%s, SERVER_CONTROLS, ManageDSAit) failed!\n",
867                                 ri->ri_hostname, NULL, NULL );
868                         ldap_unbind( ri->ri_ldp );
869                         ri->ri_ldp = NULL;
870                         return BIND_ERR_MANAGEDSAIT;
871                 }
872         }
873
874         return( BIND_OK );
875 }
876
877
878
879
880
881 /*
882  * For debugging.  Print the contents of an ldmarr array.
883  */
884 #ifdef SLAPD_UNUSED
885 static void
886 dump_ldm_array(
887     LDAPMod **ldmarr
888 )
889 {
890     int                  i, j;
891     LDAPMod             *ldm;
892     struct berval       *b;
893     char                *msgbuf;
894
895     for ( i = 0; ldmarr[ i ] != NULL; i++ ) {
896         ldm = ldmarr[ i ];
897         Debug( LDAP_DEBUG_TRACE,
898                 "Trace (%ld): *** ldmarr[ %d ] contents:\n",
899                 (long) getpid(), i, 0 );
900         Debug( LDAP_DEBUG_TRACE,
901                 "Trace (%ld): *** ldm->mod_op: %d\n",
902                 (long) getpid(), ldm->mod_op, 0 );
903         Debug( LDAP_DEBUG_TRACE,
904                 "Trace (%ld): *** ldm->mod_type: %s\n",
905                 (long) getpid(), ldm->mod_type, 0 );
906         if ( ldm->mod_bvalues != NULL ) {
907             for ( j = 0; ( b = ldm->mod_bvalues[ j ] ) != NULL; j++ ) {
908                 msgbuf = ch_malloc( b->bv_len + 512 );
909                 sprintf( msgbuf, "***** bv[ %d ] len = %ld, val = <%s>",
910                         j, b->bv_len, b->bv_val );
911                 Debug( LDAP_DEBUG_TRACE,
912                         "Trace (%ld):%s\n", (long) getpid(), msgbuf, 0 );
913                 free( msgbuf );
914             }
915         }
916     }
917 }
918 #endif