]> git.sur5r.net Git - openldap/blob - servers/slurpd/ldap_op.c
Suck in latest changes from 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 (( "operation", 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 (( "operation", 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 (( "operation", 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 (( "operation", 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 (( "operation", 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 (( "operation", 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 (( "operation", 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 (( "operation", 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 (( "operation", 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 (( "operation", 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 (( "operation", 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 (( "operation", 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 (( "operation", 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 (( "operation", 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 (( "operation", 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 (( "operation", 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 (( "operation", 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 (( "operation", 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 (( "operation", 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         int buf2len = strlen( re->re_dn ) + strlen( mi->mi_val ) + 11;
567
568         snprintf( buf, sizeof(buf), "%s:%d", ri->ri_hostname, ri->ri_port );
569
570         buf2 = (char *) ch_malloc( buf2len );
571         snprintf( buf2, buf2len, "(\"%s\" -> \"%s\")", re->re_dn, mi->mi_val );
572
573 #ifdef NEW_LOGGING
574         LDAP_LOG (( "operation", LDAP_LEVEL_ARGS, 
575                 "op_ldap_modrdn: replica %s - modify rdn %s (flag: %d)\n",
576                 buf, buf2, drdnflag ));
577 #else
578         Debug( LDAP_DEBUG_ARGS,
579                 "replica %s - modify rdn %s (flag: %d)\n",
580                 buf, buf2, drdnflag );
581 #endif
582         free( buf2 );
583     }
584 #endif /* LDAP_DEBUG */
585
586     assert( newrdn );
587
588     /* Do the modrdn */
589     rc = ldap_rename2_s( ri->ri_ldp, re->re_dn, newrdn, newsup, drdnflag );
590
591         ldap_get_option( ri->ri_ldp, LDAP_OPT_ERROR_NUMBER, &lderr);
592     return( lderr );
593 }
594
595
596
597 /*
598  * Allocate and initialize an ldapmod struct.
599  */
600 static LDAPMod *
601 alloc_ldapmod( void )
602 {
603     LDAPMod     *ldm;
604
605     ldm = ( struct ldapmod * ) ch_malloc( sizeof ( struct ldapmod ));
606     ldm->mod_type = NULL;
607     ldm->mod_bvalues = ( struct berval ** ) NULL;
608     return( ldm );
609 }
610
611
612
613 /*
614  * Free an ldapmod struct associated mod_bvalues.  NOTE - it is assumed
615  * that mod_bvalues and mod_type contain pointers to the same block of memory
616  * pointed to by the repl struct.  Therefore, it's not freed here.
617  */
618 static void
619 free_ldapmod(
620 LDAPMod *ldm )
621 {
622     int         i;
623
624     if ( ldm == NULL ) {
625         return;
626     }
627     if ( ldm->mod_bvalues != NULL ) {
628         for ( i = 0; ldm->mod_bvalues[ i ] != NULL; i++ ) {
629             free( ldm->mod_bvalues[ i ] );
630         }
631         free( ldm->mod_bvalues );
632     }
633     free( ldm );
634     return;
635 }
636
637
638 /*
639  * Free an an array of LDAPMod pointers and the LDAPMod structs they point
640  * to.
641  */
642 static void
643 free_ldmarr(
644 LDAPMod **ldmarr )
645 {
646     int i;
647
648     for ( i = 0; ldmarr[ i ] != NULL; i++ ) {
649         free_ldapmod( ldmarr[ i ] );
650     }
651     free( ldmarr );
652 }
653
654
655 /*
656  * Create a berval with a single value. 
657  */
658 static struct berval **
659 make_singlevalued_berval( 
660 char    *value,
661 int     len )
662 {
663     struct berval **p;
664
665     p = ( struct berval ** ) ch_malloc( 2 * sizeof( struct berval * ));
666     p[ 0 ] = ( struct berval * ) ch_malloc( sizeof( struct berval ));
667     p[ 1 ] = NULL;
668     p[ 0 ]->bv_val = value;
669     p[ 0 ]->bv_len = len;
670     return( p );
671 }
672
673
674 /*
675  * Given a modification type (string), return an enumerated type.
676  * Avoids ugly copy in op_ldap_modify - lets us use a switch statement
677  * there.
678  */
679 static int
680 getmodtype( 
681 char *type )
682 {
683     if ( !strcmp( type, T_MODSEPSTR )) {
684         return( T_MODSEP );
685     }
686     if ( !strcmp( type, T_MODOPADDSTR )) {
687         return( T_MODOPADD );
688     }
689     if ( !strcmp( type, T_MODOPREPLACESTR )) {
690         return( T_MODOPREPLACE );
691     }
692     if ( !strcmp( type, T_MODOPDELETESTR )) {
693         return( T_MODOPDELETE );
694     }
695     return( T_ERR );
696 }
697
698
699 /*
700  * Perform an LDAP unbind operation.  If replica is NULL, or the
701  * repl_ldp is NULL, just return LDAP_SUCCESS.  Otherwise, unbind,
702  * set the ldp to NULL, and return the result of the unbind call.
703  */
704 static int
705 do_unbind(
706     Ri  *ri
707 )
708 {
709     int         rc = LDAP_SUCCESS;
710
711     if (( ri != NULL ) && ( ri->ri_ldp != NULL )) {
712         rc = ldap_unbind( ri->ri_ldp );
713         if ( rc != LDAP_SUCCESS ) {
714 #ifdef NEW_LOGGING
715                 LDAP_LOG (( "operation", LDAP_LEVEL_ERR, 
716                         "do_unbind: ldap_unbind failed for %s:%d: %s\n",
717                     ri->ri_hostname, ri->ri_port, ldap_err2string( rc ) ));
718 #else
719             Debug( LDAP_DEBUG_ANY,
720                     "Error: do_unbind: ldap_unbind failed for %s:%d: %s\n",
721                     ri->ri_hostname, ri->ri_port, ldap_err2string( rc ) );
722 #endif
723         }
724         ri->ri_ldp = NULL;
725     }
726     return rc;
727 }
728
729
730
731 /*
732  * Perform an LDAP bind operation to the replication site given
733  * by replica.  If replica->repl_ldp is non-NULL, then we unbind
734  * from the replica before rebinding.  It should be safe to call
735  * this to re-connect if the replica's connection goes away
736  * for some reason.
737  *
738  * Returns 0 on success, -1 if an LDAP error occurred, and a return
739  * code > 0 if some other error occurred, e.g. invalid bind method.
740  * If an LDAP error occurs, the LDAP error is returned in lderr.
741  */
742 static int
743 do_bind( 
744     Ri  *ri,
745     int *lderr
746 )
747 {
748     int         ldrc;
749
750     *lderr = 0;
751
752     if ( ri == NULL ) {
753 #ifdef NEW_LOGGING
754         LDAP_LOG (( "operation", LDAP_LEVEL_ERR, "do_bind: null ri ptr\n" ));
755 #else
756         Debug( LDAP_DEBUG_ANY, "Error: do_bind: null ri ptr\n", 0, 0, 0 );
757 #endif
758         return( BIND_ERR_BADRI );
759     }
760
761     if ( ri->ri_ldp != NULL ) {
762         ldrc = ldap_unbind( ri->ri_ldp );
763         if ( ldrc != LDAP_SUCCESS ) {
764 #ifdef NEW_LOGGING
765                 LDAP_LOG (( "operation", LDAP_LEVEL_ERR, 
766                         "do_bind: ldap_unbind failed: %s\n", ldap_err2string( ldrc ) ));
767 #else
768             Debug( LDAP_DEBUG_ANY,
769                     "Error: do_bind: ldap_unbind failed: %s\n",
770                     ldap_err2string( ldrc ), 0, 0 );
771 #endif
772         }
773         ri->ri_ldp = NULL;
774     }
775
776 #ifdef NEW_LOGGING
777         LDAP_LOG (( "operation", LDAP_LEVEL_ARGS, 
778                 "do_bind: Initializing session to %s:%d\n", 
779             ri->ri_hostname, ri->ri_port ));
780 #else
781     Debug( LDAP_DEBUG_ARGS, "Initializing session to %s:%d\n",
782             ri->ri_hostname, ri->ri_port, 0 );
783 #endif
784
785     ri->ri_ldp = ldap_init( ri->ri_hostname, ri->ri_port );
786     if ( ri->ri_ldp == NULL ) {
787 #ifdef NEW_LOGGING
788                 LDAP_LOG (( "operation", LDAP_LEVEL_ERR, 
789                         "do_bind: ldap_init (%s, %d) failed: %s\n",
790                         ri->ri_hostname, ri->ri_port, sys_errlist[ errno ] ));
791 #else
792                 Debug( LDAP_DEBUG_ANY, "Error: ldap_init(%s, %d) failed: %s\n",
793                         ri->ri_hostname, ri->ri_port, sys_errlist[ errno ] );
794 #endif
795                 return( BIND_ERR_OPEN );
796     }
797
798         {       /* set version 3 */
799                 int err, version = 3;
800                 err = ldap_set_option(ri->ri_ldp,
801                         LDAP_OPT_PROTOCOL_VERSION, &version);
802
803                 if( err != LDAP_OPT_SUCCESS ) {
804 #ifdef NEW_LOGGING
805                         LDAP_LOG (( "operation", LDAP_LEVEL_ERR, "do_bind: ",
806                                 "Error: ldap_set_option(%s, LDAP_OPT_VERSION, 3) failed!\n",
807                                 ri->ri_hostname ));
808 #else
809                         Debug( LDAP_DEBUG_ANY,
810                                 "Error: ldap_set_option(%s, LDAP_OPT_VERSION, 3) failed!\n",
811                                 ri->ri_hostname, NULL, NULL );
812 #endif
813
814                         ldap_unbind( ri->ri_ldp );
815                         ri->ri_ldp = NULL;
816                         return BIND_ERR_VERSION;
817                 }
818         }
819
820     /*
821      * Set ldap library options to (1) not follow referrals, and 
822      * (2) restart the select() system call.
823      */
824         {
825                 int err;
826                 err = ldap_set_option(ri->ri_ldp, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
827
828                 if( err != LDAP_OPT_SUCCESS ) {
829 #ifdef NEW_LOGGING
830                         LDAP_LOG (( "operation", LDAP_LEVEL_ERR, "do_bind: ",
831                                 "Error: ldap_set_option(%s, REFERRALS, OFF) failed!\n",
832                                 ri->ri_hostname ));
833 #else
834                         Debug( LDAP_DEBUG_ANY,
835                                 "Error: ldap_set_option(%s,REFERRALS, OFF) failed!\n",
836                                 ri->ri_hostname, NULL, NULL );
837 #endif
838                         ldap_unbind( ri->ri_ldp );
839                         ri->ri_ldp = NULL;
840                         return BIND_ERR_REFERRALS;
841                 }
842         }
843         ldap_set_option(ri->ri_ldp, LDAP_OPT_RESTART, LDAP_OPT_ON);
844
845         if( ri->ri_tls ) {
846                 int err;
847                 err = ldap_start_tls_s(ri->ri_ldp, NULL, NULL);
848
849                 if( err != LDAP_SUCCESS ) {
850 #ifdef NEW_LOGGING
851                         LDAP_LOG (( "operation", LDAP_LEVEL_ERR, "do_bind: ",
852                                 "%s: ldap_start_tls failed: %s (%d)\n",
853                                 ri->ri_tls == TLS_CRITICAL ? "Error" : "Warning",
854                                 ldap_err2string( err ), err ));
855 #else
856                         Debug( LDAP_DEBUG_ANY,
857                                 "%s: ldap_start_tls failed: %s (%d)\n",
858                                 ri->ri_tls == TLS_CRITICAL ? "Error" : "Warning",
859                                 ldap_err2string( err ), err );
860 #endif
861
862                         if( ri->ri_tls == TLS_CRITICAL ) {
863                                 ldap_unbind( ri->ri_ldp );
864                                 ri->ri_ldp = NULL;
865                                 return BIND_ERR_TLS_FAILED;
866                         }
867                 }
868         }
869
870     switch ( ri->ri_bind_method ) {
871     case AUTH_SIMPLE:
872         /*
873          * Bind with a plaintext password.
874          */
875 #ifdef NEW_LOGGING
876         LDAP_LOG (( "operation", LDAP_LEVEL_ARGS, 
877                 "do_bind: bind to %s:%d as %s (simple)\n", 
878                 ri->ri_hostname, ri->ri_port, ri->ri_bind_dn ));
879 #else
880         Debug( LDAP_DEBUG_ARGS, "bind to %s:%d as %s (simple)\n",
881                 ri->ri_hostname, ri->ri_port, ri->ri_bind_dn );
882 #endif
883         ldrc = ldap_simple_bind_s( ri->ri_ldp, ri->ri_bind_dn,
884                 ri->ri_password );
885         if ( ldrc != LDAP_SUCCESS ) {
886 #ifdef NEW_LOGGING
887                 LDAP_LOG (( "operation", LDAP_LEVEL_ERR, "do_bind: "
888                     "Error: ldap_simple_bind_s for %s:%d failed: %s\n",
889                     ri->ri_hostname, ri->ri_port, ldap_err2string( ldrc ) ));
890 #else
891             Debug( LDAP_DEBUG_ANY,
892                     "Error: ldap_simple_bind_s for %s:%d failed: %s\n",
893                     ri->ri_hostname, ri->ri_port, ldap_err2string( ldrc ));
894 #endif
895             *lderr = ldrc;
896                 ldap_unbind( ri->ri_ldp );
897                 ri->ri_ldp = NULL;
898             return( BIND_ERR_SIMPLE_FAILED );
899         }
900         break;
901
902         case AUTH_SASL:
903 #ifdef NEW_LOGGING
904         LDAP_LOG (( "operation", LDAP_LEVEL_ARGS, 
905                 "do_bind: bind to %s as %s via %s (SASL)\n", 
906                 ri->ri_hostname, ri->ri_authcId, ri->ri_saslmech ));
907 #else
908         Debug( LDAP_DEBUG_ARGS, "bind to %s as %s via %s (SASL)\n",
909                 ri->ri_hostname, ri->ri_authcId, ri->ri_saslmech );
910 #endif
911
912 #ifdef HAVE_CYRUS_SASL
913         if( ri->ri_secprops != NULL ) {
914                 int err;
915                 err = ldap_set_option(ri->ri_ldp, LDAP_OPT_X_SASL_SECPROPS,
916                         ri->ri_secprops);
917
918                 if( err != LDAP_OPT_SUCCESS ) {
919 #ifdef NEW_LOGGING
920                         LDAP_LOG (( "operation", LDAP_LEVEL_ERR, "do_bind: "
921                                 "Error: ldap_set_option(%s,SECPROPS,\"%s\") failed!\n",
922                                 ri->ri_hostname, ri->ri_secprops ));
923 #else
924                         Debug( LDAP_DEBUG_ANY,
925                                 "Error: ldap_set_option(%s,SECPROPS,\"%s\") failed!\n",
926                                 ri->ri_hostname, ri->ri_secprops, NULL );
927 #endif
928                         ldap_unbind( ri->ri_ldp );
929                         ri->ri_ldp = NULL;
930                         return BIND_ERR_SASL_FAILED;
931                 }
932         }
933
934         {
935                 char *passwd = ri->ri_password ? ber_strdup( ri->ri_password ) : NULL;
936                 void *defaults = lutil_sasl_defaults( ri->ri_ldp, ri->ri_saslmech,
937                     ri->ri_realm, ri->ri_authcId, passwd, ri->ri_authzId );
938
939                 ldrc = ldap_sasl_interactive_bind_s( ri->ri_ldp, ri->ri_bind_dn,
940                     ri->ri_saslmech, NULL, NULL,
941                     LDAP_SASL_QUIET, lutil_sasl_interact, defaults );
942                 if ( ldrc != LDAP_SUCCESS ) {
943 #ifdef NEW_LOGGING
944                         LDAP_LOG (( "operation", LDAP_LEVEL_ERR, "do_bind: "
945                                 "Error: LDAP SASL for %s:%d failed: %s\n",
946                             ri->ri_hostname, ri->ri_port, ldap_err2string( ldrc ) ));
947 #else
948                         Debug( LDAP_DEBUG_ANY, "Error: LDAP SASL for %s:%d failed: %s\n",
949                             ri->ri_hostname, ri->ri_port, ldap_err2string( ldrc ));
950 #endif
951                         *lderr = ldrc;
952                         ldap_unbind( ri->ri_ldp );
953                         ri->ri_ldp = NULL;
954                         return( BIND_ERR_SASL_FAILED );
955                 }
956
957                 ber_memfree( passwd );
958                 ber_memfree( defaults );
959         }
960         break;
961 #else
962 #ifdef NEW_LOGGING
963         LDAP_LOG (( "operation", LDAP_LEVEL_ERR, "do_bind: "
964                 "Error: do_bind: SASL not supported %s:%d\n",
965                  ri->ri_hostname, ri->ri_port ));
966 #else
967         Debug( LDAP_DEBUG_ANY,
968                 "Error: do_bind: SASL not supported %s:%d\n",
969                  ri->ri_hostname, ri->ri_port, NULL );
970 #endif
971         ldap_unbind( ri->ri_ldp );
972         ri->ri_ldp = NULL;
973         return( BIND_ERR_BAD_ATYPE );
974 #endif
975
976     default:
977 #ifdef NEW_LOGGING
978         LDAP_LOG (( "operation", LDAP_LEVEL_ERR, "do_bind: "
979                 "Error: do_bind: unknown auth type \"%d\" for %s:%d\n",
980                 ri->ri_bind_method, ri->ri_hostname, ri->ri_port ));
981 #else
982         Debug(  LDAP_DEBUG_ANY,
983                 "Error: do_bind: unknown auth type \"%d\" for %s:%d\n",
984                 ri->ri_bind_method, ri->ri_hostname, ri->ri_port );
985 #endif
986         ldap_unbind( ri->ri_ldp );
987         ri->ri_ldp = NULL;
988         return( BIND_ERR_BAD_ATYPE );
989     }
990
991         {
992                 int err;
993                 LDAPControl c;
994                 LDAPControl *ctrls[2];
995                 ctrls[0] = &c;
996                 ctrls[1] = NULL;
997
998                 c.ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
999                 c.ldctl_value.bv_val = NULL;
1000                 c.ldctl_value.bv_len = 0;
1001                 c.ldctl_iscritical = 0;
1002
1003                 err = ldap_set_option(ri->ri_ldp, LDAP_OPT_SERVER_CONTROLS, &ctrls);
1004
1005                 if( err != LDAP_OPT_SUCCESS ) {
1006 #ifdef NEW_LOGGING
1007                         LDAP_LOG (( "operation", LDAP_LEVEL_ERR, "do_bind: "
1008                                 "ldap_set_option(%s, SERVER_CONTROLS, ManageDSAit) failed!\n",
1009                                 ri->ri_hostname ));
1010 #else
1011                         Debug( LDAP_DEBUG_ANY, "Error: "
1012                                 "ldap_set_option(%s, SERVER_CONTROLS, ManageDSAit) failed!\n",
1013                                 ri->ri_hostname, NULL, NULL );
1014 #endif
1015                         ldap_unbind( ri->ri_ldp );
1016                         ri->ri_ldp = NULL;
1017                         return BIND_ERR_MANAGEDSAIT;
1018                 }
1019         }
1020
1021         return( BIND_OK );
1022 }
1023
1024
1025
1026
1027
1028 /*
1029  * For debugging.  Print the contents of an ldmarr array.
1030  */
1031 static void
1032 dump_ldm_array(
1033     LDAPMod **ldmarr
1034 )
1035 {
1036     int                  i, j;
1037     LDAPMod             *ldm;
1038     struct berval       *b;
1039     char                *msgbuf;
1040
1041     for ( i = 0; ldmarr[ i ] != NULL; i++ ) {
1042         ldm = ldmarr[ i ];
1043 #ifdef NEW_LOGGING
1044         LDAP_LOG (( "operation", LDAP_LEVEL_INFO, "dump_ldm_array: "
1045                 "Trace (%ld): *** ldmarr[ %d ] contents:\n",
1046                 (long) getpid(), i ));
1047         LDAP_LOG (( "operation", LDAP_LEVEL_INFO, "dump_ldm_array: "
1048                 "Trace (%ld): *** ldm->mod_op: %d\n",
1049                 (long) getpid(), ldm->mod_op ));
1050         LDAP_LOG (( "operation", LDAP_LEVEL_INFO, "dump_ldm_array: "
1051                 "Trace (%ld): *** ldm->mod_type: %s\n",
1052                 (long) getpid(), ldm->mod_type ));
1053 #else
1054         Debug( LDAP_DEBUG_TRACE,
1055                 "Trace (%ld): *** ldmarr[ %d ] contents:\n",
1056                 (long) getpid(), i, 0 );
1057         Debug( LDAP_DEBUG_TRACE,
1058                 "Trace (%ld): *** ldm->mod_op: %d\n",
1059                 (long) getpid(), ldm->mod_op, 0 );
1060         Debug( LDAP_DEBUG_TRACE,
1061                 "Trace (%ld): *** ldm->mod_type: %s\n",
1062                 (long) getpid(), ldm->mod_type, 0 );
1063 #endif
1064         if ( ldm->mod_bvalues != NULL ) {
1065             for ( j = 0; ( b = ldm->mod_bvalues[ j ] ) != NULL; j++ ) {
1066                 msgbuf = ch_malloc( b->bv_len + 512 );
1067                 sprintf( msgbuf, "***** bv[ %d ] len = %ld, val = <%s>",
1068                         j, b->bv_len, b->bv_val );
1069 #ifdef NEW_LOGGING
1070                 LDAP_LOG (( "operation", LDAP_LEVEL_INFO, "dump_ldm_array: "
1071                         "Trace (%ld):%s\n", (long) getpid(), msgbuf ));
1072 #else
1073                 Debug( LDAP_DEBUG_TRACE,
1074                         "Trace (%ld):%s\n", (long) getpid(), msgbuf, 0 );
1075 #endif
1076                 free( msgbuf );
1077             }
1078         }
1079     }
1080 }