2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1998-2003 The OpenLDAP Foundation.
5 * Portions Copyright 2000 Mark Adamson, Carnegie Mellon.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
21 #include <ac/stdlib.h>
22 #include <ac/string.h>
30 #define SASLREGEX_REPLACE 10
32 #define LDAP_X_SCOPE_EXACT ((ber_int_t) 0x0010)
33 #define LDAP_X_SCOPE_REGEX ((ber_int_t) 0x0020)
34 #define LDAP_X_SCOPE_CHILDREN ((ber_int_t) 0x0030)
35 #define LDAP_X_SCOPE_SUBTREE ((ber_int_t) 0x0040)
38 * IDs in DNauthzid form can now have a type specifier, that
39 * influences how they are used in related operations.
41 * syntax: dn[.{exact|regex}]:<val>
43 * dn.exact: the value must pass normalization and is used
45 * dn.regex: the value is treated as a regular expression
46 * in matching DN values in saslAuthz{To|From}
48 * dn: for backwards compatibility reasons, the value
49 * is treated as a regular expression, and thus
50 * it is not normalized nor validated; it is used
51 * in exact or regex comparisons based on the
54 * IDs in DNauthzid form can now have a type specifier, that
55 * influences how they are used in related operations.
57 * syntax: u[.mech[/realm]]:<val>
59 * where mech is a SIMPLE, AUTHZ, or a SASL mechanism name
60 * and realm is mechanism specific realm (separate to those
61 * which are representable as part of the principal).
64 typedef struct sasl_regexp {
65 char *sr_match; /* regexp match pattern */
66 char *sr_replace; /* regexp replace pattern */
67 regex_t sr_workspace; /* workspace for regexp engine */
68 int sr_offset[SASLREGEX_REPLACE+2]; /* offsets of $1,$2... in *replace */
71 static int nSaslRegexp = 0;
72 static SaslRegexp_t *SaslRegexp = NULL;
74 /* What SASL proxy authorization policies are allowed? */
75 #define SASL_AUTHZ_NONE 0
76 #define SASL_AUTHZ_FROM 1
77 #define SASL_AUTHZ_TO 2
79 static int authz_policy = SASL_AUTHZ_NONE;
81 int slap_sasl_setpolicy( const char *arg )
83 int rc = LDAP_SUCCESS;
85 if ( strcasecmp( arg, "none" ) == 0 ) {
86 authz_policy = SASL_AUTHZ_NONE;
87 } else if ( strcasecmp( arg, "from" ) == 0 ) {
88 authz_policy = SASL_AUTHZ_FROM;
89 } else if ( strcasecmp( arg, "to" ) == 0 ) {
90 authz_policy = SASL_AUTHZ_TO;
91 } else if ( strcasecmp( arg, "both" ) == 0 ) {
92 authz_policy = SASL_AUTHZ_FROM | SASL_AUTHZ_TO;
99 int slap_parse_user( struct berval *id, struct berval *user,
100 struct berval *realm, struct berval *mech )
105 assert( id->bv_val );
112 if ( u != 'u' && u != 'U' ) {
113 /* called with something other than u: */
114 return LDAP_PROTOCOL_ERROR;
118 * u[.mech[/realm]]:user
121 user->bv_val = strchr( id->bv_val, ':' );
122 if ( user->bv_val == NULL ) {
123 return LDAP_PROTOCOL_ERROR;
125 user->bv_val[ 0 ] = '\0';
127 user->bv_len = id->bv_len - ( user->bv_val - id->bv_val );
129 mech->bv_val = strchr( id->bv_val, '.' );
130 if ( mech->bv_val != NULL ) {
131 mech->bv_val[ 0 ] = '\0';
134 realm->bv_val = strchr( mech->bv_val, '/' );
136 if ( realm->bv_val ) {
137 realm->bv_val[ 0 ] = '\0';
139 mech->bv_len = realm->bv_val - mech->bv_val - 1;
140 realm->bv_len = user->bv_val - realm->bv_val - 1;
142 mech->bv_len = user->bv_val - mech->bv_val - 1;
146 realm->bv_val = NULL;
149 if ( id->bv_val[ 1 ] != '\0' ) {
150 return LDAP_PROTOCOL_ERROR;
153 if ( mech->bv_val != NULL ) {
154 assert( mech->bv_val == id->bv_val + 2 );
156 AC_MEMCPY( mech->bv_val - 2, mech->bv_val, mech->bv_len + 1 );
160 if ( realm->bv_val ) {
161 assert( realm->bv_val >= id->bv_val + 2 );
163 AC_MEMCPY( realm->bv_val - 2, realm->bv_val, realm->bv_len + 1 );
167 /* leave "u:" before user */
170 user->bv_val[ 0 ] = u;
171 user->bv_val[ 1 ] = ':';
176 static int slap_parseURI( Operation *op, struct berval *uri,
177 struct berval *base, struct berval *nbase,
178 int *scope, Filter **filter, struct berval *fstr )
184 assert( uri != NULL && uri->bv_val != NULL );
187 nbase->bv_val = NULL;
195 LDAP_LOG( TRANSPORT, ENTRY,
196 "slap_parseURI: parsing %s\n", uri->bv_val, 0, 0 );
198 Debug( LDAP_DEBUG_TRACE,
199 "slap_parseURI: parsing %s\n", uri->bv_val, 0, 0 );
202 rc = LDAP_PROTOCOL_ERROR;
203 if ( !strncasecmp( uri->bv_val, "dn", sizeof( "dn" ) - 1 ) ) {
204 bv.bv_val = uri->bv_val + sizeof( "dn" ) - 1;
206 if ( bv.bv_val[ 0 ] == '.' ) {
209 if ( !strncasecmp( bv.bv_val, "exact:", sizeof( "exact:" ) - 1 ) ) {
210 bv.bv_val += sizeof( "exact" ) - 1;
211 *scope = LDAP_X_SCOPE_EXACT;
213 } else if ( !strncasecmp( bv.bv_val, "regex:", sizeof( "regex:" ) - 1 ) ) {
214 bv.bv_val += sizeof( "regex" ) - 1;
215 *scope = LDAP_X_SCOPE_REGEX;
217 } else if ( !strncasecmp( bv.bv_val, "children:", sizeof( "chldren:" ) - 1 ) ) {
218 bv.bv_val += sizeof( "children" ) - 1;
219 *scope = LDAP_X_SCOPE_CHILDREN;
221 } else if ( !strncasecmp( bv.bv_val, "subtree:", sizeof( "subtree:" ) - 1 ) ) {
222 bv.bv_val += sizeof( "subtree" ) - 1;
223 *scope = LDAP_X_SCOPE_SUBTREE;
226 return LDAP_PROTOCOL_ERROR;
230 if ( bv.bv_val[ 0 ] != ':' ) {
231 return LDAP_PROTOCOL_ERROR;
235 bv.bv_val += strspn( bv.bv_val, " " );
236 /* jump here in case no type specification was present
237 * and uir was not an URI... HEADS-UP: assuming EXACT */
238 is_dn: bv.bv_len = uri->bv_len - (bv.bv_val - uri->bv_val);
241 case LDAP_X_SCOPE_EXACT:
242 case LDAP_X_SCOPE_CHILDREN:
243 case LDAP_X_SCOPE_SUBTREE:
244 rc = dnNormalize( 0, NULL, NULL, &bv, nbase, op->o_tmpmemctx );
245 if( rc != LDAP_SUCCESS ) {
250 case LDAP_X_SCOPE_REGEX:
251 ber_dupbv_x( nbase, &bv, op->o_tmpmemctx );
262 } else if ( ( uri->bv_val[ 0 ] == 'u' || uri->bv_val[ 0 ] == 'U' )
263 && ( uri->bv_val[ 1 ] == ':'
264 || uri->bv_val[ 1 ] == '/'
265 || uri->bv_val[ 1 ] == '.' ) )
267 Connection c = *op->o_conn;
268 char buf[ SLAP_LDAPDN_MAXLEN ];
274 if ( sizeof( buf ) <= uri->bv_len ) {
275 return LDAP_INVALID_SYNTAX;
278 id.bv_len = uri->bv_len;
280 strncpy( buf, uri->bv_val, sizeof( buf ) );
282 rc = slap_parse_user( &id, &user, &realm, &mech );
283 if ( rc != LDAP_SUCCESS ) {
288 c.c_sasl_bind_mech = mech;
290 c.c_sasl_bind_mech.bv_val = "AUTHZ";
291 c.c_sasl_bind_mech.bv_len = sizeof( "AUTHZ" ) - 1;
294 rc = slap_sasl_getdn( &c, op, user.bv_val, user.bv_len,
295 realm.bv_val, nbase, SLAP_GETDN_AUTHZID );
297 if ( rc == LDAP_SUCCESS ) {
298 *scope = LDAP_X_SCOPE_EXACT;
304 rc = ldap_url_parse( uri->bv_val, &ludp );
305 if ( rc == LDAP_URL_ERR_BADSCHEME ) {
306 /* last chance: assume it's a(n exact) DN ... */
307 bv.bv_val = uri->bv_val;
308 *scope = LDAP_X_SCOPE_EXACT;
312 if ( rc != LDAP_URL_SUCCESS ) {
313 return LDAP_PROTOCOL_ERROR;
316 if (( ludp->lud_host && *ludp->lud_host )
317 || ludp->lud_attrs || ludp->lud_exts )
319 /* host part must be empty */
320 /* attrs and extensions parts must be empty */
321 rc = LDAP_PROTOCOL_ERROR;
326 *scope = ludp->lud_scope;
328 /* Grab the filter */
329 if ( ludp->lud_filter ) {
330 *filter = str2filter_x( op, ludp->lud_filter );
331 if ( *filter == NULL ) {
332 rc = LDAP_PROTOCOL_ERROR;
335 ber_str2bv( ludp->lud_filter, 0, 0, fstr );
338 /* Grab the searchbase */
339 ber_str2bv( ludp->lud_dn, 0, 0, base );
340 rc = dnNormalize( 0, NULL, NULL, base, nbase, op->o_tmpmemctx );
343 if( rc != LDAP_SUCCESS ) {
344 if( *filter ) filter_free_x( op, *filter );
350 /* Don't free these, return them to caller */
351 ludp->lud_filter = NULL;
355 ldap_free_urldesc( ludp );
359 static int slap_sasl_rx_off(char *rep, int *off)
364 /* Precompile replace pattern. Find the $<n> placeholders */
367 for ( c = rep; *c; c++ ) {
368 if ( *c == '\\' && c[1] ) {
373 if ( n == SASLREGEX_REPLACE ) {
375 LDAP_LOG( TRANSPORT, ERR,
376 "slap_sasl_rx_off: \"%s\" has too many $n "
377 "placeholders (max %d)\n", rep, SASLREGEX_REPLACE, 0 );
379 Debug( LDAP_DEBUG_ANY,
380 "SASL replace pattern %s has too many $n "
381 "placeholders (max %d)\n",
382 rep, SASLREGEX_REPLACE, 0 );
385 return( LDAP_OTHER );
392 /* Final placeholder, after the last $n */
396 return( LDAP_SUCCESS );
399 int slap_sasl_regexp_config( const char *match, const char *replace )
404 SaslRegexp = (SaslRegexp_t *) ch_realloc( (char *) SaslRegexp,
405 (nSaslRegexp + 1) * sizeof(SaslRegexp_t) );
407 reg = &SaslRegexp[nSaslRegexp];
409 reg->sr_match = ch_strdup( match );
410 reg->sr_replace = ch_strdup( replace );
412 /* Precompile matching pattern */
413 rc = regcomp( ®->sr_workspace, reg->sr_match, REG_EXTENDED|REG_ICASE );
416 LDAP_LOG( TRANSPORT, ERR,
417 "slap_sasl_regexp_config: \"%s\" could not be compiled.\n",
418 reg->sr_match, 0, 0 );
420 Debug( LDAP_DEBUG_ANY,
421 "SASL match pattern %s could not be compiled by regexp engine\n",
422 reg->sr_match, 0, 0 );
425 return( LDAP_OTHER );
428 rc = slap_sasl_rx_off( reg->sr_replace, reg->sr_offset );
429 if ( rc != LDAP_SUCCESS ) return rc;
432 return( LDAP_SUCCESS );
436 /* Perform replacement on regexp matches */
437 static void slap_sasl_rx_exp(
441 const char *saslname,
445 int i, n, len, insert;
447 /* Get the total length of the final URI */
451 while( off[n] >= 0 ) {
452 /* Len of next section from replacement string (x,y,z above) */
453 len += off[n] - off[n-1] - 2;
457 /* Len of string from saslname that matched next $i (b,d above) */
458 i = rep[ off[n] + 1 ] - '0';
459 len += str[i].rm_eo - str[i].rm_so;
462 out->bv_val = sl_malloc( len + 1, ctx );
465 /* Fill in URI with replace string, replacing $i as we go */
468 while( off[n] >= 0) {
469 /* Paste in next section from replacement string (x,y,z above) */
470 len = off[n] - off[n-1] - 2;
471 strncpy( out->bv_val+insert, rep + off[n-1] + 2, len);
476 /* Paste in string from saslname that matched next $i (b,d above) */
477 i = rep[ off[n] + 1 ] - '0';
478 len = str[i].rm_eo - str[i].rm_so;
479 strncpy( out->bv_val+insert, saslname + str[i].rm_so, len );
485 out->bv_val[insert] = '\0';
488 /* Take the passed in SASL name and attempt to convert it into an
489 LDAP URI to find the matching LDAP entry, using the pattern matching
490 strings given in the saslregexp config file directive(s) */
492 static int slap_sasl_regexp( struct berval *in, struct berval *out, void *ctx )
494 char *saslname = in->bv_val;
496 regmatch_t sr_strings[SASLREGEX_REPLACE]; /* strings matching $1,$2 ... */
499 memset( out, 0, sizeof( *out ) );
502 LDAP_LOG( TRANSPORT, ENTRY,
503 "slap_sasl_regexp: converting SASL name %s\n", saslname, 0, 0 );
505 Debug( LDAP_DEBUG_TRACE, "slap_sasl_regexp: converting SASL name %s\n",
509 if (( saslname == NULL ) || ( nSaslRegexp == 0 )) {
513 /* Match the normalized SASL name to the saslregexp patterns */
514 for( reg = SaslRegexp,i=0; i<nSaslRegexp; i++,reg++ ) {
515 if ( regexec( ®->sr_workspace, saslname, SASLREGEX_REPLACE,
516 sr_strings, 0) == 0 )
520 if( i >= nSaslRegexp ) return( 0 );
523 * The match pattern may have been of the form "a(b.*)c(d.*)e" and the
524 * replace pattern of the form "x$1y$2z". The returned string needs
525 * to replace the $1,$2 with the strings that matched (b.*) and (d.*)
527 slap_sasl_rx_exp( reg->sr_replace, reg->sr_offset,
528 sr_strings, saslname, out, ctx );
531 LDAP_LOG( TRANSPORT, ENTRY,
532 "slap_sasl_regexp: converted SASL name to %s\n",
533 out->bv_len ? out->bv_val : "", 0, 0 );
535 Debug( LDAP_DEBUG_TRACE,
536 "slap_sasl_regexp: converted SASL name to %s\n",
537 out->bv_len ? out->bv_val : "", 0, 0 );
543 /* This callback actually does some work...*/
544 static int sasl_sc_sasl2dn( Operation *o, SlapReply *rs )
546 struct berval *ndn = o->o_callback->sc_private;
548 if (rs->sr_type != REP_SEARCH) return 0;
550 /* We only want to be called once */
552 o->o_tmpfree(ndn->bv_val, o->o_tmpmemctx);
556 LDAP_LOG( TRANSPORT, DETAIL1,
557 "slap_sc_sasl2dn: search DN returned more than 1 entry\n", 0, 0, 0 );
559 Debug( LDAP_DEBUG_TRACE,
560 "slap_sc_sasl2dn: search DN returned more than 1 entry\n", 0, 0, 0 );
565 ber_dupbv_x(ndn, &rs->sr_entry->e_nname, o->o_tmpmemctx);
570 typedef struct smatch_info {
575 static int sasl_sc_smatch( Operation *o, SlapReply *rs )
577 smatch_info *sm = o->o_callback->sc_private;
579 if (rs->sr_type != REP_SEARCH) return 0;
581 if (dn_match(sm->dn, &rs->sr_entry->e_nname)) {
583 return -1; /* short-circuit the search */
590 * Map a SASL regexp rule to a DN. If the rule is just a DN or a scope=base
591 * URI, just strcmp the rule (or its searchbase) to the *assertDN. Otherwise,
592 * the rule must be used as an internal search for entries. If that search
593 * returns the *assertDN entry, the match is successful.
595 * The assertDN should not have the dn: prefix
599 int slap_sasl_match( Operation *opx, struct berval *rule,
600 struct berval *assertDN, struct berval *authc )
605 slap_callback cb = { NULL, sasl_sc_smatch, NULL, NULL };
607 SlapReply rs = {REP_RESULT};
610 LDAP_LOG( TRANSPORT, ENTRY,
611 "slap_sasl_match: comparing DN %s to rule %s\n",
612 assertDN->bv_val, rule->bv_val,0 );
614 Debug( LDAP_DEBUG_TRACE,
615 "===>slap_sasl_match: comparing DN %s to rule %s\n",
616 assertDN->bv_val, rule->bv_val, 0 );
619 rc = slap_parseURI( opx, rule, &op.o_req_dn,
620 &op.o_req_ndn, &op.oq_search.rs_scope, &op.oq_search.rs_filter,
622 if( rc != LDAP_SUCCESS ) goto CONCLUDED;
624 /* Massive shortcut: search scope == base */
625 switch ( op.oq_search.rs_scope ) {
626 case LDAP_SCOPE_BASE:
627 case LDAP_X_SCOPE_EXACT:
629 if ( dn_match( &op.o_req_ndn, assertDN ) ) {
632 rc = LDAP_INAPPROPRIATE_AUTH;
636 case LDAP_X_SCOPE_CHILDREN:
637 case LDAP_X_SCOPE_SUBTREE:
639 int d = assertDN->bv_len - op.o_req_ndn.bv_len;
641 rc = LDAP_INAPPROPRIATE_AUTH;
643 if ( d == 0 && op.oq_search.rs_scope == LDAP_X_SCOPE_SUBTREE ) {
646 } else if ( d > 0 ) {
649 bv.bv_len = op.o_req_ndn.bv_len;
650 bv.bv_val = assertDN->bv_val + d;
652 if ( bv.bv_val[ -1 ] == ',' && dn_match( &op.o_req_ndn, &bv ) ) {
659 case LDAP_X_SCOPE_REGEX:
660 rc = regcomp(®, op.o_req_ndn.bv_val,
661 REG_EXTENDED|REG_ICASE|REG_NOSUB);
663 rc = regexec(®, assertDN->bv_val, 0, NULL, 0);
669 rc = LDAP_INAPPROPRIATE_AUTH;
677 /* Must run an internal search. */
678 if ( op.oq_search.rs_filter == NULL ) {
679 rc = LDAP_FILTER_ERROR;
684 LDAP_LOG( TRANSPORT, DETAIL1,
685 "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
686 op.o_req_ndn.bv_val, op.oq_search.rs_scope, 0 );
688 Debug( LDAP_DEBUG_TRACE,
689 "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
690 op.o_req_ndn.bv_val, op.oq_search.rs_scope, 0 );
693 op.o_bd = select_backend( &op.o_req_ndn, 0, 1 );
694 if(( op.o_bd == NULL ) || ( op.o_bd->be_search == NULL)) {
695 rc = LDAP_INAPPROPRIATE_AUTH;
703 op.o_tag = LDAP_REQ_SEARCH;
704 op.o_protocol = LDAP_VERSION3;
707 op.o_time = slap_get_time();
708 op.o_do_not_cache = 1;
709 op.o_is_auth_check = 1;
710 op.o_threadctx = opx->o_threadctx;
711 op.o_tmpmemctx = opx->o_tmpmemctx;
712 op.o_tmpmfuncs = opx->o_tmpmfuncs;
716 op.o_conn = opx->o_conn;
717 op.o_connid = opx->o_connid;
718 op.o_req_dn = op.o_req_ndn;
720 op.o_bd->be_search( &op, &rs );
725 rc = LDAP_INAPPROPRIATE_AUTH;
729 if( op.o_req_dn.bv_len ) ch_free( op.o_req_dn.bv_val );
730 if( op.o_req_ndn.bv_len ) sl_free( op.o_req_ndn.bv_val, opx->o_tmpmemctx );
731 if( op.oq_search.rs_filter ) filter_free_x( opx, op.oq_search.rs_filter );
732 if( op.ors_filterstr.bv_len ) ch_free( op.ors_filterstr.bv_val );
735 LDAP_LOG( TRANSPORT, ENTRY,
736 "slap_sasl_match: comparison returned %d\n", rc, 0, 0 );
738 Debug( LDAP_DEBUG_TRACE,
739 "<===slap_sasl_match: comparison returned %d\n", rc, 0, 0);
747 * This function answers the question, "Can this ID authorize to that ID?",
748 * based on authorization rules. The rules are stored in the *searchDN, in the
749 * attribute named by *attr. If any of those rules map to the *assertDN, the
750 * authorization is approved.
752 * The DNs should not have the dn: prefix
755 slap_sasl_check_authz( Operation *op,
756 struct berval *searchDN,
757 struct berval *assertDN,
758 AttributeDescription *ad,
759 struct berval *authc )
765 LDAP_LOG( TRANSPORT, ENTRY,
766 "slap_sasl_check_authz: does %s match %s rule in %s?\n",
767 assertDN->bv_val, ad->ad_cname.bv_val, searchDN->bv_val);
769 Debug( LDAP_DEBUG_TRACE,
770 "==>slap_sasl_check_authz: does %s match %s rule in %s?\n",
771 assertDN->bv_val, ad->ad_cname.bv_val, searchDN->bv_val);
774 rc = backend_attribute( op, NULL,
775 searchDN, ad, &vals );
776 if( rc != LDAP_SUCCESS ) goto COMPLETE;
778 /* Check if the *assertDN matches any **vals */
780 for( i=0; vals[i].bv_val != NULL; i++ ) {
781 rc = slap_sasl_match( op, &vals[i], assertDN, authc );
782 if ( rc == LDAP_SUCCESS ) goto COMPLETE;
785 rc = LDAP_INAPPROPRIATE_AUTH;
788 if( vals ) ber_bvarray_free_x( vals, op->o_tmpmemctx );
791 LDAP_LOG( TRANSPORT, RESULTS,
792 "slap_sasl_check_authz: %s check returning %s\n",
793 ad->ad_cname.bv_val, rc, 0 );
795 Debug( LDAP_DEBUG_TRACE,
796 "<==slap_sasl_check_authz: %s check returning %d\n",
797 ad->ad_cname.bv_val, rc, 0);
804 * Given a SASL name (e.g. "UID=name,cn=REALM,cn=MECH,cn=AUTH")
805 * return the LDAP DN to which it matches. The SASL regexp rules in the config
806 * file turn the SASL name into an LDAP URI. If the URI is just a DN (or a
807 * search with scope=base), just return the URI (or its searchbase). Otherwise
808 * an internal search must be done, and if that search returns exactly one
809 * entry, return the DN of that one entry.
811 void slap_sasl2dn( Operation *opx,
812 struct berval *saslname, struct berval *sasldn )
815 slap_callback cb = { NULL, sasl_sc_sasl2dn, NULL, NULL };
817 SlapReply rs = {REP_RESULT};
818 struct berval regout = { 0, NULL };
821 LDAP_LOG( TRANSPORT, ENTRY,
822 "slap_sasl2dn: converting SASL name %s to DN.\n",
823 saslname->bv_val, 0, 0 );
825 Debug( LDAP_DEBUG_TRACE, "==>slap_sasl2dn: "
826 "converting SASL name %s to a DN\n",
827 saslname->bv_val, 0,0 );
830 sasldn->bv_val = NULL;
832 cb.sc_private = sasldn;
834 /* Convert the SASL name into a minimal URI */
835 if( !slap_sasl_regexp( saslname, ®out, opx->o_tmpmemctx ) ) {
839 rc = slap_parseURI( opx, ®out, &op.o_req_dn,
840 &op.o_req_ndn, &op.oq_search.rs_scope, &op.oq_search.rs_filter,
842 if( regout.bv_val ) sl_free( regout.bv_val, opx->o_tmpmemctx );
843 if( rc != LDAP_SUCCESS ) {
847 /* Must do an internal search */
848 op.o_bd = select_backend( &op.o_req_ndn, 0, 1 );
850 /* Massive shortcut: search scope == base */
851 switch ( op.oq_search.rs_scope ) {
852 case LDAP_SCOPE_BASE:
853 case LDAP_X_SCOPE_EXACT:
854 *sasldn = op.o_req_ndn;
855 op.o_req_ndn.bv_len = 0;
856 op.o_req_ndn.bv_val = NULL;
857 /* intentionally continue to next case */
859 case LDAP_X_SCOPE_REGEX:
860 case LDAP_X_SCOPE_SUBTREE:
861 case LDAP_X_SCOPE_CHILDREN:
862 /* correctly parsed, but illegal */
865 case LDAP_SCOPE_ONELEVEL:
866 case LDAP_SCOPE_SUBTREE:
867 case LDAP_SCOPE_SUBORDINATE:
872 /* catch unhandled cases (there shouldn't be) */
877 LDAP_LOG( TRANSPORT, DETAIL1,
878 "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
879 op.o_req_ndn.bv_val, op.oq_search.rs_scope, 0 );
881 Debug( LDAP_DEBUG_TRACE,
882 "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
883 op.o_req_ndn.bv_val, op.oq_search.rs_scope, 0 );
886 if(( op.o_bd == NULL ) || ( op.o_bd->be_search == NULL)) {
890 op.o_conn = opx->o_conn;
891 op.o_connid = opx->o_connid;
892 op.o_tag = LDAP_REQ_SEARCH;
893 op.o_protocol = LDAP_VERSION3;
894 op.o_ndn = opx->o_conn->c_ndn;
896 op.o_time = slap_get_time();
897 op.o_do_not_cache = 1;
898 op.o_is_auth_check = 1;
899 op.o_threadctx = opx->o_threadctx;
900 op.o_tmpmemctx = opx->o_tmpmemctx;
901 op.o_tmpmfuncs = opx->o_tmpmfuncs;
905 op.oq_search.rs_deref = LDAP_DEREF_NEVER;
906 op.oq_search.rs_slimit = 1;
907 op.oq_search.rs_attrsonly = 1;
908 op.o_req_dn = op.o_req_ndn;
910 op.o_bd->be_search( &op, &rs );
913 if( sasldn->bv_len ) {
914 opx->o_conn->c_authz_backend = op.o_bd;
916 if( op.o_req_dn.bv_len ) ch_free( op.o_req_dn.bv_val );
917 if( op.o_req_ndn.bv_len ) sl_free( op.o_req_ndn.bv_val, opx->o_tmpmemctx );
918 if( op.oq_search.rs_filter ) filter_free_x( opx, op.oq_search.rs_filter );
919 if( op.ors_filterstr.bv_len ) ch_free( op.ors_filterstr.bv_val );
922 LDAP_LOG( TRANSPORT, ENTRY,
923 "slap_sasl2dn: Converted SASL name to %s\n",
924 sasldn->bv_len ? sasldn->bv_val : "<nothing>", 0, 0 );
926 Debug( LDAP_DEBUG_TRACE, "<==slap_sasl2dn: Converted SASL name to %s\n",
927 sasldn->bv_len ? sasldn->bv_val : "<nothing>", 0, 0 );
934 /* Check if a bind can SASL authorize to another identity.
935 * The DNs should not have the dn: prefix
938 int slap_sasl_authorized( Operation *op,
939 struct berval *authcDN, struct berval *authzDN )
941 int rc = LDAP_INAPPROPRIATE_AUTH;
943 /* User binding as anonymous */
944 if ( authzDN == NULL ) {
950 LDAP_LOG( TRANSPORT, ENTRY,
951 "slap_sasl_authorized: can %s become %s?\n",
952 authcDN->bv_val, authzDN->bv_val, 0 );
954 Debug( LDAP_DEBUG_TRACE,
955 "==>slap_sasl_authorized: can %s become %s?\n",
956 authcDN->bv_val, authzDN->bv_val, 0 );
959 /* If person is authorizing to self, succeed */
960 if ( dn_match( authcDN, authzDN ) ) {
965 /* Allow the manager to authorize as any DN. */
966 if( op->o_conn->c_authz_backend && be_isroot( op->o_conn->c_authz_backend, authcDN )) {
971 /* Check source rules */
972 if( authz_policy & SASL_AUTHZ_TO ) {
973 rc = slap_sasl_check_authz( op, authcDN, authzDN,
974 slap_schema.si_ad_saslAuthzTo, authcDN );
975 if( rc == LDAP_SUCCESS ) {
980 /* Check destination rules */
981 if( authz_policy & SASL_AUTHZ_FROM ) {
982 rc = slap_sasl_check_authz( op, authzDN, authcDN,
983 slap_schema.si_ad_saslAuthzFrom, authcDN );
984 if( rc == LDAP_SUCCESS ) {
989 rc = LDAP_INAPPROPRIATE_AUTH;
994 LDAP_LOG( TRANSPORT, RESULTS, "slap_sasl_authorized: return %d\n", rc,0,0 );
996 Debug( LDAP_DEBUG_TRACE,
997 "<== slap_sasl_authorized: return %d\n", rc, 0, 0 );