]> git.sur5r.net Git - openldap/blob - servers/slurpd/ldap_op.c
Update slurpd(8)
[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 #ifdef LDAP_MOD_INCREMENT
357         case T_MODOPINCREMENT:
358             state = T_MODOPINCREMENT;
359             ldmarr = ( LDAPMod ** )
360                     ch_realloc(ldmarr, (( nops + 2 ) * ( sizeof( LDAPMod * ))));
361             ldmarr[ nops ] = ldm = alloc_ldapmod();
362             ldm->mod_op = LDAP_MOD_INCREMENT | LDAP_MOD_BVALUES;
363             ldm->mod_type = value;
364             nvals = 0;
365             nops++;
366             break;
367 #endif
368         default:
369             if ( state == AWAITING_OP ) {
370 #ifdef NEW_LOGGING
371                 LDAP_LOG ( OPERATION, ERR, 
372                         "op_ldap_modify: Error: unknown mod type \"%s\"\n", type, 0, 0 );
373 #else
374                 Debug( LDAP_DEBUG_ANY,
375                         "Error: op_ldap_modify: unknown mod type \"%s\"\n",
376                         type, 0, 0 );
377 #endif
378                 continue;
379             }
380
381             assert( ldm );
382
383             /*
384              * We should have an attribute: value pair here.
385              * Construct the mod_bvalues part of the ldapmod struct.
386              */
387             if ( strcasecmp( type, ldm->mod_type )) {
388 #ifdef NEW_LOGGING
389                 LDAP_LOG ( OPERATION, ERR, 
390                         "op_ldap_modify: Error: "
391                         "malformed modify op, %s: %s (expecting \"%s\")\n", 
392                         type, value, ldm->mod_type );
393 #else
394                 Debug( LDAP_DEBUG_ANY,
395                         "Error: malformed modify op, %s: %s (expecting %s:)\n",
396                         type, value, ldm->mod_type );
397 #endif
398                 continue;
399             }
400             ldm->mod_bvalues = ( struct berval ** )
401                     ch_realloc( ldm->mod_bvalues,
402                     ( nvals + 2 ) * sizeof( struct berval * ));
403             ldm->mod_bvalues[ nvals + 1 ] = NULL;
404             ldm->mod_bvalues[ nvals ] = ( struct berval * )
405                     ch_malloc( sizeof( struct berval ));
406             ldm->mod_bvalues[ nvals ]->bv_val = value;
407             ldm->mod_bvalues[ nvals ]->bv_len = len;
408             nvals++;
409         }
410     }
411     ldmarr[ nops ] = NULL;
412
413     if ( nops > 0 ) {
414         /* Actually perform the LDAP operation */
415 #ifdef NEW_LOGGING
416         LDAP_LOG ( OPERATION, DETAIL1, 
417                 "op_ldap_modify: replica %s:%d - modify dn \"%s\"\n", 
418                 ri->ri_hostname, ri->ri_port, re->re_dn );
419 #else
420         Debug( LDAP_DEBUG_ARGS, "replica %s:%d - modify dn \"%s\"\n",
421                 ri->ri_hostname, ri->ri_port, re->re_dn );
422 #endif
423         rc = ldap_modify_s( ri->ri_ldp, re->re_dn, ldmarr );
424         ldap_get_option( ri->ri_ldp, LDAP_OPT_ERROR_STRING, errmsg);
425         *errfree = 1;
426     }
427     free_ldmarr( ldmarr );
428     return( rc );
429 }
430
431
432
433
434 /*
435  * Perform an ldap delete operation.
436  */
437 static int
438 op_ldap_delete(
439     Ri          *ri,
440     Re          *re,
441     char        **errmsg,
442     int         *errfree
443 )
444 {
445     int         rc;
446
447 #ifdef NEW_LOGGING
448         LDAP_LOG ( OPERATION, ARGS, 
449                 "op_ldap_delete: replica %s:%d - delete dn \"%s\"\n",
450             ri->ri_hostname, ri->ri_port, re->re_dn );
451 #else
452     Debug( LDAP_DEBUG_ARGS, "replica %s:%d - delete dn \"%s\"\n",
453             ri->ri_hostname, ri->ri_port, re->re_dn );
454 #endif
455     rc = ldap_delete_s( ri->ri_ldp, re->re_dn );
456     ldap_get_option( ri->ri_ldp, LDAP_OPT_ERROR_STRING, errmsg);
457     *errfree = 1;
458
459     return( rc );
460 }
461
462
463
464
465 /*
466  * Perform an ldap modrdn operation.
467  */
468 #define GOT_NEWRDN              0x1
469 #define GOT_DELOLDRDN   0x2
470 #define GOT_NEWSUP              0x4
471
472 #define GOT_MODDN_REQ   (GOT_NEWRDN|GOT_DELOLDRDN)
473 #define GOT_ALL_MODDN(f)        (((f) & GOT_MODDN_REQ) == GOT_MODDN_REQ)
474 static int
475 op_ldap_modrdn(
476     Ri          *ri,
477     Re          *re,
478     char        **errmsg,
479     int         *errfree
480 )
481 {
482     int         rc = 0;
483     Mi          *mi;
484     int         i;
485         int             lderr = 0;
486     int         state = 0;
487     int         drdnflag = -1;
488     char        *newrdn = NULL;
489         char    *newsup = NULL;
490
491     if ( re->re_mods == NULL ) {
492         *errmsg = "No arguments given";
493 #ifdef NEW_LOGGING
494         LDAP_LOG ( OPERATION, ERR, 
495                 "op_ldap_modrdn: Error: no arguments\n" , 0, 0, 0 );
496 #else
497         Debug( LDAP_DEBUG_ANY, "Error: op_ldap_modrdn: no arguments\n",
498                 0, 0, 0 );
499 #endif
500             return -1;
501     }
502
503     /*
504      * Get the arguments: should see newrdn: and deleteoldrdn: args.
505      */
506     for ( mi = re->re_mods, i = 0; mi[ i ].mi_type != NULL; i++ ) {
507         if ( !strcmp( mi[ i ].mi_type, T_NEWRDNSTR )) {
508                 if( state & GOT_NEWRDN ) {
509 #ifdef NEW_LOGGING
510                 LDAP_LOG ( OPERATION, ERR, 
511                         "op_ldap_modrdn: Error: multiple newrdn arg \"%s\"\n",
512                         mi[ i ].mi_val, 0, 0 );
513 #else
514                 Debug( LDAP_DEBUG_ANY,
515                         "Error: op_ldap_modrdn: multiple newrdn arg \"%s\"\n",
516                         mi[ i ].mi_val, 0, 0 );
517 #endif
518                 *errmsg = "Multiple newrdn argument";
519                 return -1;
520                 }
521
522             newrdn = mi[ i ].mi_val;
523             state |= GOT_NEWRDN;
524
525         } else if ( !strcmp( mi[ i ].mi_type, T_DELOLDRDNSTR )) {
526                 if( state & GOT_DELOLDRDN ) {
527 #ifdef NEW_LOGGING
528                 LDAP_LOG ( OPERATION, ERR, 
529                         "op_ldap_modrdn: Error: multiple deleteoldrdn arg \"%s\"\n",
530                         mi[ i ].mi_val, 0, 0 );
531 #else
532                 Debug( LDAP_DEBUG_ANY,
533                         "Error: op_ldap_modrdn: multiple deleteoldrdn arg \"%s\"\n",
534                         mi[ i ].mi_val, 0, 0 );
535 #endif
536                 *errmsg = "Multiple newrdn argument";
537                 return -1;
538                 }
539
540             state |= GOT_DELOLDRDN;
541             if ( !strcmp( mi[ i ].mi_val, "0" )) {
542                 drdnflag = 0;
543             } else if ( !strcmp( mi[ i ].mi_val, "1" )) {
544                 drdnflag = 1;
545             } else {
546 #ifdef NEW_LOGGING
547                 LDAP_LOG ( OPERATION, ERR, 
548                         "op_ldap_modrdn: Error: bad deleteoldrdn arg \"%s\"\n",
549                         mi[ i ].mi_val, 0, 0 );
550 #else
551                 Debug( LDAP_DEBUG_ANY,
552                         "Error: op_ldap_modrdn: bad deleteoldrdn arg \"%s\"\n",
553                         mi[ i ].mi_val, 0, 0 );
554 #endif
555                 *errmsg = "Incorrect argument to deleteoldrdn";
556                 return -1;
557             }
558
559         } else if ( !strcmp( mi[ i ].mi_type, T_NEWSUPSTR )) {
560                 if( state & GOT_NEWSUP ) {
561 #ifdef NEW_LOGGING
562                 LDAP_LOG ( OPERATION, ERR, 
563                         "op_ldap_modrdn: Error: multiple newsuperior arg \"%s\"\n",
564                         mi[ i ].mi_val, 0, 0 );
565 #else
566                 Debug( LDAP_DEBUG_ANY,
567                         "Error: op_ldap_modrdn: multiple newsuperior arg \"%s\"\n",
568                         mi[ i ].mi_val, 0, 0 );
569 #endif
570                 *errmsg = "Multiple newsuperior argument";
571                 return -1;
572                 }
573
574                 newsup = mi[ i ].mi_val;
575             state |= GOT_NEWSUP;
576
577         } else {
578 #ifdef NEW_LOGGING
579                 LDAP_LOG ( OPERATION, ERR, 
580                         "op_ldap_modrdn: Error: bad type \"%s\"\n",
581                         mi[ i ].mi_type, 0, 0 );
582 #else
583             Debug( LDAP_DEBUG_ANY, "Error: op_ldap_modrdn: bad type \"%s\"\n",
584                     mi[ i ].mi_type, 0, 0 );
585 #endif
586             *errmsg = "Bad value in replication log entry";
587             return -1;
588         }
589     }
590
591     /*
592      * Punt if we don't have all the args.
593      */
594     if ( !GOT_ALL_MODDN(state) ) {
595 #ifdef NEW_LOGGING
596                 LDAP_LOG ( OPERATION, ERR, 
597                         "op_ldap_modrdn: Error: missing arguments\n" , 0, 0, 0 );
598 #else
599         Debug( LDAP_DEBUG_ANY, "Error: op_ldap_modrdn: missing arguments\n",
600                 0, 0, 0 );
601 #endif
602         *errmsg = "Missing argument: requires \"newrdn\" and \"deleteoldrdn\"";
603         return -1;
604     }
605
606 #ifdef LDAP_DEBUG
607     if ( ldap_debug & LDAP_DEBUG_ARGS ) {
608         char buf[ 256 ];
609         char *buf2;
610         int buf2len = strlen( re->re_dn ) + strlen( mi->mi_val ) + 11;
611
612         snprintf( buf, sizeof(buf), "%s:%d", ri->ri_hostname, ri->ri_port );
613
614         buf2 = (char *) ch_malloc( buf2len );
615         snprintf( buf2, buf2len, "(\"%s\" -> \"%s\")", re->re_dn, mi->mi_val );
616
617 #ifdef NEW_LOGGING
618         LDAP_LOG ( OPERATION, ARGS, 
619                 "op_ldap_modrdn: replica %s - modify rdn %s (flag: %d)\n",
620                 buf, buf2, drdnflag );
621 #else
622         Debug( LDAP_DEBUG_ARGS,
623                 "replica %s - modify rdn %s (flag: %d)\n",
624                 buf, buf2, drdnflag );
625 #endif
626         free( buf2 );
627     }
628 #endif /* LDAP_DEBUG */
629
630     assert( newrdn );
631
632     /* Do the modrdn */
633     rc = ldap_rename2_s( ri->ri_ldp, re->re_dn, newrdn, newsup, drdnflag );
634
635         ldap_get_option( ri->ri_ldp, LDAP_OPT_ERROR_NUMBER, &lderr);
636         ldap_get_option( ri->ri_ldp, LDAP_OPT_ERROR_STRING, errmsg);
637         *errfree = 1;
638     return( lderr );
639 }
640
641
642
643 /*
644  * Allocate and initialize an ldapmod struct.
645  */
646 static LDAPMod *
647 alloc_ldapmod( void )
648 {
649     LDAPMod     *ldm;
650
651     ldm = ( struct ldapmod * ) ch_malloc( sizeof ( struct ldapmod ));
652     ldm->mod_type = NULL;
653     ldm->mod_bvalues = ( struct berval ** ) NULL;
654     return( ldm );
655 }
656
657
658
659 /*
660  * Free an ldapmod struct associated mod_bvalues.  NOTE - it is assumed
661  * that mod_bvalues and mod_type contain pointers to the same block of memory
662  * pointed to by the repl struct.  Therefore, it's not freed here.
663  */
664 static void
665 free_ldapmod(
666 LDAPMod *ldm )
667 {
668     int         i;
669
670     if ( ldm == NULL ) {
671         return;
672     }
673     if ( ldm->mod_bvalues != NULL ) {
674         for ( i = 0; ldm->mod_bvalues[ i ] != NULL; i++ ) {
675             free( ldm->mod_bvalues[ i ] );
676         }
677         free( ldm->mod_bvalues );
678     }
679     free( ldm );
680     return;
681 }
682
683
684 /*
685  * Free an an array of LDAPMod pointers and the LDAPMod structs they point
686  * to.
687  */
688 static void
689 free_ldmarr(
690 LDAPMod **ldmarr )
691 {
692     int i;
693
694     for ( i = 0; ldmarr[ i ] != NULL; i++ ) {
695         free_ldapmod( ldmarr[ i ] );
696     }
697     free( ldmarr );
698 }
699
700
701 /*
702  * Create a berval with a single value. 
703  */
704 static struct berval **
705 make_singlevalued_berval( 
706 char    *value,
707 int     len )
708 {
709     struct berval **p;
710
711     p = ( struct berval ** ) ch_malloc( 2 * sizeof( struct berval * ));
712     p[ 0 ] = ( struct berval * ) ch_malloc( sizeof( struct berval ));
713     p[ 1 ] = NULL;
714     p[ 0 ]->bv_val = value;
715     p[ 0 ]->bv_len = len;
716     return( p );
717 }
718
719
720 /*
721  * Given a modification type (string), return an enumerated type.
722  * Avoids ugly copy in op_ldap_modify - lets us use a switch statement
723  * there.
724  */
725 static int
726 getmodtype( 
727 char *type )
728 {
729     if ( !strcmp( type, T_MODSEPSTR )) {
730         return( T_MODSEP );
731     }
732     if ( !strcmp( type, T_MODOPADDSTR )) {
733         return( T_MODOPADD );
734     }
735     if ( !strcmp( type, T_MODOPREPLACESTR )) {
736         return( T_MODOPREPLACE );
737     }
738     if ( !strcmp( type, T_MODOPDELETESTR )) {
739         return( T_MODOPDELETE );
740     }
741     if ( !strcmp( type, T_MODOPINCREMENTSTR )) {
742         return( T_MODOPINCREMENT );
743     }
744     return( T_ERR );
745 }
746
747
748 /*
749  * Perform an LDAP unbind operation.  If replica is NULL, or the
750  * repl_ldp is NULL, just return LDAP_SUCCESS.  Otherwise, unbind,
751  * set the ldp to NULL, and return the result of the unbind call.
752  */
753 static int
754 do_unbind(
755     Ri  *ri
756 )
757 {
758     int         rc = LDAP_SUCCESS;
759
760     if (( ri != NULL ) && ( ri->ri_ldp != NULL )) {
761         rc = ldap_unbind( ri->ri_ldp );
762         if ( rc != LDAP_SUCCESS ) {
763 #ifdef NEW_LOGGING
764                 LDAP_LOG ( OPERATION, ERR, 
765                         "do_unbind: ldap_unbind failed for %s:%d: %s\n",
766                     ri->ri_hostname, ri->ri_port, ldap_err2string( rc ) );
767 #else
768             Debug( LDAP_DEBUG_ANY,
769                     "Error: do_unbind: ldap_unbind failed for %s:%d: %s\n",
770                     ri->ri_hostname, ri->ri_port, ldap_err2string( rc ) );
771 #endif
772         }
773         ri->ri_ldp = NULL;
774     }
775     return rc;
776 }
777
778
779
780 /*
781  * Perform an LDAP bind operation to the replication site given
782  * by replica.  If replica->repl_ldp is non-NULL, then we unbind
783  * from the replica before rebinding.  It should be safe to call
784  * this to re-connect if the replica's connection goes away
785  * for some reason.
786  *
787  * Returns 0 on success, -1 if an LDAP error occurred, and a return
788  * code > 0 if some other error occurred, e.g. invalid bind method.
789  * If an LDAP error occurs, the LDAP error is returned in lderr.
790  */
791 static int
792 do_bind( 
793     Ri  *ri,
794     int *lderr
795 )
796 {
797     int         ldrc;
798     int         do_tls = ri->ri_tls;
799
800     *lderr = 0;
801
802     if ( ri == NULL ) {
803 #ifdef NEW_LOGGING
804         LDAP_LOG ( OPERATION, ERR, "do_bind: null ri ptr\n" , 0, 0, 0 );
805 #else
806         Debug( LDAP_DEBUG_ANY, "Error: do_bind: null ri ptr\n", 0, 0, 0 );
807 #endif
808         return( BIND_ERR_BADRI );
809     }
810
811 retry:
812     if ( ri->ri_ldp != NULL ) {
813         ldrc = ldap_unbind( ri->ri_ldp );
814         if ( ldrc != LDAP_SUCCESS ) {
815 #ifdef NEW_LOGGING
816                 LDAP_LOG ( OPERATION, ERR, 
817                         "do_bind: ldap_unbind failed: %s\n", ldap_err2string( ldrc ), 0, 0 );
818 #else
819             Debug( LDAP_DEBUG_ANY,
820                     "Error: do_bind: ldap_unbind failed: %s\n",
821                     ldap_err2string( ldrc ), 0, 0 );
822 #endif
823         }
824         ri->ri_ldp = NULL;
825     }
826     
827         if ( ri->ri_uri != NULL ) { /* new URI style */
828 #ifdef NEW_LOGGING
829                 LDAP_LOG ( OPERATION, ARGS, 
830                         "do_bind: Initializing session to %s\n", 
831                     ri->ri_uri, 0, 0);
832 #else
833             Debug( LDAP_DEBUG_ARGS, "Initializing session to %s\n",
834                     ri->ri_uri, 0, 0 );
835 #endif
836
837                 ldrc = ldap_initialize( &(ri->ri_ldp), ri->ri_uri);
838
839                 if (ldrc != LDAP_SUCCESS) {
840 #ifdef NEW_LOGGING
841                 LDAP_LOG ( OPERATION, ERR, 
842                         "do_bind: ldap_initalize (0, %s) failed: %s\n",
843                         ri->ri_uri, ldap_err2string(ldrc), 0 );
844 #else
845                 Debug( LDAP_DEBUG_ANY, "Error: ldap_initialize(0, %s) failed: %s\n",
846                         ri->ri_uri, ldap_err2string(ldrc), 0 );
847 #endif
848                 return( BIND_ERR_OPEN );                
849                 }
850         } else { /* old HOST style */
851 #ifdef NEW_LOGGING
852         LDAP_LOG ( OPERATION, ARGS, 
853                 "do_bind: Initializing session to %s:%d\n", 
854             ri->ri_hostname, ri->ri_port, 0 );
855 #else
856     Debug( LDAP_DEBUG_ARGS, "Initializing session to %s:%d\n",
857             ri->ri_hostname, ri->ri_port, 0 );
858 #endif
859
860     ri->ri_ldp = ldap_init( ri->ri_hostname, ri->ri_port );
861     if ( ri->ri_ldp == NULL ) {
862 #ifdef NEW_LOGGING
863                 LDAP_LOG ( OPERATION, ERR, 
864                         "do_bind: ldap_init (%s, %d) failed: %s\n",
865                         ri->ri_hostname, ri->ri_port, sys_errlist[ errno ] );
866 #else
867                 Debug( LDAP_DEBUG_ANY, "Error: ldap_init(%s, %d) failed: %s\n",
868                         ri->ri_hostname, ri->ri_port, sys_errlist[ errno ] );
869 #endif
870                 return( BIND_ERR_OPEN );
871     }
872     }
873
874         {       /* set version 3 */
875                 int err, version = 3;
876                 err = ldap_set_option(ri->ri_ldp,
877                         LDAP_OPT_PROTOCOL_VERSION, &version);
878
879                 if( err != LDAP_OPT_SUCCESS ) {
880 #ifdef NEW_LOGGING
881                         LDAP_LOG ( OPERATION, ERR, "do_bind: "
882                                 "Error: ldap_set_option(%s, LDAP_OPT_VERSION, 3) failed!\n",
883                                 ri->ri_hostname, 0, 0 );
884 #else
885                         Debug( LDAP_DEBUG_ANY,
886                                 "Error: ldap_set_option(%s, LDAP_OPT_VERSION, 3) failed!\n",
887                                 ri->ri_hostname, NULL, NULL );
888 #endif
889
890                         ldap_unbind( ri->ri_ldp );
891                         ri->ri_ldp = NULL;
892                         return BIND_ERR_VERSION;
893                 }
894         }
895
896     /*
897      * Set ldap library options to (1) not follow referrals, and 
898      * (2) restart the select() system call.
899      */
900         {
901                 int err;
902                 err = ldap_set_option(ri->ri_ldp, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
903
904                 if( err != LDAP_OPT_SUCCESS ) {
905 #ifdef NEW_LOGGING
906                         LDAP_LOG ( OPERATION, ERR, "do_bind: "
907                                 "Error: ldap_set_option(%s, REFERRALS, OFF) failed!\n",
908                                 ri->ri_hostname, 0, 0 );
909 #else
910                         Debug( LDAP_DEBUG_ANY,
911                                 "Error: ldap_set_option(%s,REFERRALS, OFF) failed!\n",
912                                 ri->ri_hostname, NULL, NULL );
913 #endif
914                         ldap_unbind( ri->ri_ldp );
915                         ri->ri_ldp = NULL;
916                         return BIND_ERR_REFERRALS;
917                 }
918         }
919         ldap_set_option(ri->ri_ldp, LDAP_OPT_RESTART, LDAP_OPT_ON);
920
921         if( do_tls ) {
922                 int err = ldap_start_tls_s(ri->ri_ldp, NULL, NULL);
923
924                 if( err != LDAP_SUCCESS ) {
925 #ifdef NEW_LOGGING
926                         LDAP_LOG ( OPERATION, ERR, "do_bind: "
927                                 "%s: ldap_start_tls failed: %s (%d)\n",
928                                 ri->ri_tls == TLS_CRITICAL ? "Error" : "Warning",
929                                 ldap_err2string( err ), err );
930 #else
931                         Debug( LDAP_DEBUG_ANY,
932                                 "%s: ldap_start_tls failed: %s (%d)\n",
933                                 ri->ri_tls == TLS_CRITICAL ? "Error" : "Warning",
934                                 ldap_err2string( err ), err );
935 #endif
936
937                         if( ri->ri_tls == TLS_CRITICAL ) {
938                                 *lderr = err;
939                                 ldap_unbind( ri->ri_ldp );
940                                 ri->ri_ldp = NULL;
941                                 return BIND_ERR_TLS_FAILED;
942                         }
943                         do_tls = TLS_OFF;
944                         goto retry;
945                 }
946         }
947
948     switch ( ri->ri_bind_method ) {
949     case LDAP_AUTH_SIMPLE:
950         /*
951          * Bind with a plaintext password.
952          */
953 #ifdef NEW_LOGGING
954         LDAP_LOG ( OPERATION, ARGS, 
955                 "do_bind: bind to %s:%d as %s (simple)\n", 
956                 ri->ri_hostname, ri->ri_port, ri->ri_bind_dn );
957 #else
958         Debug( LDAP_DEBUG_ARGS, "bind to %s:%d as %s (simple)\n",
959                 ri->ri_hostname, ri->ri_port, ri->ri_bind_dn );
960 #endif
961         ldrc = ldap_simple_bind_s( ri->ri_ldp, ri->ri_bind_dn,
962                 ri->ri_password );
963         if ( ldrc != LDAP_SUCCESS ) {
964 #ifdef NEW_LOGGING
965                 LDAP_LOG ( OPERATION, ERR, "do_bind: "
966                     "Error: ldap_simple_bind_s for %s:%d failed: %s\n",
967                     ri->ri_hostname, ri->ri_port, ldap_err2string( ldrc ) );
968 #else
969             Debug( LDAP_DEBUG_ANY,
970                     "Error: ldap_simple_bind_s for %s:%d failed: %s\n",
971                     ri->ri_hostname, ri->ri_port, ldap_err2string( ldrc ));
972 #endif
973             *lderr = ldrc;
974                 ldap_unbind( ri->ri_ldp );
975                 ri->ri_ldp = NULL;
976             return( BIND_ERR_SIMPLE_FAILED );
977         }
978         break;
979
980         case LDAP_AUTH_SASL:
981 #ifdef NEW_LOGGING
982         LDAP_LOG ( OPERATION, ARGS, 
983                 "do_bind: bind to %s as %s via %s (SASL)\n", 
984                 ri->ri_hostname,
985                 ri->ri_authcId ? ri->ri_authcId : "-",
986                 ri->ri_saslmech );
987 #else
988         Debug( LDAP_DEBUG_ARGS, "bind to %s as %s via %s (SASL)\n",
989                 ri->ri_hostname,
990                 ri->ri_authcId ? ri->ri_authcId : "-",
991                 ri->ri_saslmech );
992 #endif
993
994 #ifdef HAVE_CYRUS_SASL
995         if( ri->ri_secprops != NULL ) {
996                 int err = ldap_set_option(ri->ri_ldp,
997                         LDAP_OPT_X_SASL_SECPROPS, ri->ri_secprops);
998
999                 if( err != LDAP_OPT_SUCCESS ) {
1000 #ifdef NEW_LOGGING
1001                         LDAP_LOG ( OPERATION, ERR, "do_bind: "
1002                                 "Error: ldap_set_option(%s,SECPROPS,\"%s\") failed!\n",
1003                                 ri->ri_hostname, ri->ri_secprops, 0 );
1004 #else
1005                         Debug( LDAP_DEBUG_ANY,
1006                                 "Error: ldap_set_option(%s,SECPROPS,\"%s\") failed!\n",
1007                                 ri->ri_hostname, ri->ri_secprops, NULL );
1008 #endif
1009                         ldap_unbind( ri->ri_ldp );
1010                         ri->ri_ldp = NULL;
1011                         return BIND_ERR_SASL_FAILED;
1012                 }
1013         }
1014
1015         {
1016                 void *defaults = lutil_sasl_defaults( ri->ri_ldp, ri->ri_saslmech,
1017                     ri->ri_realm, ri->ri_authcId, ri->ri_password, ri->ri_authzId );
1018
1019                 ldrc = ldap_sasl_interactive_bind_s( ri->ri_ldp, ri->ri_bind_dn,
1020                     ri->ri_saslmech, NULL, NULL,
1021                     LDAP_SASL_QUIET, lutil_sasl_interact, defaults );
1022
1023                 lutil_sasl_freedefs( defaults );
1024                 if ( ldrc != LDAP_SUCCESS ) {
1025 #ifdef NEW_LOGGING
1026                         LDAP_LOG ( OPERATION, ERR, "do_bind: "
1027                                 "Error: LDAP SASL for %s:%d failed: %s\n",
1028                             ri->ri_hostname, ri->ri_port, ldap_err2string( ldrc ) );
1029 #else
1030                         Debug( LDAP_DEBUG_ANY, "Error: LDAP SASL for %s:%d failed: %s\n",
1031                             ri->ri_hostname, ri->ri_port, ldap_err2string( ldrc ));
1032 #endif
1033                         *lderr = ldrc;
1034                         ldap_unbind( ri->ri_ldp );
1035                         ri->ri_ldp = NULL;
1036                         return( BIND_ERR_SASL_FAILED );
1037                 }
1038         }
1039         break;
1040 #else
1041 #ifdef NEW_LOGGING
1042         LDAP_LOG ( OPERATION, ERR, "do_bind: "
1043                 "Error: do_bind: SASL not supported %s:%d\n",
1044                 ri->ri_hostname, ri->ri_port, 0 );
1045 #else
1046         Debug( LDAP_DEBUG_ANY,
1047                 "Error: do_bind: SASL not supported %s:%d\n",
1048                  ri->ri_hostname, ri->ri_port, NULL );
1049 #endif
1050         ldap_unbind( ri->ri_ldp );
1051         ri->ri_ldp = NULL;
1052         return( BIND_ERR_BAD_ATYPE );
1053 #endif
1054
1055     default:
1056 #ifdef NEW_LOGGING
1057         LDAP_LOG ( OPERATION, ERR, "do_bind: "
1058                 "Error: do_bind: unknown auth type \"%d\" for %s:%d\n",
1059                 ri->ri_bind_method, ri->ri_hostname, ri->ri_port );
1060 #else
1061         Debug(  LDAP_DEBUG_ANY,
1062                 "Error: do_bind: unknown auth type \"%d\" for %s:%d\n",
1063                 ri->ri_bind_method, ri->ri_hostname, ri->ri_port );
1064 #endif
1065         ldap_unbind( ri->ri_ldp );
1066         ri->ri_ldp = NULL;
1067         return( BIND_ERR_BAD_ATYPE );
1068     }
1069
1070         {
1071                 int err;
1072                 LDAPControl c;
1073                 LDAPControl *ctrls[2];
1074                 ctrls[0] = &c;
1075                 ctrls[1] = NULL;
1076
1077                 c.ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
1078                 c.ldctl_value.bv_val = NULL;
1079                 c.ldctl_value.bv_len = 0;
1080                 c.ldctl_iscritical = 0;
1081
1082                 err = ldap_set_option(ri->ri_ldp, LDAP_OPT_SERVER_CONTROLS, &ctrls);
1083
1084                 if( err != LDAP_OPT_SUCCESS ) {
1085 #ifdef NEW_LOGGING
1086                         LDAP_LOG ( OPERATION, ERR, "do_bind: "
1087                                 "ldap_set_option(%s, SERVER_CONTROLS, ManageDSAit) failed!\n",
1088                                 ri->ri_hostname, 0, 0 );
1089 #else
1090                         Debug( LDAP_DEBUG_ANY, "Error: "
1091                                 "ldap_set_option(%s, SERVER_CONTROLS, ManageDSAit) failed!\n",
1092                                 ri->ri_hostname, NULL, NULL );
1093 #endif
1094                         ldap_unbind( ri->ri_ldp );
1095                         ri->ri_ldp = NULL;
1096                         return BIND_ERR_MANAGEDSAIT;
1097                 }
1098         }
1099
1100         return( BIND_OK );
1101 }
1102
1103
1104
1105
1106
1107 /*
1108  * For debugging.  Print the contents of an ldmarr array.
1109  */
1110 static void
1111 dump_ldm_array(
1112     LDAPMod **ldmarr
1113 )
1114 {
1115     int                  i, j;
1116     LDAPMod             *ldm;
1117     struct berval       *b;
1118     char                *msgbuf;
1119
1120     for ( i = 0; ldmarr[ i ] != NULL; i++ ) {
1121         ldm = ldmarr[ i ];
1122 #ifdef NEW_LOGGING
1123         LDAP_LOG ( OPERATION, INFO, "dump_ldm_array: "
1124                 "Trace (%ld): *** ldmarr[ %d ] contents:\n",
1125                 (long) getpid(), i, 0 );
1126         LDAP_LOG ( OPERATION, INFO, "dump_ldm_array: "
1127                 "Trace (%ld): *** ldm->mod_op: %d\n",
1128                 (long) getpid(), ldm->mod_op, 0 );
1129         LDAP_LOG ( OPERATION, INFO, "dump_ldm_array: "
1130                 "Trace (%ld): *** ldm->mod_type: %s\n",
1131                 (long) getpid(), ldm->mod_type, 0 );
1132 #else
1133         Debug( LDAP_DEBUG_TRACE,
1134                 "Trace (%ld): *** ldmarr[ %d ] contents:\n",
1135                 (long) getpid(), i, 0 );
1136         Debug( LDAP_DEBUG_TRACE,
1137                 "Trace (%ld): *** ldm->mod_op: %d\n",
1138                 (long) getpid(), ldm->mod_op, 0 );
1139         Debug( LDAP_DEBUG_TRACE,
1140                 "Trace (%ld): *** ldm->mod_type: %s\n",
1141                 (long) getpid(), ldm->mod_type, 0 );
1142 #endif
1143         if ( ldm->mod_bvalues != NULL ) {
1144             for ( j = 0; ( b = ldm->mod_bvalues[ j ] ) != NULL; j++ ) {
1145                 msgbuf = ch_malloc( b->bv_len + 512 );
1146                 sprintf( msgbuf, "***** bv[ %d ] len = %ld, val = <%s>",
1147                         j, b->bv_len, b->bv_val );
1148 #ifdef NEW_LOGGING
1149                 LDAP_LOG ( OPERATION, INFO, "dump_ldm_array: "
1150                         "Trace (%ld):%s\n", (long) getpid(), msgbuf, 0 );
1151 #else
1152                 Debug( LDAP_DEBUG_TRACE,
1153                         "Trace (%ld):%s\n", (long) getpid(), msgbuf, 0 );
1154 #endif
1155                 free( msgbuf );
1156             }
1157         }
1158     }
1159 }