3 * Copyright 1999-2000 The OpenLDAP Foundation, All Rights Reserved.
4 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
12 #include <ac/socket.h>
13 #include <ac/string.h>
19 #ifdef HAVE_CYRUS_SASL
23 * Various Cyrus SASL related stuff.
26 #define SASL_MAX_BUFF_SIZE 65536
27 #define SASL_MIN_BUFF_SIZE 4096
29 int ldap_int_sasl_init( void )
31 /* XXX not threadsafe */
32 static int sasl_initialized = 0;
34 static sasl_callback_t client_callbacks[] = {
35 #ifdef SASL_CB_GETREALM
36 { SASL_CB_GETREALM, NULL, NULL },
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 }
46 if ( sasl_initialized ) {
56 #endif /* CSRIMALLOC */
60 ldap_pvt_sasl_mutex_new,
61 ldap_pvt_sasl_mutex_lock,
62 ldap_pvt_sasl_mutex_unlock,
63 ldap_pvt_sasl_mutex_dispose );
66 if ( sasl_client_init( client_callbacks ) == SASL_OK ) {
75 * SASL encryption support for LBER Sockbufs
79 sasl_conn_t *sasl_context;
80 Sockbuf_Buf sec_buf_in;
86 sb_sasl_setup( Sockbuf_IO_Desc *sbiod, void *arg )
88 struct sb_sasl_data *p;
90 assert( sbiod != NULL );
92 p = LBER_MALLOC( sizeof( *p ) );
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 ) {
104 sbiod->sbiod_pvt = p;
110 sb_sasl_remove( Sockbuf_IO_Desc *sbiod )
112 struct sb_sasl_data *p;
114 assert( sbiod != NULL );
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 );
121 sbiod->sbiod_pvt = NULL;
126 sb_sasl_pkt_length( const char *buf, int debuglevel )
131 assert( buf != NULL );
133 tmp = *((long *)buf);
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. */
144 return size + 4; /* include the size !!! */
147 /* Drop a processed packet from the input buffer */
149 sb_sasl_drop_packet ( Sockbuf_Buf *sec_buf_in, int debuglevel )
153 len = sec_buf_in->buf_ptr - sec_buf_in->buf_end;
155 memmove( sec_buf_in->buf_base, sec_buf_in->buf_base +
156 sec_buf_in->buf_end, len );
159 sec_buf_in->buf_end = sb_sasl_pkt_length( sec_buf_in->buf_base,
163 sec_buf_in->buf_end = 0;
165 sec_buf_in->buf_ptr = len;
169 sb_sasl_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
171 struct sb_sasl_data *p;
172 ber_slen_t ret, bufptr;
174 assert( sbiod != NULL );
175 assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
177 p = (struct sb_sasl_data *)sbiod->sbiod_pvt;
179 /* Are there anything left in the buffer? */
180 ret = ber_pvt_sb_copy_out( &p->buf_in, buf, len );
187 ber_pvt_sb_buf_destroy( &p->buf_in );
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 );
194 if ( ( ret < 0 ) && ( errno == EINTR ) )
200 p->sec_buf_in.buf_ptr += ret;
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 );
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 ) {
213 p->sec_buf_in.buf_end = ret;
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;
220 ret = LBER_SBIOD_READ_NEXT( sbiod, p->sec_buf_in.buf_base +
221 p->sec_buf_in.buf_ptr, ret );
223 if ( ( ret < 0 ) && ( errno == EINTR ) )
229 p->sec_buf_in.buf_ptr += ret;
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 );
246 /* Drop the packet from the input buffer */
247 sb_sasl_drop_packet( &p->sec_buf_in, sbiod->sbiod_sb->sb_debug );
249 p->buf_in.buf_size = p->buf_in.buf_end;
251 bufptr += ber_pvt_sb_copy_out( &p->buf_in, (char*) buf + bufptr, len );
257 sb_sasl_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
259 struct sb_sasl_data *p;
262 assert( sbiod != NULL );
263 assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
265 p = (struct sb_sasl_data *)sbiod->sbiod_pvt;
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 );
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 ) );
284 p->buf_out.buf_end = p->buf_out.buf_size;
286 ret = ber_pvt_sb_do_write( sbiod, &p->buf_out );
293 sb_sasl_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
295 struct sb_sasl_data *p;
297 p = (struct sb_sasl_data *)sbiod->sbiod_pvt;
299 if ( opt == LBER_SB_OPT_DATA_READY ) {
300 if ( p->buf_in.buf_ptr != p->buf_in.buf_end )
304 return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
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 */
316 int ldap_pvt_sasl_install( Sockbuf *sb, void *ctx_arg )
318 Debug( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_install\n",
321 /* don't install the stuff unless security has been negotiated */
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 );
332 sasl_err2ldap( int saslerr )
338 rc = LDAP_MORE_RESULTS_TO_RETURN;
344 rc = LDAP_LOCAL_ERROR;
350 rc = LDAP_AUTH_UNKNOWN;
353 rc = LDAP_AUTH_UNKNOWN;
356 rc = LDAP_PARAM_ERROR;
360 rc = LDAP_AUTH_UNKNOWN;
363 rc = LDAP_LOCAL_ERROR;
367 assert( rc == LDAP_SUCCESS || LDAP_API_ERROR( rc ) );
380 assert( lc->lconn_sasl_ctx == NULL );
382 if ( host == NULL ) {
383 ld->ld_errno = LDAP_UNAVAILABLE;
387 rc = sasl_client_new( "ldap", host,
389 #ifdef LDAP_SASL_SECURITY_LAYER
396 if ( rc != SASL_OK ) {
397 ld->ld_errno = sasl_err2ldap( rc );
401 Debug( LDAP_DEBUG_TRACE, "ldap_int_sasl_open: %s\n",
404 lc->lconn_sasl_ctx = ctx;
407 sasl_external_properties_t extprops;
408 memset(&extprops, 0L, sizeof(extprops));
411 (void) sasl_setprop( ctx, SASL_SSF_EXTERNAL,
412 (void *) &extprops );
414 Debug( LDAP_DEBUG_TRACE, "ldap_int_sasl_open: ssf=%ld\n",
421 int ldap_int_sasl_close( LDAP *ld, LDAPConn *lc )
423 sasl_conn_t *ctx = lc->lconn_sasl_ctx;
424 assert( ctx != NULL );
427 sasl_dispose( &ctx );
428 lc->lconn_sasl_ctx = NULL;
439 LDAPControl **sctrls,
440 LDAPControl **cctrls )
442 const char *mech = NULL;
443 const char *pmech = NULL;
445 sasl_ssf_t *ssf = NULL;
447 sasl_interact_t *prompts = NULL;
449 struct berval ccred, *scred;
452 Debug( LDAP_DEBUG_TRACE, "ldap_int_sasl_bind: %s\n",
453 mechs ? mechs : "<null>", 0, 0 );
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;
461 ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd );
463 if ( sd == AC_SOCKET_INVALID ) {
464 /* not connected yet */
465 int rc = ldap_open_defconn( ld );
467 if( rc < 0 ) return ld->ld_errno;
468 ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd );
470 if( sd == AC_SOCKET_INVALID ) {
471 ld->ld_errno = LDAP_UNAVAILABLE;
476 ctx = ld->ld_defconn->lconn_sasl_ctx;
479 ld->ld_errno = LDAP_UNAVAILABLE;
483 /* (re)set security properties */
484 sasl_setprop( ctx, SASL_SEC_PROPS,
485 &ld->ld_options.ldo_sasl_secprops );
491 saslrc = sasl_client_start( ctx,
499 if( pmech == NULL && mech != NULL ) {
503 "SASL/%s authentication started\n",
507 if( saslrc == SASL_INTERACT ) {
508 if( !ld->ld_options.ldo_sasl_interact ) break;
510 rc = (ld->ld_options.ldo_sasl_interact)( ld, prompts );
511 if( rc != LDAP_SUCCESS ) {
515 } while ( saslrc == SASL_INTERACT );
517 ccred.bv_len = credlen;
519 if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
520 ld->ld_errno = sasl_err2ldap( saslrc );
529 rc = ldap_sasl_bind_s( ld, dn, mech, &ccred, sctrls, cctrls, &scred );
531 if ( rc == LDAP_SUCCESS ) {
533 } else if ( rc != LDAP_SASL_BIND_IN_PROGRESS ) {
534 if ( ccred.bv_val != NULL ) {
535 LDAP_FREE( ccred.bv_val );
540 if ( ccred.bv_val != NULL ) {
541 LDAP_FREE( ccred.bv_val );
546 saslrc = sasl_client_step( ctx,
547 (scred == NULL) ? NULL : scred->bv_val,
548 (scred == NULL) ? 0 : scred->bv_len,
553 Debug( LDAP_DEBUG_TRACE, "sasl_client_start: %d\n",
556 if( saslrc == SASL_INTERACT ) {
557 fprintf(stderr, "Interacting\n");
558 if( !ld->ld_options.ldo_sasl_interact ) break;
560 rc = (ld->ld_options.ldo_sasl_interact)( ld, prompts );
561 if( rc != LDAP_SUCCESS ) {
565 } while ( saslrc == SASL_INTERACT );
567 ccred.bv_len = credlen;
570 if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
571 ld->ld_errno = sasl_err2ldap( saslrc );
574 } while ( rc == LDAP_SASL_BIND_IN_PROGRESS );
576 assert ( rc == LDAP_SUCCESS );
578 if ( sasl_getprop( ctx, SASL_SSF, (void **) &ssf )
579 == SASL_OK && ssf && *ssf > 1 )
581 #ifdef LDAP_SASL_SECURITY_LAYER
582 fprintf(stderr, "Installing Security Layer: ssf=%lu\n",
583 (unsigned long) *ssf );
585 ldap_pvt_sasl_install( ld->ld_sb, ctx );
587 fprintf(stderr, "SASL Security Factor is %lu\n",
588 (unsigned long) *ssf );
595 int ldap_pvt_sasl_secprops(
597 sasl_security_properties_t *secprops )
600 char **props = ldap_str2charray( in, "," );
608 int got_maxbufsize = 0;
610 if( props == NULL || secprops == NULL ) {
611 return LDAP_PARAM_ERROR;
614 for( i=0; props[i]; i++ ) {
615 if( !strcasecmp(props[i], "none") ) {
618 } else if( !strcasecmp(props[i], "noplain") ) {
620 sflags |= SASL_SEC_NOPLAINTEXT;
622 } else if( !strcasecmp(props[i], "noactive") ) {
624 sflags |= SASL_SEC_NOACTIVE;
626 } else if( !strcasecmp(props[i], "nodict") ) {
628 sflags |= SASL_SEC_NODICTIONARY;
630 } else if( !strcasecmp(props[i], "forwardsec") ) {
632 sflags |= SASL_SEC_FORWARD_SECRECY;
634 } else if( !strcasecmp(props[i], "noanonymous")) {
636 sflags |= SASL_SEC_NOANONYMOUS;
638 } else if( !strcasecmp(props[i], "passcred") ) {
640 sflags |= SASL_SEC_PASS_CREDENTIALS;
642 } else if( !strncasecmp(props[i],
643 "minssf=", sizeof("minssf")) )
645 if( isdigit( props[i][sizeof("minssf")] ) ) {
647 min_ssf = atoi( &props[i][sizeof("minssf")] );
649 return LDAP_NOT_SUPPORTED;
652 } else if( !strncasecmp(props[i],
653 "maxssf=", sizeof("maxssf")) )
655 if( isdigit( props[i][sizeof("maxssf")] ) ) {
657 max_ssf = atoi( &props[i][sizeof("maxssf")] );
659 return LDAP_NOT_SUPPORTED;
662 } else if( !strncasecmp(props[i],
663 "maxbufsize=", sizeof("maxbufsize")) )
665 if( isdigit( props[i][sizeof("maxbufsize")] ) ) {
667 maxbufsize = atoi( &props[i][sizeof("maxbufsize")] );
669 return LDAP_NOT_SUPPORTED;
673 return LDAP_NOT_SUPPORTED;
678 secprops->security_flags = sflags;
681 secprops->min_ssf = min_ssf;
684 secprops->max_ssf = max_ssf;
687 secprops->maxbufsize = maxbufsize;
690 ldap_charray_free( props );
695 ldap_int_sasl_config( struct ldapoptions *lo, int option, const char *arg )
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;
709 ldap_int_sasl_get_option( LDAP *ld, int option, void *arg )
715 case LDAP_OPT_X_SASL_SSF: {
720 if( ld->ld_defconn == NULL ) {
724 ctx = ld->ld_defconn->lconn_sasl_ctx;
730 sc = sasl_getprop( ctx, SASL_SSF,
733 if ( sc != SASL_OK ) {
737 *(ber_len_t *)arg = *ssf;
740 case LDAP_OPT_X_SASL_SSF_EXTERNAL:
741 /* this option is write only */
744 case LDAP_OPT_X_SASL_SSF_MIN:
745 *(ber_len_t *)arg = ld->ld_options.ldo_sasl_secprops.min_ssf;
747 case LDAP_OPT_X_SASL_SSF_MAX:
748 *(ber_len_t *)arg = ld->ld_options.ldo_sasl_secprops.max_ssf;
750 case LDAP_OPT_X_SASL_MAXBUFSIZE:
751 *(ber_len_t *)arg = ld->ld_options.ldo_sasl_secprops.maxbufsize;
754 case LDAP_OPT_X_SASL_SECPROPS:
755 /* this option is write only */
765 ldap_int_sasl_set_option( LDAP *ld, int option, void *arg )
771 case LDAP_OPT_X_SASL_SSF:
772 /* This option is read-only */
775 case LDAP_OPT_X_SASL_SSF_EXTERNAL: {
777 sasl_external_properties_t extprops;
780 if( ld->ld_defconn == NULL ) {
784 ctx = ld->ld_defconn->lconn_sasl_ctx;
790 memset(&extprops, 0L, sizeof(extprops));
792 extprops.ssf = * (ber_len_t *) arg;
794 sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL,
795 (void *) &extprops );
797 if ( sc != SASL_OK ) {
802 case LDAP_OPT_X_SASL_SSF_MIN:
803 ld->ld_options.ldo_sasl_secprops.min_ssf = *(ber_len_t *)arg;
805 case LDAP_OPT_X_SASL_SSF_MAX:
806 ld->ld_options.ldo_sasl_secprops.max_ssf = *(ber_len_t *)arg;
808 case LDAP_OPT_X_SASL_MAXBUFSIZE:
809 ld->ld_options.ldo_sasl_secprops.maxbufsize = *(ber_len_t *)arg;
812 case LDAP_OPT_X_SASL_SECPROPS: {
814 sc = ldap_pvt_sasl_secprops( (char *) arg,
815 &ld->ld_options.ldo_sasl_secprops );
817 return sc == LDAP_SUCCESS ? 0 : -1;
826 #ifdef LDAP_R_COMPILE
827 void *ldap_pvt_sasl_mutex_new(void)
829 ldap_pvt_thread_mutex_t *mutex;
831 mutex = (ldap_pvt_thread_mutex_t *) LDAP_MALLOC(
832 sizeof(ldap_pvt_thread_mutex_t) );
834 if ( ldap_pvt_thread_mutex_init( mutex ) == 0 ) {
840 int ldap_pvt_sasl_mutex_lock(void *mutex)
842 return ldap_pvt_thread_mutex_lock( (ldap_pvt_thread_mutex_t *)mutex )
843 ? SASL_FAIL : SASL_OK;
846 int ldap_pvt_sasl_mutex_unlock(void *mutex)
848 return ldap_pvt_thread_mutex_unlock( (ldap_pvt_thread_mutex_t *)mutex )
849 ? SASL_FAIL : SASL_OK;
852 void ldap_pvt_sasl_mutex_dispose(void *mutex)
854 (void) ldap_pvt_thread_mutex_destroy( (ldap_pvt_thread_mutex_t *)mutex );
860 int ldap_int_sasl_init( void )
861 { return LDAP_SUCCESS; }
863 int ldap_int_sasl_close( LDAP *ld, LDAPConn *lc )
864 { return LDAP_SUCCESS; }
871 LDAPControl **sctrls,
872 LDAPControl **cctrls )
873 { return LDAP_NOT_SUPPORTED; }
874 #endif /* HAVE_CYRUS_SASL */