]> git.sur5r.net Git - openldap/blob - servers/slurpd/ldap_op.c
Suck in HEAD changes since 2.1alpha
[openldap] / servers / slurpd / ldap_op.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2002 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 = NULL, **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             assert( ldm );
293
294             /*
295              * We should have an attribute: value pair here.
296              * Construct the mod_bvalues part of the ldapmod struct.
297              */
298             if ( strcasecmp( type, ldm->mod_type )) {
299                 Debug( LDAP_DEBUG_ANY,
300                         "Error: malformed modify op, %s: %s (expecting %s:)\n",
301                         type, value, ldm->mod_type );
302                 continue;
303             }
304             ldm->mod_bvalues = ( struct berval ** )
305                     ch_realloc( ldm->mod_bvalues,
306                     ( nvals + 2 ) * sizeof( struct berval * ));
307             ldm->mod_bvalues[ nvals + 1 ] = NULL;
308             ldm->mod_bvalues[ nvals ] = ( struct berval * )
309                     ch_malloc( sizeof( struct berval ));
310             ldm->mod_bvalues[ nvals ]->bv_val = value;
311             ldm->mod_bvalues[ nvals ]->bv_len = len;
312             nvals++;
313         }
314     }
315     ldmarr[ nops ] = NULL;
316
317     if ( nops > 0 ) {
318         /* Actually perform the LDAP operation */
319         Debug( LDAP_DEBUG_ARGS, "replica %s:%d - modify dn \"%s\"\n",
320                 ri->ri_hostname, ri->ri_port, re->re_dn );
321         rc = ldap_modify_s( ri->ri_ldp, re->re_dn, ldmarr );
322     }
323     free_ldmarr( ldmarr );
324     return( rc );
325 }
326
327
328
329
330 /*
331  * Perform an ldap delete operation.
332  */
333 static int
334 op_ldap_delete(
335     Ri          *ri,
336     Re          *re,
337     char        **errmsg
338 )
339 {
340     int         rc;
341
342     Debug( LDAP_DEBUG_ARGS, "replica %s:%d - delete dn \"%s\"\n",
343             ri->ri_hostname, ri->ri_port, re->re_dn );
344     rc = ldap_delete_s( ri->ri_ldp, re->re_dn );
345
346     return( rc );
347 }
348
349
350
351
352 /*
353  * Perform an ldap modrdn operation.
354  */
355 #define GOT_NEWRDN              0x1
356 #define GOT_DELOLDRDN   0x2
357 #define GOT_NEWSUP              0x4
358
359 #define GOT_MODDN_REQ   (GOT_NEWRDN|GOT_DELOLDRDN)
360 #define GOT_ALL_MODDN(f)        (((f) & GOT_MODDN_REQ) == GOT_MODDN_REQ)
361 static int
362 op_ldap_modrdn(
363     Ri          *ri,
364     Re          *re,
365     char        **errmsg
366 )
367 {
368     int         rc = 0;
369     Mi          *mi;
370     int         i;
371         int             lderr = 0;
372     int         state = 0;
373     int         drdnflag = -1;
374     char        *newrdn = NULL;
375         char    *newsup = NULL;
376
377     if ( re->re_mods == NULL ) {
378         *errmsg = "No arguments given";
379         Debug( LDAP_DEBUG_ANY, "Error: op_ldap_modrdn: no arguments\n",
380                 0, 0, 0 );
381             return -1;
382     }
383
384     /*
385      * Get the arguments: should see newrdn: and deleteoldrdn: args.
386      */
387     for ( mi = re->re_mods, i = 0; mi[ i ].mi_type != NULL; i++ ) {
388         if ( !strcmp( mi[ i ].mi_type, T_NEWRDNSTR )) {
389                 if( state & GOT_NEWRDN ) {
390                 Debug( LDAP_DEBUG_ANY,
391                         "Error: op_ldap_modrdn: multiple newrdn arg \"%s\"\n",
392                         mi[ i ].mi_val, 0, 0 );
393                 *errmsg = "Multiple newrdn argument";
394                 return -1;
395                 }
396
397             newrdn = mi[ i ].mi_val;
398             state |= GOT_NEWRDN;
399
400         } else if ( !strcmp( mi[ i ].mi_type, T_DELOLDRDNSTR )) {
401                 if( state & GOT_DELOLDRDN ) {
402                 Debug( LDAP_DEBUG_ANY,
403                         "Error: op_ldap_modrdn: multiple deleteoldrdn arg \"%s\"\n",
404                         mi[ i ].mi_val, 0, 0 );
405                 *errmsg = "Multiple newrdn argument";
406                 return -1;
407                 }
408
409             state |= GOT_DELOLDRDN;
410             if ( !strcmp( mi[ i ].mi_val, "0" )) {
411                 drdnflag = 0;
412             } else if ( !strcmp( mi[ i ].mi_val, "1" )) {
413                 drdnflag = 1;
414             } else {
415                 Debug( LDAP_DEBUG_ANY,
416                         "Error: op_ldap_modrdn: bad deleteoldrdn arg \"%s\"\n",
417                         mi[ i ].mi_val, 0, 0 );
418                 *errmsg = "Incorrect argument to deleteoldrdn";
419                 return -1;
420             }
421
422         } else if ( !strcmp( mi[ i ].mi_type, T_NEWSUPSTR )) {
423                 if( state & GOT_NEWSUP ) {
424                 Debug( LDAP_DEBUG_ANY,
425                         "Error: op_ldap_modrdn: multiple newsuperior arg \"%s\"\n",
426                         mi[ i ].mi_val, 0, 0 );
427                 *errmsg = "Multiple newsuperior argument";
428                 return -1;
429                 }
430
431                 newsup = mi[ i ].mi_val;
432             state |= GOT_NEWSUP;
433
434         } else {
435             Debug( LDAP_DEBUG_ANY, "Error: op_ldap_modrdn: bad type \"%s\"\n",
436                     mi[ i ].mi_type, 0, 0 );
437             *errmsg = "Bad value in replication log entry";
438             return -1;
439         }
440     }
441
442     /*
443      * Punt if we don't have all the args.
444      */
445     if ( !GOT_ALL_MODDN(state) ) {
446         Debug( LDAP_DEBUG_ANY, "Error: op_ldap_modrdn: missing arguments\n",
447                 0, 0, 0 );
448         *errmsg = "Missing argument: requires \"newrdn\" and \"deleteoldrdn\"";
449         return -1;
450     }
451
452 #ifdef LDAP_DEBUG
453     if ( ldap_debug & LDAP_DEBUG_ARGS ) {
454         char buf[ 256 ];
455         char *buf2;
456         sprintf( buf, "%s:%d", ri->ri_hostname, ri->ri_port );
457         buf2 = (char *) ch_malloc( strlen( re->re_dn ) + strlen( mi->mi_val )
458                 + 10 );
459         sprintf( buf2, "(\"%s\" -> \"%s\")", re->re_dn, mi->mi_val );
460         Debug( LDAP_DEBUG_ARGS,
461                 "replica %s - modify rdn %s (flag: %d)\n",
462                 buf, buf2, drdnflag );
463         free( buf2 );
464     }
465 #endif /* LDAP_DEBUG */
466
467     assert( newrdn );
468
469     /* Do the modrdn */
470     rc = ldap_rename2_s( ri->ri_ldp, re->re_dn, newrdn, newsup, drdnflag );
471
472         ldap_get_option( ri->ri_ldp, LDAP_OPT_ERROR_NUMBER, &lderr);
473     return( lderr );
474 }
475
476
477
478 /*
479  * Allocate and initialize an ldapmod struct.
480  */
481 static LDAPMod *
482 alloc_ldapmod( void )
483 {
484     LDAPMod     *ldm;
485
486     ldm = ( struct ldapmod * ) ch_malloc( sizeof ( struct ldapmod ));
487     ldm->mod_type = NULL;
488     ldm->mod_bvalues = ( struct berval ** ) NULL;
489     return( ldm );
490 }
491
492
493
494 /*
495  * Free an ldapmod struct associated mod_bvalues.  NOTE - it is assumed
496  * that mod_bvalues and mod_type contain pointers to the same block of memory
497  * pointed to by the repl struct.  Therefore, it's not freed here.
498  */
499 static void
500 free_ldapmod(
501 LDAPMod *ldm )
502 {
503     int         i;
504
505     if ( ldm == NULL ) {
506         return;
507     }
508     if ( ldm->mod_bvalues != NULL ) {
509         for ( i = 0; ldm->mod_bvalues[ i ] != NULL; i++ ) {
510             free( ldm->mod_bvalues[ i ] );
511         }
512         free( ldm->mod_bvalues );
513     }
514     free( ldm );
515     return;
516 }
517
518
519 /*
520  * Free an an array of LDAPMod pointers and the LDAPMod structs they point
521  * to.
522  */
523 static void
524 free_ldmarr(
525 LDAPMod **ldmarr )
526 {
527     int i;
528
529     for ( i = 0; ldmarr[ i ] != NULL; i++ ) {
530         free_ldapmod( ldmarr[ i ] );
531     }
532     free( ldmarr );
533 }
534
535
536 /*
537  * Create a berval with a single value. 
538  */
539 static struct berval **
540 make_singlevalued_berval( 
541 char    *value,
542 int     len )
543 {
544     struct berval **p;
545
546     p = ( struct berval ** ) ch_malloc( 2 * sizeof( struct berval * ));
547     p[ 0 ] = ( struct berval * ) ch_malloc( sizeof( struct berval ));
548     p[ 1 ] = NULL;
549     p[ 0 ]->bv_val = value;
550     p[ 0 ]->bv_len = len;
551     return( p );
552 }
553
554
555 /*
556  * Given a modification type (string), return an enumerated type.
557  * Avoids ugly copy in op_ldap_modify - lets us use a switch statement
558  * there.
559  */
560 static int
561 getmodtype( 
562 char *type )
563 {
564     if ( !strcmp( type, T_MODSEPSTR )) {
565         return( T_MODSEP );
566     }
567     if ( !strcmp( type, T_MODOPADDSTR )) {
568         return( T_MODOPADD );
569     }
570     if ( !strcmp( type, T_MODOPREPLACESTR )) {
571         return( T_MODOPREPLACE );
572     }
573     if ( !strcmp( type, T_MODOPDELETESTR )) {
574         return( T_MODOPDELETE );
575     }
576     return( T_ERR );
577 }
578
579
580 /*
581  * Perform an LDAP unbind operation.  If replica is NULL, or the
582  * repl_ldp is NULL, just return LDAP_SUCCESS.  Otherwise, unbind,
583  * set the ldp to NULL, and return the result of the unbind call.
584  */
585 static int
586 do_unbind(
587     Ri  *ri
588 )
589 {
590     int         rc = LDAP_SUCCESS;
591
592     if (( ri != NULL ) && ( ri->ri_ldp != NULL )) {
593         rc = ldap_unbind( ri->ri_ldp );
594         if ( rc != LDAP_SUCCESS ) {
595             Debug( LDAP_DEBUG_ANY,
596                     "Error: do_unbind: ldap_unbind failed for %s:%d: %s\n",
597                     ri->ri_hostname, ri->ri_port, ldap_err2string( rc ) );
598         }
599         ri->ri_ldp = NULL;
600     }
601     return rc;
602 }
603
604
605
606 /*
607  * Perform an LDAP bind operation to the replication site given
608  * by replica.  If replica->repl_ldp is non-NULL, then we unbind
609  * from the replica before rebinding.  It should be safe to call
610  * this to re-connect if the replica's connection goes away
611  * for some reason.
612  *
613  * Returns 0 on success, -1 if an LDAP error occurred, and a return
614  * code > 0 if some other error occurred, e.g. invalid bind method.
615  * If an LDAP error occurs, the LDAP error is returned in lderr.
616  */
617 static int
618 do_bind( 
619     Ri  *ri,
620     int *lderr
621 )
622 {
623     int         ldrc;
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 ? "Error" : "Warning",
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         {
746                 char *passwd = ri->ri_password ? ber_strdup( ri->ri_password ) : NULL;
747                 void *defaults = lutil_sasl_defaults( ri->ri_ldp, ri->ri_saslmech,
748                     ri->ri_realm, ri->ri_authcId, passwd, ri->ri_authzId );
749
750                 ldrc = ldap_sasl_interactive_bind_s( ri->ri_ldp, ri->ri_bind_dn,
751                     ri->ri_saslmech, NULL, NULL,
752                     LDAP_SASL_QUIET, lutil_sasl_interact, defaults );
753                 if ( ldrc != LDAP_SUCCESS ) {
754                         Debug( LDAP_DEBUG_ANY, "Error: LDAP SASL for %s:%d failed: %s\n",
755                             ri->ri_hostname, ri->ri_port, ldap_err2string( ldrc ));
756                         *lderr = ldrc;
757                         ldap_unbind( ri->ri_ldp );
758                         ri->ri_ldp = NULL;
759                         return( BIND_ERR_SASL_FAILED );
760                 }
761
762                 ber_memfree( passwd );
763                 ber_memfree( defaults );
764         }
765         break;
766 #else
767         Debug( LDAP_DEBUG_ANY,
768                 "Error: do_bind: SASL not supported %s:%d\n",
769                  ri->ri_hostname, ri->ri_port, NULL );
770         ldap_unbind( ri->ri_ldp );
771         ri->ri_ldp = NULL;
772         return( BIND_ERR_BAD_ATYPE );
773 #endif
774
775     default:
776         Debug(  LDAP_DEBUG_ANY,
777                 "Error: do_bind: unknown auth type \"%d\" for %s:%d\n",
778                 ri->ri_bind_method, ri->ri_hostname, ri->ri_port );
779         ldap_unbind( ri->ri_ldp );
780         ri->ri_ldp = NULL;
781         return( BIND_ERR_BAD_ATYPE );
782     }
783
784         {
785                 int err;
786                 LDAPControl c;
787                 LDAPControl *ctrls[2];
788                 ctrls[0] = &c;
789                 ctrls[1] = NULL;
790
791                 c.ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
792                 c.ldctl_value.bv_val = NULL;
793                 c.ldctl_value.bv_len = 0;
794                 c.ldctl_iscritical = 0;
795
796                 err = ldap_set_option(ri->ri_ldp, LDAP_OPT_SERVER_CONTROLS, &ctrls);
797
798                 if( err != LDAP_OPT_SUCCESS ) {
799                         Debug( LDAP_DEBUG_ANY, "Error: "
800                                 "ldap_set_option(%s, SERVER_CONTROLS, ManageDSAit) failed!\n",
801                                 ri->ri_hostname, NULL, NULL );
802                         ldap_unbind( ri->ri_ldp );
803                         ri->ri_ldp = NULL;
804                         return BIND_ERR_MANAGEDSAIT;
805                 }
806         }
807
808         return( BIND_OK );
809 }
810
811
812
813
814
815 /*
816  * For debugging.  Print the contents of an ldmarr array.
817  */
818 static void
819 dump_ldm_array(
820     LDAPMod **ldmarr
821 )
822 {
823     int                  i, j;
824     LDAPMod             *ldm;
825     struct berval       *b;
826     char                *msgbuf;
827
828     for ( i = 0; ldmarr[ i ] != NULL; i++ ) {
829         ldm = ldmarr[ i ];
830         Debug( LDAP_DEBUG_TRACE,
831                 "Trace (%ld): *** ldmarr[ %d ] contents:\n",
832                 (long) getpid(), i, 0 );
833         Debug( LDAP_DEBUG_TRACE,
834                 "Trace (%ld): *** ldm->mod_op: %d\n",
835                 (long) getpid(), ldm->mod_op, 0 );
836         Debug( LDAP_DEBUG_TRACE,
837                 "Trace (%ld): *** ldm->mod_type: %s\n",
838                 (long) getpid(), ldm->mod_type, 0 );
839         if ( ldm->mod_bvalues != NULL ) {
840             for ( j = 0; ( b = ldm->mod_bvalues[ j ] ) != NULL; j++ ) {
841                 msgbuf = ch_malloc( b->bv_len + 512 );
842                 sprintf( msgbuf, "***** bv[ %d ] len = %ld, val = <%s>",
843                         j, b->bv_len, b->bv_val );
844                 Debug( LDAP_DEBUG_TRACE,
845                         "Trace (%ld):%s\n", (long) getpid(), msgbuf, 0 );
846                 free( msgbuf );
847             }
848         }
849     }
850 }