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