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