]> git.sur5r.net Git - openldap/blob - servers/slurpd/ldap_op.c
Changes from HEAD for beta
[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
767     *lderr = 0;
768
769     if ( ri == NULL ) {
770 #ifdef NEW_LOGGING
771         LDAP_LOG ( OPERATION, ERR, "do_bind: null ri ptr\n" , 0, 0, 0 );
772 #else
773         Debug( LDAP_DEBUG_ANY, "Error: do_bind: null ri ptr\n", 0, 0, 0 );
774 #endif
775         return( BIND_ERR_BADRI );
776     }
777
778 retry:
779     if ( ri->ri_ldp != NULL ) {
780         ldrc = ldap_unbind( ri->ri_ldp );
781         if ( ldrc != LDAP_SUCCESS ) {
782 #ifdef NEW_LOGGING
783                 LDAP_LOG ( OPERATION, ERR, 
784                         "do_bind: ldap_unbind failed: %s\n", ldap_err2string( ldrc ), 0, 0 );
785 #else
786             Debug( LDAP_DEBUG_ANY,
787                     "Error: do_bind: ldap_unbind failed: %s\n",
788                     ldap_err2string( ldrc ), 0, 0 );
789 #endif
790         }
791         ri->ri_ldp = NULL;
792     }
793     
794         if ( ri->ri_uri != NULL ) { /* new URI style */
795 #ifdef NEW_LOGGING
796                 LDAP_LOG ( OPERATION, ARGS, 
797                         "do_bind: Initializing session to %s\n", 
798                     ri->ri_uri, 0, 0);
799 #else
800             Debug( LDAP_DEBUG_ARGS, "Initializing session to %s\n",
801                     ri->ri_uri, 0, 0 );
802 #endif
803
804                 ldrc = ldap_initialize( &(ri->ri_ldp), ri->ri_uri);
805
806                 if (ldrc != LDAP_SUCCESS) {
807 #ifdef NEW_LOGGING
808                 LDAP_LOG ( OPERATION, ERR, 
809                         "do_bind: ldap_initalize (0, %s) failed: %s\n",
810                         ri->ri_uri, ldap_err2string(ldrc), 0 );
811 #else
812                 Debug( LDAP_DEBUG_ANY, "Error: ldap_initialize(0, %s) failed: %s\n",
813                         ri->ri_uri, ldap_err2string(ldrc), 0 );
814 #endif
815                 return( BIND_ERR_OPEN );                
816                 }
817         } else { /* old HOST style */
818 #ifdef NEW_LOGGING
819         LDAP_LOG ( OPERATION, ARGS, 
820                 "do_bind: Initializing session to %s:%d\n", 
821             ri->ri_hostname, ri->ri_port, 0 );
822 #else
823     Debug( LDAP_DEBUG_ARGS, "Initializing session to %s:%d\n",
824             ri->ri_hostname, ri->ri_port, 0 );
825 #endif
826
827     ri->ri_ldp = ldap_init( ri->ri_hostname, ri->ri_port );
828     if ( ri->ri_ldp == NULL ) {
829 #ifdef NEW_LOGGING
830                 LDAP_LOG ( OPERATION, ERR, 
831                         "do_bind: ldap_init (%s, %d) failed: %s\n",
832                         ri->ri_hostname, ri->ri_port, sys_errlist[ errno ] );
833 #else
834                 Debug( LDAP_DEBUG_ANY, "Error: ldap_init(%s, %d) failed: %s\n",
835                         ri->ri_hostname, ri->ri_port, sys_errlist[ errno ] );
836 #endif
837                 return( BIND_ERR_OPEN );
838     }
839     }
840
841         {       /* set version 3 */
842                 int err, version = 3;
843                 err = ldap_set_option(ri->ri_ldp,
844                         LDAP_OPT_PROTOCOL_VERSION, &version);
845
846                 if( err != LDAP_OPT_SUCCESS ) {
847 #ifdef NEW_LOGGING
848                         LDAP_LOG ( OPERATION, ERR, "do_bind: "
849                                 "Error: ldap_set_option(%s, LDAP_OPT_VERSION, 3) failed!\n",
850                                 ri->ri_hostname, 0, 0 );
851 #else
852                         Debug( LDAP_DEBUG_ANY,
853                                 "Error: ldap_set_option(%s, LDAP_OPT_VERSION, 3) failed!\n",
854                                 ri->ri_hostname, NULL, NULL );
855 #endif
856
857                         ldap_unbind( ri->ri_ldp );
858                         ri->ri_ldp = NULL;
859                         return BIND_ERR_VERSION;
860                 }
861         }
862
863     /*
864      * Set ldap library options to (1) not follow referrals, and 
865      * (2) restart the select() system call.
866      */
867         {
868                 int err;
869                 err = ldap_set_option(ri->ri_ldp, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
870
871                 if( err != LDAP_OPT_SUCCESS ) {
872 #ifdef NEW_LOGGING
873                         LDAP_LOG ( OPERATION, ERR, "do_bind: "
874                                 "Error: ldap_set_option(%s, REFERRALS, OFF) failed!\n",
875                                 ri->ri_hostname, 0, 0 );
876 #else
877                         Debug( LDAP_DEBUG_ANY,
878                                 "Error: ldap_set_option(%s,REFERRALS, OFF) failed!\n",
879                                 ri->ri_hostname, NULL, NULL );
880 #endif
881                         ldap_unbind( ri->ri_ldp );
882                         ri->ri_ldp = NULL;
883                         return BIND_ERR_REFERRALS;
884                 }
885         }
886         ldap_set_option(ri->ri_ldp, LDAP_OPT_RESTART, LDAP_OPT_ON);
887
888         if( ri->ri_tls ) {
889                 int err = ldap_start_tls_s(ri->ri_ldp, NULL, NULL);
890
891                 if( err != LDAP_SUCCESS ) {
892 #ifdef NEW_LOGGING
893                         LDAP_LOG ( OPERATION, ERR, "do_bind: "
894                                 "%s: ldap_start_tls failed: %s (%d)\n",
895                                 ri->ri_tls == TLS_CRITICAL ? "Error" : "Warning",
896                                 ldap_err2string( err ), err );
897 #else
898                         Debug( LDAP_DEBUG_ANY,
899                                 "%s: ldap_start_tls failed: %s (%d)\n",
900                                 ri->ri_tls == TLS_CRITICAL ? "Error" : "Warning",
901                                 ldap_err2string( err ), err );
902 #endif
903
904                         if( ri->ri_tls == TLS_CRITICAL ) {
905                                 *lderr = err;
906                                 ldap_unbind( ri->ri_ldp );
907                                 ri->ri_ldp = NULL;
908                                 return BIND_ERR_TLS_FAILED;
909                         }
910                         ri->ri_tls = TLS_OFF;
911                         goto retry;
912                 }
913         }
914
915     switch ( ri->ri_bind_method ) {
916     case AUTH_SIMPLE:
917         /*
918          * Bind with a plaintext password.
919          */
920 #ifdef NEW_LOGGING
921         LDAP_LOG ( OPERATION, ARGS, 
922                 "do_bind: bind to %s:%d as %s (simple)\n", 
923                 ri->ri_hostname, ri->ri_port, ri->ri_bind_dn );
924 #else
925         Debug( LDAP_DEBUG_ARGS, "bind to %s:%d as %s (simple)\n",
926                 ri->ri_hostname, ri->ri_port, ri->ri_bind_dn );
927 #endif
928         ldrc = ldap_simple_bind_s( ri->ri_ldp, ri->ri_bind_dn,
929                 ri->ri_password );
930         if ( ldrc != LDAP_SUCCESS ) {
931 #ifdef NEW_LOGGING
932                 LDAP_LOG ( OPERATION, ERR, "do_bind: "
933                     "Error: ldap_simple_bind_s for %s:%d failed: %s\n",
934                     ri->ri_hostname, ri->ri_port, ldap_err2string( ldrc ) );
935 #else
936             Debug( LDAP_DEBUG_ANY,
937                     "Error: ldap_simple_bind_s for %s:%d failed: %s\n",
938                     ri->ri_hostname, ri->ri_port, ldap_err2string( ldrc ));
939 #endif
940             *lderr = ldrc;
941                 ldap_unbind( ri->ri_ldp );
942                 ri->ri_ldp = NULL;
943             return( BIND_ERR_SIMPLE_FAILED );
944         }
945         break;
946
947         case AUTH_SASL:
948 #ifdef NEW_LOGGING
949         LDAP_LOG ( OPERATION, ARGS, 
950                 "do_bind: bind to %s as %s via %s (SASL)\n", 
951                 ri->ri_hostname,
952                 ri->ri_authcId ? ri->ri_authcId : "-",
953                 ri->ri_saslmech );
954 #else
955         Debug( LDAP_DEBUG_ARGS, "bind to %s as %s via %s (SASL)\n",
956                 ri->ri_hostname,
957                 ri->ri_authcId ? ri->ri_authcId : "-",
958                 ri->ri_saslmech );
959 #endif
960
961 #ifdef HAVE_CYRUS_SASL
962         if( ri->ri_secprops != NULL ) {
963                 int err = ldap_set_option(ri->ri_ldp,
964                         LDAP_OPT_X_SASL_SECPROPS, ri->ri_secprops);
965
966                 if( err != LDAP_OPT_SUCCESS ) {
967 #ifdef NEW_LOGGING
968                         LDAP_LOG ( OPERATION, ERR, "do_bind: "
969                                 "Error: ldap_set_option(%s,SECPROPS,\"%s\") failed!\n",
970                                 ri->ri_hostname, ri->ri_secprops, 0 );
971 #else
972                         Debug( LDAP_DEBUG_ANY,
973                                 "Error: ldap_set_option(%s,SECPROPS,\"%s\") failed!\n",
974                                 ri->ri_hostname, ri->ri_secprops, NULL );
975 #endif
976                         ldap_unbind( ri->ri_ldp );
977                         ri->ri_ldp = NULL;
978                         return BIND_ERR_SASL_FAILED;
979                 }
980         }
981
982         {
983                 void *defaults = lutil_sasl_defaults( ri->ri_ldp, ri->ri_saslmech,
984                     ri->ri_realm, ri->ri_authcId, ri->ri_password, ri->ri_authzId );
985
986                 ldrc = ldap_sasl_interactive_bind_s( ri->ri_ldp, ri->ri_bind_dn,
987                     ri->ri_saslmech, NULL, NULL,
988                     LDAP_SASL_QUIET, lutil_sasl_interact, defaults );
989
990                 lutil_sasl_freedefs( defaults );
991                 if ( ldrc != LDAP_SUCCESS ) {
992 #ifdef NEW_LOGGING
993                         LDAP_LOG ( OPERATION, ERR, "do_bind: "
994                                 "Error: LDAP SASL for %s:%d failed: %s\n",
995                             ri->ri_hostname, ri->ri_port, ldap_err2string( ldrc ) );
996 #else
997                         Debug( LDAP_DEBUG_ANY, "Error: LDAP SASL for %s:%d failed: %s\n",
998                             ri->ri_hostname, ri->ri_port, ldap_err2string( ldrc ));
999 #endif
1000                         *lderr = ldrc;
1001                         ldap_unbind( ri->ri_ldp );
1002                         ri->ri_ldp = NULL;
1003                         return( BIND_ERR_SASL_FAILED );
1004                 }
1005         }
1006         break;
1007 #else
1008 #ifdef NEW_LOGGING
1009         LDAP_LOG ( OPERATION, ERR, "do_bind: "
1010                 "Error: do_bind: SASL not supported %s:%d\n",
1011                 ri->ri_hostname, ri->ri_port, 0 );
1012 #else
1013         Debug( LDAP_DEBUG_ANY,
1014                 "Error: do_bind: SASL not supported %s:%d\n",
1015                  ri->ri_hostname, ri->ri_port, NULL );
1016 #endif
1017         ldap_unbind( ri->ri_ldp );
1018         ri->ri_ldp = NULL;
1019         return( BIND_ERR_BAD_ATYPE );
1020 #endif
1021
1022     default:
1023 #ifdef NEW_LOGGING
1024         LDAP_LOG ( OPERATION, ERR, "do_bind: "
1025                 "Error: do_bind: unknown auth type \"%d\" for %s:%d\n",
1026                 ri->ri_bind_method, ri->ri_hostname, ri->ri_port );
1027 #else
1028         Debug(  LDAP_DEBUG_ANY,
1029                 "Error: do_bind: unknown auth type \"%d\" for %s:%d\n",
1030                 ri->ri_bind_method, ri->ri_hostname, ri->ri_port );
1031 #endif
1032         ldap_unbind( ri->ri_ldp );
1033         ri->ri_ldp = NULL;
1034         return( BIND_ERR_BAD_ATYPE );
1035     }
1036
1037         {
1038                 int err;
1039                 LDAPControl c;
1040                 LDAPControl *ctrls[2];
1041                 ctrls[0] = &c;
1042                 ctrls[1] = NULL;
1043
1044                 c.ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
1045                 c.ldctl_value.bv_val = NULL;
1046                 c.ldctl_value.bv_len = 0;
1047                 c.ldctl_iscritical = 0;
1048
1049                 err = ldap_set_option(ri->ri_ldp, LDAP_OPT_SERVER_CONTROLS, &ctrls);
1050
1051                 if( err != LDAP_OPT_SUCCESS ) {
1052 #ifdef NEW_LOGGING
1053                         LDAP_LOG ( OPERATION, ERR, "do_bind: "
1054                                 "ldap_set_option(%s, SERVER_CONTROLS, ManageDSAit) failed!\n",
1055                                 ri->ri_hostname, 0, 0 );
1056 #else
1057                         Debug( LDAP_DEBUG_ANY, "Error: "
1058                                 "ldap_set_option(%s, SERVER_CONTROLS, ManageDSAit) failed!\n",
1059                                 ri->ri_hostname, NULL, NULL );
1060 #endif
1061                         ldap_unbind( ri->ri_ldp );
1062                         ri->ri_ldp = NULL;
1063                         return BIND_ERR_MANAGEDSAIT;
1064                 }
1065         }
1066
1067         return( BIND_OK );
1068 }
1069
1070
1071
1072
1073
1074 /*
1075  * For debugging.  Print the contents of an ldmarr array.
1076  */
1077 static void
1078 dump_ldm_array(
1079     LDAPMod **ldmarr
1080 )
1081 {
1082     int                  i, j;
1083     LDAPMod             *ldm;
1084     struct berval       *b;
1085     char                *msgbuf;
1086
1087     for ( i = 0; ldmarr[ i ] != NULL; i++ ) {
1088         ldm = ldmarr[ i ];
1089 #ifdef NEW_LOGGING
1090         LDAP_LOG ( OPERATION, INFO, "dump_ldm_array: "
1091                 "Trace (%ld): *** ldmarr[ %d ] contents:\n",
1092                 (long) getpid(), i, 0 );
1093         LDAP_LOG ( OPERATION, INFO, "dump_ldm_array: "
1094                 "Trace (%ld): *** ldm->mod_op: %d\n",
1095                 (long) getpid(), ldm->mod_op, 0 );
1096         LDAP_LOG ( OPERATION, INFO, "dump_ldm_array: "
1097                 "Trace (%ld): *** ldm->mod_type: %s\n",
1098                 (long) getpid(), ldm->mod_type, 0 );
1099 #else
1100         Debug( LDAP_DEBUG_TRACE,
1101                 "Trace (%ld): *** ldmarr[ %d ] contents:\n",
1102                 (long) getpid(), i, 0 );
1103         Debug( LDAP_DEBUG_TRACE,
1104                 "Trace (%ld): *** ldm->mod_op: %d\n",
1105                 (long) getpid(), ldm->mod_op, 0 );
1106         Debug( LDAP_DEBUG_TRACE,
1107                 "Trace (%ld): *** ldm->mod_type: %s\n",
1108                 (long) getpid(), ldm->mod_type, 0 );
1109 #endif
1110         if ( ldm->mod_bvalues != NULL ) {
1111             for ( j = 0; ( b = ldm->mod_bvalues[ j ] ) != NULL; j++ ) {
1112                 msgbuf = ch_malloc( b->bv_len + 512 );
1113                 sprintf( msgbuf, "***** bv[ %d ] len = %ld, val = <%s>",
1114                         j, b->bv_len, b->bv_val );
1115 #ifdef NEW_LOGGING
1116                 LDAP_LOG ( OPERATION, INFO, "dump_ldm_array: "
1117                         "Trace (%ld):%s\n", (long) getpid(), msgbuf, 0 );
1118 #else
1119                 Debug( LDAP_DEBUG_TRACE,
1120                         "Trace (%ld):%s\n", (long) getpid(), msgbuf, 0 );
1121 #endif
1122                 free( msgbuf );
1123             }
1124         }
1125     }
1126 }