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