1 /* $OpenLDAP: pkg/ldap/libraries/libldap/cyrus.c,v 1.133.2.8 2008/02/11 23:26:41 kurt Exp $ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1998-2008 The OpenLDAP Foundation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
11 * A copy of this license is available in the file LICENSE in the
12 * top-level directory of the distribution or, alternatively, at
13 * <http://www.OpenLDAP.org/license.html>.
20 #include <ac/socket.h>
21 #include <ac/stdlib.h>
22 #include <ac/string.h>
26 #include <ac/unistd.h>
34 #ifdef HAVE_CYRUS_SASL
41 #define INT_MAX 2147483647 /* 32 bit signed max */
45 ldap_pvt_thread_mutex_t ldap_int_sasl_mutex
;
48 #ifdef HAVE_SASL_SASL_H
49 #include <sasl/sasl.h>
54 #if SASL_VERSION_MAJOR >= 2
55 #define SASL_CONST const
61 * Various Cyrus SASL related stuff.
64 static const sasl_callback_t client_callbacks
[] = {
65 #ifdef SASL_CB_GETREALM
66 { SASL_CB_GETREALM
, NULL
, NULL
},
68 { SASL_CB_USER
, NULL
, NULL
},
69 { SASL_CB_AUTHNAME
, NULL
, NULL
},
70 { SASL_CB_PASS
, NULL
, NULL
},
71 { SASL_CB_ECHOPROMPT
, NULL
, NULL
},
72 { SASL_CB_NOECHOPROMPT
, NULL
, NULL
},
73 { SASL_CB_LIST_END
, NULL
, NULL
}
76 int ldap_int_sasl_init( void )
78 /* XXX not threadsafe */
79 static int sasl_initialized
= 0;
81 #ifdef HAVE_SASL_VERSION
82 /* stringify the version number, sasl.h doesn't do it for us */
83 #define VSTR0(maj, min, pat) #maj "." #min "." #pat
84 #define VSTR(maj, min, pat) VSTR0(maj, min, pat)
85 #define SASL_VERSION_STRING VSTR(SASL_VERSION_MAJOR, SASL_VERSION_MINOR, \
88 sasl_version( NULL
, &rc
);
89 if ( ((rc
>> 16) != ((SASL_VERSION_MAJOR
<< 8)|SASL_VERSION_MINOR
)) ||
90 (rc
& 0xffff) < SASL_VERSION_STEP
) {
91 char version
[sizeof("xxx.xxx.xxxxx")];
92 sprintf( version
, "%u.%d.%d", (unsigned)rc
>> 24, (rc
>> 16) & 0xff,
95 Debug( LDAP_DEBUG_ANY
,
96 "ldap_int_sasl_init: SASL library version mismatch:"
97 " expected " SASL_VERSION_STRING
","
98 " got %s\n", version
, 0, 0 );
103 if ( sasl_initialized
) {
107 /* SASL 2 takes care of its own memory completely internally */
108 #if SASL_VERSION_MAJOR < 2 && !defined(CSRIMALLOC)
114 #endif /* CSRIMALLOC */
116 #ifdef LDAP_R_COMPILE
118 ldap_pvt_sasl_mutex_new
,
119 ldap_pvt_sasl_mutex_lock
,
120 ldap_pvt_sasl_mutex_unlock
,
121 ldap_pvt_sasl_mutex_dispose
);
124 if ( sasl_client_init( NULL
) == SASL_OK
) {
125 sasl_initialized
= 1;
129 #if SASL_VERSION_MAJOR < 2
130 /* A no-op to make sure we link with Cyrus 1.5 */
131 sasl_client_auth( NULL
, NULL
, NULL
, 0, NULL
, NULL
);
137 * SASL encryption support for LBER Sockbufs
140 struct sb_sasl_data
{
141 sasl_conn_t
*sasl_context
;
142 unsigned *sasl_maxbuf
;
143 Sockbuf_Buf sec_buf_in
;
149 sb_sasl_setup( Sockbuf_IO_Desc
*sbiod
, void *arg
)
151 struct sb_sasl_data
*p
;
153 assert( sbiod
!= NULL
);
155 p
= LBER_MALLOC( sizeof( *p
) );
158 p
->sasl_context
= (sasl_conn_t
*)arg
;
159 ber_pvt_sb_buf_init( &p
->sec_buf_in
);
160 ber_pvt_sb_buf_init( &p
->buf_in
);
161 ber_pvt_sb_buf_init( &p
->buf_out
);
162 if ( ber_pvt_sb_grow_buffer( &p
->sec_buf_in
, SASL_MIN_BUFF_SIZE
) < 0 ) {
167 sasl_getprop( p
->sasl_context
, SASL_MAXOUTBUF
,
168 (SASL_CONST
void **)(char *) &p
->sasl_maxbuf
);
170 sbiod
->sbiod_pvt
= p
;
176 sb_sasl_remove( Sockbuf_IO_Desc
*sbiod
)
178 struct sb_sasl_data
*p
;
180 assert( sbiod
!= NULL
);
182 p
= (struct sb_sasl_data
*)sbiod
->sbiod_pvt
;
183 #if SASL_VERSION_MAJOR >= 2
185 * SASLv2 encode/decode buffers are managed by
186 * libsasl2. Ensure they are not freed by liblber.
188 p
->buf_in
.buf_base
= NULL
;
189 p
->buf_out
.buf_base
= NULL
;
191 ber_pvt_sb_buf_destroy( &p
->sec_buf_in
);
192 ber_pvt_sb_buf_destroy( &p
->buf_in
);
193 ber_pvt_sb_buf_destroy( &p
->buf_out
);
195 sbiod
->sbiod_pvt
= NULL
;
200 sb_sasl_pkt_length( const unsigned char *buf
, int debuglevel
)
204 assert( buf
!= NULL
);
211 if ( size
> SASL_MAX_BUFF_SIZE
) {
212 /* somebody is trying to mess me up. */
213 ber_log_printf( LDAP_DEBUG_ANY
, debuglevel
,
214 "sb_sasl_pkt_length: received illegal packet length "
215 "of %lu bytes\n", (unsigned long)size
);
216 size
= 16; /* this should lead to an error. */
219 return size
+ 4; /* include the size !!! */
222 /* Drop a processed packet from the input buffer */
224 sb_sasl_drop_packet ( Sockbuf_Buf
*sec_buf_in
, int debuglevel
)
228 len
= sec_buf_in
->buf_ptr
- sec_buf_in
->buf_end
;
230 AC_MEMCPY( sec_buf_in
->buf_base
, sec_buf_in
->buf_base
+
231 sec_buf_in
->buf_end
, len
);
234 sec_buf_in
->buf_end
= sb_sasl_pkt_length(
235 (unsigned char *) sec_buf_in
->buf_base
, debuglevel
);
238 sec_buf_in
->buf_end
= 0;
240 sec_buf_in
->buf_ptr
= len
;
244 sb_sasl_read( Sockbuf_IO_Desc
*sbiod
, void *buf
, ber_len_t len
)
246 struct sb_sasl_data
*p
;
247 ber_slen_t ret
, bufptr
;
249 assert( sbiod
!= NULL
);
250 assert( SOCKBUF_VALID( sbiod
->sbiod_sb
) );
252 p
= (struct sb_sasl_data
*)sbiod
->sbiod_pvt
;
254 /* Are there anything left in the buffer? */
255 ret
= ber_pvt_sb_copy_out( &p
->buf_in
, buf
, len
);
262 #if SASL_VERSION_MAJOR >= 2
263 ber_pvt_sb_buf_init( &p
->buf_in
);
265 ber_pvt_sb_buf_destroy( &p
->buf_in
);
268 /* Read the length of the packet */
269 while ( p
->sec_buf_in
.buf_ptr
< 4 ) {
270 ret
= LBER_SBIOD_READ_NEXT( sbiod
, p
->sec_buf_in
.buf_base
+
271 p
->sec_buf_in
.buf_ptr
,
272 4 - p
->sec_buf_in
.buf_ptr
);
274 if ( ( ret
< 0 ) && ( errno
== EINTR
) )
278 return bufptr
? bufptr
: ret
;
280 p
->sec_buf_in
.buf_ptr
+= ret
;
283 /* The new packet always starts at p->sec_buf_in.buf_base */
284 ret
= sb_sasl_pkt_length( (unsigned char *) p
->sec_buf_in
.buf_base
,
285 sbiod
->sbiod_sb
->sb_debug
);
287 /* Grow the packet buffer if neccessary */
288 if ( ( p
->sec_buf_in
.buf_size
< (ber_len_t
) ret
) &&
289 ber_pvt_sb_grow_buffer( &p
->sec_buf_in
, ret
) < 0 )
294 p
->sec_buf_in
.buf_end
= ret
;
296 /* Did we read the whole encrypted packet? */
297 while ( p
->sec_buf_in
.buf_ptr
< p
->sec_buf_in
.buf_end
) {
298 /* No, we have got only a part of it */
299 ret
= p
->sec_buf_in
.buf_end
- p
->sec_buf_in
.buf_ptr
;
301 ret
= LBER_SBIOD_READ_NEXT( sbiod
, p
->sec_buf_in
.buf_base
+
302 p
->sec_buf_in
.buf_ptr
, ret
);
304 if ( ( ret
< 0 ) && ( errno
== EINTR
) )
308 return bufptr
? bufptr
: ret
;
310 p
->sec_buf_in
.buf_ptr
+= ret
;
313 /* Decode the packet */
315 unsigned tmpsize
= p
->buf_in
.buf_end
;
316 ret
= sasl_decode( p
->sasl_context
, p
->sec_buf_in
.buf_base
,
317 p
->sec_buf_in
.buf_end
,
318 (SASL_CONST
char **)&p
->buf_in
.buf_base
,
319 (unsigned *)&tmpsize
);
320 p
->buf_in
.buf_end
= tmpsize
;
323 /* Drop the packet from the input buffer */
324 sb_sasl_drop_packet( &p
->sec_buf_in
, sbiod
->sbiod_sb
->sb_debug
);
326 if ( ret
!= SASL_OK
) {
327 ber_log_printf( LDAP_DEBUG_ANY
, sbiod
->sbiod_sb
->sb_debug
,
328 "sb_sasl_read: failed to decode packet: %s\n",
329 sasl_errstring( ret
, NULL
, NULL
) );
334 p
->buf_in
.buf_size
= p
->buf_in
.buf_end
;
336 bufptr
+= ber_pvt_sb_copy_out( &p
->buf_in
, (char*) buf
+ bufptr
, len
);
342 sb_sasl_write( Sockbuf_IO_Desc
*sbiod
, void *buf
, ber_len_t len
)
344 struct sb_sasl_data
*p
;
347 assert( sbiod
!= NULL
);
348 assert( SOCKBUF_VALID( sbiod
->sbiod_sb
) );
350 p
= (struct sb_sasl_data
*)sbiod
->sbiod_pvt
;
352 /* Are there anything left in the buffer? */
353 if ( p
->buf_out
.buf_ptr
!= p
->buf_out
.buf_end
) {
354 ret
= ber_pvt_sb_do_write( sbiod
, &p
->buf_out
);
355 if ( ret
< 0 ) return ret
;
357 /* Still have something left?? */
358 if ( p
->buf_out
.buf_ptr
!= p
->buf_out
.buf_end
) {
364 /* now encode the next packet. */
365 #if SASL_VERSION_MAJOR >= 2
366 ber_pvt_sb_buf_init( &p
->buf_out
);
368 ber_pvt_sb_buf_destroy( &p
->buf_out
);
370 if ( len
> *p
->sasl_maxbuf
- 100 ) {
371 len
= *p
->sasl_maxbuf
- 100; /* For safety margin */
375 unsigned tmpsize
= p
->buf_out
.buf_size
;
376 ret
= sasl_encode( p
->sasl_context
, buf
, len
,
377 (SASL_CONST
char **)&p
->buf_out
.buf_base
,
379 p
->buf_out
.buf_size
= tmpsize
;
382 if ( ret
!= SASL_OK
) {
383 ber_log_printf( LDAP_DEBUG_ANY
, sbiod
->sbiod_sb
->sb_debug
,
384 "sb_sasl_write: failed to encode packet: %s\n",
385 sasl_errstring( ret
, NULL
, NULL
) );
389 p
->buf_out
.buf_end
= p
->buf_out
.buf_size
;
391 ret
= ber_pvt_sb_do_write( sbiod
, &p
->buf_out
);
393 /* return number of bytes encoded, not written, to ensure
394 * no byte is encoded twice (even if only sent once).
400 sb_sasl_ctrl( Sockbuf_IO_Desc
*sbiod
, int opt
, void *arg
)
402 struct sb_sasl_data
*p
;
404 p
= (struct sb_sasl_data
*)sbiod
->sbiod_pvt
;
406 if ( opt
== LBER_SB_OPT_DATA_READY
) {
407 if ( p
->buf_in
.buf_ptr
!= p
->buf_in
.buf_end
) return 1;
410 return LBER_SBIOD_CTRL_NEXT( sbiod
, opt
, arg
);
413 Sockbuf_IO ldap_pvt_sockbuf_io_sasl
= {
414 sb_sasl_setup
, /* sbi_setup */
415 sb_sasl_remove
, /* sbi_remove */
416 sb_sasl_ctrl
, /* sbi_ctrl */
417 sb_sasl_read
, /* sbi_read */
418 sb_sasl_write
, /* sbi_write */
422 int ldap_pvt_sasl_install( Sockbuf
*sb
, void *ctx_arg
)
424 Debug( LDAP_DEBUG_TRACE
, "ldap_pvt_sasl_install\n",
427 /* don't install the stuff unless security has been negotiated */
429 if ( !ber_sockbuf_ctrl( sb
, LBER_SB_OPT_HAS_IO
,
430 &ldap_pvt_sockbuf_io_sasl
) )
433 ber_sockbuf_add_io( sb
, &ber_sockbuf_io_debug
,
434 LBER_SBIOD_LEVEL_APPLICATION
, (void *)"sasl_" );
436 ber_sockbuf_add_io( sb
, &ldap_pvt_sockbuf_io_sasl
,
437 LBER_SBIOD_LEVEL_APPLICATION
, ctx_arg
);
443 void ldap_pvt_sasl_remove( Sockbuf
*sb
)
445 ber_sockbuf_remove_io( sb
, &ldap_pvt_sockbuf_io_sasl
,
446 LBER_SBIOD_LEVEL_APPLICATION
);
448 ber_sockbuf_remove_io( sb
, &ber_sockbuf_io_debug
,
449 LBER_SBIOD_LEVEL_APPLICATION
);
454 sasl_err2ldap( int saslerr
)
458 /* map SASL errors to LDAP API errors returned by:
460 * SASL_OK, SASL_NOMECH, SASL_NOMEM
461 * sasl_client_start()
462 * SASL_OK, SASL_NOMECH, SASL_NOMEM, SASL_INTERACT
464 * SASL_OK, SASL_INTERACT, SASL_BADPROT, SASL_BADSERV
469 rc
= LDAP_MORE_RESULTS_TO_RETURN
;
472 rc
= LDAP_LOCAL_ERROR
;
481 rc
= LDAP_AUTH_UNKNOWN
;
484 rc
= LDAP_DECODING_ERROR
;
487 rc
= LDAP_AUTH_UNKNOWN
;
492 rc
= LDAP_AUTH_UNKNOWN
;
495 rc
= LDAP_PARAM_ERROR
;
498 rc
= LDAP_LOCAL_ERROR
;
502 rc
= LDAP_AUTH_UNKNOWN
;
505 rc
= LDAP_LOCAL_ERROR
;
509 assert( rc
== LDAP_SUCCESS
|| LDAP_API_ERROR( rc
) );
522 assert( lc
->lconn_sasl_authctx
== NULL
);
524 if ( host
== NULL
) {
525 ld
->ld_errno
= LDAP_LOCAL_ERROR
;
529 if ( ldap_int_sasl_init() ) {
530 ld
->ld_errno
= LDAP_LOCAL_ERROR
;
534 #if SASL_VERSION_MAJOR >= 2
535 rc
= sasl_client_new( "ldap", host
, NULL
, NULL
,
536 client_callbacks
, 0, &ctx
);
538 rc
= sasl_client_new( "ldap", host
, client_callbacks
,
539 SASL_SECURITY_LAYER
, &ctx
);
542 if ( rc
!= SASL_OK
) {
543 ld
->ld_errno
= sasl_err2ldap( rc
);
547 Debug( LDAP_DEBUG_TRACE
, "ldap_int_sasl_open: host=%s\n",
550 lc
->lconn_sasl_authctx
= ctx
;
555 int ldap_int_sasl_close( LDAP
*ld
, LDAPConn
*lc
)
557 sasl_conn_t
*ctx
= lc
->lconn_sasl_authctx
;
560 sasl_dispose( &ctx
);
561 if ( lc
->lconn_sasl_sockctx
&&
562 lc
->lconn_sasl_authctx
!= lc
->lconn_sasl_sockctx
) {
563 ctx
= lc
->lconn_sasl_sockctx
;
564 sasl_dispose( &ctx
);
566 lc
->lconn_sasl_sockctx
= NULL
;
567 lc
->lconn_sasl_authctx
= NULL
;
578 LDAPControl
**sctrls
,
579 LDAPControl
**cctrls
,
581 LDAP_SASL_INTERACT_PROC
*interact
,
585 const char *mech
= NULL
;
586 const char *pmech
= NULL
;
588 sasl_ssf_t
*ssf
= NULL
;
589 sasl_conn_t
*ctx
, *oldctx
= NULL
;
590 sasl_interact_t
*prompts
= NULL
;
596 Debug( LDAP_DEBUG_TRACE
, "ldap_int_sasl_bind: %s\n",
597 mechs
? mechs
: "<null>", 0, 0 );
599 /* do a quick !LDAPv3 check... ldap_sasl_bind will do the rest. */
600 if (ld
->ld_version
< LDAP_VERSION3
) {
601 ld
->ld_errno
= LDAP_NOT_SUPPORTED
;
606 #ifdef LDAP_R_COMPILE
607 ldap_pvt_thread_mutex_lock( &ld
->ld_req_mutex
);
609 ber_sockbuf_ctrl( ld
->ld_sb
, LBER_SB_OPT_GET_FD
, &sd
);
611 if ( sd
== AC_SOCKET_INVALID
) {
612 /* not connected yet */
614 rc
= ldap_open_defconn( ld
);
617 ber_sockbuf_ctrl( ld
->ld_defconn
->lconn_sb
,
618 LBER_SB_OPT_GET_FD
, &sd
);
620 if( sd
== AC_SOCKET_INVALID
) {
621 ld
->ld_errno
= LDAP_LOCAL_ERROR
;
626 #ifdef LDAP_R_COMPILE
627 ldap_pvt_thread_mutex_unlock( &ld
->ld_req_mutex
);
629 if( rc
!= 0 ) return ld
->ld_errno
;
631 oldctx
= ld
->ld_defconn
->lconn_sasl_authctx
;
633 /* If we already have an authentication context, clear it out */
635 if ( oldctx
!= ld
->ld_defconn
->lconn_sasl_sockctx
) {
636 sasl_dispose( &oldctx
);
638 ld
->ld_defconn
->lconn_sasl_authctx
= NULL
;
642 char *saslhost
= ldap_host_connected_to( ld
->ld_defconn
->lconn_sb
,
644 rc
= ldap_int_sasl_open( ld
, ld
->ld_defconn
, saslhost
);
645 LDAP_FREE( saslhost
);
648 if ( rc
!= LDAP_SUCCESS
) return rc
;
650 ctx
= ld
->ld_defconn
->lconn_sasl_authctx
;
653 ssl
= ldap_pvt_tls_sb_ctx( ld
->ld_defconn
->lconn_sb
);
655 struct berval authid
= BER_BVNULL
;
658 fac
= ldap_pvt_tls_get_strength( ssl
);
659 /* failure is OK, we just can't use SASL EXTERNAL */
660 (void) ldap_pvt_tls_get_my_dn( ssl
, &authid
, NULL
, 0 );
662 (void) ldap_int_sasl_external( ld
, ld
->ld_defconn
, authid
.bv_val
, fac
);
663 LDAP_FREE( authid
.bv_val
);
667 /* Check for local */
668 if ( ldap_pvt_url_scheme2proto(
669 ld
->ld_defconn
->lconn_server
->lud_scheme
) == LDAP_PROTO_IPC
)
671 char authid
[sizeof("gidNumber=4294967295+uidNumber=4294967295,"
672 "cn=peercred,cn=external,cn=auth")];
673 sprintf( authid
, "gidNumber=%u+uidNumber=%u,"
674 "cn=peercred,cn=external,cn=auth",
675 getegid(), geteuid() );
676 (void) ldap_int_sasl_external( ld
, ld
->ld_defconn
, authid
,
677 LDAP_PVT_SASL_LOCAL_SSF
);
681 /* (re)set security properties */
682 sasl_setprop( ctx
, SASL_SEC_PROPS
,
683 &ld
->ld_options
.ldo_sasl_secprops
);
689 saslrc
= sasl_client_start( ctx
,
691 #if SASL_VERSION_MAJOR < 2
695 (SASL_CONST
char **)&ccred
.bv_val
,
699 if( pmech
== NULL
&& mech
!= NULL
) {
702 if( flags
!= LDAP_SASL_QUIET
) {
704 "SASL/%s authentication started\n",
709 if( saslrc
== SASL_INTERACT
) {
711 if( !interact
) break;
712 res
= (interact
)( ld
, flags
, defaults
, prompts
);
714 if( res
!= LDAP_SUCCESS
) break;
716 } while ( saslrc
== SASL_INTERACT
);
718 ccred
.bv_len
= credlen
;
720 if ( (saslrc
!= SASL_OK
) && (saslrc
!= SASL_CONTINUE
) ) {
721 rc
= ld
->ld_errno
= sasl_err2ldap( saslrc
);
722 #if SASL_VERSION_MAJOR >= 2
723 if ( ld
->ld_error
) {
724 LDAP_FREE( ld
->ld_error
);
726 ld
->ld_error
= LDAP_STRDUP( sasl_errdetail( ctx
) );
732 struct berval
*scred
;
737 rc
= ldap_sasl_bind_s( ld
, dn
, mech
, &ccred
, sctrls
, cctrls
,
740 if ( ccred
.bv_val
!= NULL
) {
741 #if SASL_VERSION_MAJOR < 2
742 LDAP_FREE( ccred
.bv_val
);
747 if ( rc
!= LDAP_SUCCESS
&& rc
!= LDAP_SASL_BIND_IN_PROGRESS
) {
749 /* and server provided us with data? */
750 Debug( LDAP_DEBUG_TRACE
,
751 "ldap_int_sasl_bind: rc=%d sasl=%d len=%ld\n",
752 rc
, saslrc
, scred
? scred
->bv_len
: -1 );
760 if( rc
== LDAP_SUCCESS
&& saslrc
== SASL_OK
) {
761 /* we're done, no need to step */
763 /* but we got additional data? */
764 #define KLUDGE_FOR_MSAD
765 #ifdef KLUDGE_FOR_MSAD
767 * MSAD provides empty additional data in violation of LDAP
768 * technical specifications. As no existing SASL mechanism
769 * allows empty data with an outcome message, just ignore it
770 * for now. Hopefully MS will fix their bug before someone
771 * defines a mechanism with possibly empty additional data.
773 if( scred
->bv_len
== 0 ) {
774 Debug( LDAP_DEBUG_ANY
,
775 "ldap_int_sasl_bind: ignoring "
776 " bogus empty data provided with SASL outcome message.\n",
777 rc
, saslrc
, scred
->bv_len
);
782 Debug( LDAP_DEBUG_TRACE
,
783 "ldap_int_sasl_bind: rc=%d sasl=%d len=%ld\n",
784 rc
, saslrc
, scred
->bv_len
);
785 rc
= ld
->ld_errno
= LDAP_LOCAL_ERROR
;
796 Debug( LDAP_DEBUG_TRACE
,
797 "ldap_int_sasl_bind: no data in step!\n",
801 saslrc
= sasl_client_step( ctx
,
802 (scred
== NULL
) ? NULL
: scred
->bv_val
,
803 (scred
== NULL
) ? 0 : scred
->bv_len
,
805 (SASL_CONST
char **)&ccred
.bv_val
,
808 Debug( LDAP_DEBUG_TRACE
, "sasl_client_step: %d\n",
811 if( saslrc
== SASL_INTERACT
) {
813 if( !interact
) break;
814 res
= (interact
)( ld
, flags
, defaults
, prompts
);
815 if( res
!= LDAP_SUCCESS
) break;
817 } while ( saslrc
== SASL_INTERACT
);
819 ccred
.bv_len
= credlen
;
822 if ( (saslrc
!= SASL_OK
) && (saslrc
!= SASL_CONTINUE
) ) {
823 ld
->ld_errno
= sasl_err2ldap( saslrc
);
824 #if SASL_VERSION_MAJOR >= 2
825 if ( ld
->ld_error
) {
826 LDAP_FREE( ld
->ld_error
);
828 ld
->ld_error
= LDAP_STRDUP( sasl_errdetail( ctx
) );
833 } while ( rc
== LDAP_SASL_BIND_IN_PROGRESS
);
835 if ( rc
!= LDAP_SUCCESS
) goto done
;
837 if ( saslrc
!= SASL_OK
) {
838 #if SASL_VERSION_MAJOR >= 2
839 if ( ld
->ld_error
) {
840 LDAP_FREE( ld
->ld_error
);
842 ld
->ld_error
= LDAP_STRDUP( sasl_errdetail( ctx
) );
844 rc
= ld
->ld_errno
= sasl_err2ldap( saslrc
);
848 if( flags
!= LDAP_SASL_QUIET
) {
849 saslrc
= sasl_getprop( ctx
, SASL_USERNAME
,
850 (SASL_CONST
void **)(char *) &data
);
851 if( saslrc
== SASL_OK
&& data
&& *data
) {
852 fprintf( stderr
, "SASL username: %s\n", data
);
855 #if SASL_VERSION_MAJOR < 2
856 saslrc
= sasl_getprop( ctx
, SASL_REALM
,
857 (SASL_CONST
void **) &data
);
858 if( saslrc
== SASL_OK
&& data
&& *data
) {
859 fprintf( stderr
, "SASL realm: %s\n", data
);
864 saslrc
= sasl_getprop( ctx
, SASL_SSF
, (SASL_CONST
void **)(char *) &ssf
);
865 if( saslrc
== SASL_OK
) {
866 if( flags
!= LDAP_SASL_QUIET
) {
867 fprintf( stderr
, "SASL SSF: %lu\n",
868 (unsigned long) *ssf
);
872 if ( ld
->ld_defconn
->lconn_sasl_sockctx
) {
873 oldctx
= ld
->ld_defconn
->lconn_sasl_sockctx
;
874 sasl_dispose( &oldctx
);
875 ldap_pvt_sasl_remove( ld
->ld_defconn
->lconn_sb
);
877 ldap_pvt_sasl_install( ld
->ld_defconn
->lconn_sb
, ctx
);
878 ld
->ld_defconn
->lconn_sasl_sockctx
= ctx
;
880 if( flags
!= LDAP_SASL_QUIET
) {
881 fprintf( stderr
, "SASL data security layer installed.\n" );
885 ld
->ld_defconn
->lconn_sasl_authctx
= ctx
;
892 ldap_int_sasl_external(
900 #if SASL_VERSION_MAJOR < 2
901 sasl_external_properties_t extprops
;
903 sasl_ssf_t sasl_ssf
= ssf
;
906 ctx
= conn
->lconn_sasl_authctx
;
909 return LDAP_LOCAL_ERROR
;
912 #if SASL_VERSION_MAJOR >= 2
913 sc
= sasl_setprop( ctx
, SASL_SSF_EXTERNAL
, &sasl_ssf
);
915 sc
= sasl_setprop( ctx
, SASL_AUTH_EXTERNAL
, authid
);
917 memset( &extprops
, '\0', sizeof(extprops
) );
919 extprops
.auth_id
= (char *) authid
;
921 sc
= sasl_setprop( ctx
, SASL_SSF_EXTERNAL
,
922 (void *) &extprops
);
925 if ( sc
!= SASL_OK
) {
926 return LDAP_LOCAL_ERROR
;
943 { BER_BVC("none"), 0, 0, 0 },
944 { BER_BVC("nodict"), SASL_SEC_NODICTIONARY
, 0, 0 },
945 { BER_BVC("noplain"), SASL_SEC_NOPLAINTEXT
, 0, 0 },
946 { BER_BVC("noactive"), SASL_SEC_NOACTIVE
, 0, 0 },
947 { BER_BVC("passcred"), SASL_SEC_PASS_CREDENTIALS
, 0, 0 },
948 { BER_BVC("forwardsec"), SASL_SEC_FORWARD_SECRECY
, 0, 0 },
949 { BER_BVC("noanonymous"), SASL_SEC_NOANONYMOUS
, 0, 0 },
950 { BER_BVC("minssf="), 0, GOT_MINSSF
, 0 },
951 { BER_BVC("maxssf="), 0, GOT_MAXSSF
, INT_MAX
},
952 { BER_BVC("maxbufsize="), 0, GOT_MAXBUF
, 65536 },
953 { BER_BVNULL
, 0, 0, 0 }
956 void ldap_pvt_sasl_secprops_unparse(
957 sasl_security_properties_t
*secprops
,
964 if ( secprops
== NULL
|| out
== NULL
) {
969 for ( i
=0; !BER_BVISNULL( &sprops
[i
].key
); i
++ ) {
970 if ( sprops
[i
].ival
) {
973 switch( sprops
[i
].ival
) {
974 case GOT_MINSSF
: v
= secprops
->min_ssf
; break;
975 case GOT_MAXSSF
: v
= secprops
->max_ssf
; break;
976 case GOT_MAXBUF
: v
= secprops
->maxbufsize
; break;
978 /* It is the default, ignore it */
979 if ( v
== sprops
[i
].idef
) continue;
981 l
+= sprops
[i
].key
.bv_len
+ 24;
982 } else if ( sprops
[i
].sflag
) {
983 if ( sprops
[i
].sflag
& secprops
->security_flags
) {
984 l
+= sprops
[i
].key
.bv_len
;
986 } else if ( secprops
->security_flags
== 0 ) {
987 l
+= sprops
[i
].key
.bv_len
;
994 out
->bv_val
= LDAP_MALLOC( l
);
995 if ( out
->bv_val
== NULL
) {
1002 for ( i
=0; !BER_BVISNULL( &sprops
[i
].key
); i
++ ) {
1003 if ( sprops
[i
].ival
) {
1006 switch( sprops
[i
].ival
) {
1007 case GOT_MINSSF
: v
= secprops
->min_ssf
; break;
1008 case GOT_MAXSSF
: v
= secprops
->max_ssf
; break;
1009 case GOT_MAXBUF
: v
= secprops
->maxbufsize
; break;
1011 /* It is the default, ignore it */
1012 if ( v
== sprops
[i
].idef
) continue;
1014 if ( comma
) *ptr
++ = ',';
1015 ptr
+= sprintf(ptr
, "%s%d", sprops
[i
].key
.bv_val
, v
);
1017 } else if ( sprops
[i
].sflag
) {
1018 if ( sprops
[i
].sflag
& secprops
->security_flags
) {
1019 if ( comma
) *ptr
++ = ',';
1020 ptr
+= sprintf(ptr
, "%s", sprops
[i
].key
.bv_val
);
1023 } else if ( secprops
->security_flags
== 0 ) {
1024 if ( comma
) *ptr
++ = ',';
1025 ptr
+= sprintf(ptr
, "%s", sprops
[i
].key
.bv_val
);
1029 out
->bv_len
= ptr
- out
->bv_val
;
1032 int ldap_pvt_sasl_secprops(
1034 sasl_security_properties_t
*secprops
)
1038 unsigned sflags
= 0;
1040 sasl_ssf_t max_ssf
= 0;
1041 int got_max_ssf
= 0;
1042 sasl_ssf_t min_ssf
= 0;
1043 int got_min_ssf
= 0;
1044 unsigned maxbufsize
= 0;
1045 int got_maxbufsize
= 0;
1047 if( secprops
== NULL
) {
1048 return LDAP_PARAM_ERROR
;
1050 props
= ldap_str2charray( in
, "," );
1051 if( props
== NULL
) {
1052 return LDAP_PARAM_ERROR
;
1055 for( i
=0; props
[i
]; i
++ ) {
1056 l
= strlen( props
[i
] );
1057 for ( j
=0; !BER_BVISNULL( &sprops
[j
].key
); j
++ ) {
1058 if ( l
< sprops
[j
].key
.bv_len
) continue;
1059 if ( strncasecmp( props
[i
], sprops
[j
].key
.bv_val
,
1060 sprops
[j
].key
.bv_len
)) continue;
1061 if ( sprops
[j
].ival
) {
1064 if ( !isdigit( (unsigned char)props
[i
][sprops
[j
].key
.bv_len
] ))
1066 v
= strtoul( &props
[i
][sprops
[j
].key
.bv_len
], &next
, 10 );
1067 if ( next
== &props
[i
][sprops
[j
].key
.bv_len
] || next
[0] != '\0' ) continue;
1068 switch( sprops
[j
].ival
) {
1070 min_ssf
= v
; got_min_ssf
++; break;
1072 max_ssf
= v
; got_max_ssf
++; break;
1074 maxbufsize
= v
; got_maxbufsize
++; break;
1077 if ( props
[i
][sprops
[j
].key
.bv_len
] ) continue;
1078 if ( sprops
[j
].sflag
)
1079 sflags
|= sprops
[j
].sflag
;
1086 if ( BER_BVISNULL( &sprops
[j
].key
)) {
1087 ldap_charray_free( props
);
1088 return LDAP_NOT_SUPPORTED
;
1093 secprops
->security_flags
= sflags
;
1096 secprops
->min_ssf
= min_ssf
;
1099 secprops
->max_ssf
= max_ssf
;
1101 if(got_maxbufsize
) {
1102 secprops
->maxbufsize
= maxbufsize
;
1105 ldap_charray_free( props
);
1106 return LDAP_SUCCESS
;
1110 ldap_int_sasl_config( struct ldapoptions
*lo
, int option
, const char *arg
)
1115 case LDAP_OPT_X_SASL_SECPROPS
:
1116 rc
= ldap_pvt_sasl_secprops( arg
, &lo
->ldo_sasl_secprops
);
1117 if( rc
== LDAP_SUCCESS
) return 0;
1124 ldap_int_sasl_get_option( LDAP
*ld
, int option
, void *arg
)
1130 case LDAP_OPT_X_SASL_MECH
: {
1131 *(char **)arg
= ld
->ld_options
.ldo_def_sasl_mech
1132 ? LDAP_STRDUP( ld
->ld_options
.ldo_def_sasl_mech
) : NULL
;
1134 case LDAP_OPT_X_SASL_REALM
: {
1135 *(char **)arg
= ld
->ld_options
.ldo_def_sasl_realm
1136 ? LDAP_STRDUP( ld
->ld_options
.ldo_def_sasl_realm
) : NULL
;
1138 case LDAP_OPT_X_SASL_AUTHCID
: {
1139 *(char **)arg
= ld
->ld_options
.ldo_def_sasl_authcid
1140 ? LDAP_STRDUP( ld
->ld_options
.ldo_def_sasl_authcid
) : NULL
;
1142 case LDAP_OPT_X_SASL_AUTHZID
: {
1143 *(char **)arg
= ld
->ld_options
.ldo_def_sasl_authzid
1144 ? LDAP_STRDUP( ld
->ld_options
.ldo_def_sasl_authzid
) : NULL
;
1147 case LDAP_OPT_X_SASL_SSF
: {
1152 if( ld
->ld_defconn
== NULL
) {
1156 ctx
= ld
->ld_defconn
->lconn_sasl_sockctx
;
1158 if ( ctx
== NULL
) {
1162 sc
= sasl_getprop( ctx
, SASL_SSF
,
1163 (SASL_CONST
void **)(char *) &ssf
);
1165 if ( sc
!= SASL_OK
) {
1169 *(ber_len_t
*)arg
= *ssf
;
1172 case LDAP_OPT_X_SASL_SSF_EXTERNAL
:
1173 /* this option is write only */
1176 case LDAP_OPT_X_SASL_SSF_MIN
:
1177 *(ber_len_t
*)arg
= ld
->ld_options
.ldo_sasl_secprops
.min_ssf
;
1179 case LDAP_OPT_X_SASL_SSF_MAX
:
1180 *(ber_len_t
*)arg
= ld
->ld_options
.ldo_sasl_secprops
.max_ssf
;
1182 case LDAP_OPT_X_SASL_MAXBUFSIZE
:
1183 *(ber_len_t
*)arg
= ld
->ld_options
.ldo_sasl_secprops
.maxbufsize
;
1186 case LDAP_OPT_X_SASL_SECPROPS
:
1187 /* this option is write only */
1197 ldap_int_sasl_set_option( LDAP
*ld
, int option
, void *arg
)
1199 if ( ld
== NULL
|| arg
== NULL
)
1203 case LDAP_OPT_X_SASL_SSF
:
1204 /* This option is read-only */
1207 case LDAP_OPT_X_SASL_SSF_EXTERNAL
: {
1209 #if SASL_VERSION_MAJOR < 2
1210 sasl_external_properties_t extprops
;
1212 sasl_ssf_t sasl_ssf
;
1216 if( ld
->ld_defconn
== NULL
) {
1220 ctx
= ld
->ld_defconn
->lconn_sasl_authctx
;
1222 if ( ctx
== NULL
) {
1226 #if SASL_VERSION_MAJOR >= 2
1227 sasl_ssf
= * (ber_len_t
*)arg
;
1228 sc
= sasl_setprop( ctx
, SASL_SSF_EXTERNAL
, &sasl_ssf
);
1230 memset(&extprops
, 0L, sizeof(extprops
));
1232 extprops
.ssf
= * (ber_len_t
*) arg
;
1234 sc
= sasl_setprop( ctx
, SASL_SSF_EXTERNAL
,
1235 (void *) &extprops
);
1238 if ( sc
!= SASL_OK
) {
1243 case LDAP_OPT_X_SASL_SSF_MIN
:
1244 ld
->ld_options
.ldo_sasl_secprops
.min_ssf
= *(ber_len_t
*)arg
;
1246 case LDAP_OPT_X_SASL_SSF_MAX
:
1247 ld
->ld_options
.ldo_sasl_secprops
.max_ssf
= *(ber_len_t
*)arg
;
1249 case LDAP_OPT_X_SASL_MAXBUFSIZE
:
1250 ld
->ld_options
.ldo_sasl_secprops
.maxbufsize
= *(ber_len_t
*)arg
;
1253 case LDAP_OPT_X_SASL_SECPROPS
: {
1255 sc
= ldap_pvt_sasl_secprops( (char *) arg
,
1256 &ld
->ld_options
.ldo_sasl_secprops
);
1258 return sc
== LDAP_SUCCESS
? 0 : -1;
1267 #ifdef LDAP_R_COMPILE
1268 #define LDAP_DEBUG_R_SASL
1269 void *ldap_pvt_sasl_mutex_new(void)
1271 ldap_pvt_thread_mutex_t
*mutex
;
1273 mutex
= (ldap_pvt_thread_mutex_t
*) LDAP_CALLOC( 1,
1274 sizeof(ldap_pvt_thread_mutex_t
) );
1276 if ( ldap_pvt_thread_mutex_init( mutex
) == 0 ) {
1279 #ifndef LDAP_DEBUG_R_SASL
1281 #endif /* !LDAP_DEBUG_R_SASL */
1285 int ldap_pvt_sasl_mutex_lock(void *mutex
)
1287 #ifdef LDAP_DEBUG_R_SASL
1288 if ( mutex
== NULL
) {
1291 #else /* !LDAP_DEBUG_R_SASL */
1292 assert( mutex
!= NULL
);
1293 #endif /* !LDAP_DEBUG_R_SASL */
1294 return ldap_pvt_thread_mutex_lock( (ldap_pvt_thread_mutex_t
*)mutex
)
1295 ? SASL_FAIL
: SASL_OK
;
1298 int ldap_pvt_sasl_mutex_unlock(void *mutex
)
1300 #ifdef LDAP_DEBUG_R_SASL
1301 if ( mutex
== NULL
) {
1304 #else /* !LDAP_DEBUG_R_SASL */
1305 assert( mutex
!= NULL
);
1306 #endif /* !LDAP_DEBUG_R_SASL */
1307 return ldap_pvt_thread_mutex_unlock( (ldap_pvt_thread_mutex_t
*)mutex
)
1308 ? SASL_FAIL
: SASL_OK
;
1311 void ldap_pvt_sasl_mutex_dispose(void *mutex
)
1313 #ifdef LDAP_DEBUG_R_SASL
1314 if ( mutex
== NULL
) {
1317 #else /* !LDAP_DEBUG_R_SASL */
1318 assert( mutex
!= NULL
);
1319 #endif /* !LDAP_DEBUG_R_SASL */
1320 (void) ldap_pvt_thread_mutex_destroy( (ldap_pvt_thread_mutex_t
*)mutex
);
1326 int ldap_int_sasl_init( void )
1327 { return LDAP_SUCCESS
; }
1329 int ldap_int_sasl_close( LDAP
*ld
, LDAPConn
*lc
)
1330 { return LDAP_SUCCESS
; }
1337 LDAPControl
**sctrls
,
1338 LDAPControl
**cctrls
,
1340 LDAP_SASL_INTERACT_PROC
*interact
,
1342 { return LDAP_NOT_SUPPORTED
; }
1345 ldap_int_sasl_external(
1348 const char * authid
,
1350 { return LDAP_SUCCESS
; }
1352 #endif /* HAVE_CYRUS_SASL */