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