]> git.sur5r.net Git - openldap/blob - libraries/libldap/cyrus.c
libldap/cyrus.c's ldap_pvt_sasl_install fix
[openldap] / libraries / libldap / cyrus.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1999-2000 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6
7 #include "portable.h"
8
9 #include <stdlib.h>
10 #include <stdio.h>
11
12 #include <ac/socket.h>
13 #include <ac/string.h>
14 #include <ac/time.h>
15 #include <ac/errno.h>
16 #include <ac/ctype.h>
17
18 #include "ldap-int.h"
19 #ifdef LDAP_R_COMPILE
20 #include "ldap_pvt_thread.h"
21 #endif
22
23 #ifdef HAVE_CYRUS_SASL
24 #include <sasl.h>
25
26 /*
27 * Various Cyrus SASL related stuff.
28 */
29
30 int ldap_int_sasl_init( void )
31 {
32         /* XXX not threadsafe */
33         static int sasl_initialized = 0;
34
35         static sasl_callback_t client_callbacks[] = {
36 #ifdef SASL_CB_GETREALM
37                 { SASL_CB_GETREALM, NULL, NULL },
38 #endif
39                 { SASL_CB_USER, NULL, NULL },
40                 { SASL_CB_AUTHNAME, NULL, NULL },
41                 { SASL_CB_PASS, NULL, NULL },
42                 { SASL_CB_ECHOPROMPT, NULL, NULL },
43                 { SASL_CB_NOECHOPROMPT, NULL, NULL },
44                 { SASL_CB_LIST_END, NULL, NULL }
45         };
46
47         if ( sasl_initialized ) {
48                 return 0;
49         }
50
51 #ifndef CSRIMALLOC
52         sasl_set_alloc(
53                 ber_memalloc,
54                 ber_memcalloc,
55                 ber_memrealloc,
56                 ber_memfree );
57 #endif /* CSRIMALLOC */
58
59 #ifdef LDAP_R_COMPILE
60         sasl_set_mutex(
61                 ldap_pvt_sasl_mutex_new,
62                 ldap_pvt_sasl_mutex_lock,
63                 ldap_pvt_sasl_mutex_unlock,    
64                 ldap_pvt_sasl_mutex_dispose );    
65 #endif
66
67         if ( sasl_client_init( client_callbacks ) == SASL_OK ) {
68                 sasl_initialized = 1;
69                 return 0;
70         }
71
72         return -1;
73 }
74
75 /*
76  * SASL encryption support for LBER Sockbufs
77  */
78
79 struct sb_sasl_data {
80         sasl_conn_t             *sasl_context;
81         Sockbuf_Buf             sec_buf_in;
82         Sockbuf_Buf             buf_in;
83         Sockbuf_Buf             buf_out;
84 };
85
86 static int
87 sb_sasl_setup( Sockbuf_IO_Desc *sbiod, void *arg )
88 {
89         struct sb_sasl_data     *p;
90
91         assert( sbiod != NULL );
92
93         p = LBER_MALLOC( sizeof( *p ) );
94         if ( p == NULL )
95                 return -1;
96         p->sasl_context = (sasl_conn_t *)arg;
97         ber_pvt_sb_buf_init( &p->sec_buf_in );
98         ber_pvt_sb_buf_init( &p->buf_in );
99         ber_pvt_sb_buf_init( &p->buf_out );
100         if ( ber_pvt_sb_grow_buffer( &p->sec_buf_in, SASL_MIN_BUFF_SIZE ) < 0 ) {
101                 errno = ENOMEM;
102                 return -1;
103         }
104
105         sbiod->sbiod_pvt = p;
106
107         return 0;
108 }
109
110 static int
111 sb_sasl_remove( Sockbuf_IO_Desc *sbiod )
112 {
113         struct sb_sasl_data     *p;
114
115         assert( sbiod != NULL );
116         
117         p = (struct sb_sasl_data *)sbiod->sbiod_pvt;
118         ber_pvt_sb_buf_destroy( &p->sec_buf_in );
119         ber_pvt_sb_buf_destroy( &p->buf_in );
120         ber_pvt_sb_buf_destroy( &p->buf_out );
121         LBER_FREE( p );
122         sbiod->sbiod_pvt = NULL;
123         return 0;
124 }
125
126 static ber_len_t
127 sb_sasl_pkt_length( const unsigned char *buf, int debuglevel )
128 {
129         ber_len_t               size;
130
131         assert( buf != NULL );
132
133         size = buf[0] << 24
134                 | buf[1] << 16
135                 | buf[2] << 8
136                 | buf[3];
137    
138         /* we really should check against actual buffer size set
139          * in the secopts.
140          */
141         if ( size > SASL_MAX_BUFF_SIZE ) {
142                 /* somebody is trying to mess me up. */
143                 ber_log_printf( LDAP_DEBUG_ANY, debuglevel,
144                         "sb_sasl_pkt_length: received illegal packet length "
145                         "of %lu bytes\n", (unsigned long)size );      
146                 size = 16; /* this should lead to an error. */
147         }
148
149         return size + 4; /* include the size !!! */
150 }
151
152 /* Drop a processed packet from the input buffer */
153 static void
154 sb_sasl_drop_packet ( Sockbuf_Buf *sec_buf_in, int debuglevel )
155 {
156         ber_slen_t                      len;
157
158         len = sec_buf_in->buf_ptr - sec_buf_in->buf_end;
159         if ( len > 0 )
160                 memmove( sec_buf_in->buf_base, sec_buf_in->buf_base +
161                         sec_buf_in->buf_end, len );
162    
163         if ( len >= 4 ) {
164                 sec_buf_in->buf_end = sb_sasl_pkt_length( sec_buf_in->buf_base,
165                         debuglevel);
166         }
167         else {
168                 sec_buf_in->buf_end = 0;
169         }
170         sec_buf_in->buf_ptr = len;
171 }
172
173 static ber_slen_t
174 sb_sasl_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
175 {
176         struct sb_sasl_data     *p;
177         ber_slen_t              ret, bufptr;
178    
179         assert( sbiod != NULL );
180         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
181
182         p = (struct sb_sasl_data *)sbiod->sbiod_pvt;
183
184         /* Are there anything left in the buffer? */
185         ret = ber_pvt_sb_copy_out( &p->buf_in, buf, len );
186         bufptr = ret;
187         len -= ret;
188
189         if ( len == 0 )
190                 return bufptr;
191
192         ber_pvt_sb_buf_destroy( &p->buf_in );
193
194         /* Read the length of the packet */
195         while ( p->sec_buf_in.buf_ptr < 4 ) {
196                 ret = LBER_SBIOD_READ_NEXT( sbiod, p->sec_buf_in.buf_base,
197                         4 - p->sec_buf_in.buf_ptr );
198 #ifdef EINTR
199                 if ( ( ret < 0 ) && ( errno == EINTR ) )
200                         continue;
201 #endif
202                 if ( ret <= 0 )
203                         return ret;
204
205                 p->sec_buf_in.buf_ptr += ret;
206         }
207
208         /* The new packet always starts at p->sec_buf_in.buf_base */
209         ret = sb_sasl_pkt_length( p->sec_buf_in.buf_base,
210                 sbiod->sbiod_sb->sb_debug );
211
212         /* Grow the packet buffer if neccessary */
213         if ( ( p->sec_buf_in.buf_size < ret ) && 
214                 ber_pvt_sb_grow_buffer( &p->sec_buf_in, ret ) < 0 )
215         {
216                 errno = ENOMEM;
217                 return -1;
218         }
219         p->sec_buf_in.buf_end = ret;
220
221         /* Did we read the whole encrypted packet? */
222         while ( p->sec_buf_in.buf_ptr < p->sec_buf_in.buf_end ) {
223                 /* No, we have got only a part of it */
224                 ret = p->sec_buf_in.buf_end - p->sec_buf_in.buf_ptr;
225
226                 ret = LBER_SBIOD_READ_NEXT( sbiod, p->sec_buf_in.buf_base +
227                         p->sec_buf_in.buf_ptr, ret );
228 #ifdef EINTR
229                 if ( ( ret < 0 ) && ( errno == EINTR ) )
230                         continue;
231 #endif
232                 if ( ret <= 0 )
233                         return ret;
234
235                 p->sec_buf_in.buf_ptr += ret;
236         }
237
238         /* Decode the packet */
239         ret = sasl_decode( p->sasl_context, p->sec_buf_in.buf_base,
240                 p->sec_buf_in.buf_end, &p->buf_in.buf_base,
241                 (unsigned *)&p->buf_in.buf_end );
242         if ( ret != SASL_OK ) {
243                 ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug,
244                         "sb_sasl_read: failed to decode packet: %s\n",
245                         sasl_errstring( ret, NULL, NULL ) );
246                 sb_sasl_drop_packet( &p->sec_buf_in,
247                         sbiod->sbiod_sb->sb_debug );
248                 errno = EIO;
249                 return -1;
250         }
251         
252         /* Drop the packet from the input buffer */
253         sb_sasl_drop_packet( &p->sec_buf_in, sbiod->sbiod_sb->sb_debug );
254
255         p->buf_in.buf_size = p->buf_in.buf_end;
256
257         bufptr += ber_pvt_sb_copy_out( &p->buf_in, (char*) buf + bufptr, len );
258
259         return bufptr;
260 }
261
262 static ber_slen_t
263 sb_sasl_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
264 {
265         struct sb_sasl_data     *p;
266         int                     ret;
267
268         assert( sbiod != NULL );
269         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
270
271         p = (struct sb_sasl_data *)sbiod->sbiod_pvt;
272
273         /* Are there anything left in the buffer? */
274         if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) {
275                 ret = ber_pvt_sb_do_write( sbiod, &p->buf_out );
276                 if ( ret <= 0 )
277                         return ret;
278         }
279
280         /* now encode the next packet. */
281         ber_pvt_sb_buf_destroy( &p->buf_out );
282         ret = sasl_encode( p->sasl_context, buf, len, &p->buf_out.buf_base,
283                 (unsigned *)&p->buf_out.buf_size );
284         if ( ret != SASL_OK ) {
285                 ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug,
286                         "sb_sasl_write: failed to encode packet: %s\n",
287                         sasl_errstring( ret, NULL, NULL ) );
288                 return -1;
289         }
290         p->buf_out.buf_end = p->buf_out.buf_size;
291
292         ret = ber_pvt_sb_do_write( sbiod, &p->buf_out );
293         if ( ret <= 0 )
294                 return ret;
295         return len;
296 }
297
298 static int
299 sb_sasl_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
300 {
301         struct sb_sasl_data     *p;
302
303         p = (struct sb_sasl_data *)sbiod->sbiod_pvt;
304
305         if ( opt == LBER_SB_OPT_DATA_READY ) {
306                 if ( p->buf_in.buf_ptr != p->buf_in.buf_end )
307                         return 1;
308         }
309         
310         return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
311 }
312
313 Sockbuf_IO ldap_pvt_sockbuf_io_sasl = {
314         sb_sasl_setup,          /* sbi_setup */
315         sb_sasl_remove,         /* sbi_remove */
316         sb_sasl_ctrl,           /* sbi_ctrl */
317         sb_sasl_read,           /* sbi_read */
318         sb_sasl_write,          /* sbi_write */
319         NULL                    /* sbi_close */
320 };
321
322 int ldap_pvt_sasl_install( Sockbuf *sb, void *ctx_arg )
323 {
324         Debug( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_install\n",
325                 0, 0, 0 );
326
327         /* don't install the stuff unless security has been negotiated */
328
329         if ( !ber_sockbuf_ctrl( sb, LBER_SB_OPT_HAS_IO,
330                         &ldap_pvt_sockbuf_io_sasl ) )
331         {
332 #ifdef LDAP_DEBUG
333                 ber_sockbuf_add_io( sb, &ber_sockbuf_io_debug,
334                         LBER_SBIOD_LEVEL_APPLICATION, (void *)"sasl_" );
335 #endif
336                 ber_sockbuf_add_io( sb, &ldap_pvt_sockbuf_io_sasl,
337                         LBER_SBIOD_LEVEL_APPLICATION, ctx_arg );
338         }
339
340         return LDAP_SUCCESS;
341 }
342
343 static int
344 sasl_err2ldap( int saslerr )
345 {
346         int rc;
347
348         switch (saslerr) {
349                 case SASL_CONTINUE:
350                         rc = LDAP_MORE_RESULTS_TO_RETURN;
351                         break;
352                 case SASL_INTERACT:
353                         rc = LDAP_LOCAL_ERROR;
354                         break;
355                 case SASL_OK:
356                         rc = LDAP_SUCCESS;
357                         break;
358                 case SASL_FAIL:
359                         rc = LDAP_LOCAL_ERROR;
360                         break;
361                 case SASL_NOMEM:
362                         rc = LDAP_NO_MEMORY;
363                         break;
364                 case SASL_NOMECH:
365                         rc = LDAP_AUTH_UNKNOWN;
366                         break;
367                 case SASL_BADAUTH:
368                         rc = LDAP_AUTH_UNKNOWN;
369                         break;
370                 case SASL_NOAUTHZ:
371                         rc = LDAP_PARAM_ERROR;
372                         break;
373                 case SASL_TOOWEAK:
374                 case SASL_ENCRYPT:
375                         rc = LDAP_AUTH_UNKNOWN;
376                         break;
377                 default:
378                         rc = LDAP_LOCAL_ERROR;
379                         break;
380         }
381
382         assert( rc == LDAP_SUCCESS || LDAP_API_ERROR( rc ) );
383         return rc;
384 }
385
386 int
387 ldap_int_sasl_open(
388         LDAP *ld, 
389         LDAPConn *lc,
390         const char * host,
391         ber_len_t ssf )
392 {
393         int rc;
394         sasl_conn_t *ctx;
395
396         sasl_callback_t *session_callbacks =
397                 ber_memcalloc( 2, sizeof( sasl_callback_t ) );
398
399         if( session_callbacks == NULL ) return LDAP_NO_MEMORY;
400
401         session_callbacks[0].id = SASL_CB_USER;
402         session_callbacks[0].proc = NULL;
403         session_callbacks[0].context = ld;
404
405         session_callbacks[1].id = SASL_CB_LIST_END;
406         session_callbacks[1].proc = NULL;
407         session_callbacks[1].context = NULL;
408
409         assert( lc->lconn_sasl_ctx == NULL );
410
411         if ( host == NULL ) {
412                 ld->ld_errno = LDAP_LOCAL_ERROR;
413                 return ld->ld_errno;
414         }
415
416         rc = sasl_client_new( "ldap", host, session_callbacks,
417                 SASL_SECURITY_LAYER, &ctx );
418
419         if ( rc != SASL_OK ) {
420                 ld->ld_errno = sasl_err2ldap( rc );
421                 return ld->ld_errno;
422         }
423
424         Debug( LDAP_DEBUG_TRACE, "ldap_int_sasl_open: %s\n",
425                 host, 0, 0 );
426
427         lc->lconn_sasl_ctx = ctx;
428
429         if( ssf ) {
430                 sasl_external_properties_t extprops;
431                 memset(&extprops, 0L, sizeof(extprops));
432                 extprops.ssf = ssf;
433
434                 (void) sasl_setprop( ctx, SASL_SSF_EXTERNAL,
435                         (void *) &extprops );
436
437                 Debug( LDAP_DEBUG_TRACE, "ldap_int_sasl_open: ssf=%ld\n",
438                         (long) ssf, 0, 0 );
439         }
440
441         return LDAP_SUCCESS;
442 }
443
444 int ldap_int_sasl_close( LDAP *ld, LDAPConn *lc )
445 {
446         sasl_conn_t *ctx = lc->lconn_sasl_ctx;
447
448         if( ctx != NULL ) {
449                 sasl_dispose( &ctx );
450                 lc->lconn_sasl_ctx = NULL;
451         }
452
453         return LDAP_SUCCESS;
454 }
455
456 int
457 ldap_int_sasl_bind(
458         LDAP                    *ld,
459         const char              *dn,
460         const char              *mechs,
461         LDAPControl             **sctrls,
462         LDAPControl             **cctrls,
463         unsigned                flags,
464         LDAP_SASL_INTERACT_PROC *interact,
465         void * defaults )
466 {
467         char *data;
468         const char *mech = NULL;
469         const char *pmech = NULL;
470         int                     saslrc, rc;
471         sasl_ssf_t              *ssf = NULL;
472         sasl_conn_t     *ctx;
473         sasl_interact_t *prompts = NULL;
474         unsigned credlen;
475         struct berval ccred;
476         ber_socket_t            sd;
477
478         Debug( LDAP_DEBUG_TRACE, "ldap_int_sasl_bind: %s\n",
479                 mechs ? mechs : "<null>", 0, 0 );
480
481         /* do a quick !LDAPv3 check... ldap_sasl_bind will do the rest. */
482         if (ld->ld_version < LDAP_VERSION3) {
483                 ld->ld_errno = LDAP_NOT_SUPPORTED;
484                 return ld->ld_errno;
485         }
486
487         ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd );
488
489         if ( sd == AC_SOCKET_INVALID ) {
490                 /* not connected yet */
491                 int rc;
492
493                 rc = ldap_open_defconn( ld );
494                 if( rc < 0 ) return ld->ld_errno;
495
496                 ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd );
497
498                 if( sd == AC_SOCKET_INVALID ) {
499                         ld->ld_errno = LDAP_LOCAL_ERROR;
500                         return ld->ld_errno;
501                 }
502         }   
503
504         ctx = ld->ld_defconn->lconn_sasl_ctx;
505
506         if( ctx == NULL ) {
507                 ld->ld_errno = LDAP_LOCAL_ERROR;
508                 return ld->ld_errno;
509         }
510
511         /* (re)set security properties */
512         sasl_setprop( ctx, SASL_SEC_PROPS,
513                 &ld->ld_options.ldo_sasl_secprops );
514
515         ccred.bv_val = NULL;
516         ccred.bv_len = 0;
517
518         do {
519                 saslrc = sasl_client_start( ctx,
520                         mechs,
521                         NULL,
522                         &prompts,
523                         &ccred.bv_val,
524                         &credlen,
525                         &mech );
526
527                 if( pmech == NULL && mech != NULL ) {
528                         pmech = mech;
529
530                         if( flags != LDAP_SASL_QUIET ) {
531                                 fprintf(stderr,
532                                         "SASL/%s authentication started\n",
533                                         pmech );
534                         }
535                 }
536
537                 if( saslrc == SASL_INTERACT ) {
538                         int res;
539                         if( !interact ) break;
540                         res = (interact)( ld, flags, defaults, prompts );
541                         if( res != LDAP_SUCCESS ) {
542                                 break;
543                         }
544                 }
545         } while ( saslrc == SASL_INTERACT );
546
547         ccred.bv_len = credlen;
548
549         if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
550                 ld->ld_errno = sasl_err2ldap( saslrc );
551                 return ld->ld_errno;
552         }
553
554         do {
555                 struct berval *scred;
556                 unsigned credlen;
557
558                 scred = NULL;
559
560                 rc = ldap_sasl_bind_s( ld, dn, mech, &ccred, sctrls, cctrls, &scred );
561
562                 if ( ccred.bv_val != NULL ) {
563                         LDAP_FREE( ccred.bv_val );
564                         ccred.bv_val = NULL;
565                 }
566
567                 if ( rc != LDAP_SUCCESS && rc != LDAP_SASL_BIND_IN_PROGRESS ) {
568                         if( scred && scred->bv_len ) {
569                                 /* and server provided us with data? */
570                                 Debug( LDAP_DEBUG_TRACE,
571                                         "ldap_int_sasl_bind: rc=%d sasl=%d len=%ld\n",
572                                         rc, saslrc, scred->bv_len );
573                                 ber_bvfree( scred );
574                         }
575                         return ld->ld_errno;
576                 }
577
578                 if( rc == LDAP_SUCCESS && saslrc == SASL_OK ) {
579                         /* we're done, no need to step */
580                         if( scred && scred->bv_len ) {
581                                 /* but server provided us with data! */
582                                 Debug( LDAP_DEBUG_TRACE,
583                                         "ldap_int_sasl_bind: rc=%d sasl=%d len=%ld\n",
584                                         rc, saslrc, scred->bv_len );
585                                 ber_bvfree( scred );
586                                 return ld->ld_errno = LDAP_LOCAL_ERROR;
587                         }
588                         break;
589                 }
590
591                 do {
592                         saslrc = sasl_client_step( ctx,
593                                 (scred == NULL) ? NULL : scred->bv_val,
594                                 (scred == NULL) ? 0 : scred->bv_len,
595                                 &prompts,
596                                 &ccred.bv_val,
597                                 &credlen );
598
599                         Debug( LDAP_DEBUG_TRACE, "sasl_client_start: %d\n",
600                                 saslrc, 0, 0 );
601
602                         if( saslrc == SASL_INTERACT ) {
603                                 int res;
604                                 if( !interact ) break;
605                                 res = (interact)( ld, flags, defaults, prompts );
606                                 if( res != LDAP_SUCCESS ) {
607                                         break;
608                                 }
609                         }
610                 } while ( saslrc == SASL_INTERACT );
611
612                 ccred.bv_len = credlen;
613                 ber_bvfree( scred );
614
615                 if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
616                         ld->ld_errno = sasl_err2ldap( saslrc );
617                         return ld->ld_errno;
618                 }
619         } while ( rc == LDAP_SASL_BIND_IN_PROGRESS );
620
621         if ( rc != LDAP_SUCCESS ) {
622                 return rc;
623         }
624
625         if ( saslrc != SASL_OK ) {
626                 return ld->ld_errno = sasl_err2ldap( saslrc );
627         }
628
629         if( flags != LDAP_SASL_QUIET ) {
630                 saslrc = sasl_getprop( ctx, SASL_USERNAME, (void **) &data );
631                 if( saslrc == SASL_OK && data && *data ) {
632                         fprintf( stderr, "SASL username: %s\n", data );
633                 }
634
635                 saslrc = sasl_getprop( ctx, SASL_REALM, (void **) &data );
636                 if( saslrc == SASL_OK && data && *data ) {
637                         fprintf( stderr, "SASL realm: %s\n", data );
638                 }
639         }
640
641         saslrc = sasl_getprop( ctx, SASL_SSF, (void **) &ssf );
642         if( saslrc == SASL_OK ) {
643                 if( flags != LDAP_SASL_QUIET ) {
644                         fprintf( stderr, "SASL SSF: %lu\n",
645                                 (unsigned long) *ssf );
646                 }
647
648                 if( ssf && *ssf ) {
649                         if( flags != LDAP_SASL_QUIET ) {
650                                 fprintf( stderr, "SASL installing layers\n" );
651                         }
652                         ldap_pvt_sasl_install( ld->ld_conns->lconn_sb, ctx );
653                 }
654         }
655
656         return rc;
657 }
658
659 int
660 ldap_int_sasl_external(
661         LDAP *ld,
662         const char * authid,
663         ber_len_t ssf )
664 {
665         int sc;
666         sasl_conn_t *ctx;
667         sasl_external_properties_t extprops;
668
669         if( ld->ld_defconn == NULL ) {
670                 return LDAP_LOCAL_ERROR;
671         }
672
673         ctx = ld->ld_defconn->lconn_sasl_ctx;
674
675         if ( ctx == NULL ) {
676                 return LDAP_LOCAL_ERROR;
677         }
678     
679         memset( &extprops, '\0', sizeof(extprops) );
680         extprops.ssf = ssf;
681         extprops.auth_id = (char *) authid;
682     
683         sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL,
684                 (void *) &extprops );
685     
686         if ( sc != SASL_OK ) {
687                 return LDAP_LOCAL_ERROR;
688         }
689
690         return LDAP_SUCCESS;
691 }
692
693
694 int ldap_pvt_sasl_secprops(
695         const char *in,
696         sasl_security_properties_t *secprops )
697 {
698         int i;
699         char **props = ldap_str2charray( in, "," );
700         unsigned sflags = 0;
701         int got_sflags = 0;
702         sasl_ssf_t max_ssf = 0;
703         int got_max_ssf = 0;
704         sasl_ssf_t min_ssf = 0;
705         int got_min_ssf = 0;
706         unsigned maxbufsize = 0;
707         int got_maxbufsize = 0;
708
709         if( props == NULL || secprops == NULL ) {
710                 return LDAP_PARAM_ERROR;
711         }
712
713         for( i=0; props[i]; i++ ) {
714                 if( !strcasecmp(props[i], "none") ) {
715                         got_sflags++;
716
717                 } else if( !strcasecmp(props[i], "noplain") ) {
718                         got_sflags++;
719                         sflags |= SASL_SEC_NOPLAINTEXT;
720
721                 } else if( !strcasecmp(props[i], "noactive") ) {
722                         got_sflags++;
723                         sflags |= SASL_SEC_NOACTIVE;
724
725                 } else if( !strcasecmp(props[i], "nodict") ) {
726                         got_sflags++;
727                         sflags |= SASL_SEC_NODICTIONARY;
728
729                 } else if( !strcasecmp(props[i], "forwardsec") ) {
730                         got_sflags++;
731                         sflags |= SASL_SEC_FORWARD_SECRECY;
732
733                 } else if( !strcasecmp(props[i], "noanonymous")) {
734                         got_sflags++;
735                         sflags |= SASL_SEC_NOANONYMOUS;
736
737                 } else if( !strcasecmp(props[i], "passcred") ) {
738                         got_sflags++;
739                         sflags |= SASL_SEC_PASS_CREDENTIALS;
740
741                 } else if( !strncasecmp(props[i],
742                         "minssf=", sizeof("minssf")) )
743                 {
744                         if( isdigit( props[i][sizeof("minssf")] ) ) {
745                                 got_min_ssf++;
746                                 min_ssf = atoi( &props[i][sizeof("minssf")] );
747                         } else {
748                                 return LDAP_NOT_SUPPORTED;
749                         }
750
751                 } else if( !strncasecmp(props[i],
752                         "maxssf=", sizeof("maxssf")) )
753                 {
754                         if( isdigit( props[i][sizeof("maxssf")] ) ) {
755                                 got_max_ssf++;
756                                 max_ssf = atoi( &props[i][sizeof("maxssf")] );
757                         } else {
758                                 return LDAP_NOT_SUPPORTED;
759                         }
760
761                 } else if( !strncasecmp(props[i],
762                         "maxbufsize=", sizeof("maxbufsize")) )
763                 {
764                         if( isdigit( props[i][sizeof("maxbufsize")] ) ) {
765                                 got_maxbufsize++;
766                                 maxbufsize = atoi( &props[i][sizeof("maxbufsize")] );
767                         } else {
768                                 return LDAP_NOT_SUPPORTED;
769                         }
770
771                         if( maxbufsize && (( maxbufsize < SASL_MIN_BUFF_SIZE )
772                                 || (maxbufsize > SASL_MAX_BUFF_SIZE )))
773                         {
774                                 /* bad maxbufsize */
775                                 return LDAP_PARAM_ERROR;
776                         }
777
778                 } else {
779                         return LDAP_NOT_SUPPORTED;
780                 }
781         }
782
783         if(got_sflags) {
784                 secprops->security_flags = sflags;
785         }
786         if(got_min_ssf) {
787                 secprops->min_ssf = min_ssf;
788         }
789         if(got_max_ssf) {
790                 secprops->max_ssf = max_ssf;
791         }
792         if(got_maxbufsize) {
793                 secprops->maxbufsize = maxbufsize;
794         }
795
796         ldap_charray_free( props );
797         return LDAP_SUCCESS;
798 }
799
800 int
801 ldap_int_sasl_config( struct ldapoptions *lo, int option, const char *arg )
802 {
803         int rc;
804
805         switch( option ) {
806         case LDAP_OPT_X_SASL_SECPROPS:
807                 rc = ldap_pvt_sasl_secprops( arg, &lo->ldo_sasl_secprops );
808                 if( rc == LDAP_SUCCESS ) return 0;
809         }
810
811         return -1;
812 }
813
814 int
815 ldap_int_sasl_get_option( LDAP *ld, int option, void *arg )
816 {
817         if ( ld == NULL )
818                 return -1;
819
820         switch ( option ) {
821                 case LDAP_OPT_X_SASL_MECH: {
822                         *(char **)arg = ld->ld_options.ldo_def_sasl_mech
823                                 ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_mech ) : NULL;
824                 } break;
825                 case LDAP_OPT_X_SASL_REALM: {
826                         *(char **)arg = ld->ld_options.ldo_def_sasl_realm
827                                 ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_realm ) : NULL;
828                 } break;
829                 case LDAP_OPT_X_SASL_AUTHCID: {
830                         *(char **)arg = ld->ld_options.ldo_def_sasl_authcid
831                                 ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_authcid ) : NULL;
832                 } break;
833                 case LDAP_OPT_X_SASL_AUTHZID: {
834                         *(char **)arg = ld->ld_options.ldo_def_sasl_authzid
835                                 ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_authzid ) : NULL;
836                 } break;
837
838                 case LDAP_OPT_X_SASL_SSF: {
839                         int sc;
840                         sasl_ssf_t      *ssf;
841                         sasl_conn_t *ctx;
842
843                         if( ld->ld_defconn == NULL ) {
844                                 return -1;
845                         }
846
847                         ctx = ld->ld_defconn->lconn_sasl_ctx;
848
849                         if ( ctx == NULL ) {
850                                 return -1;
851                         }
852
853                         sc = sasl_getprop( ctx, SASL_SSF,
854                                 (void **) &ssf );
855
856                         if ( sc != SASL_OK ) {
857                                 return -1;
858                         }
859
860                         *(ber_len_t *)arg = *ssf;
861                 } break;
862
863                 case LDAP_OPT_X_SASL_SSF_EXTERNAL:
864                         /* this option is write only */
865                         return -1;
866
867                 case LDAP_OPT_X_SASL_SSF_MIN:
868                         *(ber_len_t *)arg = ld->ld_options.ldo_sasl_secprops.min_ssf;
869                         break;
870                 case LDAP_OPT_X_SASL_SSF_MAX:
871                         *(ber_len_t *)arg = ld->ld_options.ldo_sasl_secprops.max_ssf;
872                         break;
873                 case LDAP_OPT_X_SASL_MAXBUFSIZE:
874                         *(ber_len_t *)arg = ld->ld_options.ldo_sasl_secprops.maxbufsize;
875                         break;
876
877                 case LDAP_OPT_X_SASL_SECPROPS:
878                         /* this option is write only */
879                         return -1;
880
881                 default:
882                         return -1;
883         }
884         return 0;
885 }
886
887 int
888 ldap_int_sasl_set_option( LDAP *ld, int option, void *arg )
889 {
890         if ( ld == NULL )
891                 return -1;
892
893         switch ( option ) {
894         case LDAP_OPT_X_SASL_SSF:
895                 /* This option is read-only */
896                 return -1;
897
898         case LDAP_OPT_X_SASL_SSF_EXTERNAL: {
899                 int sc;
900                 sasl_external_properties_t extprops;
901                 sasl_conn_t *ctx;
902
903                 if( ld->ld_defconn == NULL ) {
904                         return -1;
905                 }
906
907                 ctx = ld->ld_defconn->lconn_sasl_ctx;
908
909                 if ( ctx == NULL ) {
910                         return -1;
911                 }
912
913                 memset(&extprops, 0L, sizeof(extprops));
914
915                 extprops.ssf = * (ber_len_t *) arg;
916
917                 sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL,
918                         (void *) &extprops );
919
920                 if ( sc != SASL_OK ) {
921                         return -1;
922                 }
923                 } break;
924
925         case LDAP_OPT_X_SASL_SSF_MIN:
926                 ld->ld_options.ldo_sasl_secprops.min_ssf = *(ber_len_t *)arg;
927                 break;
928         case LDAP_OPT_X_SASL_SSF_MAX:
929                 ld->ld_options.ldo_sasl_secprops.max_ssf = *(ber_len_t *)arg;
930                 break;
931         case LDAP_OPT_X_SASL_MAXBUFSIZE:
932                 ld->ld_options.ldo_sasl_secprops.maxbufsize = *(ber_len_t *)arg;
933                 break;
934
935         case LDAP_OPT_X_SASL_SECPROPS: {
936                 int sc;
937                 sc = ldap_pvt_sasl_secprops( (char *) arg,
938                         &ld->ld_options.ldo_sasl_secprops );
939
940                 return sc == LDAP_SUCCESS ? 0 : -1;
941                 }
942
943         default:
944                 return -1;
945         }
946         return 0;
947 }
948
949 #ifdef LDAP_R_COMPILE
950 void *ldap_pvt_sasl_mutex_new(void)
951 {
952         ldap_pvt_thread_mutex_t *mutex;
953
954         mutex = (ldap_pvt_thread_mutex_t *) LDAP_MALLOC(
955                 sizeof(ldap_pvt_thread_mutex_t) );
956
957         if ( ldap_pvt_thread_mutex_init( mutex ) == 0 ) {
958                 return mutex;
959         }
960         return NULL;
961 }
962
963 int ldap_pvt_sasl_mutex_lock(void *mutex)
964 {
965         return ldap_pvt_thread_mutex_lock( (ldap_pvt_thread_mutex_t *)mutex )
966                 ? SASL_FAIL : SASL_OK;
967 }
968
969 int ldap_pvt_sasl_mutex_unlock(void *mutex)
970 {
971         return ldap_pvt_thread_mutex_unlock( (ldap_pvt_thread_mutex_t *)mutex )
972                 ? SASL_FAIL : SASL_OK;
973 }
974
975 void ldap_pvt_sasl_mutex_dispose(void *mutex)
976 {
977         (void) ldap_pvt_thread_mutex_destroy( (ldap_pvt_thread_mutex_t *)mutex );
978         LDAP_FREE( mutex );
979 }
980 #endif
981
982 #else
983 int ldap_int_sasl_init( void )
984 { return LDAP_SUCCESS; }
985
986 int ldap_int_sasl_close( LDAP *ld, LDAPConn *lc )
987 { return LDAP_SUCCESS; }
988
989 int
990 ldap_int_sasl_bind(
991         LDAP                    *ld,
992         const char              *dn,
993         const char              *mechs,
994         LDAPControl             **sctrls,
995         LDAPControl             **cctrls,
996         unsigned                flags,
997         LDAP_SASL_INTERACT_PROC *interact,
998         void * defaults )
999 { return LDAP_NOT_SUPPORTED; }
1000
1001 int
1002 ldap_int_sasl_external(
1003         LDAP *ld,
1004         const char * authid,
1005         ber_len_t ssf )
1006 { return LDAP_SUCCESS; }
1007
1008 #endif /* HAVE_CYRUS_SASL */