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