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