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