2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1998-2022 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>.
21 #ifdef HAVE_CYRUS_SASL
25 #include <ac/socket.h>
26 #include <ac/stdlib.h>
27 #include <ac/string.h>
30 #include <ac/unistd.h>
37 #define INT_MAX 2147483647 /* 32 bit signed max */
40 #if !defined(HOST_NAME_MAX) && defined(_POSIX_HOST_NAME_MAX)
41 #define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
44 #ifdef HAVE_SASL_SASL_H
45 #include <sasl/sasl.h>
50 #if SASL_VERSION_MAJOR >= 2
51 #define SASL_CONST const
57 * Various Cyrus SASL related stuff.
60 static const sasl_callback_t client_callbacks
[] = {
61 #ifdef SASL_CB_GETREALM
62 { SASL_CB_GETREALM
, NULL
, NULL
},
64 { SASL_CB_USER
, NULL
, NULL
},
65 { SASL_CB_AUTHNAME
, NULL
, NULL
},
66 { SASL_CB_PASS
, NULL
, NULL
},
67 { SASL_CB_ECHOPROMPT
, NULL
, NULL
},
68 { SASL_CB_NOECHOPROMPT
, NULL
, NULL
},
69 { SASL_CB_LIST_END
, NULL
, NULL
}
73 * ldap_int_initialize is responsible for calling this only once.
75 int ldap_int_sasl_init( void )
77 #ifdef HAVE_SASL_VERSION
78 /* stringify the version number, sasl.h doesn't do it for us */
79 #define VSTR0(maj, min, pat) #maj "." #min "." #pat
80 #define VSTR(maj, min, pat) VSTR0(maj, min, pat)
81 #define SASL_VERSION_STRING VSTR(SASL_VERSION_MAJOR, SASL_VERSION_MINOR, \
84 sasl_version( NULL
, &rc
);
85 if ( ((rc
>> 16) != ((SASL_VERSION_MAJOR
<< 8)|SASL_VERSION_MINOR
)) ||
86 (rc
& 0xffff) < SASL_VERSION_STEP
) {
87 char version
[sizeof("xxx.xxx.xxxxx")];
88 sprintf( version
, "%u.%d.%d", (unsigned)rc
>> 24, (rc
>> 16) & 0xff,
91 Debug1( LDAP_DEBUG_ANY
,
92 "ldap_int_sasl_init: SASL library version mismatch:"
93 " expected " SASL_VERSION_STRING
","
94 " got %s\n", version
);
100 /* SASL 2 takes care of its own memory completely internally */
101 #if SASL_VERSION_MAJOR < 2 && !defined(CSRIMALLOC)
107 #endif /* CSRIMALLOC */
109 #ifdef LDAP_R_COMPILE
111 ldap_pvt_sasl_mutex_new
,
112 ldap_pvt_sasl_mutex_lock
,
113 ldap_pvt_sasl_mutex_unlock
,
114 ldap_pvt_sasl_mutex_dispose
);
117 if ( sasl_client_init( NULL
) == SASL_OK
) {
121 #if SASL_VERSION_MAJOR < 2
122 /* A no-op to make sure we link with Cyrus 1.5 */
123 sasl_client_auth( NULL
, NULL
, NULL
, 0, NULL
, NULL
);
130 struct sb_sasl_generic_data
*p
,
135 sasl_conn_t
*sasl_context
= (sasl_conn_t
*)p
->ops_private
;
138 sasl_getprop( sasl_context
, SASL_MAXOUTBUF
,
139 (SASL_CONST
void **)(char *) &maxbuf
);
141 *min_send
= SASL_MIN_BUFF_SIZE
;
143 *max_recv
= SASL_MAX_BUFF_SIZE
;
147 sb_sasl_cyrus_encode(
148 struct sb_sasl_generic_data
*p
,
153 sasl_conn_t
*sasl_context
= (sasl_conn_t
*)p
->ops_private
;
155 unsigned tmpsize
= dst
->buf_size
;
157 ret
= sasl_encode( sasl_context
, (char *)buf
, len
,
158 (SASL_CONST
char **)&dst
->buf_base
,
161 dst
->buf_size
= tmpsize
;
162 dst
->buf_end
= dst
->buf_size
;
164 if ( ret
!= SASL_OK
) {
165 ber_log_printf( LDAP_DEBUG_ANY
, p
->sbiod
->sbiod_sb
->sb_debug
,
166 "sb_sasl_cyrus_encode: failed to encode packet: %s\n",
167 sasl_errstring( ret
, NULL
, NULL
) );
175 sb_sasl_cyrus_decode(
176 struct sb_sasl_generic_data
*p
,
177 const Sockbuf_Buf
*src
,
180 sasl_conn_t
*sasl_context
= (sasl_conn_t
*)p
->ops_private
;
182 unsigned tmpsize
= dst
->buf_size
;
184 ret
= sasl_decode( sasl_context
,
185 src
->buf_base
, src
->buf_end
,
186 (SASL_CONST
char **)&dst
->buf_base
,
187 (unsigned *)&tmpsize
);
190 dst
->buf_size
= tmpsize
;
191 dst
->buf_end
= dst
->buf_size
;
193 if ( ret
!= SASL_OK
) {
194 ber_log_printf( LDAP_DEBUG_ANY
, p
->sbiod
->sbiod_sb
->sb_debug
,
195 "sb_sasl_cyrus_decode: failed to decode packet: %s\n",
196 sasl_errstring( ret
, NULL
, NULL
) );
204 sb_sasl_cyrus_reset_buf(
205 struct sb_sasl_generic_data
*p
,
208 #if SASL_VERSION_MAJOR >= 2
209 ber_pvt_sb_buf_init( buf
);
211 ber_pvt_sb_buf_destroy( buf
);
217 struct sb_sasl_generic_data
*p
)
219 #if SASL_VERSION_MAJOR >= 2
221 * SASLv2 encode/decode buffers are managed by
222 * libsasl2. Ensure they are not freed by liblber.
224 p
->buf_in
.buf_base
= NULL
;
225 p
->buf_out
.buf_base
= NULL
;
229 static const struct sb_sasl_generic_ops sb_sasl_cyrus_ops
= {
231 sb_sasl_cyrus_encode
,
232 sb_sasl_cyrus_decode
,
233 sb_sasl_cyrus_reset_buf
,
237 int ldap_pvt_sasl_install( Sockbuf
*sb
, void *ctx_arg
)
239 struct sb_sasl_generic_install install_arg
;
241 install_arg
.ops
= &sb_sasl_cyrus_ops
;
242 install_arg
.ops_private
= ctx_arg
;
244 return ldap_pvt_sasl_generic_install( sb
, &install_arg
);
247 void ldap_pvt_sasl_remove( Sockbuf
*sb
)
249 ldap_pvt_sasl_generic_remove( sb
);
253 sasl_err2ldap( int saslerr
)
257 /* map SASL errors to LDAP API errors returned by:
259 * SASL_OK, SASL_NOMECH, SASL_NOMEM
260 * sasl_client_start()
261 * SASL_OK, SASL_NOMECH, SASL_NOMEM, SASL_INTERACT
263 * SASL_OK, SASL_INTERACT, SASL_BADPROT, SASL_BADSERV
268 rc
= LDAP_MORE_RESULTS_TO_RETURN
;
271 rc
= LDAP_LOCAL_ERROR
;
280 rc
= LDAP_AUTH_UNKNOWN
;
283 rc
= LDAP_DECODING_ERROR
;
286 rc
= LDAP_AUTH_UNKNOWN
;
291 rc
= LDAP_AUTH_UNKNOWN
;
294 rc
= LDAP_PARAM_ERROR
;
297 rc
= LDAP_LOCAL_ERROR
;
301 rc
= LDAP_AUTH_UNKNOWN
;
304 rc
= LDAP_LOCAL_ERROR
;
308 assert( rc
== LDAP_SUCCESS
|| LDAP_API_ERROR( rc
) );
321 assert( lc
->lconn_sasl_authctx
== NULL
);
323 if ( host
== NULL
) {
324 ld
->ld_errno
= LDAP_LOCAL_ERROR
;
328 #if SASL_VERSION_MAJOR >= 2
329 rc
= sasl_client_new( "ldap", host
, NULL
, NULL
,
330 client_callbacks
, 0, &ctx
);
332 rc
= sasl_client_new( "ldap", host
, client_callbacks
,
333 SASL_SECURITY_LAYER
, &ctx
);
336 if ( rc
!= SASL_OK
) {
337 ld
->ld_errno
= sasl_err2ldap( rc
);
341 Debug1( LDAP_DEBUG_TRACE
, "ldap_int_sasl_open: host=%s\n",
344 lc
->lconn_sasl_authctx
= ctx
;
349 int ldap_int_sasl_close( LDAP
*ld
, LDAPConn
*lc
)
351 sasl_conn_t
*ctx
= lc
->lconn_sasl_authctx
;
354 sasl_dispose( &ctx
);
355 if ( lc
->lconn_sasl_sockctx
&&
356 lc
->lconn_sasl_authctx
!= lc
->lconn_sasl_sockctx
) {
357 ctx
= lc
->lconn_sasl_sockctx
;
358 sasl_dispose( &ctx
);
360 lc
->lconn_sasl_sockctx
= NULL
;
361 lc
->lconn_sasl_authctx
= NULL
;
363 if( lc
->lconn_sasl_cbind
) {
364 ldap_memfree( lc
->lconn_sasl_cbind
);
365 lc
->lconn_sasl_cbind
= NULL
;
371 int ldap_pvt_sasl_cbinding_parse( const char *arg
)
375 if ( strcasecmp(arg
, "none") == 0 )
376 i
= LDAP_OPT_X_SASL_CBINDING_NONE
;
377 else if ( strcasecmp(arg
, "tls-unique") == 0 )
378 i
= LDAP_OPT_X_SASL_CBINDING_TLS_UNIQUE
;
379 else if ( strcasecmp(arg
, "tls-endpoint") == 0 )
380 i
= LDAP_OPT_X_SASL_CBINDING_TLS_ENDPOINT
;
385 void *ldap_pvt_sasl_cbinding( void *ssl
, int type
, int is_server
)
387 #if defined(SASL_CHANNEL_BINDING) && defined(HAVE_TLS)
388 char unique_prefix
[] = "tls-unique:";
389 char endpoint_prefix
[] = "tls-server-end-point:";
391 struct berval cbv
= { 64, cbinding
};
392 unsigned char *cb_data
; /* used since cb->data is const* */
393 sasl_channel_binding_t
*cb
;
398 case LDAP_OPT_X_SASL_CBINDING_NONE
:
400 case LDAP_OPT_X_SASL_CBINDING_TLS_UNIQUE
:
401 if ( !ldap_pvt_tls_get_unique( ssl
, &cbv
, is_server
))
403 prefix
= unique_prefix
;
404 plen
= sizeof(unique_prefix
) -1;
406 case LDAP_OPT_X_SASL_CBINDING_TLS_ENDPOINT
:
407 if ( !ldap_pvt_tls_get_endpoint( ssl
, &cbv
, is_server
))
409 prefix
= endpoint_prefix
;
410 plen
= sizeof(endpoint_prefix
) -1;
416 cb
= ldap_memalloc( sizeof(*cb
) + plen
+ cbv
.bv_len
);
417 cb
->len
= plen
+ cbv
.bv_len
;
418 cb
->data
= cb_data
= (unsigned char *)(cb
+1);
419 memcpy( cb_data
, prefix
, plen
);
420 memcpy( cb_data
+ plen
, cbv
.bv_val
, cbv
.bv_len
);
435 LDAPControl
**sctrls
,
436 LDAPControl
**cctrls
,
438 LDAP_SASL_INTERACT_PROC
*interact
,
447 sasl_interact_t
*prompts
= NULL
;
448 struct berval ccred
= BER_BVNULL
;
452 char my_hostname
[HOST_NAME_MAX
+ 1];
454 int free_saslhost
= 0;
456 Debug1( LDAP_DEBUG_TRACE
, "ldap_int_sasl_bind: %s\n",
457 mechs
? mechs
: "<null>" );
459 /* do a quick !LDAPv3 check... ldap_sasl_bind will do the rest. */
460 if (ld
->ld_version
< LDAP_VERSION3
) {
461 ld
->ld_errno
= LDAP_NOT_SUPPORTED
;
465 /* Starting a Bind */
467 const char *pmech
= NULL
;
473 LDAP_MUTEX_LOCK( &ld
->ld_conn_mutex
);
474 ber_sockbuf_ctrl( ld
->ld_sb
, LBER_SB_OPT_GET_FD
, &sd
);
476 if ( sd
== AC_SOCKET_INVALID
|| !ld
->ld_defconn
) {
477 /* not connected yet */
479 rc
= ldap_open_defconn( ld
);
482 ber_sockbuf_ctrl( ld
->ld_defconn
->lconn_sb
,
483 LBER_SB_OPT_GET_FD
, &sd
);
485 if( sd
== AC_SOCKET_INVALID
) {
486 ld
->ld_errno
= LDAP_LOCAL_ERROR
;
491 if ( rc
== 0 && ld
->ld_defconn
&&
492 ld
->ld_defconn
->lconn_status
== LDAP_CONNST_CONNECTING
) {
493 rc
= ldap_int_check_async_open( ld
, sd
);
495 LDAP_MUTEX_UNLOCK( &ld
->ld_conn_mutex
);
496 if( rc
!= 0 ) return ld
->ld_errno
;
498 oldctx
= ld
->ld_defconn
->lconn_sasl_authctx
;
500 /* If we already have an authentication context, clear it out */
502 if ( oldctx
!= ld
->ld_defconn
->lconn_sasl_sockctx
) {
503 sasl_dispose( &oldctx
);
505 ld
->ld_defconn
->lconn_sasl_authctx
= NULL
;
510 int nocanon
= (int)LDAP_BOOL_GET( &ld
->ld_options
,
511 LDAP_BOOL_SASL_NOCANON
);
513 /* If we don't need to canonicalize just use the host
515 * Always use the result of gethostname() for LDAPI.
516 * Skip for Windows which doesn't support LDAPI.
519 if (ld
->ld_defconn
->lconn_server
->lud_scheme
!= NULL
&&
520 strcmp("ldapi", ld
->ld_defconn
->lconn_server
->lud_scheme
) == 0) {
521 rc
= gethostname(my_hostname
, HOST_NAME_MAX
+ 1);
523 saslhost
= my_hostname
;
525 saslhost
= "localhost";
530 saslhost
= ld
->ld_defconn
->lconn_server
->lud_host
;
532 saslhost
= ldap_host_connected_to( ld
->ld_defconn
->lconn_sb
,
536 rc
= ldap_int_sasl_open( ld
, ld
->ld_defconn
, saslhost
);
538 LDAP_FREE( saslhost
);
541 if ( rc
!= LDAP_SUCCESS
) return rc
;
543 ctx
= ld
->ld_defconn
->lconn_sasl_authctx
;
547 ssl
= ldap_pvt_tls_sb_ctx( ld
->ld_defconn
->lconn_sb
);
549 struct berval authid
= BER_BVNULL
;
552 fac
= ldap_pvt_tls_get_strength( ssl
);
553 /* failure is OK, we just can't use SASL EXTERNAL */
554 (void) ldap_pvt_tls_get_my_dn( ssl
, &authid
, NULL
, 0 );
556 (void) ldap_int_sasl_external( ld
, ld
->ld_defconn
, authid
.bv_val
, fac
);
557 LDAP_FREE( authid
.bv_val
);
558 #ifdef SASL_CHANNEL_BINDING /* 2.1.25+ */
559 if ( ld
->ld_defconn
->lconn_sasl_cbind
== NULL
) {
561 cb
= ldap_pvt_sasl_cbinding( ssl
,
562 ld
->ld_options
.ldo_sasl_cbinding
,
565 sasl_setprop( ld
->ld_defconn
->lconn_sasl_authctx
,
566 SASL_CHANNEL_BINDING
, cb
);
567 ld
->ld_defconn
->lconn_sasl_cbind
= cb
;
575 /* Check for local */
576 if ( ldap_pvt_url_scheme2proto(
577 ld
->ld_defconn
->lconn_server
->lud_scheme
) == LDAP_PROTO_IPC
)
579 char authid
[sizeof("gidNumber=4294967295+uidNumber=4294967295,"
580 "cn=peercred,cn=external,cn=auth")];
581 sprintf( authid
, "gidNumber=%u+uidNumber=%u,"
582 "cn=peercred,cn=external,cn=auth",
583 getegid(), geteuid() );
584 (void) ldap_int_sasl_external( ld
, ld
->ld_defconn
, authid
,
585 LDAP_PVT_SASL_LOCAL_SSF
);
589 /* (re)set security properties */
590 sasl_setprop( ctx
, SASL_SEC_PROPS
,
591 &ld
->ld_options
.ldo_sasl_secprops
);
596 saslrc
= sasl_client_start( ctx
,
598 #if SASL_VERSION_MAJOR < 2
602 (SASL_CONST
char **)&ccred
.bv_val
,
606 if( pmech
== NULL
&& mech
!= NULL
) {
610 if( flags
!= LDAP_SASL_QUIET
) {
612 "SASL/%s authentication started\n",
617 if( saslrc
== SASL_INTERACT
) {
619 if( !interact
) break;
620 res
= (interact
)( ld
, flags
, defaults
, prompts
);
622 if( res
!= LDAP_SUCCESS
) break;
624 } while ( saslrc
== SASL_INTERACT
);
625 rc
= LDAP_SASL_BIND_IN_PROGRESS
;
628 /* continuing an in-progress Bind */
629 struct berval
*scred
= NULL
;
631 ctx
= ld
->ld_defconn
->lconn_sasl_authctx
;
633 rc
= ldap_parse_sasl_bind_result( ld
, result
, &scred
, 0 );
634 if ( rc
!= LDAP_SUCCESS
) {
640 rc
= ldap_result2error( ld
, result
, 0 );
641 if ( rc
!= LDAP_SUCCESS
&& rc
!= LDAP_SASL_BIND_IN_PROGRESS
) {
643 /* and server provided us with data? */
644 Debug2( LDAP_DEBUG_TRACE
,
645 "ldap_int_sasl_bind: rc=%d len=%ld\n",
646 rc
, scred
? (long) scred
->bv_len
: -1L );
654 if ( rc
== LDAP_SUCCESS
&& mech
== NULL
) {
663 Debug0( LDAP_DEBUG_TRACE
,
664 "ldap_int_sasl_bind: no data in step!\n" );
667 saslrc
= sasl_client_step( ctx
,
668 (scred
== NULL
) ? NULL
: scred
->bv_val
,
669 (scred
== NULL
) ? 0 : scred
->bv_len
,
671 (SASL_CONST
char **)&ccred
.bv_val
,
674 Debug1( LDAP_DEBUG_TRACE
, "sasl_client_step: %d\n",
677 if( saslrc
== SASL_INTERACT
) {
679 if( !interact
) break;
680 res
= (interact
)( ld
, flags
, defaults
, prompts
);
681 if( res
!= LDAP_SUCCESS
) break;
683 } while ( saslrc
== SASL_INTERACT
);
688 if ( (saslrc
!= SASL_OK
) && (saslrc
!= SASL_CONTINUE
) ) {
689 rc
= ld
->ld_errno
= sasl_err2ldap( saslrc
);
690 #if SASL_VERSION_MAJOR >= 2
691 if ( ld
->ld_error
) {
692 LDAP_FREE( ld
->ld_error
);
694 ld
->ld_error
= LDAP_STRDUP( sasl_errdetail( ctx
) );
699 if ( saslrc
== SASL_OK
)
702 ccred
.bv_len
= credlen
;
704 if ( rc
== LDAP_SASL_BIND_IN_PROGRESS
) {
705 rc
= ldap_sasl_bind( ld
, dn
, mech
, &ccred
, sctrls
, cctrls
, msgid
);
707 if ( ccred
.bv_val
!= NULL
) {
708 #if SASL_VERSION_MAJOR < 2
709 LDAP_FREE( ccred
.bv_val
);
713 if ( rc
== LDAP_SUCCESS
)
714 rc
= LDAP_SASL_BIND_IN_PROGRESS
;
719 /* Conversation was completed successfully by now */
720 if( flags
!= LDAP_SASL_QUIET
) {
722 saslrc
= sasl_getprop( ctx
, SASL_USERNAME
,
723 (SASL_CONST
void **)(char *) &data
);
724 if( saslrc
== SASL_OK
&& data
&& *data
) {
725 fprintf( stderr
, "SASL username: %s\n", data
);
728 #if SASL_VERSION_MAJOR < 2
729 saslrc
= sasl_getprop( ctx
, SASL_REALM
,
730 (SASL_CONST
void **) &data
);
731 if( saslrc
== SASL_OK
&& data
&& *data
) {
732 fprintf( stderr
, "SASL realm: %s\n", data
);
738 saslrc
= sasl_getprop( ctx
, SASL_SSF
, (SASL_CONST
void **)(char *) &ssf
);
739 if( saslrc
== SASL_OK
) {
740 if( flags
!= LDAP_SASL_QUIET
) {
741 fprintf( stderr
, "SASL SSF: %lu\n",
742 (unsigned long) *ssf
);
746 if ( ld
->ld_defconn
->lconn_sasl_sockctx
) {
747 sasl_conn_t
*oldctx
= ld
->ld_defconn
->lconn_sasl_sockctx
;
748 sasl_dispose( &oldctx
);
749 ldap_pvt_sasl_remove( ld
->ld_defconn
->lconn_sb
);
751 ldap_pvt_sasl_install( ld
->ld_defconn
->lconn_sb
, ctx
);
752 ld
->ld_defconn
->lconn_sasl_sockctx
= ctx
;
754 if( flags
!= LDAP_SASL_QUIET
) {
755 fprintf( stderr
, "SASL data security layer installed.\n" );
759 ld
->ld_defconn
->lconn_sasl_authctx
= ctx
;
766 ldap_int_sasl_external(
774 #if SASL_VERSION_MAJOR < 2
775 sasl_external_properties_t extprops
;
777 sasl_ssf_t sasl_ssf
= ssf
;
780 ctx
= conn
->lconn_sasl_authctx
;
783 return LDAP_LOCAL_ERROR
;
786 #if SASL_VERSION_MAJOR >= 2
787 sc
= sasl_setprop( ctx
, SASL_SSF_EXTERNAL
, &sasl_ssf
);
789 sc
= sasl_setprop( ctx
, SASL_AUTH_EXTERNAL
, authid
);
791 memset( &extprops
, '\0', sizeof(extprops
) );
793 extprops
.auth_id
= (char *) authid
;
795 sc
= sasl_setprop( ctx
, SASL_SSF_EXTERNAL
,
796 (void *) &extprops
);
799 if ( sc
!= SASL_OK
) {
800 return LDAP_LOCAL_ERROR
;
817 { BER_BVC("none"), 0, 0, 0 },
818 { BER_BVC("nodict"), SASL_SEC_NODICTIONARY
, 0, 0 },
819 { BER_BVC("noplain"), SASL_SEC_NOPLAINTEXT
, 0, 0 },
820 { BER_BVC("noactive"), SASL_SEC_NOACTIVE
, 0, 0 },
821 { BER_BVC("passcred"), SASL_SEC_PASS_CREDENTIALS
, 0, 0 },
822 { BER_BVC("forwardsec"), SASL_SEC_FORWARD_SECRECY
, 0, 0 },
823 { BER_BVC("noanonymous"), SASL_SEC_NOANONYMOUS
, 0, 0 },
824 { BER_BVC("minssf="), 0, GOT_MINSSF
, 0 },
825 { BER_BVC("maxssf="), 0, GOT_MAXSSF
, INT_MAX
},
826 { BER_BVC("maxbufsize="), 0, GOT_MAXBUF
, 65536 },
827 { BER_BVNULL
, 0, 0, 0 }
830 void ldap_pvt_sasl_secprops_unparse(
831 sasl_security_properties_t
*secprops
,
838 if ( secprops
== NULL
|| out
== NULL
) {
843 for ( i
=0; !BER_BVISNULL( &sprops
[i
].key
); i
++ ) {
844 if ( sprops
[i
].ival
) {
847 switch( sprops
[i
].ival
) {
848 case GOT_MINSSF
: v
= secprops
->min_ssf
; break;
849 case GOT_MAXSSF
: v
= secprops
->max_ssf
; break;
850 case GOT_MAXBUF
: v
= secprops
->maxbufsize
; break;
852 /* It is the default, ignore it */
853 if ( v
== sprops
[i
].idef
) continue;
855 l
+= sprops
[i
].key
.bv_len
+ 24;
856 } else if ( sprops
[i
].sflag
) {
857 if ( sprops
[i
].sflag
& secprops
->security_flags
) {
858 l
+= sprops
[i
].key
.bv_len
;
860 } else if ( secprops
->security_flags
== 0 ) {
861 l
+= sprops
[i
].key
.bv_len
;
868 out
->bv_val
= LDAP_MALLOC( l
);
869 if ( out
->bv_val
== NULL
) {
876 for ( i
=0; !BER_BVISNULL( &sprops
[i
].key
); i
++ ) {
877 if ( sprops
[i
].ival
) {
880 switch( sprops
[i
].ival
) {
881 case GOT_MINSSF
: v
= secprops
->min_ssf
; break;
882 case GOT_MAXSSF
: v
= secprops
->max_ssf
; break;
883 case GOT_MAXBUF
: v
= secprops
->maxbufsize
; break;
885 /* It is the default, ignore it */
886 if ( v
== sprops
[i
].idef
) continue;
888 if ( comma
) *ptr
++ = ',';
889 ptr
+= sprintf(ptr
, "%s%d", sprops
[i
].key
.bv_val
, v
);
891 } else if ( sprops
[i
].sflag
) {
892 if ( sprops
[i
].sflag
& secprops
->security_flags
) {
893 if ( comma
) *ptr
++ = ',';
894 ptr
+= sprintf(ptr
, "%s", sprops
[i
].key
.bv_val
);
897 } else if ( secprops
->security_flags
== 0 ) {
898 if ( comma
) *ptr
++ = ',';
899 ptr
+= sprintf(ptr
, "%s", sprops
[i
].key
.bv_val
);
903 out
->bv_len
= ptr
- out
->bv_val
;
906 int ldap_pvt_sasl_secprops(
908 sasl_security_properties_t
*secprops
)
914 sasl_ssf_t max_ssf
= 0;
916 sasl_ssf_t min_ssf
= 0;
918 unsigned maxbufsize
= 0;
919 int got_maxbufsize
= 0;
921 if( secprops
== NULL
) {
922 return LDAP_PARAM_ERROR
;
924 props
= ldap_str2charray( in
, "," );
925 if( props
== NULL
) {
926 return LDAP_PARAM_ERROR
;
929 for( i
=0; props
[i
]; i
++ ) {
930 l
= strlen( props
[i
] );
931 for ( j
=0; !BER_BVISNULL( &sprops
[j
].key
); j
++ ) {
932 if ( l
< sprops
[j
].key
.bv_len
) continue;
933 if ( strncasecmp( props
[i
], sprops
[j
].key
.bv_val
,
934 sprops
[j
].key
.bv_len
)) continue;
935 if ( sprops
[j
].ival
) {
938 if ( !isdigit( (unsigned char)props
[i
][sprops
[j
].key
.bv_len
] ))
940 v
= strtoul( &props
[i
][sprops
[j
].key
.bv_len
], &next
, 10 );
941 if ( next
== &props
[i
][sprops
[j
].key
.bv_len
] || next
[0] != '\0' ) continue;
942 switch( sprops
[j
].ival
) {
944 min_ssf
= v
; got_min_ssf
++; break;
946 max_ssf
= v
; got_max_ssf
++; break;
948 maxbufsize
= v
; got_maxbufsize
++; break;
951 if ( props
[i
][sprops
[j
].key
.bv_len
] ) continue;
952 if ( sprops
[j
].sflag
)
953 sflags
|= sprops
[j
].sflag
;
960 if ( BER_BVISNULL( &sprops
[j
].key
)) {
961 ldap_charray_free( props
);
962 return LDAP_NOT_SUPPORTED
;
967 secprops
->security_flags
= sflags
;
970 secprops
->min_ssf
= min_ssf
;
973 secprops
->max_ssf
= max_ssf
;
976 secprops
->maxbufsize
= maxbufsize
;
979 ldap_charray_free( props
);
984 ldap_int_sasl_config( struct ldapoptions
*lo
, int option
, const char *arg
)
989 case LDAP_OPT_X_SASL_SECPROPS
:
990 rc
= ldap_pvt_sasl_secprops( arg
, &lo
->ldo_sasl_secprops
);
991 if( rc
== LDAP_SUCCESS
) return 0;
993 case LDAP_OPT_X_SASL_CBINDING
:
994 i
= ldap_pvt_sasl_cbinding_parse( arg
);
996 lo
->ldo_sasl_cbinding
= i
;
1006 ldap_int_sasl_get_option( LDAP
*ld
, int option
, void *arg
)
1008 if ( option
== LDAP_OPT_X_SASL_MECHLIST
) {
1009 *(char ***)arg
= (char **)sasl_global_listmech();
1017 case LDAP_OPT_X_SASL_MECH
: {
1018 *(char **)arg
= ld
->ld_options
.ldo_def_sasl_mech
1019 ? LDAP_STRDUP( ld
->ld_options
.ldo_def_sasl_mech
) : NULL
;
1021 case LDAP_OPT_X_SASL_REALM
: {
1022 *(char **)arg
= ld
->ld_options
.ldo_def_sasl_realm
1023 ? LDAP_STRDUP( ld
->ld_options
.ldo_def_sasl_realm
) : NULL
;
1025 case LDAP_OPT_X_SASL_AUTHCID
: {
1026 *(char **)arg
= ld
->ld_options
.ldo_def_sasl_authcid
1027 ? LDAP_STRDUP( ld
->ld_options
.ldo_def_sasl_authcid
) : NULL
;
1029 case LDAP_OPT_X_SASL_AUTHZID
: {
1030 *(char **)arg
= ld
->ld_options
.ldo_def_sasl_authzid
1031 ? LDAP_STRDUP( ld
->ld_options
.ldo_def_sasl_authzid
) : NULL
;
1034 case LDAP_OPT_X_SASL_SSF
: {
1039 if( ld
->ld_defconn
== NULL
) {
1043 ctx
= ld
->ld_defconn
->lconn_sasl_sockctx
;
1045 if ( ctx
== NULL
) {
1049 sc
= sasl_getprop( ctx
, SASL_SSF
,
1050 (SASL_CONST
void **)(char *) &ssf
);
1052 if ( sc
!= SASL_OK
) {
1056 *(ber_len_t
*)arg
= *ssf
;
1059 case LDAP_OPT_X_SASL_SSF_EXTERNAL
:
1060 /* this option is write only */
1063 case LDAP_OPT_X_SASL_SSF_MIN
:
1064 *(ber_len_t
*)arg
= ld
->ld_options
.ldo_sasl_secprops
.min_ssf
;
1066 case LDAP_OPT_X_SASL_SSF_MAX
:
1067 *(ber_len_t
*)arg
= ld
->ld_options
.ldo_sasl_secprops
.max_ssf
;
1069 case LDAP_OPT_X_SASL_MAXBUFSIZE
:
1070 *(ber_len_t
*)arg
= ld
->ld_options
.ldo_sasl_secprops
.maxbufsize
;
1072 case LDAP_OPT_X_SASL_NOCANON
:
1073 *(int *)arg
= (int) LDAP_BOOL_GET(&ld
->ld_options
, LDAP_BOOL_SASL_NOCANON
);
1076 case LDAP_OPT_X_SASL_USERNAME
: {
1081 if( ld
->ld_defconn
== NULL
) {
1085 ctx
= ld
->ld_defconn
->lconn_sasl_authctx
;
1087 if ( ctx
== NULL
) {
1091 sc
= sasl_getprop( ctx
, SASL_USERNAME
,
1092 (SASL_CONST
void **)(char **) &username
);
1094 if ( sc
!= SASL_OK
) {
1098 *(char **)arg
= username
? LDAP_STRDUP( username
) : NULL
;
1101 case LDAP_OPT_X_SASL_SECPROPS
:
1102 /* this option is write only */
1105 case LDAP_OPT_X_SASL_CBINDING
:
1106 *(int *)arg
= ld
->ld_options
.ldo_sasl_cbinding
;
1109 #ifdef SASL_GSS_CREDS
1110 case LDAP_OPT_X_SASL_GSS_CREDS
: {
1114 if ( ld
->ld_defconn
== NULL
)
1117 ctx
= ld
->ld_defconn
->lconn_sasl_authctx
;
1121 sc
= sasl_getprop( ctx
, SASL_GSS_CREDS
, arg
);
1122 if ( sc
!= SASL_OK
)
1135 ldap_int_sasl_set_option( LDAP
*ld
, int option
, void *arg
)
1140 if ( arg
== NULL
&& option
!= LDAP_OPT_X_SASL_NOCANON
)
1144 case LDAP_OPT_X_SASL_SSF
:
1145 case LDAP_OPT_X_SASL_USERNAME
:
1146 /* This option is read-only */
1149 case LDAP_OPT_X_SASL_SSF_EXTERNAL
: {
1151 #if SASL_VERSION_MAJOR < 2
1152 sasl_external_properties_t extprops
;
1154 sasl_ssf_t sasl_ssf
;
1158 if( ld
->ld_defconn
== NULL
) {
1162 ctx
= ld
->ld_defconn
->lconn_sasl_authctx
;
1164 if ( ctx
== NULL
) {
1168 #if SASL_VERSION_MAJOR >= 2
1169 sasl_ssf
= * (ber_len_t
*)arg
;
1170 sc
= sasl_setprop( ctx
, SASL_SSF_EXTERNAL
, &sasl_ssf
);
1172 memset(&extprops
, 0L, sizeof(extprops
));
1174 extprops
.ssf
= * (ber_len_t
*) arg
;
1176 sc
= sasl_setprop( ctx
, SASL_SSF_EXTERNAL
,
1177 (void *) &extprops
);
1180 if ( sc
!= SASL_OK
) {
1185 case LDAP_OPT_X_SASL_SSF_MIN
:
1186 ld
->ld_options
.ldo_sasl_secprops
.min_ssf
= *(ber_len_t
*)arg
;
1188 case LDAP_OPT_X_SASL_SSF_MAX
:
1189 ld
->ld_options
.ldo_sasl_secprops
.max_ssf
= *(ber_len_t
*)arg
;
1191 case LDAP_OPT_X_SASL_MAXBUFSIZE
:
1192 ld
->ld_options
.ldo_sasl_secprops
.maxbufsize
= *(ber_len_t
*)arg
;
1194 case LDAP_OPT_X_SASL_NOCANON
:
1195 if ( arg
== LDAP_OPT_OFF
) {
1196 LDAP_BOOL_CLR(&ld
->ld_options
, LDAP_BOOL_SASL_NOCANON
);
1198 LDAP_BOOL_SET(&ld
->ld_options
, LDAP_BOOL_SASL_NOCANON
);
1202 case LDAP_OPT_X_SASL_SECPROPS
: {
1204 sc
= ldap_pvt_sasl_secprops( (char *) arg
,
1205 &ld
->ld_options
.ldo_sasl_secprops
);
1207 return sc
== LDAP_SUCCESS
? 0 : -1;
1210 case LDAP_OPT_X_SASL_CBINDING
:
1211 if ( !arg
) return -1;
1212 switch( *(int *) arg
) {
1213 case LDAP_OPT_X_SASL_CBINDING_NONE
:
1214 case LDAP_OPT_X_SASL_CBINDING_TLS_UNIQUE
:
1215 case LDAP_OPT_X_SASL_CBINDING_TLS_ENDPOINT
:
1216 ld
->ld_options
.ldo_sasl_cbinding
= *(int *) arg
;
1221 #ifdef SASL_GSS_CREDS
1222 case LDAP_OPT_X_SASL_GSS_CREDS
: {
1226 if ( ld
->ld_defconn
== NULL
)
1229 ctx
= ld
->ld_defconn
->lconn_sasl_authctx
;
1233 sc
= sasl_setprop( ctx
, SASL_GSS_CREDS
, arg
);
1234 if ( sc
!= SASL_OK
)
1246 #ifdef LDAP_R_COMPILE
1247 #define LDAP_DEBUG_R_SASL
1248 void *ldap_pvt_sasl_mutex_new(void)
1250 ldap_pvt_thread_mutex_t
*mutex
;
1252 mutex
= (ldap_pvt_thread_mutex_t
*) LDAP_CALLOC( 1,
1253 sizeof(ldap_pvt_thread_mutex_t
) );
1255 if ( ldap_pvt_thread_mutex_init( mutex
) == 0 ) {
1259 #ifndef LDAP_DEBUG_R_SASL
1261 #endif /* !LDAP_DEBUG_R_SASL */
1265 int ldap_pvt_sasl_mutex_lock(void *mutex
)
1267 #ifdef LDAP_DEBUG_R_SASL
1268 if ( mutex
== NULL
) {
1271 #else /* !LDAP_DEBUG_R_SASL */
1272 assert( mutex
!= NULL
);
1273 #endif /* !LDAP_DEBUG_R_SASL */
1274 return ldap_pvt_thread_mutex_lock( (ldap_pvt_thread_mutex_t
*)mutex
)
1275 ? SASL_FAIL
: SASL_OK
;
1278 int ldap_pvt_sasl_mutex_unlock(void *mutex
)
1280 #ifdef LDAP_DEBUG_R_SASL
1281 if ( mutex
== NULL
) {
1284 #else /* !LDAP_DEBUG_R_SASL */
1285 assert( mutex
!= NULL
);
1286 #endif /* !LDAP_DEBUG_R_SASL */
1287 return ldap_pvt_thread_mutex_unlock( (ldap_pvt_thread_mutex_t
*)mutex
)
1288 ? SASL_FAIL
: SASL_OK
;
1291 void ldap_pvt_sasl_mutex_dispose(void *mutex
)
1293 #ifdef LDAP_DEBUG_R_SASL
1294 if ( mutex
== NULL
) {
1297 #else /* !LDAP_DEBUG_R_SASL */
1298 assert( mutex
!= NULL
);
1299 #endif /* !LDAP_DEBUG_R_SASL */
1300 (void) ldap_pvt_thread_mutex_destroy( (ldap_pvt_thread_mutex_t
*)mutex
);
1306 int ldap_int_sasl_init( void )
1307 { return LDAP_SUCCESS
; }
1309 int ldap_int_sasl_close( LDAP
*ld
, LDAPConn
*lc
)
1310 { return LDAP_SUCCESS
; }
1317 LDAPControl
**sctrls
,
1318 LDAPControl
**cctrls
,
1320 LDAP_SASL_INTERACT_PROC
*interact
,
1322 LDAPMessage
*result
,
1325 { return LDAP_NOT_SUPPORTED
; }
1328 ldap_int_sasl_external(
1331 const char * authid
,
1333 { return LDAP_SUCCESS
; }
1335 #endif /* HAVE_CYRUS_SASL */