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