3 * Copyright 1999-2003 The OpenLDAP Foundation, All Rights Reserved.
4 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
11 #include <ac/socket.h>
12 #include <ac/stdlib.h>
13 #include <ac/string.h>
20 #ifdef HAVE_CYRUS_SASL
23 ldap_pvt_thread_mutex_t ldap_int_sasl_mutex;
26 #ifdef HAVE_SASL_SASL_H
27 #include <sasl/sasl.h>
32 #if SASL_VERSION_MAJOR >= 2
33 #define SASL_CONST const
39 * Various Cyrus SASL related stuff.
42 int ldap_int_sasl_init( void )
44 /* XXX not threadsafe */
45 static int sasl_initialized = 0;
47 static sasl_callback_t client_callbacks[] = {
48 #ifdef SASL_CB_GETREALM
49 { SASL_CB_GETREALM, NULL, NULL },
51 { SASL_CB_USER, NULL, NULL },
52 { SASL_CB_AUTHNAME, NULL, NULL },
53 { SASL_CB_PASS, NULL, NULL },
54 { SASL_CB_ECHOPROMPT, NULL, NULL },
55 { SASL_CB_NOECHOPROMPT, NULL, NULL },
56 { SASL_CB_LIST_END, NULL, NULL }
59 #ifdef HAVE_SASL_VERSION
60 /* stringify the version number, sasl.h doesn't do it for us */
61 #define VSTR0(maj, min, pat) #maj "." #min "." #pat
62 #define VSTR(maj, min, pat) VSTR0(maj, min, pat)
63 #define SASL_VERSION_STRING VSTR(SASL_VERSION_MAJOR, SASL_VERSION_MINOR, \
66 sasl_version( NULL, &rc );
67 if ( ((rc >> 16) != ((SASL_VERSION_MAJOR << 8)|SASL_VERSION_MINOR)) ||
68 (rc & 0xffff) < SASL_VERSION_STEP) {
69 char version[sizeof("xxx.xxx.xxxxx")];
70 sprintf( version, "%u.%d.%d", (unsigned)rc >> 24, (rc >> 16) & 0xff,
74 LDAP_LOG( TRANSPORT, INFO,
75 "ldap_int_sasl_init: SASL library version mismatch:"
76 " expected " SASL_VERSION_STRING ","
77 " got %s\n", version, 0, 0 );
79 Debug( LDAP_DEBUG_ANY,
80 "ldap_int_sasl_init: SASL library version mismatch:"
81 " expected " SASL_VERSION_STRING ","
82 " got %s\n", version, 0, 0 );
88 if ( sasl_initialized ) {
92 /* SASL 2 takes care of its own memory completely internally */
93 #if SASL_VERSION_MAJOR < 2 && !defined(CSRIMALLOC)
99 #endif /* CSRIMALLOC */
101 #ifdef LDAP_R_COMPILE
103 ldap_pvt_sasl_mutex_new,
104 ldap_pvt_sasl_mutex_lock,
105 ldap_pvt_sasl_mutex_unlock,
106 ldap_pvt_sasl_mutex_dispose );
108 ldap_pvt_thread_mutex_init( &ldap_int_sasl_mutex );
111 if ( sasl_client_init( client_callbacks ) == SASL_OK ) {
112 sasl_initialized = 1;
116 #if SASL_VERSION_MAJOR < 2
117 /* A no-op to make sure we link with Cyrus 1.5 */
118 sasl_client_auth( NULL, NULL, NULL, 0, NULL, NULL );
124 * SASL encryption support for LBER Sockbufs
127 struct sb_sasl_data {
128 sasl_conn_t *sasl_context;
129 unsigned *sasl_maxbuf;
130 Sockbuf_Buf sec_buf_in;
136 sb_sasl_setup( Sockbuf_IO_Desc *sbiod, void *arg )
138 struct sb_sasl_data *p;
140 assert( sbiod != NULL );
142 p = LBER_MALLOC( sizeof( *p ) );
145 p->sasl_context = (sasl_conn_t *)arg;
146 ber_pvt_sb_buf_init( &p->sec_buf_in );
147 ber_pvt_sb_buf_init( &p->buf_in );
148 ber_pvt_sb_buf_init( &p->buf_out );
149 if ( ber_pvt_sb_grow_buffer( &p->sec_buf_in, SASL_MIN_BUFF_SIZE ) < 0 ) {
154 sasl_getprop( p->sasl_context, SASL_MAXOUTBUF,
155 (SASL_CONST void **) &p->sasl_maxbuf );
157 sbiod->sbiod_pvt = p;
163 sb_sasl_remove( Sockbuf_IO_Desc *sbiod )
165 struct sb_sasl_data *p;
167 assert( sbiod != NULL );
169 p = (struct sb_sasl_data *)sbiod->sbiod_pvt;
170 #if SASL_VERSION_MAJOR >= 2
172 * SASLv2 encode/decode buffers are managed by
173 * libsasl2. Ensure they are not freed by liblber.
175 p->buf_in.buf_base = NULL;
176 p->buf_out.buf_base = NULL;
178 ber_pvt_sb_buf_destroy( &p->sec_buf_in );
179 ber_pvt_sb_buf_destroy( &p->buf_in );
180 ber_pvt_sb_buf_destroy( &p->buf_out );
182 sbiod->sbiod_pvt = NULL;
187 sb_sasl_pkt_length( const unsigned char *buf, unsigned max, int debuglevel )
191 assert( buf != NULL );
198 if ( size > SASL_MAX_BUFF_SIZE ) {
199 /* somebody is trying to mess me up. */
200 ber_log_printf( LDAP_DEBUG_ANY, debuglevel,
201 "sb_sasl_pkt_length: received illegal packet length "
202 "of %lu bytes\n", (unsigned long)size );
203 size = 16; /* this should lead to an error. */
206 return size + 4; /* include the size !!! */
209 /* Drop a processed packet from the input buffer */
211 sb_sasl_drop_packet ( Sockbuf_Buf *sec_buf_in, unsigned max, int debuglevel )
215 len = sec_buf_in->buf_ptr - sec_buf_in->buf_end;
217 AC_MEMCPY( sec_buf_in->buf_base, sec_buf_in->buf_base +
218 sec_buf_in->buf_end, len );
221 sec_buf_in->buf_end = sb_sasl_pkt_length(
222 (unsigned char *) sec_buf_in->buf_base, max, debuglevel);
225 sec_buf_in->buf_end = 0;
227 sec_buf_in->buf_ptr = len;
231 sb_sasl_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
233 struct sb_sasl_data *p;
234 ber_slen_t ret, bufptr;
236 assert( sbiod != NULL );
237 assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
239 p = (struct sb_sasl_data *)sbiod->sbiod_pvt;
241 /* Are there anything left in the buffer? */
242 ret = ber_pvt_sb_copy_out( &p->buf_in, buf, len );
249 #if SASL_VERSION_MAJOR >= 2
250 ber_pvt_sb_buf_init( &p->buf_in );
252 ber_pvt_sb_buf_destroy( &p->buf_in );
255 /* Read the length of the packet */
256 while ( p->sec_buf_in.buf_ptr < 4 ) {
257 ret = LBER_SBIOD_READ_NEXT( sbiod, p->sec_buf_in.buf_base,
258 4 - p->sec_buf_in.buf_ptr );
260 if ( ( ret < 0 ) && ( errno == EINTR ) )
264 return bufptr ? bufptr : ret;
266 p->sec_buf_in.buf_ptr += ret;
269 /* The new packet always starts at p->sec_buf_in.buf_base */
270 ret = sb_sasl_pkt_length( (unsigned char *) p->sec_buf_in.buf_base,
271 *p->sasl_maxbuf, sbiod->sbiod_sb->sb_debug );
273 /* Grow the packet buffer if neccessary */
274 if ( ( p->sec_buf_in.buf_size < (ber_len_t) ret ) &&
275 ber_pvt_sb_grow_buffer( &p->sec_buf_in, ret ) < 0 )
280 p->sec_buf_in.buf_end = ret;
282 /* Did we read the whole encrypted packet? */
283 while ( p->sec_buf_in.buf_ptr < p->sec_buf_in.buf_end ) {
284 /* No, we have got only a part of it */
285 ret = p->sec_buf_in.buf_end - p->sec_buf_in.buf_ptr;
287 ret = LBER_SBIOD_READ_NEXT( sbiod, p->sec_buf_in.buf_base +
288 p->sec_buf_in.buf_ptr, ret );
290 if ( ( ret < 0 ) && ( errno == EINTR ) )
294 return bufptr ? bufptr : ret;
296 p->sec_buf_in.buf_ptr += ret;
299 /* Decode the packet */
300 ret = sasl_decode( p->sasl_context, p->sec_buf_in.buf_base,
301 p->sec_buf_in.buf_end,
302 (SASL_CONST char **)&p->buf_in.buf_base,
303 (unsigned *)&p->buf_in.buf_end );
305 /* Drop the packet from the input buffer */
306 sb_sasl_drop_packet( &p->sec_buf_in,
307 *p->sasl_maxbuf, sbiod->sbiod_sb->sb_debug );
309 if ( ret != SASL_OK ) {
310 ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug,
311 "sb_sasl_read: failed to decode packet: %s\n",
312 sasl_errstring( ret, NULL, NULL ) );
317 p->buf_in.buf_size = p->buf_in.buf_end;
319 bufptr += ber_pvt_sb_copy_out( &p->buf_in, (char*) buf + bufptr, len );
325 sb_sasl_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
327 struct sb_sasl_data *p;
330 assert( sbiod != NULL );
331 assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
333 p = (struct sb_sasl_data *)sbiod->sbiod_pvt;
335 /* Are there anything left in the buffer? */
336 if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) {
337 ret = ber_pvt_sb_do_write( sbiod, &p->buf_out );
340 /* Still have something left?? */
341 if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) {
347 /* now encode the next packet. */
348 #if SASL_VERSION_MAJOR >= 2
349 ber_pvt_sb_buf_init( &p->buf_out );
350 /* sasl v2 makes sure this number is correct */
351 if ( len > *p->sasl_maxbuf )
352 len = *p->sasl_maxbuf;
354 ber_pvt_sb_buf_destroy( &p->buf_out );
355 if ( len > *p->sasl_maxbuf - 100 )
356 len = *p->sasl_maxbuf - 100; /* For safety margin */
358 ret = sasl_encode( p->sasl_context, buf, len,
359 (SASL_CONST char **)&p->buf_out.buf_base,
360 (unsigned *)&p->buf_out.buf_size );
361 if ( ret != SASL_OK ) {
362 ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug,
363 "sb_sasl_write: failed to encode packet: %s\n",
364 sasl_errstring( ret, NULL, NULL ) );
367 p->buf_out.buf_end = p->buf_out.buf_size;
369 ret = ber_pvt_sb_do_write( sbiod, &p->buf_out );
376 sb_sasl_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
378 struct sb_sasl_data *p;
380 p = (struct sb_sasl_data *)sbiod->sbiod_pvt;
382 if ( opt == LBER_SB_OPT_DATA_READY ) {
383 if ( p->buf_in.buf_ptr != p->buf_in.buf_end )
387 return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
390 Sockbuf_IO ldap_pvt_sockbuf_io_sasl = {
391 sb_sasl_setup, /* sbi_setup */
392 sb_sasl_remove, /* sbi_remove */
393 sb_sasl_ctrl, /* sbi_ctrl */
394 sb_sasl_read, /* sbi_read */
395 sb_sasl_write, /* sbi_write */
399 int ldap_pvt_sasl_install( Sockbuf *sb, void *ctx_arg )
402 LDAP_LOG ( TRANSPORT, ENTRY, "ldap_pvt_sasl_install\n", 0, 0, 0 );
404 Debug( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_install\n",
408 /* don't install the stuff unless security has been negotiated */
410 if ( !ber_sockbuf_ctrl( sb, LBER_SB_OPT_HAS_IO,
411 &ldap_pvt_sockbuf_io_sasl ) )
414 ber_sockbuf_add_io( sb, &ber_sockbuf_io_debug,
415 LBER_SBIOD_LEVEL_APPLICATION, (void *)"sasl_" );
417 ber_sockbuf_add_io( sb, &ldap_pvt_sockbuf_io_sasl,
418 LBER_SBIOD_LEVEL_APPLICATION, ctx_arg );
424 void ldap_pvt_sasl_remove( Sockbuf *sb )
426 ber_sockbuf_remove_io( sb, &ldap_pvt_sockbuf_io_sasl,
427 LBER_SBIOD_LEVEL_APPLICATION );
429 ber_sockbuf_remove_io( sb, &ber_sockbuf_io_debug,
430 LBER_SBIOD_LEVEL_APPLICATION );
435 sasl_err2ldap( int saslerr )
441 rc = LDAP_MORE_RESULTS_TO_RETURN;
444 rc = LDAP_LOCAL_ERROR;
450 rc = LDAP_LOCAL_ERROR;
456 rc = LDAP_AUTH_UNKNOWN;
459 rc = LDAP_AUTH_UNKNOWN;
462 rc = LDAP_PARAM_ERROR;
466 rc = LDAP_AUTH_UNKNOWN;
469 rc = LDAP_LOCAL_ERROR;
473 assert( rc == LDAP_SUCCESS || LDAP_API_ERROR( rc ) );
486 assert( lc->lconn_sasl_authctx == NULL );
488 if ( host == NULL ) {
489 ld->ld_errno = LDAP_LOCAL_ERROR;
493 #if SASL_VERSION_MAJOR >= 2
494 rc = sasl_client_new( "ldap", host, NULL, NULL,
497 rc = sasl_client_new( "ldap", host, NULL,
498 SASL_SECURITY_LAYER, &ctx );
501 if ( rc != SASL_OK ) {
502 ld->ld_errno = sasl_err2ldap( rc );
507 LDAP_LOG ( TRANSPORT, DETAIL1, "ldap_int_sasl_open: host=%s\n",
510 Debug( LDAP_DEBUG_TRACE, "ldap_int_sasl_open: host=%s\n",
514 lc->lconn_sasl_authctx = ctx;
519 int ldap_int_sasl_close( LDAP *ld, LDAPConn *lc )
521 sasl_conn_t *ctx = lc->lconn_sasl_authctx;
524 sasl_dispose( &ctx );
525 if ( lc->lconn_sasl_sockctx &&
526 lc->lconn_sasl_authctx != lc->lconn_sasl_sockctx ) {
527 ctx = lc->lconn_sasl_sockctx;
528 sasl_dispose( &ctx );
530 lc->lconn_sasl_sockctx = NULL;
531 lc->lconn_sasl_authctx = NULL;
542 LDAPControl **sctrls,
543 LDAPControl **cctrls,
545 LDAP_SASL_INTERACT_PROC *interact,
549 const char *mech = NULL;
550 const char *pmech = NULL;
552 sasl_ssf_t *ssf = NULL;
553 sasl_conn_t *ctx, *oldctx = NULL;
554 sasl_interact_t *prompts = NULL;
561 LDAP_LOG ( TRANSPORT, ARGS, "ldap_int_sasl_bind: %s\n",
562 mechs ? mechs : "<null>", 0, 0 );
564 Debug( LDAP_DEBUG_TRACE, "ldap_int_sasl_bind: %s\n",
565 mechs ? mechs : "<null>", 0, 0 );
568 /* do a quick !LDAPv3 check... ldap_sasl_bind will do the rest. */
569 if (ld->ld_version < LDAP_VERSION3) {
570 ld->ld_errno = LDAP_NOT_SUPPORTED;
574 ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd );
576 if ( sd == AC_SOCKET_INVALID ) {
577 /* not connected yet */
580 rc = ldap_open_defconn( ld );
581 if( rc < 0 ) return ld->ld_errno;
583 ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd );
585 if( sd == AC_SOCKET_INVALID ) {
586 ld->ld_errno = LDAP_LOCAL_ERROR;
591 oldctx = ld->ld_defconn->lconn_sasl_authctx;
593 /* If we already have an authentication context, clear it out */
595 if ( oldctx != ld->ld_defconn->lconn_sasl_sockctx ) {
596 sasl_dispose( &oldctx );
598 ld->ld_defconn->lconn_sasl_authctx = NULL;
601 rc = ldap_int_sasl_open( ld, ld->ld_defconn,
602 ld->ld_defconn->lconn_server->lud_host ?
603 ld->ld_defconn->lconn_server->lud_host : "localhost" );
605 if ( rc != LDAP_SUCCESS ) return rc;
607 ctx = ld->ld_defconn->lconn_sasl_authctx;
610 ssl = ldap_pvt_tls_sb_ctx( ld->ld_sb );
612 struct berval authid = { 0, NULL };
615 fac = ldap_pvt_tls_get_strength( ssl );
616 /* failure is OK, we just can't use SASL EXTERNAL */
617 (void) ldap_pvt_tls_get_my_dn( ssl, &authid, NULL, 0 );
619 (void) ldap_int_sasl_external( ld, ld->ld_defconn, authid.bv_val, fac );
620 LDAP_FREE( authid.bv_val );
623 /* Check for local */
624 if ( ldap_pvt_url_scheme2proto( ld->ld_defconn->lconn_server->lud_scheme ) == LDAP_PROTO_IPC ) {
625 char authid[sizeof("uidNumber=4294967295+gidNumber=4294967295,"
626 "cn=peercred,cn=external,cn=auth")];
627 sprintf( authid, "uidNumber=%d+gidNumber=%d,"
628 "cn=peercred,cn=external,cn=auth",
629 (int) geteuid(), (int) getegid() );
630 (void) ldap_int_sasl_external( ld, ld->ld_defconn, authid, LDAP_PVT_SASL_LOCAL_SSF );
633 /* (re)set security properties */
634 sasl_setprop( ctx, SASL_SEC_PROPS,
635 &ld->ld_options.ldo_sasl_secprops );
641 saslrc = sasl_client_start( ctx,
643 #if SASL_VERSION_MAJOR < 2
647 (SASL_CONST char **)&ccred.bv_val,
651 if( pmech == NULL && mech != NULL ) {
654 if( flags != LDAP_SASL_QUIET ) {
656 "SASL/%s authentication started\n",
661 if( saslrc == SASL_INTERACT ) {
663 if( !interact ) break;
664 res = (interact)( ld, flags, defaults, prompts );
666 if( res != LDAP_SUCCESS ) break;
668 } while ( saslrc == SASL_INTERACT );
670 ccred.bv_len = credlen;
672 if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
673 rc = ld->ld_errno = sasl_err2ldap( saslrc );
674 #if SASL_VERSION_MAJOR >= 2
675 ld->ld_error = LDAP_STRDUP( sasl_errdetail( ctx ) );
681 struct berval *scred;
686 rc = ldap_sasl_bind_s( ld, dn, mech, &ccred, sctrls, cctrls, &scred );
688 if ( ccred.bv_val != NULL ) {
689 #if SASL_VERSION_MAJOR < 2
690 LDAP_FREE( ccred.bv_val );
695 if ( rc != LDAP_SUCCESS && rc != LDAP_SASL_BIND_IN_PROGRESS ) {
696 if( scred && scred->bv_len ) {
697 /* and server provided us with data? */
699 LDAP_LOG ( TRANSPORT, DETAIL1,
700 "ldap_int_sasl_bind: rc=%d sasl=%d len=%ld\n",
701 rc, saslrc, scred->bv_len );
703 Debug( LDAP_DEBUG_TRACE,
704 "ldap_int_sasl_bind: rc=%d sasl=%d len=%ld\n",
705 rc, saslrc, scred->bv_len );
713 if( rc == LDAP_SUCCESS && saslrc == SASL_OK ) {
714 /* we're done, no need to step */
715 if( scred && scred->bv_len ) {
716 /* but server provided us with data! */
718 LDAP_LOG ( TRANSPORT, DETAIL1,
719 "ldap_int_sasl_bind: rc=%d sasl=%d len=%ld\n",
720 rc, saslrc, scred->bv_len );
722 Debug( LDAP_DEBUG_TRACE,
723 "ldap_int_sasl_bind: rc=%d sasl=%d len=%ld\n",
724 rc, saslrc, scred->bv_len );
727 rc = ld->ld_errno = LDAP_LOCAL_ERROR;
734 saslrc = sasl_client_step( ctx,
735 (scred == NULL) ? NULL : scred->bv_val,
736 (scred == NULL) ? 0 : scred->bv_len,
738 (SASL_CONST char **)&ccred.bv_val,
742 LDAP_LOG ( TRANSPORT, DETAIL1,
743 "ldap_int_sasl_bind: sasl_client_step: %d\n", saslrc,0,0 );
745 Debug( LDAP_DEBUG_TRACE, "sasl_client_step: %d\n",
749 if( saslrc == SASL_INTERACT ) {
751 if( !interact ) break;
752 res = (interact)( ld, flags, defaults, prompts );
753 if( res != LDAP_SUCCESS ) break;
755 } while ( saslrc == SASL_INTERACT );
757 ccred.bv_len = credlen;
760 if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
761 ld->ld_errno = sasl_err2ldap( saslrc );
762 #if SASL_VERSION_MAJOR >= 2
763 ld->ld_error = LDAP_STRDUP( sasl_errdetail( ctx ) );
768 } while ( rc == LDAP_SASL_BIND_IN_PROGRESS );
770 if ( rc != LDAP_SUCCESS ) goto done;
772 if ( saslrc != SASL_OK ) {
773 #if SASL_VERSION_MAJOR >= 2
774 ld->ld_error = LDAP_STRDUP( sasl_errdetail( ctx ) );
776 rc = ld->ld_errno = sasl_err2ldap( saslrc );
780 if( flags != LDAP_SASL_QUIET ) {
781 saslrc = sasl_getprop( ctx, SASL_USERNAME, (SASL_CONST void **) &data );
782 if( saslrc == SASL_OK && data && *data ) {
783 fprintf( stderr, "SASL username: %s\n", data );
786 #if SASL_VERSION_MAJOR < 2
787 saslrc = sasl_getprop( ctx, SASL_REALM, (SASL_CONST void **) &data );
788 if( saslrc == SASL_OK && data && *data ) {
789 fprintf( stderr, "SASL realm: %s\n", data );
794 saslrc = sasl_getprop( ctx, SASL_SSF, (SASL_CONST void **) &ssf );
795 if( saslrc == SASL_OK ) {
796 if( flags != LDAP_SASL_QUIET ) {
797 fprintf( stderr, "SASL SSF: %lu\n",
798 (unsigned long) *ssf );
802 if( flags != LDAP_SASL_QUIET ) {
803 fprintf( stderr, "SASL installing layers\n" );
805 if ( ld->ld_defconn->lconn_sasl_sockctx ) {
806 oldctx = ld->ld_defconn->lconn_sasl_sockctx;
807 sasl_dispose( &oldctx );
808 ldap_pvt_sasl_remove( ld->ld_sb );
810 ldap_pvt_sasl_install( ld->ld_conns->lconn_sb, ctx );
811 ld->ld_defconn->lconn_sasl_sockctx = ctx;
814 ld->ld_defconn->lconn_sasl_authctx = ctx;
821 ldap_int_sasl_external(
829 #if SASL_VERSION_MAJOR < 2
830 sasl_external_properties_t extprops;
833 ctx = conn->lconn_sasl_authctx;
836 return LDAP_LOCAL_ERROR;
839 #if SASL_VERSION_MAJOR >= 2
840 sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL, &ssf );
842 sc = sasl_setprop( ctx, SASL_AUTH_EXTERNAL, authid );
844 memset( &extprops, '\0', sizeof(extprops) );
846 extprops.auth_id = (char *) authid;
848 sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL,
849 (void *) &extprops );
852 if ( sc != SASL_OK ) {
853 return LDAP_LOCAL_ERROR;
860 int ldap_pvt_sasl_secprops(
862 sasl_security_properties_t *secprops )
865 char **props = ldap_str2charray( in, "," );
868 sasl_ssf_t max_ssf = 0;
870 sasl_ssf_t min_ssf = 0;
872 unsigned maxbufsize = 0;
873 int got_maxbufsize = 0;
875 if( props == NULL || secprops == NULL ) {
876 return LDAP_PARAM_ERROR;
879 for( i=0; props[i]; i++ ) {
880 if( !strcasecmp(props[i], "none") ) {
883 } else if( !strcasecmp(props[i], "noplain") ) {
885 sflags |= SASL_SEC_NOPLAINTEXT;
887 } else if( !strcasecmp(props[i], "noactive") ) {
889 sflags |= SASL_SEC_NOACTIVE;
891 } else if( !strcasecmp(props[i], "nodict") ) {
893 sflags |= SASL_SEC_NODICTIONARY;
895 } else if( !strcasecmp(props[i], "forwardsec") ) {
897 sflags |= SASL_SEC_FORWARD_SECRECY;
899 } else if( !strcasecmp(props[i], "noanonymous")) {
901 sflags |= SASL_SEC_NOANONYMOUS;
903 } else if( !strcasecmp(props[i], "passcred") ) {
905 sflags |= SASL_SEC_PASS_CREDENTIALS;
907 } else if( !strncasecmp(props[i],
908 "minssf=", sizeof("minssf")) )
910 if( isdigit( (unsigned char) props[i][sizeof("minssf")] ) ) {
912 min_ssf = atoi( &props[i][sizeof("minssf")] );
914 return LDAP_NOT_SUPPORTED;
917 } else if( !strncasecmp(props[i],
918 "maxssf=", sizeof("maxssf")) )
920 if( isdigit( (unsigned char) props[i][sizeof("maxssf")] ) ) {
922 max_ssf = atoi( &props[i][sizeof("maxssf")] );
924 return LDAP_NOT_SUPPORTED;
927 } else if( !strncasecmp(props[i],
928 "maxbufsize=", sizeof("maxbufsize")) )
930 if( isdigit( (unsigned char) props[i][sizeof("maxbufsize")] ) ) {
932 maxbufsize = atoi( &props[i][sizeof("maxbufsize")] );
934 return LDAP_NOT_SUPPORTED;
937 if( maxbufsize && (( maxbufsize < SASL_MIN_BUFF_SIZE )
938 || (maxbufsize > SASL_MAX_BUFF_SIZE )))
941 return LDAP_PARAM_ERROR;
945 return LDAP_NOT_SUPPORTED;
950 secprops->security_flags = sflags;
953 secprops->min_ssf = min_ssf;
956 secprops->max_ssf = max_ssf;
959 secprops->maxbufsize = maxbufsize;
962 ldap_charray_free( props );
967 ldap_int_sasl_config( struct ldapoptions *lo, int option, const char *arg )
972 case LDAP_OPT_X_SASL_SECPROPS:
973 rc = ldap_pvt_sasl_secprops( arg, &lo->ldo_sasl_secprops );
974 if( rc == LDAP_SUCCESS ) return 0;
981 ldap_int_sasl_get_option( LDAP *ld, int option, void *arg )
987 case LDAP_OPT_X_SASL_MECH: {
988 *(char **)arg = ld->ld_options.ldo_def_sasl_mech
989 ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_mech ) : NULL;
991 case LDAP_OPT_X_SASL_REALM: {
992 *(char **)arg = ld->ld_options.ldo_def_sasl_realm
993 ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_realm ) : NULL;
995 case LDAP_OPT_X_SASL_AUTHCID: {
996 *(char **)arg = ld->ld_options.ldo_def_sasl_authcid
997 ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_authcid ) : NULL;
999 case LDAP_OPT_X_SASL_AUTHZID: {
1000 *(char **)arg = ld->ld_options.ldo_def_sasl_authzid
1001 ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_authzid ) : NULL;
1004 case LDAP_OPT_X_SASL_SSF: {
1009 if( ld->ld_defconn == NULL ) {
1013 ctx = ld->ld_defconn->lconn_sasl_sockctx;
1015 if ( ctx == NULL ) {
1019 sc = sasl_getprop( ctx, SASL_SSF,
1020 (SASL_CONST void **) &ssf );
1022 if ( sc != SASL_OK ) {
1026 *(ber_len_t *)arg = *ssf;
1029 case LDAP_OPT_X_SASL_SSF_EXTERNAL:
1030 /* this option is write only */
1033 case LDAP_OPT_X_SASL_SSF_MIN:
1034 *(ber_len_t *)arg = ld->ld_options.ldo_sasl_secprops.min_ssf;
1036 case LDAP_OPT_X_SASL_SSF_MAX:
1037 *(ber_len_t *)arg = ld->ld_options.ldo_sasl_secprops.max_ssf;
1039 case LDAP_OPT_X_SASL_MAXBUFSIZE:
1040 *(ber_len_t *)arg = ld->ld_options.ldo_sasl_secprops.maxbufsize;
1043 case LDAP_OPT_X_SASL_SECPROPS:
1044 /* this option is write only */
1054 ldap_int_sasl_set_option( LDAP *ld, int option, void *arg )
1060 case LDAP_OPT_X_SASL_SSF:
1061 /* This option is read-only */
1064 case LDAP_OPT_X_SASL_SSF_EXTERNAL: {
1066 #if SASL_VERSION_MAJOR < 2
1067 sasl_external_properties_t extprops;
1071 if( ld->ld_defconn == NULL ) {
1075 ctx = ld->ld_defconn->lconn_sasl_authctx;
1077 if ( ctx == NULL ) {
1081 #if SASL_VERSION_MAJOR >= 2
1082 sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL, arg);
1084 memset(&extprops, 0L, sizeof(extprops));
1086 extprops.ssf = * (ber_len_t *) arg;
1088 sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL,
1089 (void *) &extprops );
1092 if ( sc != SASL_OK ) {
1097 case LDAP_OPT_X_SASL_SSF_MIN:
1098 ld->ld_options.ldo_sasl_secprops.min_ssf = *(ber_len_t *)arg;
1100 case LDAP_OPT_X_SASL_SSF_MAX:
1101 ld->ld_options.ldo_sasl_secprops.max_ssf = *(ber_len_t *)arg;
1103 case LDAP_OPT_X_SASL_MAXBUFSIZE:
1104 ld->ld_options.ldo_sasl_secprops.maxbufsize = *(ber_len_t *)arg;
1107 case LDAP_OPT_X_SASL_SECPROPS: {
1109 sc = ldap_pvt_sasl_secprops( (char *) arg,
1110 &ld->ld_options.ldo_sasl_secprops );
1112 return sc == LDAP_SUCCESS ? 0 : -1;
1121 #ifdef LDAP_R_COMPILE
1122 #define LDAP_DEBUG_R_SASL
1123 void *ldap_pvt_sasl_mutex_new(void)
1125 ldap_pvt_thread_mutex_t *mutex;
1127 mutex = (ldap_pvt_thread_mutex_t *) LDAP_MALLOC(
1128 sizeof(ldap_pvt_thread_mutex_t) );
1130 if ( ldap_pvt_thread_mutex_init( mutex ) == 0 ) {
1133 #ifndef LDAP_DEBUG_R_SASL
1135 #endif /* !LDAP_DEBUG_R_SASL */
1139 int ldap_pvt_sasl_mutex_lock(void *mutex)
1141 #ifdef LDAP_DEBUG_R_SASL
1142 if ( mutex == NULL ) {
1145 #else /* !LDAP_DEBUG_R_SASL */
1147 #endif /* !LDAP_DEBUG_R_SASL */
1148 return ldap_pvt_thread_mutex_lock( (ldap_pvt_thread_mutex_t *)mutex )
1149 ? SASL_FAIL : SASL_OK;
1152 int ldap_pvt_sasl_mutex_unlock(void *mutex)
1154 #ifdef LDAP_DEBUG_R_SASL
1155 if ( mutex == NULL ) {
1158 #else /* !LDAP_DEBUG_R_SASL */
1160 #endif /* !LDAP_DEBUG_R_SASL */
1161 return ldap_pvt_thread_mutex_unlock( (ldap_pvt_thread_mutex_t *)mutex )
1162 ? SASL_FAIL : SASL_OK;
1165 void ldap_pvt_sasl_mutex_dispose(void *mutex)
1167 #ifdef LDAP_DEBUG_R_SASL
1168 if ( mutex == NULL ) {
1171 #else /* !LDAP_DEBUG_R_SASL */
1173 #endif /* !LDAP_DEBUG_R_SASL */
1174 (void) ldap_pvt_thread_mutex_destroy( (ldap_pvt_thread_mutex_t *)mutex );
1180 int ldap_int_sasl_init( void )
1181 { return LDAP_SUCCESS; }
1183 int ldap_int_sasl_close( LDAP *ld, LDAPConn *lc )
1184 { return LDAP_SUCCESS; }
1191 LDAPControl **sctrls,
1192 LDAPControl **cctrls,
1194 LDAP_SASL_INTERACT_PROC *interact,
1196 { return LDAP_NOT_SUPPORTED; }
1199 ldap_int_sasl_external(
1202 const char * authid,
1204 { return LDAP_SUCCESS; }
1206 #endif /* HAVE_CYRUS_SASL */