]> git.sur5r.net Git - openldap/blob - servers/slurpd/ldap_op.c
Merge in all -devel changes made since branch was created.
[openldap] / servers / slurpd / ldap_op.c
1 /*
2  * Copyright (c) 1996 Regents of the University of Michigan.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that this notice is preserved and that due credit is given
7  * to the University of Michigan at Ann Arbor. The name of the University
8  * may not be used to endorse or promote products derived from this
9  * software without specific prior written permission. This software
10  * is provided ``as is'' without express or implied warranty.
11  */
12
13 /*
14  * ldap_op.c - routines to perform LDAP operations
15  */
16
17 #include "portable.h"
18
19 #include <stdio.h>
20
21 #include <ac/stdlib.h>
22
23 #include <ac/errno.h>
24 #include <ac/string.h>
25 #include <ac/ctype.h>
26 #include <ac/time.h>
27 #include <ac/unistd.h>
28
29 #include <ac/krb.h>
30
31 #if defined( STR_TRANSLATION ) && defined( LDAP_DEFAULT_CHARSET )
32 /* Get LDAP->ld_lberoptions.  Must precede slurp.h, both define ldap_debug. */
33 #include "../../libraries/libldap/ldap-int.h"
34 #endif
35
36 #include <lber.h>
37 #include <ldap.h>
38
39 #include "slurp.h"
40
41 /* Forward references */
42 static struct berval **make_singlevalued_berval LDAP_P(( char   *, int ));
43 static int op_ldap_add LDAP_P(( Ri *, Re *, char ** ));
44 static int op_ldap_modify LDAP_P(( Ri *, Re *, char ** ));
45 static int op_ldap_delete LDAP_P(( Ri *, Re *, char ** ));
46 static int op_ldap_modrdn LDAP_P(( Ri *, Re *, char ** ));
47 static LDAPMod *alloc_ldapmod LDAP_P(( void ));
48 static void free_ldapmod LDAP_P(( LDAPMod * ));
49 static void free_ldmarr LDAP_P(( LDAPMod ** ));
50 static int getmodtype LDAP_P(( char * ));
51 static void dump_ldm_array LDAP_P(( LDAPMod ** ));
52 static char **read_krbnames LDAP_P(( Ri * ));
53 static void upcase LDAP_P(( char * ));
54 static int do_bind LDAP_P(( Ri *, int * ));
55 static int do_unbind LDAP_P(( Ri * ));
56
57
58 static char *kattrs[] = {"kerberosName", NULL };
59 static struct timeval kst = {30L, 0L};
60
61
62
63 /*
64  * Determine the type of ldap operation being performed and call the
65  * appropriate routine.
66  * - If successful, returns ERR_DO_LDAP_OK
67  * - If a retryable error occurs, ERR_DO_LDAP_RETRYABLE is returned.
68  *   The caller should wait a while and retry the operation.
69  * - If a fatal error occurs, ERR_DO_LDAP_FATAL is returned.  The caller
70  *   should reject the operation and continue with the next replication
71  *   entry.
72  */
73 int
74 do_ldap(
75     Ri          *ri,
76     Re          *re,
77     char        **errmsg
78 )
79 {
80     int rc = 0;
81     int lderr = LDAP_SUCCESS;
82     int retry = 2;
83
84     *errmsg = NULL;
85
86     while ( retry > 0 ) {
87         if ( ri->ri_ldp == NULL ) {
88             rc = do_bind( ri, &lderr );
89             if ( rc != BIND_OK ) {
90                 return DO_LDAP_ERR_RETRYABLE;
91             }
92         }
93
94         switch ( re->re_changetype ) {
95         case T_ADDCT:
96             lderr = op_ldap_add( ri, re, errmsg );
97             if ( lderr != LDAP_SUCCESS ) {
98                 Debug( LDAP_DEBUG_ANY,
99                         "Error: ldap_add_s failed adding \"%s\": %s\n",
100                         *errmsg ? *errmsg : ldap_err2string( lderr ),
101                         re->re_dn, 0 );
102             }
103             break;
104         case T_MODIFYCT:
105             lderr = op_ldap_modify( ri, re, errmsg );
106             if ( lderr != LDAP_SUCCESS ) {
107                 Debug( LDAP_DEBUG_ANY,
108                         "Error: ldap_modify_s failed modifying \"%s\": %s\n",
109                         *errmsg ? *errmsg : ldap_err2string( lderr ),
110                         re->re_dn, 0 );
111             }
112             break;
113         case T_DELETECT:
114             lderr = op_ldap_delete( ri, re, errmsg );
115             if ( lderr != LDAP_SUCCESS ) {
116                 Debug( LDAP_DEBUG_ANY,
117                         "Error: ldap_delete_s failed deleting \"%s\": %s\n",
118                         *errmsg ? *errmsg : ldap_err2string( lderr ),
119                         re->re_dn, 0 );
120             }
121             break;
122         case T_MODRDNCT:
123             lderr = op_ldap_modrdn( ri, re, errmsg );
124             if ( lderr != LDAP_SUCCESS ) {
125                 Debug( LDAP_DEBUG_ANY,
126                         "Error: ldap_modrdn_s failed modifying %s: %s\n",
127                         *errmsg ? *errmsg : ldap_err2string( lderr ),
128                         re->re_dn, 0 );
129             }
130             break;
131         default:
132             Debug( LDAP_DEBUG_ANY,
133                     "Error: do_ldap: bad op \"%d\", dn = \"%s\"\n",
134                     re->re_changetype, re->re_dn, 0 );
135             return DO_LDAP_ERR_FATAL;
136         }
137
138         /*
139          * Analyze return code.  If ok, just return.  If LDAP_SERVER_DOWN,
140          * we may have been idle long enough that the remote slapd timed
141          * us out.  Rebind and try again.
142          */
143         if ( lderr == LDAP_SUCCESS ) {
144             return DO_LDAP_OK;
145         } else if ( lderr == LDAP_SERVER_DOWN ) {
146             /* The LDAP server may have timed us out - rebind and try again */
147             (void) do_unbind( ri );
148             retry--;
149         } else {
150             return DO_LDAP_ERR_FATAL;
151         }
152     }
153     return DO_LDAP_ERR_FATAL;
154 }
155
156
157
158
159 /*
160  * Perform an ldap add operation.
161  */
162 static int
163 op_ldap_add(
164     Ri          *ri,
165     Re          *re,
166     char        **errmsg
167 )
168 {
169     Mi          *mi;
170     int         nattrs, rc = 0, i;
171     LDAPMod     *ldm, **ldmarr;
172     int         lderr = 0;
173
174     nattrs = i = 0;
175     ldmarr = NULL;
176
177     /*
178      * Construct a null-terminated array of LDAPMod structs.
179      */
180     mi = re->re_mods;
181     while ( mi[ i ].mi_type != NULL ) {
182         ldm = alloc_ldapmod();
183         ldmarr = ( LDAPMod ** ) ch_realloc( ldmarr,
184                 ( nattrs + 2 ) * sizeof( LDAPMod * ));
185         ldmarr[ nattrs ] = ldm;
186         ldm->mod_op = LDAP_MOD_BVALUES;
187         ldm->mod_type = mi[ i ].mi_type;
188         ldm->mod_bvalues =
189                 make_singlevalued_berval( mi[ i ].mi_val, mi[ i ].mi_len );
190         i++;
191         nattrs++;
192     }
193
194     if ( ldmarr != NULL ) {
195         ldmarr[ nattrs ] = NULL;
196
197         /* Perform the operation */
198         Debug( LDAP_DEBUG_ARGS, "replica %s:%d - add dn \"%s\"\n",
199                 ri->ri_hostname, ri->ri_port, re->re_dn );
200         rc = ldap_add_s( ri->ri_ldp, re->re_dn, ldmarr );
201
202         ldap_get_option( ri->ri_ldp, LDAP_OPT_ERROR_NUMBER, &lderr);
203
204     } else {
205         *errmsg = "No modifications to do";
206         Debug( LDAP_DEBUG_ANY,
207                "Error: op_ldap_add: no mods to do (%s)!\n", re->re_dn, 0, 0 );
208     }
209     free_ldmarr( ldmarr );
210     return( lderr ); 
211 }
212
213
214
215
216 /*
217  * Perform an ldap modify operation.
218  */
219 #define AWAITING_OP -1
220 static int
221 op_ldap_modify(
222     Ri          *ri,
223     Re          *re,
224     char        **errmsg
225 )
226 {
227     Mi          *mi;
228     int         state;  /* This code is a simple-minded state machine */
229     int         nvals;  /* Number of values we're modifying */
230     int         nops;   /* Number of LDAPMod structs in ldmarr */
231     LDAPMod     *ldm, **ldmarr;
232     int         i, len;
233     char        *type, *value;
234     int         rc = 0;
235
236     state = AWAITING_OP;
237     nvals = 0;
238     nops = 0;
239     ldmarr = NULL;
240
241     if ( re->re_mods == NULL ) {
242         *errmsg = "No arguments given";
243         Debug( LDAP_DEBUG_ANY, "Error: op_ldap_modify: no arguments\n",
244                 0, 0, 0 );
245             return -1;
246     }
247
248     /*
249      * Construct a null-terminated array of LDAPMod structs.
250      */
251     for ( mi = re->re_mods, i = 0; mi[ i ].mi_type != NULL; i++ ) {
252         type = mi[ i ].mi_type;
253         value = mi[ i ].mi_val;
254         len = mi[ i ].mi_len;
255         switch ( getmodtype( type )) {
256         case T_MODSEP:
257             state = T_MODSEP; /* Got a separator line "-\n" */
258             continue;
259         case T_MODOPADD:
260             state = T_MODOPADD;
261             ldmarr = ( LDAPMod ** )
262                     ch_realloc(ldmarr, (( nops + 2 ) * ( sizeof( LDAPMod * ))));
263             ldmarr[ nops ] = ldm = alloc_ldapmod();
264             ldm->mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
265             ldm->mod_type = value;
266             nvals = 0;
267             nops++;
268             break;
269         case T_MODOPREPLACE:
270             state = T_MODOPREPLACE;
271             ldmarr = ( LDAPMod ** )
272                     ch_realloc(ldmarr, (( nops + 2 ) * ( sizeof( LDAPMod * ))));
273             ldmarr[ nops ] = ldm = alloc_ldapmod();
274             ldm->mod_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
275             ldm->mod_type = value;
276             nvals = 0;
277             nops++;
278             break;
279         case T_MODOPDELETE:
280             state = T_MODOPDELETE;
281             ldmarr = ( LDAPMod ** )
282                     ch_realloc(ldmarr, (( nops + 2 ) * ( sizeof( LDAPMod * ))));
283             ldmarr[ nops ] = ldm = alloc_ldapmod();
284             ldm->mod_op = LDAP_MOD_DELETE | LDAP_MOD_BVALUES;
285             ldm->mod_type = value;
286             nvals = 0;
287             nops++;
288             break;
289         default:
290             if ( state == AWAITING_OP ) {
291                 Debug( LDAP_DEBUG_ANY,
292                         "Error: op_ldap_modify: unknown mod type \"%s\"\n",
293                         type, 0, 0 );
294                 continue;
295             }
296
297             /*
298              * We should have an attribute: value pair here.
299              * Construct the mod_bvalues part of the ldapmod struct.
300              */
301             if ( strcasecmp( type, ldm->mod_type )) {
302                 Debug( LDAP_DEBUG_ANY,
303                         "Error: malformed modify op, %s: %s (expecting %s:)\n",
304                         type, value, ldm->mod_type );
305                 continue;
306             }
307             ldm->mod_bvalues = ( struct berval ** )
308                     ch_realloc( ldm->mod_bvalues,
309                     ( nvals + 2 ) * sizeof( struct berval * ));
310             ldm->mod_bvalues[ nvals + 1 ] = NULL;
311             ldm->mod_bvalues[ nvals ] = ( struct berval * )
312                     ch_malloc( sizeof( struct berval ));
313             ldm->mod_bvalues[ nvals ]->bv_val = value;
314             ldm->mod_bvalues[ nvals ]->bv_len = len;
315             nvals++;
316         }
317     }
318     ldmarr[ nops ] = NULL;
319
320     if ( nops > 0 ) {
321         /* Actually perform the LDAP operation */
322         Debug( LDAP_DEBUG_ARGS, "replica %s:%d - modify dn \"%s\"\n",
323                 ri->ri_hostname, ri->ri_port, re->re_dn );
324         rc = ldap_modify_s( ri->ri_ldp, re->re_dn, ldmarr );
325     }
326     free_ldmarr( ldmarr );
327     return( rc );
328 }
329
330
331
332
333 /*
334  * Perform an ldap delete operation.
335  */
336 static int
337 op_ldap_delete(
338     Ri          *ri,
339     Re          *re,
340     char        **errmsg
341 )
342 {
343     int         rc;
344
345     Debug( LDAP_DEBUG_ARGS, "replica %s:%d - delete dn \"%s\"\n",
346             ri->ri_hostname, ri->ri_port, re->re_dn );
347     rc = ldap_delete_s( ri->ri_ldp, re->re_dn );
348
349     return( rc );
350 }
351
352
353
354
355 /*
356  * Perform an ldap modrdn operation.
357  */
358 #define GOT_NEWRDN              0x1
359 #define GOT_DELOLDRDN   0x2
360 #define GOT_NEWSUP              0x4
361
362 #define GOT_MODDN_REQ   (GOT_NEWRDN|GOT_DELOLDRDN)
363 #define GOT_ALL_MODDN(f)        (((f) & GOT_MODDN_REQ) == GOT_MODDN_REQ)
364 static int
365 op_ldap_modrdn(
366     Ri          *ri,
367     Re          *re,
368     char        **errmsg
369 )
370 {
371     int         rc = 0;
372     Mi          *mi;
373     int         i;
374         int             lderr = 0;
375     int         state = 0;
376     int         drdnflag = -1;
377     char        *newrdn;
378         char    *newsup = NULL;
379
380     if ( re->re_mods == NULL ) {
381         *errmsg = "No arguments given";
382         Debug( LDAP_DEBUG_ANY, "Error: op_ldap_modrdn: no arguments\n",
383                 0, 0, 0 );
384             return -1;
385     }
386
387     /*
388      * Get the arguments: should see newrdn: and deleteoldrdn: args.
389      */
390     for ( mi = re->re_mods, i = 0; mi[ i ].mi_type != NULL; i++ ) {
391         if ( !strcmp( mi[ i ].mi_type, T_NEWRDNSTR )) {
392                 if( state & GOT_NEWRDN ) {
393                 Debug( LDAP_DEBUG_ANY,
394                         "Error: op_ldap_modrdn: multiple newrdn arg \"%s\"\n",
395                         mi[ i ].mi_val, 0, 0 );
396                 *errmsg = "Multiple newrdn argument";
397                 return -1;
398                 }
399
400             newrdn = mi[ i ].mi_val;
401             state |= GOT_NEWRDN;
402
403         } else if ( !strcmp( mi[ i ].mi_type, T_DELOLDRDNSTR )) {
404                 if( state & GOT_DELOLDRDN ) {
405                 Debug( LDAP_DEBUG_ANY,
406                         "Error: op_ldap_modrdn: multiple deleteoldrdn arg \"%s\"\n",
407                         mi[ i ].mi_val, 0, 0 );
408                 *errmsg = "Multiple newrdn argument";
409                 return -1;
410                 }
411
412             state |= GOT_DELOLDRDN;
413             if ( !strcmp( mi[ i ].mi_val, "0" )) {
414                 drdnflag = 0;
415             } else if ( !strcmp( mi[ i ].mi_val, "1" )) {
416                 drdnflag = 1;
417             } else {
418                 Debug( LDAP_DEBUG_ANY,
419                         "Error: op_ldap_modrdn: bad deleteoldrdn arg \"%s\"\n",
420                         mi[ i ].mi_val, 0, 0 );
421                 *errmsg = "Incorrect argument to deleteoldrdn";
422                 return -1;
423             }
424
425         } else if ( !strcmp( mi[ i ].mi_type, T_NEWSUPSTR )) {
426                 if( state & GOT_NEWSUP ) {
427                 Debug( LDAP_DEBUG_ANY,
428                         "Error: op_ldap_modrdn: multiple newsuperior arg \"%s\"\n",
429                         mi[ i ].mi_val, 0, 0 );
430                 *errmsg = "Multiple newrdn argument";
431                 return -1;
432                 }
433
434                 newrdn = mi[ i ].mi_val;
435             state |= GOT_NEWSUP;
436
437         } else {
438             Debug( LDAP_DEBUG_ANY, "Error: op_ldap_modrdn: bad type \"%s\"\n",
439                     mi[ i ].mi_type, 0, 0 );
440             *errmsg = "Bad value in replication log entry";
441             return -1;
442         }
443     }
444
445     /*
446      * Punt if we don't have all the args.
447      */
448     if ( GOT_ALL_MODDN(state) ) {
449         Debug( LDAP_DEBUG_ANY, "Error: op_ldap_modrdn: missing arguments\n",
450                 0, 0, 0 );
451         *errmsg = "Missing argument: requires \"newrdn\" and \"deleteoldrdn\"";
452         return -1;
453     }
454
455 #ifdef LDAP_DEBUG
456     if ( ldap_debug & LDAP_DEBUG_ARGS ) {
457         char buf[ 256 ];
458         char *buf2;
459         sprintf( buf, "%s:%d", ri->ri_hostname, ri->ri_port );
460         buf2 = (char *) ch_malloc( strlen( re->re_dn ) + strlen( mi->mi_val )
461                 + 10 );
462         sprintf( buf2, "(\"%s\" -> \"%s\")", re->re_dn, mi->mi_val );
463         Debug( LDAP_DEBUG_ARGS,
464                 "replica %s - modify rdn %s (flag: %d)\n",
465                 buf, buf2, drdnflag );
466         free( buf2 );
467     }
468 #endif /* LDAP_DEBUG */
469
470     /* Do the modrdn */
471     rc = ldap_rename2_s( ri->ri_ldp, re->re_dn, mi->mi_val, drdnflag, newsup );
472
473         ldap_get_option( ri->ri_ldp, LDAP_OPT_ERROR_NUMBER, &lderr);
474     return( lderr );
475 }
476
477
478
479 /*
480  * Allocate and initialize an ldapmod struct.
481  */
482 static LDAPMod *
483 alloc_ldapmod( void )
484 {
485     LDAPMod     *ldm;
486
487     ldm = ( struct ldapmod * ) ch_malloc( sizeof ( struct ldapmod ));
488     ldm->mod_type = NULL;
489     ldm->mod_bvalues = ( struct berval ** ) NULL;
490     return( ldm );
491 }
492
493
494
495 /*
496  * Free an ldapmod struct associated mod_bvalues.  NOTE - it is assumed
497  * that mod_bvalues and mod_type contain pointers to the same block of memory
498  * pointed to by the repl struct.  Therefore, it's not freed here.
499  */
500 static void
501 free_ldapmod(
502 LDAPMod *ldm )
503 {
504     int         i;
505
506     if ( ldm == NULL ) {
507         return;
508     }
509     if ( ldm->mod_bvalues != NULL ) {
510         for ( i = 0; ldm->mod_bvalues[ i ] != NULL; i++ ) {
511             free( ldm->mod_bvalues[ i ] );
512         }
513         free( ldm->mod_bvalues );
514     }
515     free( ldm );
516     return;
517 }
518
519
520 /*
521  * Free an an array of LDAPMod pointers and the LDAPMod structs they point
522  * to.
523  */
524 static void
525 free_ldmarr(
526 LDAPMod **ldmarr )
527 {
528     int i;
529
530     for ( i = 0; ldmarr[ i ] != NULL; i++ ) {
531         free_ldapmod( ldmarr[ i ] );
532     }
533     free( ldmarr );
534 }
535
536
537 /*
538  * Create a berval with a single value. 
539  */
540 static struct berval **
541 make_singlevalued_berval( 
542 char    *value,
543 int     len )
544 {
545     struct berval **p;
546
547     p = ( struct berval ** ) ch_malloc( 2 * sizeof( struct berval * ));
548     p[ 0 ] = ( struct berval * ) ch_malloc( sizeof( struct berval ));
549     p[ 1 ] = NULL;
550     p[ 0 ]->bv_val = value;
551     p[ 0 ]->bv_len = len;
552     return( p );
553 }
554
555
556 /*
557  * Given a modification type (string), return an enumerated type.
558  * Avoids ugly copy in op_ldap_modify - lets us use a switch statement
559  * there.
560  */
561 static int
562 getmodtype( 
563 char *type )
564 {
565     if ( !strcmp( type, T_MODSEPSTR )) {
566         return( T_MODSEP );
567     }
568     if ( !strcmp( type, T_MODOPADDSTR )) {
569         return( T_MODOPADD );
570     }
571     if ( !strcmp( type, T_MODOPREPLACESTR )) {
572         return( T_MODOPREPLACE );
573     }
574     if ( !strcmp( type, T_MODOPDELETESTR )) {
575         return( T_MODOPDELETE );
576     }
577     return( T_ERR );
578 }
579
580
581 /*
582  * Perform an LDAP unbind operation.  If replica is NULL, or the
583  * repl_ldp is NULL, just return LDAP_SUCCESS.  Otherwise, unbind,
584  * set the ldp to NULL, and return the result of the unbind call.
585  */
586 static int
587 do_unbind(
588     Ri  *ri
589 )
590 {
591     int         rc = LDAP_SUCCESS;
592
593     if (( ri != NULL ) && ( ri->ri_ldp != NULL )) {
594         rc = ldap_unbind( ri->ri_ldp );
595         if ( rc != LDAP_SUCCESS ) {
596             Debug( LDAP_DEBUG_ANY,
597                     "Error: do_unbind: ldap_unbind failed for %s:%d: %s\n",
598                     ri->ri_hostname, ri->ri_port, ldap_err2string( rc ) );
599         }
600         ri->ri_ldp = NULL;
601     }
602     return rc;
603 }
604
605
606
607 /*
608  * Perform an LDAP bind operation to the replication site given
609  * by replica.  If replica->repl_ldp is non-NULL, then we unbind
610  * from the replica before rebinding.  It should be safe to call
611  * this to re-connect if the replica's connection goes away
612  * for some reason.
613  *
614  * Returns 0 on success, -1 if an LDAP error occurred, and a return
615  * code > 0 if some other error occurred, e.g. invalid bind method.
616  * If an LDAP error occurs, the LDAP error is returned in lderr.
617  */
618 static int
619 do_bind( 
620     Ri  *ri,
621     int *lderr
622 )
623 {
624     int         ldrc;
625 #ifdef HAVE_KERBEROS
626     int rc;
627     int retval = 0;
628     int kni, got_tgt;
629     char **krbnames;
630     char *skrbnames[ 2 ];
631     char realm[ REALM_SZ ];
632     char name[ ANAME_SZ ];
633     char instance[ INST_SZ ];
634 #endif /* HAVE_KERBEROS */
635
636     *lderr = 0;
637
638     if ( ri == NULL ) {
639         Debug( LDAP_DEBUG_ANY, "Error: do_bind: null ri ptr\n", 0, 0, 0 );
640         return( BIND_ERR_BADRI );
641     }
642
643     if ( ri->ri_ldp != NULL ) {
644         ldrc = ldap_unbind( ri->ri_ldp );
645         if ( ldrc != LDAP_SUCCESS ) {
646             Debug( LDAP_DEBUG_ANY,
647                     "Error: do_bind: ldap_unbind failed: %s\n",
648                     ldap_err2string( ldrc ), 0, 0 );
649         }
650         ri->ri_ldp = NULL;
651     }
652
653     Debug( LDAP_DEBUG_ARGS, "Initializing session to %s:%d\n",
654             ri->ri_hostname, ri->ri_port, 0 );
655     ri->ri_ldp = ldap_init( ri->ri_hostname, ri->ri_port );
656     if ( ri->ri_ldp == NULL ) {
657         Debug( LDAP_DEBUG_ANY, "Error: ldap_init(%s, %d) failed: %s\n",
658                 ri->ri_hostname, ri->ri_port, sys_errlist[ errno ] );
659         return( BIND_ERR_OPEN );
660     }
661
662     /*
663      * Disable string translation if enabled by default.
664      * The replication log is written in the internal format,
665      * so this would do another translation, breaking havoc.
666      */
667 #if defined( STR_TRANSLATION ) && defined( LDAP_DEFAULT_CHARSET )
668         ri->ri_ldp->ld_lberoptions &= ~LBER_TRANSLATE_STRINGS;
669 #endif /* STR_TRANSLATION && LDAP_DEFAULT_CHARSET */
670
671     /*
672      * Set ldap library options to (1) not follow referrals, and 
673      * (2) restart the select() system call.
674      */
675         ldap_set_option(ri->ri_ldp, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
676         ldap_set_option(ri->ri_ldp, LDAP_OPT_RESTART, LDAP_OPT_ON);
677
678     switch ( ri->ri_bind_method ) {
679     case AUTH_KERBEROS:
680 #ifndef HAVE_KERBEROS
681         Debug( LDAP_DEBUG_ANY,
682             "Error: Kerberos bind for %s:%d, but not compiled w/kerberos\n",
683             ri->ri_hostname, ri->ri_port, 0 );
684         return( BIND_ERR_KERBEROS_FAILED );
685 #else /* HAVE_KERBEROS */
686         /*
687          * Bind using kerberos.
688          * If "bindprincipal" was given in the config file, then attempt
689          * to get a TGT for that principal (via the srvtab file).  If only
690          * a binddn was given, then we need to read that entry to get
691          * the kerberosName attributes, and try to get a TGT for one
692          * of them.  All are tried.  The first one which succeeds is
693          * returned.  XXX It might be a good idea to just require a
694          * bindprincipal.  Reading the entry every time might be a significant
695          * amount of overhead, if the connection is closed between most
696          * updates.
697          */
698
699         if ( ri->ri_principal != NULL ) {
700             skrbnames[ 0 ] = ri->ri_principal;
701             skrbnames[ 1 ] = NULL;
702             krbnames = skrbnames;
703         } else {
704             krbnames = read_krbnames( ri );
705         }       
706             
707         if (( krbnames == NULL ) || ( krbnames[ 0 ] == NULL )) {
708             Debug( LDAP_DEBUG_ANY,
709                     "Error: Can't find krbname for binddn \"%s\"\n",
710                     ri->ri_bind_dn, 0, 0 );
711             retval = BIND_ERR_KERBEROS_FAILED;
712             goto kexit;
713         }
714         /*
715          * Now we've got one or more kerberos principals.  See if any
716          * of them are in the srvtab file.
717          */
718         got_tgt = 0;
719         for ( kni = 0; krbnames[ kni ] != NULL; kni++ ) {
720             rc = kname_parse( name, instance, realm, krbnames[ kni ]);
721             if ( rc != KSUCCESS ) {
722                 continue;
723             }
724             upcase( realm );
725             rc = krb_get_svc_in_tkt( name, instance, realm, "krbtgt", realm,
726                     1, ri->ri_srvtab );
727             if ( rc != KSUCCESS) {
728                 Debug( LDAP_DEBUG_ANY, "Error: Can't get TGT for %s: %s\n",
729                         krbnames[ kni ], krb_err_txt[ rc ], 0 );
730             } else {
731                 got_tgt = 1;
732                 break;
733             }
734         }
735         if (!got_tgt) {
736             Debug( LDAP_DEBUG_ANY,
737                     "Error: Could not obtain TGT for DN \"%s\"\n", 
738                     ri->ri_bind_dn, 0, 0 );
739             retval = BIND_ERR_KERBEROS_FAILED;
740             goto kexit;
741         }
742         /*
743          * We've got a TGT.  Do a kerberos bind.
744          */
745         Debug( LDAP_DEBUG_ARGS, "bind to %s:%d as %s (kerberos)\n",
746                 ri->ri_hostname, ri->ri_port, ri->ri_bind_dn );
747         ldrc = ldap_kerberos_bind_s( ri->ri_ldp, ri->ri_bind_dn );
748         ri->ri_principal = strdup( krbnames[ kni ] );
749         if ( ldrc != LDAP_SUCCESS ) {
750             Debug( LDAP_DEBUG_ANY, "Error: kerberos bind for %s:%dfailed: %s\n",
751                 ri->ri_hostname, ri->ri_port, ldap_err2string( ldrc ));
752             *lderr = ldrc;
753             retval = BIND_ERR_KERBEROS_FAILED;
754             goto kexit;
755         }
756 kexit:  if ( krbnames != NULL ) {
757             ldap_value_free( krbnames );
758         }
759         return( retval);
760         break;
761 #endif /* HAVE_KERBEROS */
762     case AUTH_SIMPLE:
763         /*
764          * Bind with a plaintext password.
765          */
766         Debug( LDAP_DEBUG_ARGS, "bind to %s:%d as %s (simple)\n",
767                 ri->ri_hostname, ri->ri_port, ri->ri_bind_dn );
768         ldrc = ldap_simple_bind_s( ri->ri_ldp, ri->ri_bind_dn,
769                 ri->ri_password );
770         if ( ldrc != LDAP_SUCCESS ) {
771             Debug( LDAP_DEBUG_ANY,
772                     "Error: ldap_simple_bind_s for %s:%d failed: %s\n",
773                     ri->ri_hostname, ri->ri_port, ldap_err2string( ldrc ));
774             *lderr = ldrc;
775             return( BIND_ERR_SIMPLE_FAILED );
776         } else {
777             return( BIND_OK );
778         }
779         break;
780     default:
781         Debug(  LDAP_DEBUG_ANY,
782                 "Error: do_bind: unknown auth type \"%d\" for %s:%d\n",
783                 ri->ri_bind_method, ri->ri_hostname, ri->ri_port );
784         return( BIND_ERR_BAD_ATYPE );
785     }
786 }
787
788
789
790
791
792 /*
793  * For debugging.  Print the contents of an ldmarr array.
794  */
795 static void
796 dump_ldm_array(
797     LDAPMod **ldmarr
798 )
799 {
800     int                  i, j;
801     LDAPMod             *ldm;
802     struct berval       *b;
803     char                *msgbuf;
804
805     for ( i = 0; ldmarr[ i ] != NULL; i++ ) {
806         ldm = ldmarr[ i ];
807         Debug( LDAP_DEBUG_TRACE,
808                 "Trace (%ld): *** ldmarr[ %d ] contents:\n",
809                 (long) getpid(), i, 0 );
810         Debug( LDAP_DEBUG_TRACE,
811                 "Trace (%ld): *** ldm->mod_op: %d\n",
812                 (long) getpid(), ldm->mod_op, 0 );
813         Debug( LDAP_DEBUG_TRACE,
814                 "Trace (%ld): *** ldm->mod_type: %s\n",
815                 (long) getpid(), ldm->mod_type, 0 );
816         if ( ldm->mod_bvalues != NULL ) {
817             for ( j = 0; ( b = ldm->mod_bvalues[ j ] ) != NULL; j++ ) {
818                 msgbuf = ch_malloc( b->bv_len + 512 );
819                 sprintf( msgbuf, "***** bv[ %d ] len = %ld, val = <%s>",
820                         j, b->bv_len, b->bv_val );
821                 Debug( LDAP_DEBUG_TRACE,
822                         "Trace (%ld):%s\n", (long) getpid(), msgbuf, 0 );
823                 free( msgbuf );
824             }
825         }
826     }
827 }
828
829
830 /*
831  * Get the kerberos names from the binddn for "replica" via an ldap search.
832  * Returns a null-terminated array of char *, or NULL if the entry could
833  * not be found or there were no kerberosName attributes.  The caller is
834  * responsible for freeing the returned array and strings it points to.
835  */
836 static char **
837 read_krbnames(
838     Ri  *ri
839 )
840 {
841     int rc;
842     char **krbnames;
843     int ne;
844     LDAPMessage *result, *entry;
845
846     /* First need to bind as NULL */
847     rc = ldap_simple_bind_s( ri->ri_ldp, NULL, NULL );
848     if ( rc != LDAP_SUCCESS ) {
849         Debug( LDAP_DEBUG_ANY,
850                 "Error: null bind failed getting krbnames for %s:%d: %s\n",
851                 ri->ri_hostname, ri->ri_port, ldap_err2string( rc ));
852         return( NULL );
853     }
854     rc = ldap_search_st( ri->ri_ldp, ri->ri_bind_dn, LDAP_SCOPE_BASE,
855             "objectclass=*", kattrs, 0, &kst, &result );
856     if ( rc != LDAP_SUCCESS ) {
857         Debug( LDAP_DEBUG_ANY,
858                 "Error: search failed getting krbnames for %s:%d: %s\n",
859                 ri->ri_hostname, ri->ri_port, ldap_err2string( rc ));
860         return( NULL );
861     }
862     ne = ldap_count_entries( ri->ri_ldp, result );
863     if ( ne == 0 ) {
864         Debug( LDAP_DEBUG_ANY,
865                 "Error: Can't find entry \"%s\" for %s:%d kerberos bind\n",
866                 ri->ri_bind_dn, ri->ri_hostname, ri->ri_port );
867             return( NULL );
868     }
869     if ( ne > 1 ) {
870         Debug( LDAP_DEBUG_ANY,
871                 "Error: Kerberos binddn \"%s\" for %s:%dis ambiguous\n",
872                 ri->ri_bind_dn, ri->ri_hostname, ri->ri_port );
873             return( NULL );
874     }
875     entry = ldap_first_entry( ri->ri_ldp, result );
876     if ( entry == NULL ) {
877         Debug( LDAP_DEBUG_ANY,
878                 "Error: Can't find \"%s\" for kerberos binddn for %s:%d\n",
879                     ri->ri_bind_dn, ri->ri_hostname, ri->ri_port );
880         return( NULL );
881     }
882     krbnames = ldap_get_values( ri->ri_ldp, entry, "kerberosName" );
883     ldap_msgfree( result );
884     return( krbnames );
885 }
886
887
888
889 /*
890  * upcase a string
891  */
892 static void
893 upcase(
894     char *s
895 )
896 {
897     char *p;
898
899     for ( p = s; ( p != NULL ) && ( *p != '\0' ); p++ ) {
900             *p = TOUPPER( (unsigned char) *p );
901     }
902 }