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