]> git.sur5r.net Git - openldap/blob - libraries/libldap/sasl.c
Merged in preliminary support for Cyrus SASL library;
[openldap] / libraries / libldap / sasl.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6
7 /*
8  *      BindRequest ::= SEQUENCE {
9  *              version         INTEGER,
10  *              name            DistinguishedName,       -- who
11  *              authentication  CHOICE {
12  *                      simple          [0] OCTET STRING -- passwd
13 #ifdef HAVE_KERBEROS
14  *                      krbv42ldap      [1] OCTET STRING
15  *                      krbv42dsa       [2] OCTET STRING
16 #endif
17  *                      sasl            [3] SaslCredentials     -- LDAPv3
18  *              }
19  *      }
20  *
21  *      BindResponse ::= SEQUENCE {
22  *              COMPONENTS OF LDAPResult,
23  *              serverSaslCreds         OCTET STRING OPTIONAL -- LDAPv3
24  *      }
25  *
26  */
27
28 #include "portable.h"
29
30 #include <stdio.h>
31
32 #include <ac/socket.h>
33 #include <ac/string.h>
34 #include <ac/time.h>
35
36 #include "ldap-int.h"
37
38
39 /*
40  * ldap_sasl_bind - bind to the ldap server (and X.500).  The dn, mechanism, and
41  * credentials of the entry to which to bind are supplied.  The message id
42  * of the request initiated is provided upon successful (LDAP_SUCCESS) return.
43  *
44  * Example:
45  *      ldap_sasl_bind( ld, "cn=manager, o=university of michigan, c=us",
46  *          "mechanism", "secret", NULL, NULL, &msgid )
47  */
48
49 int
50 ldap_sasl_bind(
51         LDAP                    *ld,
52         LDAP_CONST char *dn,
53         LDAP_CONST char *mechanism,
54         struct berval   *cred,
55         LDAPControl             **sctrls,
56         LDAPControl             **cctrls,
57         int                             *msgidp )
58 {
59         BerElement      *ber;
60         int rc;
61
62         Debug( LDAP_DEBUG_TRACE, "ldap_sasl_bind\n", 0, 0, 0 );
63
64         assert( ld != NULL );
65         assert( LDAP_VALID( ld ) );
66         assert( msgidp != NULL );
67
68         if( msgidp == NULL ) {
69                 ld->ld_errno = LDAP_PARAM_ERROR;
70                 return ld->ld_errno;
71         }
72
73         if( mechanism == LDAP_SASL_SIMPLE ) {
74                 if( dn == NULL && cred != NULL ) {
75                         /* use default binddn */
76                         dn = ld->ld_defbinddn;
77                 }
78
79         } else if( ld->ld_version < LDAP_VERSION3 ) {
80                 ld->ld_errno = LDAP_NOT_SUPPORTED;
81                 return ld->ld_errno;
82         }
83
84         if ( dn == NULL ) {
85                 dn = "";
86         }
87
88         /* create a message to send */
89         if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
90                 ld->ld_errno = LDAP_NO_MEMORY;
91                 return ld->ld_errno;
92         }
93
94         assert( BER_VALID( ber ) );
95
96         if( mechanism == LDAP_SASL_SIMPLE ) {
97                 /* simple bind */
98                 rc = ber_printf( ber, "{it{istO}" /*}*/,
99                         ++ld->ld_msgid, LDAP_REQ_BIND,
100                         ld->ld_version, dn, LDAP_AUTH_SIMPLE,
101                         cred );
102                 
103         } else if ( cred == NULL ) {
104                 /* SASL bind w/o creditials */
105                 rc = ber_printf( ber, "{it{ist{s}}" /*}*/,
106                         ++ld->ld_msgid, LDAP_REQ_BIND,
107                         ld->ld_version, dn, LDAP_AUTH_SASL,
108                         mechanism );
109
110         } else {
111                 /* SASL bind w/ creditials */
112                 rc = ber_printf( ber, "{it{ist{sO}}" /*}*/,
113                         ++ld->ld_msgid, LDAP_REQ_BIND,
114                         ld->ld_version, dn, LDAP_AUTH_SASL,
115                         mechanism, cred );
116         }
117
118         if( rc == -1 ) {
119                 ld->ld_errno = LDAP_ENCODING_ERROR;
120                 ber_free( ber, 1 );
121                 return( -1 );
122         }
123
124         /* Put Server Controls */
125         if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) {
126                 ber_free( ber, 1 );
127                 return ld->ld_errno;
128         }
129
130         if ( ber_printf( ber, /*{*/ "}" ) == -1 ) {
131                 ld->ld_errno = LDAP_ENCODING_ERROR;
132                 ber_free( ber, 1 );
133                 return ld->ld_errno;
134         }
135
136 #ifndef LDAP_NOCACHE
137         if ( ld->ld_cache != NULL ) {
138                 ldap_flush_cache( ld );
139         }
140 #endif /* !LDAP_NOCACHE */
141
142         /* send the message */
143         *msgidp = ldap_send_initial_request( ld, LDAP_REQ_BIND, dn, ber );
144
145         if(*msgidp < 0)
146                 return ld->ld_errno;
147
148         return LDAP_SUCCESS;
149 }
150
151
152 int
153 ldap_sasl_bind_s(
154         LDAP                    *ld,
155         LDAP_CONST char *dn,
156         LDAP_CONST char *mechanism,
157         struct berval   *cred,
158         LDAPControl             **sctrls,
159         LDAPControl             **cctrls,
160         struct berval   **servercredp )
161 {
162         int     rc, msgid;
163         LDAPMessage     *result;
164         struct berval   *scredp = NULL;
165
166         Debug( LDAP_DEBUG_TRACE, "ldap_sasl_bind_s\n", 0, 0, 0 );
167
168         /* do a quick !LDAPv3 check... ldap_sasl_bind will do the rest. */
169         if( servercredp != NULL ) {
170                 if (ld->ld_version < LDAP_VERSION3) {
171                         ld->ld_errno = LDAP_NOT_SUPPORTED;
172                         return ld->ld_errno;
173                 }
174                 *servercredp = NULL;
175         }
176
177         rc = ldap_sasl_bind( ld, dn, mechanism, cred, sctrls, cctrls, &msgid );
178
179         if ( rc != LDAP_SUCCESS ) {
180                 return( rc );
181         }
182
183         if ( ldap_result( ld, msgid, 1, NULL, &result ) == -1 ) {
184                 return( ld->ld_errno ); /* ldap_result sets ld_errno */
185         }
186
187         /* parse the results */
188         scredp = NULL;
189         if( servercredp != NULL ) {
190                 rc = ldap_parse_sasl_bind_result( ld, result, &scredp, 0 );
191         }
192
193         if( rc != LDAP_SUCCESS ) {
194                 ldap_msgfree( result );
195                 return( rc );
196         }
197
198         rc = ldap_result2error( ld, result, 1 );
199
200         if( rc == LDAP_SUCCESS ) {
201                 if( servercredp != NULL ) {
202                         *servercredp = scredp;
203                 }
204
205         } else if (scredp != NULL ) {
206                 ber_bvfree(scredp);
207         }
208
209         return rc;
210 }
211
212
213 /*
214 * Parse BindResponse:
215 *
216 *   BindResponse ::= [APPLICATION 1] SEQUENCE {
217 *     COMPONENTS OF LDAPResult,
218 *     serverSaslCreds  [7] OCTET STRING OPTIONAL }
219 *
220 *   LDAPResult ::= SEQUENCE {
221 *     resultCode      ENUMERATED,
222 *     matchedDN       LDAPDN,
223 *     errorMessage    LDAPString,
224 *     referral        [3] Referral OPTIONAL }
225 */
226
227 int
228 ldap_parse_sasl_bind_result(
229         LDAP                    *ld,
230         LDAPMessage             *res,
231         struct berval   **servercredp,
232         int                             freeit )
233 {
234         ber_int_t errcode;
235         struct berval* scred;
236
237         ber_tag_t tag;
238         BerElement      *ber;
239
240         Debug( LDAP_DEBUG_TRACE, "ldap_parse_sasl_bind_result\n", 0, 0, 0 );
241
242         assert( ld != NULL );
243         assert( LDAP_VALID( ld ) );
244         assert( res != NULL );
245
246         if ( ld == NULL || res == NULL ) {
247                 return LDAP_PARAM_ERROR;
248         }
249
250         if( servercredp != NULL ) {
251                 if( ld->ld_version < LDAP_VERSION2 ) {
252                         return LDAP_NOT_SUPPORTED;
253                 }
254                 *servercredp = NULL;
255         }
256
257         if( res->lm_msgtype != LDAP_RES_BIND ) {
258                 ld->ld_errno = LDAP_PARAM_ERROR;
259                 return ld->ld_errno;
260         }
261
262         scred = NULL;
263
264         if ( ld->ld_error ) {
265                 LDAP_FREE( ld->ld_error );
266                 ld->ld_error = NULL;
267         }
268         if ( ld->ld_matched ) {
269                 LDAP_FREE( ld->ld_matched );
270                 ld->ld_matched = NULL;
271         }
272
273         /* parse results */
274
275         ber = ber_dup( res->lm_ber );
276
277         if( ber == NULL ) {
278                 ld->ld_errno = LDAP_NO_MEMORY;
279                 return ld->ld_errno;
280         }
281
282         if ( ld->ld_version < LDAP_VERSION2 ) {
283                 tag = ber_scanf( ber, "{ia}",
284                         &errcode, &ld->ld_error );
285
286                 if( tag == LBER_ERROR ) {
287                         ber_free( ber, 0 );
288                         ld->ld_errno = LDAP_DECODING_ERROR;
289                         return ld->ld_errno;
290                 }
291
292         } else {
293                 ber_len_t len;
294
295                 tag = ber_scanf( ber, "{iaa" /*}*/,
296                         &errcode, &ld->ld_matched, &ld->ld_error );
297
298                 if( tag == LBER_ERROR ) {
299                         ber_free( ber, 0 );
300                         ld->ld_errno = LDAP_DECODING_ERROR;
301                         return ld->ld_errno;
302                 }
303
304                 tag = ber_peek_tag(ber, &len);
305
306                 if( tag == LDAP_TAG_REFERRAL ) {
307                         /* skip 'em */
308                         if( ber_scanf( ber, "x" ) == LBER_ERROR ) {
309                                 ber_free( ber, 0 );
310                                 ld->ld_errno = LDAP_DECODING_ERROR;
311                                 return ld->ld_errno;
312                         }
313
314                         tag = ber_peek_tag(ber, &len);
315                 }
316
317                 if( tag == LDAP_TAG_SASL_RES_CREDS ) {
318                         if( ber_scanf( ber, "O", &scred ) == LBER_ERROR ) {
319                                 ber_free( ber, 0 );
320                                 ld->ld_errno = LDAP_DECODING_ERROR;
321                                 return ld->ld_errno;
322                         }
323                 }
324         }
325
326         ber_free( ber, 0 );
327
328         if ( servercredp != NULL ) {
329                 *servercredp = scred;
330
331         } else if ( scred != NULL ) {
332                 ber_bvfree( scred );
333         }
334
335         ld->ld_errno = errcode;
336
337         if ( freeit ) {
338                 ldap_msgfree( res );
339         }
340
341         return( ld->ld_errno );
342 }
343
344 #ifdef HAVE_CYRUS_SASL
345 /*
346 * Various Cyrus SASL related stuff.
347 */
348
349 static int sasl_setup( Sockbuf *sb, void *arg );
350 static int sasl_remove( Sockbuf *sb );
351 static ber_slen_t sasl_read( Sockbuf *sb, void *buf, ber_len_t len );
352 static ber_slen_t sasl_write( Sockbuf *sb, void *buf, ber_len_t len );
353 static int sasl_close( Sockbuf *sb );
354
355 static Sockbuf_IO sasl_io=
356 {
357 sasl_setup,
358 sasl_remove,
359 sasl_read,
360 sasl_write,
361 sasl_close
362 }; 
363
364 #define HAS_SASL( sb ) ((sb)->sb_io==&sasl_io)
365
366 static char *
367 array2str( char **a )
368 {
369         char *s, **v, *p;
370         int len = 0;
371
372         for ( v = a; *v != NULL; v++ ) {
373                 len += strlen( *v ) + 1; /* for a space */
374         }
375
376         if ( len == 0 ) {
377                 return NULL;
378         }
379
380         s = LDAP_MALLOC ( len ); /* last space holds \0 */
381
382         if ( s == NULL ) {
383                 return NULL;    
384         }
385
386         p = s;
387         for ( v = a; *v != NULL; v++ ) {
388                 int len;
389
390                 if ( v != a ) {
391                         strncpy( p, " ", 1 );
392                         ++p;
393                 }
394                 len = strlen( *v );
395                 strncpy( p, *v, len );
396                 p += len;
397         }
398
399         *p = '\0';
400
401         return s;
402 }
403
404 int ldap_pvt_sasl_init( void )
405 {
406         /* XXX not threadsafe */
407         static int sasl_initialized = 0;
408
409         if ( sasl_initialized ) {
410                 return -1;
411         }
412 #ifndef CSRIMALLOC
413         sasl_set_alloc( ber_memalloc, ber_memcalloc, ber_memrealloc, ber_memfree );
414 #endif /* CSRIMALLOC */
415
416         if ( sasl_client_init( NULL ) == SASL_OK ) {
417                 sasl_initialized = 1;
418                 return 0;
419         }
420
421         return -1;
422 }
423
424 int ldap_pvt_sasl_install( Sockbuf *sb, void *ctx_arg )
425 {
426         /* don't install the stuff unless security has been negotiated */
427
428         if ( !HAS_SASL( sb ) ) {
429                 ber_pvt_sb_clear_io( sb );
430                 ber_pvt_sb_set_io( sb, &sasl_io, ctx_arg );
431         }
432
433         return 0;
434 }
435
436 static int sasl_setup( Sockbuf *sb, void *arg )
437 {
438         sb->sb_iodata = arg;
439         return 0;
440 }
441
442 static int sasl_remove( Sockbuf *sb )
443 {
444         return 0;
445 }
446
447 static ber_slen_t sasl_read( Sockbuf *sb, void *buf, ber_len_t buflen )
448 {
449         char *recv_tok;
450         unsigned recv_tok_len;
451         sasl_conn_t *conn = (sasl_conn_t *)sb->sb_iodata;
452
453         if ((ber_pvt_sb_io_tcp.sbi_read)( sb, buf, buflen ) != buflen ) {
454                 return -1;
455         }
456
457         if ( sasl_decode( conn, buf, buflen, &recv_tok, &recv_tok_len ) != SASL_OK ) {
458                 return -1;
459         }
460
461         if ( recv_tok_len > buflen ) {
462                 LDAP_FREE( recv_tok );
463                 return -1;
464         }
465
466         memcpy( buf, recv_tok, recv_tok_len );  
467
468         LDAP_FREE( recv_tok );
469
470         return recv_tok_len;
471 }
472
473 static ber_slen_t sasl_write( Sockbuf *sb, void *buf, ber_len_t len )
474 {
475         char *wrapped_tok;
476         unsigned wrapped_tok_len;
477         sasl_conn_t *conn = (sasl_conn_t *)sb->sb_iodata;
478
479         if ( sasl_encode( conn, (const char *)buf, len,
480                 &wrapped_tok, &wrapped_tok_len ) != SASL_OK ) {
481                 return -1;
482         }
483
484         if ((ber_pvt_sb_io_tcp.sbi_write)( sb, wrapped_tok, wrapped_tok_len ) != wrapped_tok_len ) {
485                 LDAP_FREE( wrapped_tok );
486                 return -1;
487         }
488
489         LDAP_FREE( wrapped_tok );
490
491         return len;
492 }
493
494 static int sasl_close( Sockbuf *sb )
495 {
496         (ber_pvt_sb_io_tcp.sbi_close)( sb );
497 }
498
499 int
500 ldap_pvt_sasl_err2ldap( int saslerr )
501 {
502         int rc;
503
504         switch (saslerr) {
505                 case SASL_CONTINUE:
506                         rc = LDAP_SASL_BIND_IN_PROGRESS;
507                         break;
508                 case SASL_OK:
509                         rc = LDAP_SUCCESS;
510                         break;
511                 case SASL_FAIL:
512                         rc = LDAP_OPERATIONS_ERROR;
513                         break;
514                 case SASL_NOMEM:
515                         rc = LDAP_NO_MEMORY;
516                         break;
517                 case SASL_NOMECH:
518                         rc = LDAP_AUTH_METHOD_NOT_SUPPORTED;
519                         break;
520                 case SASL_BADAUTH:
521                         rc = LDAP_INVALID_CREDENTIALS;
522                         break;
523                 case SASL_NOAUTHZ:
524                         rc = LDAP_INSUFFICIENT_ACCESS;
525                         break;
526                 case SASL_TOOWEAK:
527                 case SASL_ENCRYPT:
528                         rc = LDAP_INAPPROPRIATE_AUTH;
529                         break;
530                 default:
531                         rc = LDAP_OPERATIONS_ERROR;
532                         break;
533         }
534
535         return rc;
536 }
537
538 int
539 ldap_pvt_sasl_getmechs ( LDAP *ld, LDAP_CONST char *desired, char **pmechlist )
540 {
541         /* we need to query the server for supported mechs anyway */
542         LDAPMessage *res, *e;
543         char *attrs[] = { "supportedSASLMechanisms", NULL };
544         char **values, *mechlist, **p;
545         int rc;
546
547         rc = ldap_search_s( ld, NULL, LDAP_SCOPE_BASE,
548                 "(objectclass=*)", attrs, 0, &res );
549
550         if ( rc != LDAP_SUCCESS ) {
551                 return ld->ld_errno;
552         }
553                 
554         e = ldap_first_entry( ld, res );
555         if ( e == NULL ) {
556                 if ( ld->ld_errno == LDAP_SUCCESS ) {
557                         ld->ld_errno = LDAP_UNAVAILABLE;
558                 }
559                 return ld->ld_errno;
560         }
561
562         values = ldap_get_values( ld, e, "supportedSASLMechanisms" );
563         if ( values == NULL ) {
564                 ld->ld_errno = LDAP_NO_SUCH_ATTRIBUTE;
565                 ldap_msgfree( res );
566                 return ld->ld_errno;
567         }
568
569         if ( desired != NULL ) {
570                 rc = LDAP_INAPPROPRIATE_AUTH;
571
572                 for ( p = values; *p != NULL; p++ ) {
573                         if ( !strcmp( *p, desired ) == 0 ) {
574                                 rc = LDAP_SUCCESS;
575                                 break;
576                         }
577                 }
578
579                 if ( rc == LDAP_SUCCESS ) {
580                         /* just return this */
581                         *pmechlist = LDAP_STRDUP( desired );
582                         return LDAP_SUCCESS;
583                 } else {
584                         /* couldn't find it */
585                         ld->ld_errno = LDAP_INAPPROPRIATE_AUTH;
586                         return ld->ld_errno;
587                 }
588         }
589
590         mechlist = array2str( values );
591         if ( mechlist == NULL ) {
592                 ld->ld_errno = LDAP_NO_MEMORY;
593                 ldap_value_free( values );
594                 ldap_msgfree( res );
595                 return ld->ld_errno;
596         } 
597
598         ldap_value_free( values );
599         ldap_msgfree( res );
600
601         *pmechlist = mechlist;
602
603         return LDAP_SUCCESS;
604 }
605
606 int
607 ldap_pvt_sasl_bind(
608         LDAP                    *ld,
609         LDAP_CONST char         *dn,
610         LDAP_CONST char         *mechanism,
611         const sasl_callback_t   *callbacks,
612         LDAPControl             **sctrls,
613         LDAPControl             **cctrls )
614 {
615         int     saslrc, rc, msgid, ssf = 0;
616         struct berval ccred, *scred;
617         char *mechlist = NULL;
618         char *host;
619         sasl_interact_t *client_interact = NULL;
620
621         Debug( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_bind\n", 0, 0, 0 );
622
623         /* do a quick !LDAPv3 check... ldap_sasl_bind will do the rest. */
624         if (ld->ld_version < LDAP_VERSION3) {
625                 ld->ld_errno = LDAP_NOT_SUPPORTED;
626                 return ld->ld_errno;
627         }
628
629         /*
630          * This connects to the host, side effect being that
631          * ldap_host_connected_to() works.
632          */
633         rc = ldap_pvt_sasl_getmechs( ld, mechanism, &mechlist );
634         if ( rc != LDAP_SUCCESS ) {
635                 return ld->ld_errno;
636         }
637
638         /* XXX this doesn't work with PF_LOCAL hosts */
639         host = ldap_host_connected_to( &ld->ld_sb );
640
641         if ( host == NULL ) {
642                 LDAP_FREE( mechlist );
643                 ld->ld_errno = LDAP_UNAVAILABLE;
644                 return ld->ld_errno;
645         }
646
647         if ( ld->ld_sasl_context != NULL ) {
648                 LDAP_FREE( mechlist );
649                 sasl_dispose( &ld->ld_sasl_context );
650         }
651
652         saslrc = sasl_client_new( "ldap", host, callbacks, 0, &ld->ld_sasl_context );
653
654         LDAP_FREE( host );
655
656         if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
657                 LDAP_FREE( mechlist );
658                 ld->ld_errno = ldap_pvt_sasl_err2ldap( rc );
659                 sasl_dispose( &ld->ld_sasl_context );
660                 return ld->ld_errno;
661         }
662
663         ccred.bv_val = NULL;
664         ccred.bv_len = 0;
665
666         saslrc = sasl_client_start( ld->ld_sasl_context,
667                 mechlist,
668                 NULL,
669                 &client_interact,
670                 &ccred.bv_val,
671                 (unsigned int *)&ccred.bv_len,
672                 &mechanism );
673
674         LDAP_FREE( mechlist );
675
676         if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
677                 ld->ld_errno = ldap_pvt_sasl_err2ldap( saslrc );
678                 sasl_dispose( &ld->ld_sasl_context );
679                 return ld->ld_errno;
680         }
681
682         scred = NULL;
683
684         do {
685                 sasl_interact_t *client_interact = NULL;
686
687                 rc = ldap_sasl_bind_s( ld, dn, mechanism, &ccred, sctrls, cctrls, &scred );
688                 if ( rc == LDAP_SUCCESS ) {
689                         break;
690                 } else if ( rc != LDAP_SASL_BIND_IN_PROGRESS ) {
691                         if ( ccred.bv_val != NULL ) {
692                                 LDAP_FREE( ccred.bv_val );
693                         }
694                         sasl_dispose( &ld->ld_sasl_context );
695                         return ld->ld_errno;
696                 }
697
698                 if ( ccred.bv_val != NULL ) {
699                         LDAP_FREE( ccred.bv_val );
700                         ccred.bv_val = NULL;
701                 }
702
703                 saslrc = sasl_client_step( ld->ld_sasl_context,
704                         (scred == NULL) ? NULL : scred->bv_val,
705                         (scred == NULL) ? 0 : scred->bv_len,
706                         &client_interact,
707                         &ccred.bv_val,
708                         (unsigned int *)&ccred.bv_len );
709
710                 ber_bvfree( scred );
711
712                 if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
713                         ld->ld_errno = ldap_pvt_sasl_err2ldap( saslrc );
714                         sasl_dispose( &ld->ld_sasl_context );
715                         return ld->ld_errno;
716                 }
717         } while ( rc == LDAP_SASL_BIND_IN_PROGRESS );
718
719         assert ( rc == LDAP_SUCCESS );
720
721         if ( sasl_getprop( ld->ld_sasl_context, SASL_SSF, (void **)&ssf )
722                 == SASL_OK && ssf ) {
723                 ldap_pvt_sasl_install( &ld->ld_sb, ld->ld_sasl_context );
724         }
725
726         return rc;
727 }
728
729 /* based on sample/sample-client.c */
730 static int
731 ldap_pvt_sasl_getsecret(sasl_conn_t *conn, void *context, int id, sasl_secret_t **psecret)
732 {
733         struct berval *passphrase = (struct berval *)context;
734         size_t len;           
735
736         if ( conn == NULL || psecret == NULL || id != SASL_CB_PASS ) {
737                 return SASL_BADPARAM;
738         }
739
740         len = (passphrase != NULL) ? (size_t)passphrase->bv_len: 0;
741
742         *psecret = (sasl_secret_t *) LDAP_MALLOC( sizeof( sasl_secret_t ) + len );
743         if ( *psecret == NULL ) {
744                 return SASL_NOMEM;
745         }
746
747         (*psecret)->len = passphrase->bv_len;
748
749         if ( passphrase != NULL ) {
750                 memcpy((*psecret)->data, passphrase->bv_val, len);
751         }
752
753         return SASL_OK;
754 }
755
756 static int
757 ldap_pvt_sasl_getsimple(void *context, int id, const char **result, int *len)
758 {
759         const char *value = (const char *)context;
760
761         if ( result == NULL ) {
762                 return SASL_BADPARAM;
763         }
764
765         switch ( id ) {
766                 case SASL_CB_USER:
767                 case SASL_CB_AUTHNAME:
768                         *result = value;
769                         if ( len )
770                                 *len = value ? strlen( value ) : 0;
771                         break;
772                 case SASL_CB_LANGUAGE:
773                         *result = NULL;
774                         if ( len )
775                                 *len = 0;
776                         break;
777                 default:
778                         return SASL_BADPARAM;
779         }
780
781         return SASL_OK;
782 }
783
784 /*
785  * ldap_negotiated_sasl_bind_s - bind to the ldap server (and X.500) using SASL
786  * authentication.  The dn and password of the entry to which to bind are
787  * supplied.  LDAP_SUCCESS is returned upon success, the ldap error code
788  * otherwise.
789  *
790  * Example:
791  *      ldap_negotiated_sasl_bind_s( ld, NULL,
792  *          "dn:cn=manager", NULL, "GSSAPI", NULL, NULL, NULL );
793  */
794 int
795 ldap_negotiated_sasl_bind_s(
796         LDAP *ld,
797         LDAP_CONST char *dn, /* usually NULL */
798         LDAP_CONST char *authorizationId,
799         LDAP_CONST char *authenticationId,  
800         LDAP_CONST char *saslMechanism,     
801         struct berval *passPhrase,        
802         LDAPControl **serverControls,
803         LDAPControl **clientControls)
804 {
805         sasl_callback_t callbacks[4];
806         int rc;
807
808         callbacks[0].id = SASL_CB_USER;
809         callbacks[0].proc = ldap_pvt_sasl_getsimple;
810         callbacks[0].context = (void *)authorizationId;
811         callbacks[1].id = SASL_CB_AUTHNAME;
812         callbacks[1].proc = ldap_pvt_sasl_getsimple;
813         callbacks[1].context = (void *)authenticationId;
814         callbacks[2].id = SASL_CB_PASS;
815         callbacks[2].proc = ldap_pvt_sasl_getsecret;
816         callbacks[2].context = (void *)passPhrase;
817         callbacks[3].id = SASL_CB_LIST_END;
818         callbacks[3].proc = NULL;
819         callbacks[3].context = NULL;
820
821         rc = ldap_pvt_sasl_bind(ld, dn, saslMechanism, callbacks, serverControls, clientControls);
822
823         return rc;
824 }
825 #endif /* HAVE_CYRUS_SASL */