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