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