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 DN form can now have a type specifier, that influences
39 * how they are used in related operations.
43 * dn[.{exact|regex}]:<val>
45 * dn.exact: the value must pass normalization and is used
47 * dn.regex: the value is treated as a regular expression
48 * in matching DN values in saslAuthz{To|From}
50 * dn: for backwards compatibility reasons, the value
51 * is treated as a regular expression, and thus
52 * it is not normalized nor validated; it is used
53 * in exact or regex comparisons based on the
57 typedef struct sasl_regexp {
58 char *sr_match; /* regexp match pattern */
59 char *sr_replace; /* regexp replace pattern */
60 regex_t sr_workspace; /* workspace for regexp engine */
61 int sr_offset[SASLREGEX_REPLACE+2]; /* offsets of $1,$2... in *replace */
64 static int nSaslRegexp = 0;
65 static SaslRegexp_t *SaslRegexp = NULL;
67 /* What SASL proxy authorization policies are allowed? */
68 #define SASL_AUTHZ_NONE 0
69 #define SASL_AUTHZ_FROM 1
70 #define SASL_AUTHZ_TO 2
72 static int authz_policy = SASL_AUTHZ_NONE;
74 int slap_sasl_setpolicy( const char *arg )
76 int rc = LDAP_SUCCESS;
78 if ( strcasecmp( arg, "none" ) == 0 ) {
79 authz_policy = SASL_AUTHZ_NONE;
80 } else if ( strcasecmp( arg, "from" ) == 0 ) {
81 authz_policy = SASL_AUTHZ_FROM;
82 } else if ( strcasecmp( arg, "to" ) == 0 ) {
83 authz_policy = SASL_AUTHZ_TO;
84 } else if ( strcasecmp( arg, "both" ) == 0 ) {
85 authz_policy = SASL_AUTHZ_FROM | SASL_AUTHZ_TO;
92 int slap_parse_user( struct berval *id, struct berval *user,
93 struct berval *realm, struct berval *mech )
105 assert( u == 'u' || u == 'U' );
108 * u[.mech[/realm]]:user
111 user->bv_val = strchr( id->bv_val, ':' );
112 if ( user->bv_val == NULL ) {
113 return LDAP_PROTOCOL_ERROR;
115 user->bv_val[ 0 ] = '\0';
117 user->bv_len = id->bv_len - ( user->bv_val - id->bv_val );
119 mech->bv_val = strchr( id->bv_val, '.' );
120 if ( mech->bv_val != NULL ) {
121 mech->bv_val[ 0 ] = '\0';
124 realm->bv_val = strchr( id->bv_val, '/' );
126 if ( realm->bv_val ) {
127 mech->bv_len = realm->bv_val - mech->bv_val - 1;
128 realm->bv_len = user->bv_val - realm->bv_val - 1;
130 mech->bv_len = user->bv_val - mech->bv_val - 1;
134 realm->bv_val = NULL;
137 if ( id->bv_val[ 1 ] != '\0' ) {
138 return LDAP_PROTOCOL_ERROR;
141 if ( mech->bv_val != NULL ) {
142 assert( mech->bv_val == id->bv_val + 2 );
144 AC_MEMCPY( mech->bv_val - 2, mech->bv_val, mech->bv_len + 1 );
148 if ( realm->bv_val ) {
149 assert( realm->bv_val >= id->bv_val + 2 );
151 AC_MEMCPY( realm->bv_val - 2, realm->bv_val, realm->bv_len + 1 );
155 if ( user->bv_val > id->bv_val + 2 ) {
158 user->bv_val[ 0 ] = u;
159 user->bv_val[ 1 ] = ':';
165 static int slap_parseURI( Operation *op, struct berval *uri,
166 struct berval *base, struct berval *nbase,
167 int *scope, Filter **filter, struct berval *fstr )
173 assert( uri != NULL && uri->bv_val != NULL );
176 nbase->bv_val = NULL;
184 LDAP_LOG( TRANSPORT, ENTRY,
185 "slap_parseURI: parsing %s\n", uri->bv_val, 0, 0 );
187 Debug( LDAP_DEBUG_TRACE,
188 "slap_parseURI: parsing %s\n", uri->bv_val, 0, 0 );
191 rc = LDAP_PROTOCOL_ERROR;
192 if ( !strncasecmp( uri->bv_val, "dn", sizeof( "dn" ) - 1 ) ) {
193 bv.bv_val = uri->bv_val + sizeof( "dn" ) - 1;
195 if ( bv.bv_val[ 0 ] == '.' ) {
198 if ( !strncasecmp( bv.bv_val, "exact:", sizeof( "exact:" ) - 1 ) ) {
199 bv.bv_val += sizeof( "exact" ) - 1;
200 *scope = LDAP_X_SCOPE_EXACT;
202 } else if ( !strncasecmp( bv.bv_val, "regex:", sizeof( "regex:" ) - 1 ) ) {
203 bv.bv_val += sizeof( "regex" ) - 1;
204 *scope = LDAP_X_SCOPE_REGEX;
206 } else if ( !strncasecmp( bv.bv_val, "children:", sizeof( "chldren:" ) - 1 ) ) {
207 bv.bv_val += sizeof( "children" ) - 1;
208 *scope = LDAP_X_SCOPE_CHILDREN;
210 } else if ( !strncasecmp( bv.bv_val, "subtree:", sizeof( "subtree:" ) - 1 ) ) {
211 bv.bv_val += sizeof( "subtree" ) - 1;
212 *scope = LDAP_X_SCOPE_SUBTREE;
215 return LDAP_PROTOCOL_ERROR;
219 if ( bv.bv_val[ 0 ] != ':' ) {
220 return LDAP_PROTOCOL_ERROR;
224 bv.bv_val += strspn( bv.bv_val, " " );
225 /* jump here in case no type specification was present
226 * and uir was not an URI... HEADS-UP: assuming EXACT */
227 is_dn: bv.bv_len = uri->bv_len - (bv.bv_val - uri->bv_val);
230 case LDAP_X_SCOPE_EXACT:
231 case LDAP_X_SCOPE_CHILDREN:
232 case LDAP_X_SCOPE_SUBTREE:
233 rc = dnNormalize( 0, NULL, NULL, &bv, nbase, op->o_tmpmemctx );
234 if( rc != LDAP_SUCCESS ) {
239 case LDAP_X_SCOPE_REGEX:
240 ber_dupbv_x( nbase, &bv, op->o_tmpmemctx );
251 } else if ( ( uri->bv_val[ 0 ] == 'u' || uri->bv_val[ 0 ] == 'U' )
252 && ( uri->bv_val[ 1 ] == ':'
253 || uri->bv_val[ 1 ] == '/'
254 || uri->bv_val[ 1 ] == '.' ) )
256 Connection c = *op->o_conn;
257 char buf[ SLAP_LDAPDN_MAXLEN ];
258 struct berval id = { uri->bv_len, (char *)buf },
263 if ( sizeof( buf ) <= uri->bv_len ) {
264 return LDAP_INVALID_SYNTAX;
267 strncpy( buf, uri->bv_val, sizeof( buf ) );
269 rc = slap_parse_user( &id, &user, &realm, &mech );
270 if ( rc != LDAP_SUCCESS ) {
275 c.c_sasl_bind_mech = mech;
277 c.c_sasl_bind_mech.bv_val = "AUTHZ";
278 c.c_sasl_bind_mech.bv_len = sizeof( "AUTHZ" ) - 1;
281 rc = slap_sasl_getdn( &c, op, user.bv_val, user.bv_len,
282 realm.bv_val, nbase, SLAP_GETDN_AUTHZID );
284 if ( rc == LDAP_SUCCESS ) {
285 *scope = LDAP_X_SCOPE_EXACT;
291 rc = ldap_url_parse( uri->bv_val, &ludp );
292 if ( rc == LDAP_URL_ERR_BADSCHEME ) {
293 /* last chance: assume it's a(n exact) DN ... */
294 bv.bv_val = uri->bv_val;
295 *scope = LDAP_X_SCOPE_EXACT;
299 if ( rc != LDAP_URL_SUCCESS ) {
300 return LDAP_PROTOCOL_ERROR;
303 if (( ludp->lud_host && *ludp->lud_host )
304 || ludp->lud_attrs || ludp->lud_exts )
306 /* host part must be empty */
307 /* attrs and extensions parts must be empty */
308 rc = LDAP_PROTOCOL_ERROR;
313 *scope = ludp->lud_scope;
315 /* Grab the filter */
316 if ( ludp->lud_filter ) {
317 *filter = str2filter_x( op, ludp->lud_filter );
318 if ( *filter == NULL ) {
319 rc = LDAP_PROTOCOL_ERROR;
322 ber_str2bv( ludp->lud_filter, 0, 0, fstr );
325 /* Grab the searchbase */
326 ber_str2bv( ludp->lud_dn, 0, 0, base );
327 rc = dnNormalize( 0, NULL, NULL, base, nbase, op->o_tmpmemctx );
330 if( rc != LDAP_SUCCESS ) {
331 if( *filter ) filter_free_x( op, *filter );
337 /* Don't free these, return them to caller */
338 ludp->lud_filter = NULL;
342 ldap_free_urldesc( ludp );
346 static int slap_sasl_rx_off(char *rep, int *off)
351 /* Precompile replace pattern. Find the $<n> placeholders */
354 for ( c = rep; *c; c++ ) {
355 if ( *c == '\\' && c[1] ) {
360 if ( n == SASLREGEX_REPLACE ) {
362 LDAP_LOG( TRANSPORT, ERR,
363 "slap_sasl_rx_off: \"%s\" has too many $n "
364 "placeholders (max %d)\n", rep, SASLREGEX_REPLACE, 0 );
366 Debug( LDAP_DEBUG_ANY,
367 "SASL replace pattern %s has too many $n "
368 "placeholders (max %d)\n",
369 rep, SASLREGEX_REPLACE, 0 );
372 return( LDAP_OTHER );
379 /* Final placeholder, after the last $n */
383 return( LDAP_SUCCESS );
386 int slap_sasl_regexp_config( const char *match, const char *replace )
391 SaslRegexp = (SaslRegexp_t *) ch_realloc( (char *) SaslRegexp,
392 (nSaslRegexp + 1) * sizeof(SaslRegexp_t) );
394 reg = &SaslRegexp[nSaslRegexp];
396 reg->sr_match = ch_strdup( match );
397 reg->sr_replace = ch_strdup( replace );
399 /* Precompile matching pattern */
400 rc = regcomp( ®->sr_workspace, reg->sr_match, REG_EXTENDED|REG_ICASE );
403 LDAP_LOG( TRANSPORT, ERR,
404 "slap_sasl_regexp_config: \"%s\" could not be compiled.\n",
405 reg->sr_match, 0, 0 );
407 Debug( LDAP_DEBUG_ANY,
408 "SASL match pattern %s could not be compiled by regexp engine\n",
409 reg->sr_match, 0, 0 );
412 return( LDAP_OTHER );
415 rc = slap_sasl_rx_off( reg->sr_replace, reg->sr_offset );
416 if ( rc != LDAP_SUCCESS ) return rc;
419 return( LDAP_SUCCESS );
423 /* Perform replacement on regexp matches */
424 static void slap_sasl_rx_exp(
428 const char *saslname,
432 int i, n, len, insert;
434 /* Get the total length of the final URI */
438 while( off[n] >= 0 ) {
439 /* Len of next section from replacement string (x,y,z above) */
440 len += off[n] - off[n-1] - 2;
444 /* Len of string from saslname that matched next $i (b,d above) */
445 i = rep[ off[n] + 1 ] - '0';
446 len += str[i].rm_eo - str[i].rm_so;
449 out->bv_val = sl_malloc( len + 1, ctx );
452 /* Fill in URI with replace string, replacing $i as we go */
455 while( off[n] >= 0) {
456 /* Paste in next section from replacement string (x,y,z above) */
457 len = off[n] - off[n-1] - 2;
458 strncpy( out->bv_val+insert, rep + off[n-1] + 2, len);
463 /* Paste in string from saslname that matched next $i (b,d above) */
464 i = rep[ off[n] + 1 ] - '0';
465 len = str[i].rm_eo - str[i].rm_so;
466 strncpy( out->bv_val+insert, saslname + str[i].rm_so, len );
472 out->bv_val[insert] = '\0';
475 /* Take the passed in SASL name and attempt to convert it into an
476 LDAP URI to find the matching LDAP entry, using the pattern matching
477 strings given in the saslregexp config file directive(s) */
479 static int slap_sasl_regexp( struct berval *in, struct berval *out, void *ctx )
481 char *saslname = in->bv_val;
483 regmatch_t sr_strings[SASLREGEX_REPLACE]; /* strings matching $1,$2 ... */
486 memset( out, 0, sizeof( *out ) );
489 LDAP_LOG( TRANSPORT, ENTRY,
490 "slap_sasl_regexp: converting SASL name %s\n", saslname, 0, 0 );
492 Debug( LDAP_DEBUG_TRACE, "slap_sasl_regexp: converting SASL name %s\n",
496 if (( saslname == NULL ) || ( nSaslRegexp == 0 )) {
500 /* Match the normalized SASL name to the saslregexp patterns */
501 for( reg = SaslRegexp,i=0; i<nSaslRegexp; i++,reg++ ) {
502 if ( regexec( ®->sr_workspace, saslname, SASLREGEX_REPLACE,
503 sr_strings, 0) == 0 )
507 if( i >= nSaslRegexp ) return( 0 );
510 * The match pattern may have been of the form "a(b.*)c(d.*)e" and the
511 * replace pattern of the form "x$1y$2z". The returned string needs
512 * to replace the $1,$2 with the strings that matched (b.*) and (d.*)
514 slap_sasl_rx_exp( reg->sr_replace, reg->sr_offset,
515 sr_strings, saslname, out, ctx );
518 LDAP_LOG( TRANSPORT, ENTRY,
519 "slap_sasl_regexp: converted SASL name to %s\n",
520 out->bv_len ? out->bv_val : "", 0, 0 );
522 Debug( LDAP_DEBUG_TRACE,
523 "slap_sasl_regexp: converted SASL name to %s\n",
524 out->bv_len ? out->bv_val : "", 0, 0 );
530 /* This callback actually does some work...*/
531 static int sasl_sc_sasl2dn( Operation *o, SlapReply *rs )
533 struct berval *ndn = o->o_callback->sc_private;
535 if (rs->sr_type != REP_SEARCH) return 0;
537 /* We only want to be called once */
539 o->o_tmpfree(ndn->bv_val, o->o_tmpmemctx);
543 LDAP_LOG( TRANSPORT, DETAIL1,
544 "slap_sc_sasl2dn: search DN returned more than 1 entry\n", 0, 0, 0 );
546 Debug( LDAP_DEBUG_TRACE,
547 "slap_sc_sasl2dn: search DN returned more than 1 entry\n", 0, 0, 0 );
552 ber_dupbv_x(ndn, &rs->sr_entry->e_nname, o->o_tmpmemctx);
557 typedef struct smatch_info {
562 static int sasl_sc_smatch( Operation *o, SlapReply *rs )
564 smatch_info *sm = o->o_callback->sc_private;
566 if (rs->sr_type != REP_SEARCH) return 0;
568 if (dn_match(sm->dn, &rs->sr_entry->e_nname)) {
570 return -1; /* short-circuit the search */
577 * Map a SASL regexp rule to a DN. If the rule is just a DN or a scope=base
578 * URI, just strcmp the rule (or its searchbase) to the *assertDN. Otherwise,
579 * the rule must be used as an internal search for entries. If that search
580 * returns the *assertDN entry, the match is successful.
582 * The assertDN should not have the dn: prefix
586 int slap_sasl_match( Operation *opx, struct berval *rule,
587 struct berval *assertDN, struct berval *authc )
592 slap_callback cb = { NULL, sasl_sc_smatch, NULL, NULL };
594 SlapReply rs = {REP_RESULT};
597 LDAP_LOG( TRANSPORT, ENTRY,
598 "slap_sasl_match: comparing DN %s to rule %s\n",
599 assertDN->bv_val, rule->bv_val,0 );
601 Debug( LDAP_DEBUG_TRACE,
602 "===>slap_sasl_match: comparing DN %s to rule %s\n",
603 assertDN->bv_val, rule->bv_val, 0 );
606 rc = slap_parseURI( opx, rule, &op.o_req_dn,
607 &op.o_req_ndn, &op.oq_search.rs_scope, &op.oq_search.rs_filter,
609 if( rc != LDAP_SUCCESS ) goto CONCLUDED;
611 /* Massive shortcut: search scope == base */
612 switch ( op.oq_search.rs_scope ) {
613 case LDAP_SCOPE_BASE:
614 case LDAP_X_SCOPE_EXACT:
616 if ( dn_match( &op.o_req_ndn, assertDN ) ) {
619 rc = LDAP_INAPPROPRIATE_AUTH;
623 case LDAP_X_SCOPE_CHILDREN:
624 case LDAP_X_SCOPE_SUBTREE:
626 int d = assertDN->bv_len - op.o_req_ndn.bv_len;
628 rc = LDAP_INAPPROPRIATE_AUTH;
630 if ( d == 0 && op.oq_search.rs_scope == LDAP_X_SCOPE_SUBTREE ) {
633 } else if ( d > 0 ) {
634 struct berval bv = { op.o_req_ndn.bv_len, assertDN->bv_val + d };
636 if ( bv.bv_val[ -1 ] == ',' && dn_match( &op.o_req_ndn, &bv ) ) {
643 case LDAP_X_SCOPE_REGEX:
644 rc = regcomp(®, op.o_req_ndn.bv_val,
645 REG_EXTENDED|REG_ICASE|REG_NOSUB);
647 rc = regexec(®, assertDN->bv_val, 0, NULL, 0);
653 rc = LDAP_INAPPROPRIATE_AUTH;
661 /* Must run an internal search. */
662 if ( op.oq_search.rs_filter == NULL ) {
663 rc = LDAP_FILTER_ERROR;
668 LDAP_LOG( TRANSPORT, DETAIL1,
669 "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
670 op.o_req_ndn.bv_val, op.oq_search.rs_scope, 0 );
672 Debug( LDAP_DEBUG_TRACE,
673 "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
674 op.o_req_ndn.bv_val, op.oq_search.rs_scope, 0 );
677 op.o_bd = select_backend( &op.o_req_ndn, 0, 1 );
678 if(( op.o_bd == NULL ) || ( op.o_bd->be_search == NULL)) {
679 rc = LDAP_INAPPROPRIATE_AUTH;
687 op.o_tag = LDAP_REQ_SEARCH;
688 op.o_protocol = LDAP_VERSION3;
691 op.o_time = slap_get_time();
692 op.o_do_not_cache = 1;
693 op.o_is_auth_check = 1;
694 op.o_threadctx = opx->o_threadctx;
695 op.o_tmpmemctx = opx->o_tmpmemctx;
696 op.o_tmpmfuncs = opx->o_tmpmfuncs;
700 op.o_conn = opx->o_conn;
701 op.o_connid = opx->o_connid;
702 op.o_req_dn = op.o_req_ndn;
704 op.o_bd->be_search( &op, &rs );
709 rc = LDAP_INAPPROPRIATE_AUTH;
713 if( op.o_req_dn.bv_len ) ch_free( op.o_req_dn.bv_val );
714 if( op.o_req_ndn.bv_len ) sl_free( op.o_req_ndn.bv_val, opx->o_tmpmemctx );
715 if( op.oq_search.rs_filter ) filter_free_x( opx, op.oq_search.rs_filter );
716 if( op.ors_filterstr.bv_len ) ch_free( op.ors_filterstr.bv_val );
719 LDAP_LOG( TRANSPORT, ENTRY,
720 "slap_sasl_match: comparison returned %d\n", rc, 0, 0 );
722 Debug( LDAP_DEBUG_TRACE,
723 "<===slap_sasl_match: comparison returned %d\n", rc, 0, 0);
731 * This function answers the question, "Can this ID authorize to that ID?",
732 * based on authorization rules. The rules are stored in the *searchDN, in the
733 * attribute named by *attr. If any of those rules map to the *assertDN, the
734 * authorization is approved.
736 * The DNs should not have the dn: prefix
739 slap_sasl_check_authz( Operation *op,
740 struct berval *searchDN,
741 struct berval *assertDN,
742 AttributeDescription *ad,
743 struct berval *authc )
749 LDAP_LOG( TRANSPORT, ENTRY,
750 "slap_sasl_check_authz: does %s match %s rule in %s?\n",
751 assertDN->bv_val, ad->ad_cname.bv_val, searchDN->bv_val);
753 Debug( LDAP_DEBUG_TRACE,
754 "==>slap_sasl_check_authz: does %s match %s rule in %s?\n",
755 assertDN->bv_val, ad->ad_cname.bv_val, searchDN->bv_val);
758 rc = backend_attribute( op, NULL,
759 searchDN, ad, &vals );
760 if( rc != LDAP_SUCCESS ) goto COMPLETE;
762 /* Check if the *assertDN matches any **vals */
764 for( i=0; vals[i].bv_val != NULL; i++ ) {
765 rc = slap_sasl_match( op, &vals[i], assertDN, authc );
766 if ( rc == LDAP_SUCCESS ) goto COMPLETE;
769 rc = LDAP_INAPPROPRIATE_AUTH;
772 if( vals ) ber_bvarray_free_x( vals, op->o_tmpmemctx );
775 LDAP_LOG( TRANSPORT, RESULTS,
776 "slap_sasl_check_authz: %s check returning %s\n",
777 ad->ad_cname.bv_val, rc, 0 );
779 Debug( LDAP_DEBUG_TRACE,
780 "<==slap_sasl_check_authz: %s check returning %d\n",
781 ad->ad_cname.bv_val, rc, 0);
788 * Given a SASL name (e.g. "UID=name,cn=REALM,cn=MECH,cn=AUTH")
789 * return the LDAP DN to which it matches. The SASL regexp rules in the config
790 * file turn the SASL name into an LDAP URI. If the URI is just a DN (or a
791 * search with scope=base), just return the URI (or its searchbase). Otherwise
792 * an internal search must be done, and if that search returns exactly one
793 * entry, return the DN of that one entry.
795 void slap_sasl2dn( Operation *opx,
796 struct berval *saslname, struct berval *sasldn )
799 slap_callback cb = { NULL, sasl_sc_sasl2dn, NULL, NULL };
801 SlapReply rs = {REP_RESULT};
802 struct berval regout = { 0, NULL };
805 LDAP_LOG( TRANSPORT, ENTRY,
806 "slap_sasl2dn: converting SASL name %s to DN.\n",
807 saslname->bv_val, 0, 0 );
809 Debug( LDAP_DEBUG_TRACE, "==>slap_sasl2dn: "
810 "converting SASL name %s to a DN\n",
811 saslname->bv_val, 0,0 );
814 sasldn->bv_val = NULL;
816 cb.sc_private = sasldn;
818 /* Convert the SASL name into a minimal URI */
819 if( !slap_sasl_regexp( saslname, ®out, opx->o_tmpmemctx ) ) {
823 rc = slap_parseURI( opx, ®out, &op.o_req_dn,
824 &op.o_req_ndn, &op.oq_search.rs_scope, &op.oq_search.rs_filter,
826 if( regout.bv_val ) sl_free( regout.bv_val, opx->o_tmpmemctx );
827 if( rc != LDAP_SUCCESS ) {
831 /* Must do an internal search */
832 op.o_bd = select_backend( &op.o_req_ndn, 0, 1 );
834 /* Massive shortcut: search scope == base */
835 switch ( op.oq_search.rs_scope ) {
836 case LDAP_SCOPE_BASE:
837 case LDAP_X_SCOPE_EXACT:
838 *sasldn = op.o_req_ndn;
839 op.o_req_ndn.bv_len = 0;
840 op.o_req_ndn.bv_val = NULL;
841 /* intentionally continue to next case */
843 case LDAP_X_SCOPE_REGEX:
844 case LDAP_X_SCOPE_SUBTREE:
845 case LDAP_X_SCOPE_CHILDREN:
846 /* correctly parsed, but illegal */
849 case LDAP_SCOPE_ONELEVEL:
850 case LDAP_SCOPE_SUBTREE:
855 /* catch unhandled cases (there shouldn't be) */
860 LDAP_LOG( TRANSPORT, DETAIL1,
861 "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
862 op.o_req_ndn.bv_val, op.oq_search.rs_scope, 0 );
864 Debug( LDAP_DEBUG_TRACE,
865 "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
866 op.o_req_ndn.bv_val, op.oq_search.rs_scope, 0 );
869 if(( op.o_bd == NULL ) || ( op.o_bd->be_search == NULL)) {
873 op.o_conn = opx->o_conn;
874 op.o_connid = opx->o_connid;
875 op.o_tag = LDAP_REQ_SEARCH;
876 op.o_protocol = LDAP_VERSION3;
877 op.o_ndn = opx->o_conn->c_ndn;
879 op.o_time = slap_get_time();
880 op.o_do_not_cache = 1;
881 op.o_is_auth_check = 1;
882 op.o_threadctx = opx->o_threadctx;
883 op.o_tmpmemctx = opx->o_tmpmemctx;
884 op.o_tmpmfuncs = opx->o_tmpmfuncs;
888 op.oq_search.rs_deref = LDAP_DEREF_NEVER;
889 op.oq_search.rs_slimit = 1;
890 op.oq_search.rs_attrsonly = 1;
891 op.o_req_dn = op.o_req_ndn;
893 op.o_bd->be_search( &op, &rs );
896 if( sasldn->bv_len ) {
897 opx->o_conn->c_authz_backend = op.o_bd;
899 if( op.o_req_dn.bv_len ) ch_free( op.o_req_dn.bv_val );
900 if( op.o_req_ndn.bv_len ) sl_free( op.o_req_ndn.bv_val, opx->o_tmpmemctx );
901 if( op.oq_search.rs_filter ) filter_free_x( opx, op.oq_search.rs_filter );
902 if( op.ors_filterstr.bv_len ) ch_free( op.ors_filterstr.bv_val );
905 LDAP_LOG( TRANSPORT, ENTRY,
906 "slap_sasl2dn: Converted SASL name to %s\n",
907 sasldn->bv_len ? sasldn->bv_val : "<nothing>", 0, 0 );
909 Debug( LDAP_DEBUG_TRACE, "<==slap_sasl2dn: Converted SASL name to %s\n",
910 sasldn->bv_len ? sasldn->bv_val : "<nothing>", 0, 0 );
917 /* Check if a bind can SASL authorize to another identity.
918 * The DNs should not have the dn: prefix
921 int slap_sasl_authorized( Operation *op,
922 struct berval *authcDN, struct berval *authzDN )
924 int rc = LDAP_INAPPROPRIATE_AUTH;
926 /* User binding as anonymous */
927 if ( authzDN == NULL ) {
933 LDAP_LOG( TRANSPORT, ENTRY,
934 "slap_sasl_authorized: can %s become %s?\n",
935 authcDN->bv_val, authzDN->bv_val, 0 );
937 Debug( LDAP_DEBUG_TRACE,
938 "==>slap_sasl_authorized: can %s become %s?\n",
939 authcDN->bv_val, authzDN->bv_val, 0 );
942 /* If person is authorizing to self, succeed */
943 if ( dn_match( authcDN, authzDN ) ) {
948 /* Allow the manager to authorize as any DN. */
949 if( op->o_conn->c_authz_backend && be_isroot( op->o_conn->c_authz_backend, authcDN )) {
954 /* Check source rules */
955 if( authz_policy & SASL_AUTHZ_TO ) {
956 rc = slap_sasl_check_authz( op, authcDN, authzDN,
957 slap_schema.si_ad_saslAuthzTo, authcDN );
958 if( rc == LDAP_SUCCESS ) {
963 /* Check destination rules */
964 if( authz_policy & SASL_AUTHZ_FROM ) {
965 rc = slap_sasl_check_authz( op, authzDN, authcDN,
966 slap_schema.si_ad_saslAuthzFrom, authcDN );
967 if( rc == LDAP_SUCCESS ) {
972 rc = LDAP_INAPPROPRIATE_AUTH;
977 LDAP_LOG( TRANSPORT, RESULTS, "slap_sasl_authorized: return %d\n", rc,0,0 );
979 Debug( LDAP_DEBUG_TRACE,
980 "<== slap_sasl_authorized: return %d\n", rc, 0, 0 );