1 /* $OpenLDAP: pkg/ldap/servers/slapd/sasl.c,v 1.239.2.12 2008/02/12 00:54:34 quanah 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>.
23 #include <ac/stdlib.h>
24 #include <ac/string.h>
35 #ifdef HAVE_CYRUS_SASL
36 # ifdef HAVE_SASL_SASL_H
37 # include <sasl/sasl.h>
38 # include <sasl/saslplug.h>
41 # include <saslplug.h>
44 # define SASL_CONST const
46 #define SASL_VERSION_FULL ((SASL_VERSION_MAJOR << 16) |\
47 (SASL_VERSION_MINOR << 8) | SASL_VERSION_STEP)
49 static sasl_security_properties_t sasl_secprops
;
50 #elif defined( SLAP_BUILTIN_SASL )
52 * built-in SASL implementation
53 * only supports EXTERNAL
55 typedef struct sasl_ctx
{
56 slap_ssf_t sc_external_ssf
;
57 struct berval sc_external_id
;
64 static struct berval ext_bv
= BER_BVC( "EXTERNAL" );
66 #ifdef HAVE_CYRUS_SASL
74 Connection
*conn
= context
;
78 if ( message
== NULL
) {
84 level
= LDAP_DEBUG_NONE
;
88 level
= LDAP_DEBUG_ANY
;
92 level
= LDAP_DEBUG_ANY
;
96 level
= LDAP_DEBUG_TRACE
;
100 level
= LDAP_DEBUG_TRACE
;
104 level
= LDAP_DEBUG_TRACE
;
108 level
= LDAP_DEBUG_TRACE
;
112 level
= LDAP_DEBUG_TRACE
;
113 label
= "Password Trace";
116 return SASL_BADPARAM
;
119 Debug( level
, "SASL [conn=%ld] %s: %s\n",
120 conn
? conn
->c_connid
: -1,
127 static const char *slap_propnames
[] = {
128 "*slapConn", "*slapAuthcDNlen", "*slapAuthcDN",
129 "*slapAuthzDNlen", "*slapAuthzDN", NULL
};
131 static Filter generic_filter
= { LDAP_FILTER_PRESENT
, { 0 }, NULL
};
132 static struct berval generic_filterstr
= BER_BVC("(objectclass=*)");
134 #define SLAP_SASL_PROP_CONN 0
135 #define SLAP_SASL_PROP_AUTHCLEN 1
136 #define SLAP_SASL_PROP_AUTHC 2
137 #define SLAP_SASL_PROP_AUTHZLEN 3
138 #define SLAP_SASL_PROP_AUTHZ 4
139 #define SLAP_SASL_PROP_COUNT 5 /* Number of properties we used */
141 typedef struct lookup_info
{
143 const struct propval
*list
;
144 sasl_server_params_t
*sparams
;
147 static slap_response sasl_ap_lookup
;
149 static struct berval sc_cleartext
= BER_BVC("{CLEARTEXT}");
152 sasl_ap_lookup( Operation
*op
, SlapReply
*rs
)
155 AttributeDescription
*ad
;
159 lookup_info
*sl
= (lookup_info
*)op
->o_callback
->sc_private
;
161 if (rs
->sr_type
!= REP_SEARCH
) return 0;
163 for( i
= 0; sl
->list
[i
].name
; i
++ ) {
164 const char *name
= sl
->list
[i
].name
;
166 if ( name
[0] == '*' ) {
167 if ( sl
->flags
& SASL_AUXPROP_AUTHZID
) continue;
168 /* Skip our private properties */
169 if ( !strcmp( name
, slap_propnames
[0] )) {
170 i
+= SLAP_SASL_PROP_COUNT
- 1;
174 } else if ( !(sl
->flags
& SASL_AUXPROP_AUTHZID
) )
177 if ( sl
->list
[i
].values
) {
178 if ( !(sl
->flags
& SASL_AUXPROP_OVERRIDE
) ) continue;
181 rc
= slap_str2ad( name
, &ad
, &text
);
182 if ( rc
!= LDAP_SUCCESS
) {
183 Debug( LDAP_DEBUG_TRACE
,
184 "slap_ap_lookup: str2ad(%s): %s\n", name
, text
, 0 );
188 /* If it's the rootdn and a rootpw was present, we already set
189 * it so don't override it here.
191 if ( ad
== slap_schema
.si_ad_userPassword
&& sl
->list
[i
].values
&&
192 be_isroot_dn( op
->o_bd
, &op
->o_req_ndn
))
195 a
= attr_find( rs
->sr_entry
->e_attrs
, ad
);
197 if ( ! access_allowed( op
, rs
->sr_entry
, ad
, NULL
, ACL_AUTH
, NULL
) ) {
200 if ( sl
->list
[i
].values
&& ( sl
->flags
& SASL_AUXPROP_OVERRIDE
) ) {
201 sl
->sparams
->utils
->prop_erase( sl
->sparams
->propctx
,
204 for ( bv
= a
->a_vals
; bv
->bv_val
; bv
++ ) {
205 /* ITS#3846 don't give hashed passwords to SASL */
206 if ( ad
== slap_schema
.si_ad_userPassword
&&
207 bv
->bv_val
[0] == '{' /*}*/ )
209 if ( lutil_passwd_scheme( bv
->bv_val
) ) {
210 /* If it's not a recognized scheme, just assume it's
211 * a cleartext password that happened to include brackets.
213 * If it's a recognized scheme, skip this value, unless the
214 * scheme is {CLEARTEXT}. In that case, skip over the
215 * scheme name and use the remainder. If there is nothing
216 * past the scheme name, skip this value.
218 #ifdef SLAPD_CLEARTEXT
219 if ( !strncasecmp( bv
->bv_val
, sc_cleartext
.bv_val
,
220 sc_cleartext
.bv_len
)) {
222 cbv
.bv_len
= bv
->bv_len
- sc_cleartext
.bv_len
;
223 if ( cbv
.bv_len
> 0 ) {
224 cbv
.bv_val
= bv
->bv_val
+ sc_cleartext
.bv_len
;
225 sl
->sparams
->utils
->prop_set( sl
->sparams
->propctx
,
226 sl
->list
[i
].name
, cbv
.bv_val
, cbv
.bv_len
);
233 sl
->sparams
->utils
->prop_set( sl
->sparams
->propctx
,
234 sl
->list
[i
].name
, bv
->bv_val
, bv
->bv_len
);
243 sasl_server_params_t
*sparams
,
250 Connection
*conn
= NULL
;
253 sl
.list
= sparams
->utils
->prop_get( sparams
->propctx
);
254 sl
.sparams
= sparams
;
257 /* Find our DN and conn first */
258 for( i
= 0; sl
.list
[i
].name
; i
++ ) {
259 if ( sl
.list
[i
].name
[0] == '*' ) {
260 if ( !strcmp( sl
.list
[i
].name
, slap_propnames
[SLAP_SASL_PROP_CONN
] ) ) {
261 if ( sl
.list
[i
].values
&& sl
.list
[i
].values
[0] )
262 AC_MEMCPY( &conn
, sl
.list
[i
].values
[0], sizeof( conn
) );
265 if ( flags
& SASL_AUXPROP_AUTHZID
) {
266 if ( !strcmp( sl
.list
[i
].name
, slap_propnames
[SLAP_SASL_PROP_AUTHZLEN
] )) {
267 if ( sl
.list
[i
].values
&& sl
.list
[i
].values
[0] )
268 AC_MEMCPY( &op
.o_req_ndn
.bv_len
, sl
.list
[i
].values
[0],
269 sizeof( op
.o_req_ndn
.bv_len
) );
270 } else if ( !strcmp( sl
.list
[i
].name
, slap_propnames
[SLAP_SASL_PROP_AUTHZ
] )) {
271 if ( sl
.list
[i
].values
)
272 op
.o_req_ndn
.bv_val
= (char *)sl
.list
[i
].values
[0];
277 if ( !strcmp( sl
.list
[i
].name
, slap_propnames
[SLAP_SASL_PROP_AUTHCLEN
] )) {
278 if ( sl
.list
[i
].values
&& sl
.list
[i
].values
[0] )
279 AC_MEMCPY( &op
.o_req_ndn
.bv_len
, sl
.list
[i
].values
[0],
280 sizeof( op
.o_req_ndn
.bv_len
) );
281 } else if ( !strcmp( sl
.list
[i
].name
, slap_propnames
[SLAP_SASL_PROP_AUTHC
] ) ) {
282 if ( sl
.list
[i
].values
) {
283 op
.o_req_ndn
.bv_val
= (char *)sl
.list
[i
].values
[0];
284 if ( !(flags
& SASL_AUXPROP_AUTHZID
) )
291 /* Now see what else needs to be fetched */
292 for( i
= 0; sl
.list
[i
].name
; i
++ ) {
293 const char *name
= sl
.list
[i
].name
;
295 if ( name
[0] == '*' ) {
296 if ( flags
& SASL_AUXPROP_AUTHZID
) continue;
297 /* Skip our private properties */
298 if ( !strcmp( name
, slap_propnames
[0] )) {
299 i
+= SLAP_SASL_PROP_COUNT
- 1;
303 } else if ( !(flags
& SASL_AUXPROP_AUTHZID
) )
306 if ( sl
.list
[i
].values
) {
307 if ( !(flags
& SASL_AUXPROP_OVERRIDE
) ) continue;
314 slap_callback cb
= { NULL
, sasl_ap_lookup
, NULL
, NULL
};
318 op
.o_bd
= select_backend( &op
.o_req_ndn
, 1 );
321 /* For rootdn, see if we can use the rootpw */
322 if ( be_isroot_dn( op
.o_bd
, &op
.o_req_ndn
) &&
323 !BER_BVISEMPTY( &op
.o_bd
->be_rootpw
)) {
324 struct berval cbv
= BER_BVNULL
;
326 /* If there's a recognized scheme, see if it's CLEARTEXT */
327 if ( lutil_passwd_scheme( op
.o_bd
->be_rootpw
.bv_val
)) {
328 if ( !strncasecmp( op
.o_bd
->be_rootpw
.bv_val
,
329 sc_cleartext
.bv_val
, sc_cleartext
.bv_len
)) {
331 /* If it's CLEARTEXT, skip past scheme spec */
332 cbv
.bv_len
= op
.o_bd
->be_rootpw
.bv_len
-
335 cbv
.bv_val
= op
.o_bd
->be_rootpw
.bv_val
+
339 /* No scheme, use the whole value */
341 cbv
= op
.o_bd
->be_rootpw
;
343 if ( !BER_BVISEMPTY( &cbv
)) {
344 for( i
= 0; sl
.list
[i
].name
; i
++ ) {
345 const char *name
= sl
.list
[i
].name
;
347 if ( name
[0] == '*' ) {
348 if ( flags
& SASL_AUXPROP_AUTHZID
) continue;
350 } else if ( !(flags
& SASL_AUXPROP_AUTHZID
) )
353 if ( !strcasecmp(name
,"userPassword") ) {
354 sl
.sparams
->utils
->prop_set( sl
.sparams
->propctx
,
355 sl
.list
[i
].name
, cbv
.bv_val
, cbv
.bv_len
);
362 if ( op
.o_bd
->be_search
) {
363 SlapReply rs
= {REP_RESULT
};
364 op
.o_hdr
= conn
->c_sasl_bindop
->o_hdr
;
365 op
.o_tag
= LDAP_REQ_SEARCH
;
366 op
.o_dn
= conn
->c_ndn
;
367 op
.o_ndn
= conn
->c_ndn
;
369 slap_op_time( &op
.o_time
, &op
.o_tincr
);
370 op
.o_do_not_cache
= 1;
371 op
.o_is_auth_check
= 1;
372 op
.o_req_dn
= op
.o_req_ndn
;
373 op
.ors_scope
= LDAP_SCOPE_BASE
;
374 op
.ors_deref
= LDAP_DEREF_NEVER
;
375 op
.ors_tlimit
= SLAP_NO_LIMIT
;
377 op
.ors_filter
= &generic_filter
;
378 op
.ors_filterstr
= generic_filterstr
;
379 /* FIXME: we want all attributes, right? */
382 op
.o_bd
->be_search( &op
, &rs
);
388 #if SASL_VERSION_FULL >= 0x020110
392 sasl_server_params_t
*sparams
,
393 struct propctx
*prctx
,
399 SlapReply rs
= {REP_RESULT
};
401 Connection
*conn
= NULL
;
402 const struct propval
*pr
;
403 Modifications
*modlist
= NULL
, **modtail
= &modlist
, *mod
;
404 slap_callback cb
= { NULL
, slap_null_cb
, NULL
, NULL
};
405 char textbuf
[SLAP_TEXT_BUFLEN
];
407 size_t textlen
= sizeof(textbuf
);
409 /* just checking if we are enabled */
410 if (!prctx
) return SASL_OK
;
412 if (!sparams
|| !user
) return SASL_BADPARAM
;
414 pr
= sparams
->utils
->prop_get( sparams
->propctx
);
416 /* Find our DN and conn first */
417 for( i
= 0; pr
[i
].name
; i
++ ) {
418 if ( pr
[i
].name
[0] == '*' ) {
419 if ( !strcmp( pr
[i
].name
, slap_propnames
[SLAP_SASL_PROP_CONN
] ) ) {
420 if ( pr
[i
].values
&& pr
[i
].values
[0] )
421 AC_MEMCPY( &conn
, pr
[i
].values
[0], sizeof( conn
) );
424 if ( !strcmp( pr
[i
].name
, slap_propnames
[SLAP_SASL_PROP_AUTHCLEN
] )) {
425 if ( pr
[i
].values
&& pr
[i
].values
[0] )
426 AC_MEMCPY( &op
.o_req_ndn
.bv_len
, pr
[i
].values
[0],
427 sizeof( op
.o_req_ndn
.bv_len
) );
428 } else if ( !strcmp( pr
[i
].name
, slap_propnames
[SLAP_SASL_PROP_AUTHC
] ) ) {
430 op
.o_req_ndn
.bv_val
= (char *)pr
[i
].values
[0];
434 if (!conn
|| !op
.o_req_ndn
.bv_val
) return SASL_BADPARAM
;
436 op
.o_bd
= select_backend( &op
.o_req_ndn
, 1 );
438 if ( !op
.o_bd
|| !op
.o_bd
->be_modify
) return SASL_FAIL
;
440 pr
= sparams
->utils
->prop_get( prctx
);
441 if (!pr
) return SASL_BADPARAM
;
443 for (i
=0; pr
[i
].name
; i
++);
444 if (!i
) return SASL_BADPARAM
;
446 for (i
=0; pr
[i
].name
; i
++) {
447 mod
= (Modifications
*)ch_malloc( sizeof(Modifications
) );
448 mod
->sml_op
= LDAP_MOD_REPLACE
;
450 ber_str2bv( pr
[i
].name
, 0, 0, &mod
->sml_type
);
451 mod
->sml_numvals
= pr
[i
].nvalues
;
452 mod
->sml_values
= (struct berval
*)ch_malloc( (pr
[i
].nvalues
+ 1) *
453 sizeof(struct berval
));
454 for (j
=0; j
<pr
[i
].nvalues
; j
++) {
455 ber_str2bv( pr
[i
].values
[j
], 0, 1, &mod
->sml_values
[j
]);
457 BER_BVZERO( &mod
->sml_values
[j
] );
458 mod
->sml_nvalues
= NULL
;
459 mod
->sml_desc
= NULL
;
461 modtail
= &mod
->sml_next
;
465 rc
= slap_mods_check( &op
, modlist
, &text
, textbuf
, textlen
, NULL
);
467 if ( rc
== LDAP_SUCCESS
) {
468 rc
= slap_mods_no_user_mod_check( &op
, modlist
,
469 &text
, textbuf
, textlen
);
471 if ( rc
== LDAP_SUCCESS
) {
472 if ( conn
->c_sasl_bindop
) {
473 op
.o_hdr
= conn
->c_sasl_bindop
->o_hdr
;
476 memset( &oph
, 0, sizeof(oph
) );
477 operation_fake_init( conn
, &op
, ldap_pvt_thread_pool_context(), 0 );
479 op
.o_tag
= LDAP_REQ_MODIFY
;
480 op
.o_ndn
= op
.o_req_ndn
;
482 slap_op_time( &op
.o_time
, &op
.o_tincr
);
483 op
.o_do_not_cache
= 1;
484 op
.o_is_auth_check
= 1;
485 op
.o_req_dn
= op
.o_req_ndn
;
486 op
.orm_modlist
= modlist
;
488 rc
= op
.o_bd
->be_modify( &op
, &rs
);
491 slap_mods_free( modlist
, 1 );
492 return rc
!= LDAP_SUCCESS
? SASL_FAIL
: SASL_OK
;
494 #endif /* SASL_VERSION_FULL >= 2.1.16 */
496 static sasl_auxprop_plug_t slap_auxprop_plugin
= {
499 NULL
, /* glob_context */
500 NULL
, /* auxprop_free */
503 #if SASL_VERSION_FULL >= 0x020110
504 slap_auxprop_store
/* the declaration of this member changed
505 * in cyrus SASL from 2.1.15 to 2.1.16 */
513 const sasl_utils_t
*utils
,
516 sasl_auxprop_plug_t
**plug
,
517 const char *plugname
)
519 if ( !out_version
|| !plug
) return SASL_BADPARAM
;
521 if ( max_version
< SASL_AUXPROP_PLUG_VERSION
) return SASL_BADVERS
;
523 *out_version
= SASL_AUXPROP_PLUG_VERSION
;
524 *plug
= &slap_auxprop_plugin
;
528 /* Convert a SASL authcid or authzid into a DN. Store the DN in an
529 * auxiliary property, so that we can refer to it in sasl_authorize
530 * without interfering with anything else. Also, the SASL username
531 * buffer is constrained to 256 characters, and our DNs could be
532 * much longer (SLAP_LDAPDN_MAXLEN, currently set to 8192)
535 slap_sasl_canonicalize(
541 const char *user_realm
,
546 Connection
*conn
= (Connection
*)context
;
547 struct propctx
*props
= sasl_auxprop_getctx( sconn
);
548 struct propval auxvals
[ SLAP_SASL_PROP_COUNT
] = { { 0 } };
551 const char *names
[2];
556 Debug( LDAP_DEBUG_ARGS
, "SASL Canonicalize [conn=%ld]: %s=\"%s\"\n",
557 conn
? conn
->c_connid
: -1,
558 (flags
& SASL_CU_AUTHID
) ? "authcid" : "authzid",
559 in
? in
: "<empty>");
561 /* If name is too big, just truncate. We don't care, we're
562 * using DNs, not the usernames.
564 if ( inlen
> out_max
)
567 /* This is a Simple Bind using SPASSWD. That means the in-directory
568 * userPassword of the Binding user already points at SASL, so it
569 * cannot be used to actually satisfy a password comparison. Just
570 * ignore it, some other mech will process it.
572 if ( !conn
->c_sasl_bindop
||
573 conn
->c_sasl_bindop
->orb_method
!= LDAP_AUTH_SASL
) goto done
;
575 /* See if we need to add request, can only do it once */
576 prop_getnames( props
, slap_propnames
, auxvals
);
577 if ( !auxvals
[0].name
)
578 prop_request( props
, slap_propnames
);
580 if ( flags
& SASL_CU_AUTHID
)
581 which
= SLAP_SASL_PROP_AUTHCLEN
;
583 which
= SLAP_SASL_PROP_AUTHZLEN
;
585 /* Need to store the Connection for auxprop_lookup */
586 if ( !auxvals
[SLAP_SASL_PROP_CONN
].values
) {
587 names
[0] = slap_propnames
[SLAP_SASL_PROP_CONN
];
589 prop_set( props
, names
[0], (char *)&conn
, sizeof( conn
) );
592 /* Already been here? */
593 if ( auxvals
[which
].values
)
596 /* Normally we require an authzID to have a u: or dn: prefix.
597 * However, SASL frequently gives us an authzID that is just
598 * an exact copy of the authcID, without a prefix. We need to
599 * detect and allow this condition. If SASL calls canonicalize
600 * with SASL_CU_AUTHID|SASL_CU_AUTHZID this is a no-brainer.
601 * But if it's broken into two calls, we need to remember the
602 * authcID so that we can compare the authzID later. We store
603 * the authcID temporarily in conn->c_sasl_dn. We necessarily
604 * finish Canonicalizing before Authorizing, so there is no
605 * conflict with slap_sasl_authorize's use of this temp var.
607 * The SASL EXTERNAL mech is backwards from all the other mechs,
608 * it does authzID before the authcID. If we see that authzID
609 * has already been done, don't do anything special with authcID.
611 if ( flags
== SASL_CU_AUTHID
&& !auxvals
[SLAP_SASL_PROP_AUTHZ
].values
) {
612 conn
->c_sasl_dn
.bv_val
= (char *) in
;
613 conn
->c_sasl_dn
.bv_len
= 0;
614 } else if ( flags
== SASL_CU_AUTHZID
&& conn
->c_sasl_dn
.bv_val
) {
615 rc
= strcmp( in
, conn
->c_sasl_dn
.bv_val
);
616 conn
->c_sasl_dn
.bv_val
= NULL
;
617 /* They were equal, no work needed */
618 if ( !rc
) goto done
;
621 bvin
.bv_val
= (char *)in
;
623 rc
= slap_sasl_getdn( conn
, NULL
, &bvin
, (char *)user_realm
, &dn
,
624 (flags
& SASL_CU_AUTHID
) ? SLAP_GETDN_AUTHCID
: SLAP_GETDN_AUTHZID
);
625 if ( rc
!= LDAP_SUCCESS
) {
626 sasl_seterror( sconn
, 0, ldap_err2string( rc
) );
630 names
[0] = slap_propnames
[which
];
632 prop_set( props
, names
[0], (char *)&dn
.bv_len
, sizeof( dn
.bv_len
) );
635 names
[0] = slap_propnames
[which
];
636 prop_set( props
, names
[0], dn
.bv_val
, dn
.bv_len
);
638 Debug( LDAP_DEBUG_ARGS
, "SASL Canonicalize [conn=%ld]: %s=\"%s\"\n",
639 conn
? conn
->c_connid
: -1, names
[0]+1,
640 dn
.bv_val
? dn
.bv_val
: "<EMPTY>" );
642 /* Not needed any more, SASL has copied it */
643 if ( conn
&& conn
->c_sasl_bindop
)
644 conn
->c_sasl_bindop
->o_tmpfree( dn
.bv_val
, conn
->c_sasl_bindop
->o_tmpmemctx
);
647 AC_MEMCPY( out
, in
, inlen
);
659 char *requested_user
,
663 const char *def_realm
,
665 struct propctx
*props
)
667 Connection
*conn
= (Connection
*)context
;
669 * (SLAP_SASL_PROP_COUNT - 1) because we skip "conn",
670 * + 1 for NULL termination?
672 struct propval auxvals
[ SLAP_SASL_PROP_COUNT
] = { { 0 } };
673 struct berval authcDN
, authzDN
= BER_BVNULL
;
676 /* Simple Binds don't support proxy authorization, ignore it */
677 if ( !conn
->c_sasl_bindop
||
678 conn
->c_sasl_bindop
->orb_method
!= LDAP_AUTH_SASL
) return SASL_OK
;
680 Debug( LDAP_DEBUG_ARGS
, "SASL proxy authorize [conn=%ld]: "
681 "authcid=\"%s\" authzid=\"%s\"\n",
682 conn
? conn
->c_connid
: -1, auth_identity
, requested_user
);
683 if ( conn
->c_sasl_dn
.bv_val
) {
684 BER_BVZERO( &conn
->c_sasl_dn
);
687 /* Skip SLAP_SASL_PROP_CONN */
688 prop_getnames( props
, slap_propnames
+1, auxvals
);
690 /* Should not happen */
691 if ( !auxvals
[0].values
) {
692 sasl_seterror( sconn
, 0, "invalid authcid" );
696 AC_MEMCPY( &authcDN
.bv_len
, auxvals
[0].values
[0], sizeof(authcDN
.bv_len
) );
697 authcDN
.bv_val
= auxvals
[1].values
? (char *)auxvals
[1].values
[0] : NULL
;
698 conn
->c_sasl_dn
= authcDN
;
700 /* Nothing to do if no authzID was given */
701 if ( !auxvals
[2].name
|| !auxvals
[2].values
) {
705 AC_MEMCPY( &authzDN
.bv_len
, auxvals
[2].values
[0], sizeof(authzDN
.bv_len
) );
706 authzDN
.bv_val
= auxvals
[3].values
? (char *)auxvals
[3].values
[0] : NULL
;
708 rc
= slap_sasl_authorized( conn
->c_sasl_bindop
, &authcDN
, &authzDN
);
709 if ( rc
!= LDAP_SUCCESS
) {
710 Debug( LDAP_DEBUG_TRACE
, "SASL Proxy Authorize [conn=%ld]: "
711 "proxy authorization disallowed (%d)\n",
712 (long) (conn
? conn
->c_connid
: -1), rc
, 0 );
714 sasl_seterror( sconn
, 0, "not authorized" );
718 /* FIXME: we need yet another dup because slap_sasl_getdn()
719 * is using the bind operation slab */
720 ber_dupbv( &conn
->c_sasl_authz_dn
, &authzDN
);
723 if (conn
->c_sasl_bindop
) {
724 Statslog( LDAP_DEBUG_STATS
,
725 "%s BIND authcid=\"%s\" authzid=\"%s\"\n",
726 conn
->c_sasl_bindop
->o_log_prefix
,
727 auth_identity
, requested_user
, 0, 0 );
730 Debug( LDAP_DEBUG_TRACE
, "SASL Authorize [conn=%ld]: "
731 " proxy authorization allowed authzDN=\"%s\"\n",
732 (long) (conn
? conn
->c_connid
: -1),
733 authzDN
.bv_val
? authzDN
.bv_val
: "", 0 );
738 slap_sasl_err2ldap( int saslerr
)
742 /* map SASL errors to LDAP resultCode returned by:
744 * SASL_OK, SASL_NOMEM
746 * SASL_OK, SASL_CONTINUE, SASL_TRANS, SASL_BADPARAM, SASL_BADPROT,
748 * sasl_server_start()
751 * SASL_OK, SASL_BADPARAM
759 rc
= LDAP_SASL_BIND_IN_PROGRESS
;
766 rc
= LDAP_AUTH_METHOD_NOT_SUPPORTED
;
772 rc
= LDAP_INVALID_CREDENTIALS
;
775 rc
= LDAP_INSUFFICIENT_ACCESS
;
779 rc
= LDAP_INAPPROPRIATE_AUTH
;
783 rc
= LDAP_UNAVAILABLE
;
786 rc
= LDAP_UNWILLING_TO_PERFORM
;
798 static struct berval sasl_pwscheme
= BER_BVC("{SASL}");
801 const struct berval
*sc
,
802 const struct berval
* passwd
,
803 const struct berval
* cred
,
808 void *ctx
, *sconn
= NULL
;
810 for( i
=0; i
<cred
->bv_len
; i
++) {
811 if(cred
->bv_val
[i
] == '\0') {
812 return LUTIL_PASSWD_ERR
; /* NUL character in password */
816 if( cred
->bv_val
[i
] != '\0' ) {
817 return LUTIL_PASSWD_ERR
; /* cred must behave like a string */
820 for( i
=0; i
<passwd
->bv_len
; i
++) {
821 if(passwd
->bv_val
[i
] == '\0') {
822 return LUTIL_PASSWD_ERR
; /* NUL character in password */
826 if( passwd
->bv_val
[i
] != '\0' ) {
827 return LUTIL_PASSWD_ERR
; /* passwd must behave like a string */
830 rtn
= LUTIL_PASSWD_ERR
;
832 ctx
= ldap_pvt_thread_pool_context();
833 ldap_pvt_thread_pool_getkey( ctx
, (void *)slap_sasl_bind
, &sconn
, NULL
);
835 if( sconn
!= NULL
) {
837 sc
= sasl_checkpass( sconn
,
838 passwd
->bv_val
, passwd
->bv_len
,
839 cred
->bv_val
, cred
->bv_len
);
840 rtn
= ( sc
!= SASL_OK
) ? LUTIL_PASSWD_ERR
: LUTIL_PASSWD_OK
;
845 #endif /* SLAPD_SPASSWD */
847 #endif /* HAVE_CYRUS_SASL */
849 #ifdef ENABLE_REWRITE
851 typedef struct slapd_map_data
{
853 struct berval filter
;
854 AttributeName attrs
[2];
859 slapd_rw_config( const char *fname
, int lineno
, int argc
, char **argv
)
861 slapd_map_data
*ret
= NULL
;
862 LDAPURLDesc
*lud
= NULL
;
864 AttributeDescription
*ad
= NULL
;
866 struct berval dn
, ndn
;
869 Debug( LDAP_DEBUG_ANY
,
870 "[%s:%d] slapd map needs URI\n",
876 if ( strncasecmp( uri
, "uri=", STRLENOF( "uri=" ) ) == 0 ) {
877 uri
+= STRLENOF( "uri=" );
880 if ( ldap_url_parse( uri
, &lud
) != LDAP_URL_SUCCESS
) {
881 Debug( LDAP_DEBUG_ANY
,
882 "[%s:%d] illegal URI '%s'\n",
883 fname
, lineno
, uri
);
887 if ( strcasecmp( lud
->lud_scheme
, "ldap" )) {
888 Debug( LDAP_DEBUG_ANY
,
889 "[%s:%d] illegal URI scheme '%s'\n",
890 fname
, lineno
, lud
->lud_scheme
);
894 if (( lud
->lud_host
&& lud
->lud_host
[0] ) || lud
->lud_exts
896 Debug( LDAP_DEBUG_ANY
,
897 "[%s:%d] illegal URI '%s'\n",
898 fname
, lineno
, uri
);
902 if ( lud
->lud_attrs
) {
903 if ( lud
->lud_attrs
[1] ) {
904 Debug( LDAP_DEBUG_ANY
,
905 "[%s:%d] only one attribute allowed in URI\n",
909 if ( strcasecmp( lud
->lud_attrs
[0], "dn" ) &&
910 strcasecmp( lud
->lud_attrs
[0], "entryDN" )) {
912 rc
= slap_str2ad( lud
->lud_attrs
[0], &ad
, &text
);
917 ber_str2bv( lud
->lud_dn
, 0, 0, &dn
);
918 if ( dnNormalize( 0, NULL
, NULL
, &dn
, &ndn
, NULL
))
921 if ( lud
->lud_filter
) {
922 flen
= strlen( lud
->lud_filter
) + 1;
924 ret
= ch_malloc( sizeof( slapd_map_data
) + flen
);
927 ret
->filter
.bv_val
= (char *)(ret
+1);
928 ret
->filter
.bv_len
= flen
- 1;
929 strcpy( ret
->filter
.bv_val
, lud
->lud_filter
);
931 BER_BVZERO( &ret
->filter
);
933 ret
->scope
= lud
->lud_scope
;
935 ret
->attrs
[0].an_name
= ad
->ad_cname
;
937 BER_BVZERO( &ret
->attrs
[0].an_name
);
939 ret
->attrs
[0].an_desc
= ad
;
940 BER_BVZERO( &ret
->attrs
[1].an_name
);
942 ldap_free_urldesc( lud
);
946 struct slapd_rw_info
{
947 slapd_map_data
*si_data
;
948 struct berval si_val
;
952 slapd_rw_cb( Operation
*op
, SlapReply
*rs
)
954 if ( rs
->sr_type
== REP_SEARCH
) {
955 struct slapd_rw_info
*si
= op
->o_callback
->sc_private
;
957 if ( si
->si_data
->attrs
[0].an_desc
) {
960 a
= attr_find( rs
->sr_entry
->e_attrs
,
961 si
->si_data
->attrs
[0].an_desc
);
963 ber_dupbv( &si
->si_val
, a
->a_vals
);
966 ber_dupbv( &si
->si_val
, &rs
->sr_entry
->e_name
);
973 slapd_rw_apply( void *private, const char *filter
, struct berval
*val
)
975 slapd_map_data
*sl
= private;
976 slap_callback cb
= { NULL
};
977 Connection conn
= {0};
978 OperationBuffer opbuf
;
981 SlapReply rs
= {REP_RESULT
};
982 struct slapd_rw_info si
;
986 thrctx
= ldap_pvt_thread_pool_context();
987 connection_fake_init2( &conn
, &opbuf
, thrctx
, 0 );
990 op
->o_tag
= LDAP_REQ_SEARCH
;
991 op
->o_req_dn
= op
->o_req_ndn
= sl
->base
;
992 op
->o_bd
= select_backend( &op
->o_req_ndn
, 1 );
997 BER_BVZERO( &si
.si_val
);
998 op
->ors_scope
= sl
->scope
;
999 op
->ors_deref
= LDAP_DEREF_NEVER
;
1001 op
->ors_tlimit
= SLAP_NO_LIMIT
;
1002 if ( sl
->attrs
[0].an_desc
) {
1003 op
->ors_attrs
= sl
->attrs
;
1005 op
->ors_attrs
= slap_anlist_no_attrs
;
1008 rc
= strlen( filter
);
1012 rc
+= sl
->filter
.bv_len
;
1013 ptr
= op
->ors_filterstr
.bv_val
= op
->o_tmpalloc( rc
+ 1, op
->o_tmpmemctx
);
1014 if ( sl
->filter
.bv_len
) {
1015 ptr
= lutil_strcopy( ptr
, sl
->filter
.bv_val
);
1020 strcpy( ptr
, filter
);
1022 op
->ors_filter
= str2filter_x( op
, op
->ors_filterstr
.bv_val
);
1023 if ( !op
->ors_filter
) {
1024 op
->o_tmpfree( op
->ors_filterstr
.bv_val
, op
->o_tmpmemctx
);
1028 op
->ors_attrsonly
= 0;
1029 op
->o_dn
= op
->o_bd
->be_rootdn
;
1030 op
->o_ndn
= op
->o_bd
->be_rootndn
;
1031 op
->o_do_not_cache
= 1;
1033 cb
.sc_response
= slapd_rw_cb
;
1034 cb
.sc_private
= &si
;
1035 op
->o_callback
= &cb
;
1037 rc
= op
->o_bd
->be_search( op
, &rs
);
1038 if ( rc
== LDAP_SUCCESS
&& !BER_BVISNULL( &si
.si_val
)) {
1040 rc
= REWRITE_SUCCESS
;
1042 if ( !BER_BVISNULL( &si
.si_val
)) {
1043 ch_free( si
.si_val
.bv_val
);
1047 filter_free_x( op
, op
->ors_filter
);
1048 op
->o_tmpfree( op
->ors_filterstr
.bv_val
, op
->o_tmpmemctx
);
1053 slapd_rw_destroy( void *private )
1055 slapd_map_data
*md
= private;
1057 assert( private != NULL
);
1059 ch_free( md
->base
.bv_val
);
1060 ch_free( md
->filter
.bv_val
);
1066 static const rewrite_mapper slapd_mapper
= {
1074 int slap_sasl_init( void )
1076 #ifdef HAVE_CYRUS_SASL
1078 static sasl_callback_t server_callbacks
[] = {
1079 { SASL_CB_LOG
, &slap_sasl_log
, NULL
},
1080 { SASL_CB_LIST_END
, NULL
, NULL
}
1084 #ifdef ENABLE_REWRITE
1085 rewrite_mapper_register( &slapd_mapper
);
1088 #ifdef HAVE_CYRUS_SASL
1089 #ifdef HAVE_SASL_VERSION
1090 /* stringify the version number, sasl.h doesn't do it for us */
1091 #define VSTR0(maj, min, pat) #maj "." #min "." #pat
1092 #define VSTR(maj, min, pat) VSTR0(maj, min, pat)
1093 #define SASL_VERSION_STRING VSTR(SASL_VERSION_MAJOR, SASL_VERSION_MINOR, \
1096 sasl_version( NULL
, &rc
);
1097 if ( ((rc
>> 16) != ((SASL_VERSION_MAJOR
<< 8)|SASL_VERSION_MINOR
)) ||
1098 (rc
& 0xffff) < SASL_VERSION_STEP
)
1100 char version
[sizeof("xxx.xxx.xxxxx")];
1101 sprintf( version
, "%u.%d.%d", (unsigned)rc
>> 24, (rc
>> 16) & 0xff,
1103 Debug( LDAP_DEBUG_ANY
, "slap_sasl_init: SASL library version mismatch:"
1104 " expected %s, got %s\n",
1105 SASL_VERSION_STRING
, version
, 0 );
1111 ldap_pvt_sasl_mutex_new
,
1112 ldap_pvt_sasl_mutex_lock
,
1113 ldap_pvt_sasl_mutex_unlock
,
1114 ldap_pvt_sasl_mutex_dispose
);
1116 generic_filter
.f_desc
= slap_schema
.si_ad_objectClass
;
1118 rc
= sasl_auxprop_add_plugin( "slapd", slap_auxprop_init
);
1119 if( rc
!= SASL_OK
) {
1120 Debug( LDAP_DEBUG_ANY
, "slap_sasl_init: auxprop add plugin failed\n",
1125 /* should provide callbacks for logging */
1126 /* server name should be configurable */
1127 rc
= sasl_server_init( server_callbacks
, "slapd" );
1129 if( rc
!= SASL_OK
) {
1130 Debug( LDAP_DEBUG_ANY
, "slap_sasl_init: server init failed\n",
1136 #ifdef SLAPD_SPASSWD
1137 lutil_passwd_add( &sasl_pwscheme
, chk_sasl
, NULL
);
1140 Debug( LDAP_DEBUG_TRACE
, "slap_sasl_init: initialized!\n",
1143 /* default security properties */
1144 memset( &sasl_secprops
, '\0', sizeof(sasl_secprops
) );
1145 sasl_secprops
.max_ssf
= INT_MAX
;
1146 sasl_secprops
.maxbufsize
= 65536;
1147 sasl_secprops
.security_flags
= SASL_SEC_NOPLAINTEXT
|SASL_SEC_NOANONYMOUS
;
1153 int slap_sasl_destroy( void )
1155 #ifdef HAVE_CYRUS_SASL
1165 slap_sasl_peer2ipport( struct berval
*peer
)
1169 *addr
= &peer
->bv_val
[ STRLENOF( "IP=" ) ];
1170 ber_len_t plen
= peer
->bv_len
- STRLENOF( "IP=" );
1173 if ( addr
[0] == '[' ) {
1177 ipport
= ch_strdup( &addr
[isv6
] );
1179 /* Convert IPv6/IPv4 addresses to address;port syntax. */
1180 p
= strrchr( ipport
, ':' );
1184 assert( p
[-1] == ']' );
1185 AC_MEMCPY( &p
[-1], p
, plen
- ( p
- ipport
) + 1 );
1188 } else if ( isv6
) {
1191 assert( addr
[plen
] == ']' );
1198 int slap_sasl_open( Connection
*conn
, int reopen
)
1200 int sc
= LDAP_SUCCESS
;
1201 #ifdef HAVE_CYRUS_SASL
1204 sasl_conn_t
*ctx
= NULL
;
1205 sasl_callback_t
*session_callbacks
;
1206 char *ipremoteport
= NULL
, *iplocalport
= NULL
;
1208 assert( conn
->c_sasl_authctx
== NULL
);
1211 assert( conn
->c_sasl_extra
== NULL
);
1214 SLAP_CALLOC( 5, sizeof(sasl_callback_t
));
1215 if( session_callbacks
== NULL
) {
1216 Debug( LDAP_DEBUG_ANY
,
1217 "slap_sasl_open: SLAP_MALLOC failed", 0, 0, 0 );
1220 conn
->c_sasl_extra
= session_callbacks
;
1222 session_callbacks
[cb
=0].id
= SASL_CB_LOG
;
1223 session_callbacks
[cb
].proc
= &slap_sasl_log
;
1224 session_callbacks
[cb
++].context
= conn
;
1226 session_callbacks
[cb
].id
= SASL_CB_PROXY_POLICY
;
1227 session_callbacks
[cb
].proc
= &slap_sasl_authorize
;
1228 session_callbacks
[cb
++].context
= conn
;
1230 session_callbacks
[cb
].id
= SASL_CB_CANON_USER
;
1231 session_callbacks
[cb
].proc
= &slap_sasl_canonicalize
;
1232 session_callbacks
[cb
++].context
= conn
;
1234 session_callbacks
[cb
].id
= SASL_CB_LIST_END
;
1235 session_callbacks
[cb
].proc
= NULL
;
1236 session_callbacks
[cb
++].context
= NULL
;
1238 session_callbacks
= conn
->c_sasl_extra
;
1241 conn
->c_sasl_layers
= 0;
1243 /* create new SASL context */
1244 if ( conn
->c_sock_name
.bv_len
!= 0 &&
1245 strncmp( conn
->c_sock_name
.bv_val
, "IP=", STRLENOF( "IP=" ) ) == 0 )
1247 iplocalport
= slap_sasl_peer2ipport( &conn
->c_sock_name
);
1250 if ( conn
->c_peer_name
.bv_len
!= 0 &&
1251 strncmp( conn
->c_peer_name
.bv_val
, "IP=", STRLENOF( "IP=" ) ) == 0 )
1253 ipremoteport
= slap_sasl_peer2ipport( &conn
->c_peer_name
);
1256 sc
= sasl_server_new( "ldap", sasl_host
, global_realm
,
1257 iplocalport
, ipremoteport
, session_callbacks
, SASL_SUCCESS_DATA
, &ctx
);
1258 if ( iplocalport
!= NULL
) {
1259 ch_free( iplocalport
);
1261 if ( ipremoteport
!= NULL
) {
1262 ch_free( ipremoteport
);
1265 if( sc
!= SASL_OK
) {
1266 Debug( LDAP_DEBUG_ANY
, "sasl_server_new failed: %d\n",
1272 conn
->c_sasl_authctx
= ctx
;
1274 if( sc
== SASL_OK
) {
1275 sc
= sasl_setprop( ctx
,
1276 SASL_SEC_PROPS
, &sasl_secprops
);
1278 if( sc
!= SASL_OK
) {
1279 Debug( LDAP_DEBUG_ANY
, "sasl_setprop failed: %d\n",
1282 slap_sasl_close( conn
);
1287 sc
= slap_sasl_err2ldap( sc
);
1289 #elif defined(SLAP_BUILTIN_SASL)
1290 /* built-in SASL implementation */
1291 SASL_CTX
*ctx
= (SASL_CTX
*) SLAP_MALLOC(sizeof(SASL_CTX
));
1292 if( ctx
== NULL
) return -1;
1294 ctx
->sc_external_ssf
= 0;
1295 BER_BVZERO( &ctx
->sc_external_id
);
1297 conn
->c_sasl_authctx
= ctx
;
1303 int slap_sasl_external(
1306 struct berval
*auth_id
)
1308 #ifdef HAVE_CYRUS_SASL
1310 sasl_conn_t
*ctx
= conn
->c_sasl_authctx
;
1311 sasl_ssf_t sasl_ssf
= ssf
;
1313 if ( ctx
== NULL
) {
1314 return LDAP_UNAVAILABLE
;
1317 sc
= sasl_setprop( ctx
, SASL_SSF_EXTERNAL
, &sasl_ssf
);
1319 if ( sc
!= SASL_OK
) {
1323 sc
= sasl_setprop( ctx
, SASL_AUTH_EXTERNAL
,
1324 auth_id
? auth_id
->bv_val
: NULL
);
1326 if ( sc
!= SASL_OK
) {
1329 #elif defined(SLAP_BUILTIN_SASL)
1330 /* built-in SASL implementation */
1331 SASL_CTX
*ctx
= conn
->c_sasl_authctx
;
1332 if ( ctx
== NULL
) return LDAP_UNAVAILABLE
;
1334 ctx
->sc_external_ssf
= ssf
;
1336 ctx
->sc_external_id
= *auth_id
;
1337 BER_BVZERO( auth_id
);
1339 BER_BVZERO( &ctx
->sc_external_id
);
1343 return LDAP_SUCCESS
;
1346 int slap_sasl_reset( Connection
*conn
)
1348 return LDAP_SUCCESS
;
1351 char ** slap_sasl_mechs( Connection
*conn
)
1353 char **mechs
= NULL
;
1355 #ifdef HAVE_CYRUS_SASL
1356 sasl_conn_t
*ctx
= conn
->c_sasl_authctx
;
1358 if( ctx
== NULL
) ctx
= conn
->c_sasl_sockctx
;
1362 SASL_CONST
char *mechstr
;
1364 sc
= sasl_listmech( ctx
,
1365 NULL
, NULL
, ",", NULL
,
1366 &mechstr
, NULL
, NULL
);
1368 if( sc
!= SASL_OK
) {
1369 Debug( LDAP_DEBUG_ANY
, "slap_sasl_listmech failed: %d\n",
1375 mechs
= ldap_str2charray( mechstr
, "," );
1377 #elif defined(SLAP_BUILTIN_SASL)
1378 /* builtin SASL implementation */
1379 SASL_CTX
*ctx
= conn
->c_sasl_authctx
;
1380 if ( ctx
!= NULL
&& ctx
->sc_external_id
.bv_val
) {
1381 /* should check ssf */
1382 mechs
= ldap_str2charray( "EXTERNAL", "," );
1389 int slap_sasl_close( Connection
*conn
)
1391 #ifdef HAVE_CYRUS_SASL
1392 sasl_conn_t
*ctx
= conn
->c_sasl_authctx
;
1395 sasl_dispose( &ctx
);
1397 if ( conn
->c_sasl_sockctx
&&
1398 conn
->c_sasl_authctx
!= conn
->c_sasl_sockctx
)
1400 ctx
= conn
->c_sasl_sockctx
;
1401 sasl_dispose( &ctx
);
1404 conn
->c_sasl_authctx
= NULL
;
1405 conn
->c_sasl_sockctx
= NULL
;
1406 conn
->c_sasl_done
= 0;
1408 free( conn
->c_sasl_extra
);
1409 conn
->c_sasl_extra
= NULL
;
1411 #elif defined(SLAP_BUILTIN_SASL)
1412 SASL_CTX
*ctx
= conn
->c_sasl_authctx
;
1414 if( ctx
->sc_external_id
.bv_val
) {
1415 free( ctx
->sc_external_id
.bv_val
);
1416 BER_BVZERO( &ctx
->sc_external_id
);
1419 conn
->c_sasl_authctx
= NULL
;
1423 return LDAP_SUCCESS
;
1426 int slap_sasl_bind( Operation
*op
, SlapReply
*rs
)
1428 #ifdef HAVE_CYRUS_SASL
1429 sasl_conn_t
*ctx
= op
->o_conn
->c_sasl_authctx
;
1430 struct berval response
;
1431 unsigned reslen
= 0;
1434 Debug(LDAP_DEBUG_ARGS
,
1435 "==> sasl_bind: dn=\"%s\" mech=%s datalen=%ld\n",
1436 op
->o_req_dn
.bv_len
? op
->o_req_dn
.bv_val
: "",
1437 op
->o_conn
->c_sasl_bind_in_progress
? "<continuing>" :
1438 op
->o_conn
->c_sasl_bind_mech
.bv_val
,
1439 op
->orb_cred
.bv_len
);
1442 send_ldap_error( op
, rs
, LDAP_UNAVAILABLE
,
1443 "SASL unavailable on this session" );
1447 #define START( ctx, mech, cred, clen, resp, rlen, err ) \
1448 sasl_server_start( ctx, mech, cred, clen, resp, rlen )
1449 #define STEP( ctx, cred, clen, resp, rlen, err ) \
1450 sasl_server_step( ctx, cred, clen, resp, rlen )
1452 if ( !op
->o_conn
->c_sasl_bind_in_progress
) {
1453 /* If we already authenticated once, must use a new context */
1454 if ( op
->o_conn
->c_sasl_done
) {
1456 const char *authid
= NULL
;
1457 sasl_getprop( ctx
, SASL_SSF_EXTERNAL
, (void *)&ssf
);
1458 sasl_getprop( ctx
, SASL_AUTH_EXTERNAL
, (void *)&authid
);
1459 if ( authid
) authid
= ch_strdup( authid
);
1460 if ( ctx
!= op
->o_conn
->c_sasl_sockctx
) {
1461 sasl_dispose( &ctx
);
1463 op
->o_conn
->c_sasl_authctx
= NULL
;
1465 slap_sasl_open( op
->o_conn
, 1 );
1466 ctx
= op
->o_conn
->c_sasl_authctx
;
1468 sasl_setprop( ctx
, SASL_SSF_EXTERNAL
, &ssf
);
1469 sasl_setprop( ctx
, SASL_AUTH_EXTERNAL
, authid
);
1470 ch_free( (char *)authid
);
1474 op
->o_conn
->c_sasl_bind_mech
.bv_val
,
1475 op
->orb_cred
.bv_val
, op
->orb_cred
.bv_len
,
1476 (SASL_CONST
char **)&response
.bv_val
, &reslen
, &rs
->sr_text
);
1480 op
->orb_cred
.bv_val
, op
->orb_cred
.bv_len
,
1481 (SASL_CONST
char **)&response
.bv_val
, &reslen
, &rs
->sr_text
);
1484 response
.bv_len
= reslen
;
1486 if ( sc
== SASL_OK
) {
1487 sasl_ssf_t
*ssf
= NULL
;
1489 ber_dupbv_x( &op
->orb_edn
, &op
->o_conn
->c_sasl_dn
, op
->o_tmpmemctx
);
1490 BER_BVZERO( &op
->o_conn
->c_sasl_dn
);
1491 op
->o_conn
->c_sasl_done
= 1;
1493 rs
->sr_err
= LDAP_SUCCESS
;
1495 (void) sasl_getprop( ctx
, SASL_SSF
, (void *)&ssf
);
1496 op
->orb_ssf
= ssf
? *ssf
: 0;
1500 ldap_pvt_thread_mutex_lock( &op
->o_conn
->c_mutex
);
1501 op
->o_conn
->c_sasl_layers
++;
1503 /* If there's an old layer, set sockctx to NULL to
1504 * tell connection_read() to wait for us to finish.
1505 * Otherwise there is a race condition: we have to
1506 * send the Bind response using the old security
1507 * context and then remove it before reading any
1510 if ( op
->o_conn
->c_sasl_sockctx
) {
1511 ctx
= op
->o_conn
->c_sasl_sockctx
;
1512 op
->o_conn
->c_sasl_sockctx
= NULL
;
1514 op
->o_conn
->c_sasl_sockctx
= op
->o_conn
->c_sasl_authctx
;
1516 ldap_pvt_thread_mutex_unlock( &op
->o_conn
->c_mutex
);
1519 /* Must send response using old security layer */
1520 if (response
.bv_len
) rs
->sr_sasldata
= &response
;
1521 send_ldap_sasl( op
, rs
);
1523 /* Now dispose of the old security layer.
1526 ldap_pvt_thread_mutex_lock( &op
->o_conn
->c_mutex
);
1527 ldap_pvt_sasl_remove( op
->o_conn
->c_sb
);
1528 op
->o_conn
->c_sasl_sockctx
= op
->o_conn
->c_sasl_authctx
;
1529 ldap_pvt_thread_mutex_unlock( &op
->o_conn
->c_mutex
);
1530 sasl_dispose( &ctx
);
1532 } else if ( sc
== SASL_CONTINUE
) {
1533 rs
->sr_err
= LDAP_SASL_BIND_IN_PROGRESS
,
1534 rs
->sr_text
= sasl_errdetail( ctx
);
1535 rs
->sr_sasldata
= &response
;
1536 send_ldap_sasl( op
, rs
);
1539 BER_BVZERO( &op
->o_conn
->c_sasl_dn
);
1540 rs
->sr_text
= sasl_errdetail( ctx
);
1541 rs
->sr_err
= slap_sasl_err2ldap( sc
),
1542 send_ldap_result( op
, rs
);
1545 Debug(LDAP_DEBUG_TRACE
, "<== slap_sasl_bind: rc=%d\n", rs
->sr_err
, 0, 0);
1547 #elif defined(SLAP_BUILTIN_SASL)
1548 /* built-in SASL implementation */
1549 SASL_CTX
*ctx
= op
->o_conn
->c_sasl_authctx
;
1551 if ( ctx
== NULL
) {
1552 send_ldap_error( op
, rs
, LDAP_OTHER
,
1553 "Internal SASL Error" );
1555 } else if ( bvmatch( &ext_bv
, &op
->o_conn
->c_sasl_bind_mech
) ) {
1558 if( op
->orb_cred
.bv_len
) {
1559 rs
->sr_text
= "proxy authorization not support";
1560 rs
->sr_err
= LDAP_UNWILLING_TO_PERFORM
;
1561 send_ldap_result( op
, rs
);
1564 op
->orb_edn
= ctx
->sc_external_id
;
1565 rs
->sr_err
= LDAP_SUCCESS
;
1566 rs
->sr_sasldata
= NULL
;
1567 send_ldap_sasl( op
, rs
);
1571 send_ldap_error( op
, rs
, LDAP_AUTH_METHOD_NOT_SUPPORTED
,
1572 "requested SASL mechanism not supported" );
1575 send_ldap_error( op
, rs
, LDAP_AUTH_METHOD_NOT_SUPPORTED
,
1576 "SASL not supported" );
1582 char* slap_sasl_secprops( const char *in
)
1584 #ifdef HAVE_CYRUS_SASL
1585 int rc
= ldap_pvt_sasl_secprops( in
, &sasl_secprops
);
1587 return rc
== LDAP_SUCCESS
? NULL
: "Invalid security properties";
1589 return "SASL not supported";
1593 void slap_sasl_secprops_unparse( struct berval
*bv
)
1595 #ifdef HAVE_CYRUS_SASL
1596 ldap_pvt_sasl_secprops_unparse( &sasl_secprops
, bv
);
1600 #ifdef HAVE_CYRUS_SASL
1602 slap_sasl_setpass( Operation
*op
, SlapReply
*rs
)
1604 struct berval id
= BER_BVNULL
; /* needs to come from connection */
1605 struct berval
new = BER_BVNULL
;
1606 struct berval old
= BER_BVNULL
;
1608 assert( ber_bvcmp( &slap_EXOP_MODIFY_PASSWD
, &op
->ore_reqoid
) == 0 );
1610 rs
->sr_err
= sasl_getprop( op
->o_conn
->c_sasl_authctx
, SASL_USERNAME
,
1611 (SASL_CONST
void **)(char *)&id
.bv_val
);
1613 if( rs
->sr_err
!= SASL_OK
) {
1614 rs
->sr_text
= "unable to retrieve SASL username";
1615 rs
->sr_err
= LDAP_OTHER
;
1619 Debug( LDAP_DEBUG_ARGS
, "==> slap_sasl_setpass: \"%s\"\n",
1620 id
.bv_val
? id
.bv_val
: "", 0, 0 );
1622 rs
->sr_err
= slap_passwd_parse( op
->ore_reqdata
,
1623 NULL
, &old
, &new, &rs
->sr_text
);
1625 if( rs
->sr_err
!= LDAP_SUCCESS
) {
1629 if( new.bv_len
== 0 ) {
1630 slap_passwd_generate(&new);
1632 if( new.bv_len
== 0 ) {
1633 rs
->sr_text
= "password generation failed.";
1634 rs
->sr_err
= LDAP_OTHER
;
1638 rs
->sr_rspdata
= slap_passwd_return( &new );
1641 rs
->sr_err
= sasl_setpass( op
->o_conn
->c_sasl_authctx
, id
.bv_val
,
1642 new.bv_val
, new.bv_len
, old
.bv_val
, old
.bv_len
, 0 );
1643 if( rs
->sr_err
!= SASL_OK
) {
1644 rs
->sr_text
= sasl_errdetail( op
->o_conn
->c_sasl_authctx
);
1646 switch(rs
->sr_err
) {
1648 rs
->sr_err
= LDAP_SUCCESS
;
1658 rs
->sr_err
= LDAP_OTHER
;
1664 #endif /* HAVE_CYRUS_SASL */
1666 /* Take any sort of identity string and return a DN with the "dn:" prefix. The
1667 * string returned in *dn is in its own allocated memory, and must be free'd
1668 * by the calling process. -Mark Adamson, Carnegie Mellon
1670 * The "dn:" prefix is no longer used anywhere inside slapd. It is only used
1671 * on strings passed in directly from SASL. -Howard Chu, Symas Corp.
1678 int slap_sasl_getdn( Connection
*conn
, Operation
*op
, struct berval
*id
,
1679 char *user_realm
, struct berval
*dn
, int flags
)
1681 int rc
, is_dn
= SET_NONE
, do_norm
= 1;
1682 struct berval dn2
, *mech
;
1684 assert( conn
!= NULL
);
1685 assert( id
!= NULL
);
1687 Debug( LDAP_DEBUG_ARGS
, "slap_sasl_getdn: conn %lu id=%s [len=%lu]\n",
1689 BER_BVISNULL( id
) ? "NULL" : ( BER_BVISEMPTY( id
) ? "<empty>" : id
->bv_val
),
1690 BER_BVISNULL( id
) ? 0 : ( BER_BVISEMPTY( id
) ? 0 :
1691 (unsigned long) id
->bv_len
) );
1694 op
= conn
->c_sasl_bindop
;
1696 assert( op
!= NULL
);
1700 if ( !BER_BVISNULL( id
) ) {
1701 /* Blatantly anonymous ID */
1702 static struct berval bv_anonymous
= BER_BVC( "anonymous" );
1704 if ( ber_bvstrcasecmp( id
, &bv_anonymous
) == 0 ) {
1705 return( LDAP_SUCCESS
);
1709 /* FIXME: if empty, should we stop? */
1710 BER_BVSTR( id
, "" );
1713 if ( !BER_BVISEMPTY( &conn
->c_sasl_bind_mech
) ) {
1714 mech
= &conn
->c_sasl_bind_mech
;
1716 mech
= &conn
->c_authmech
;
1719 /* An authcID needs to be converted to authzID form. Set the
1720 * values directly into *dn; they will be normalized later. (and
1721 * normalizing always makes a new copy.) An ID from a TLS certificate
1722 * is already normalized, so copy it and skip normalization.
1724 if( flags
& SLAP_GETDN_AUTHCID
) {
1725 if( bvmatch( mech
, &ext_bv
)) {
1726 /* EXTERNAL DNs are already normalized */
1727 assert( !BER_BVISNULL( id
) );
1731 ber_dupbv_x( dn
, id
, op
->o_tmpmemctx
);
1734 /* convert to u:<username> form */
1740 if( is_dn
== SET_NONE
) {
1741 if( !strncasecmp( id
->bv_val
, "u:", STRLENOF( "u:" ) ) ) {
1743 dn
->bv_val
= id
->bv_val
+ STRLENOF( "u:" );
1744 dn
->bv_len
= id
->bv_len
- STRLENOF( "u:" );
1746 } else if ( !strncasecmp( id
->bv_val
, "dn:", STRLENOF( "dn:" ) ) ) {
1748 dn
->bv_val
= id
->bv_val
+ STRLENOF( "dn:" );
1749 dn
->bv_len
= id
->bv_len
- STRLENOF( "dn:" );
1753 /* No other possibilities from here */
1754 if( is_dn
== SET_NONE
) {
1756 return( LDAP_INAPPROPRIATE_AUTH
);
1759 /* Username strings */
1760 if( is_dn
== SET_U
) {
1761 /* ITS#3419: values may need escape */
1763 LDAPAVA
*RDNs
[ 4 ][ 2 ];
1768 DN
[ irdn
] = RDNs
[ irdn
];
1769 RDNs
[ irdn
][ 0 ] = &AVAs
[ irdn
];
1770 AVAs
[ irdn
].la_attr
= slap_schema
.si_ad_uid
->ad_cname
;
1771 AVAs
[ irdn
].la_value
= *dn
;
1772 AVAs
[ irdn
].la_flags
= LDAP_AVA_NULL
;
1773 AVAs
[ irdn
].la_private
= NULL
;
1774 RDNs
[ irdn
][ 1 ] = NULL
;
1776 if ( user_realm
&& *user_realm
) {
1778 DN
[ irdn
] = RDNs
[ irdn
];
1779 RDNs
[ irdn
][ 0 ] = &AVAs
[ irdn
];
1780 AVAs
[ irdn
].la_attr
= slap_schema
.si_ad_cn
->ad_cname
;
1781 ber_str2bv( user_realm
, 0, 0, &AVAs
[ irdn
].la_value
);
1782 AVAs
[ irdn
].la_flags
= LDAP_AVA_NULL
;
1783 AVAs
[ irdn
].la_private
= NULL
;
1784 RDNs
[ irdn
][ 1 ] = NULL
;
1787 if ( !BER_BVISNULL( mech
) ) {
1789 DN
[ irdn
] = RDNs
[ irdn
];
1790 RDNs
[ irdn
][ 0 ] = &AVAs
[ irdn
];
1791 AVAs
[ irdn
].la_attr
= slap_schema
.si_ad_cn
->ad_cname
;
1792 AVAs
[ irdn
].la_value
= *mech
;
1793 AVAs
[ irdn
].la_flags
= LDAP_AVA_NULL
;
1794 AVAs
[ irdn
].la_private
= NULL
;
1795 RDNs
[ irdn
][ 1 ] = NULL
;
1799 DN
[ irdn
] = RDNs
[ irdn
];
1800 RDNs
[ irdn
][ 0 ] = &AVAs
[ irdn
];
1801 AVAs
[ irdn
].la_attr
= slap_schema
.si_ad_cn
->ad_cname
;
1802 BER_BVSTR( &AVAs
[ irdn
].la_value
, "auth" );
1803 AVAs
[ irdn
].la_flags
= LDAP_AVA_NULL
;
1804 AVAs
[ irdn
].la_private
= NULL
;
1805 RDNs
[ irdn
][ 1 ] = NULL
;
1810 rc
= ldap_dn2bv_x( DN
, dn
, LDAP_DN_FORMAT_LDAPV3
,
1812 if ( rc
!= LDAP_SUCCESS
) {
1817 Debug( LDAP_DEBUG_TRACE
,
1818 "slap_sasl_getdn: u:id converted to %s\n",
1823 /* Dup the DN in any case, so we don't risk
1824 * leaks or dangling pointers later,
1825 * and the DN value is '\0' terminated */
1826 ber_dupbv_x( &dn2
, dn
, op
->o_tmpmemctx
);
1827 dn
->bv_val
= dn2
.bv_val
;
1830 /* All strings are in DN form now. Normalize if needed. */
1832 rc
= dnNormalize( 0, NULL
, NULL
, dn
, &dn2
, op
->o_tmpmemctx
);
1834 /* User DNs were constructed above and must be freed now */
1835 slap_sl_free( dn
->bv_val
, op
->o_tmpmemctx
);
1837 if ( rc
!= LDAP_SUCCESS
) {
1844 /* Run thru regexp */
1845 slap_sasl2dn( op
, dn
, &dn2
, flags
);
1846 if( !BER_BVISNULL( &dn2
) ) {
1847 slap_sl_free( dn
->bv_val
, op
->o_tmpmemctx
);
1849 Debug( LDAP_DEBUG_TRACE
,
1850 "slap_sasl_getdn: dn:id converted to %s\n",
1854 return( LDAP_SUCCESS
);