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_EXACTREGEX (LDAP_X_SCOPE_EXACT|LDAP_X_SCOPE_REGEX)
37 * IDs in DN form can now have a type specifier, that influences
38 * how they are used in related operations.
42 * dn[.{exact|regex}]:<val>
44 * dn.exact: the value must pass normalization and is used
46 * dn.regex: the value is treated as a regular expression
47 * in matching DN values in saslAuthz{To|From}
49 * dn: for backwards compatibility reasons, the value
50 * is treated as a regular expression, and thus
51 * it is not normalized nor validated; it is used
52 * in exact or regex comparisons based on the
56 typedef struct sasl_regexp {
57 char *sr_match; /* regexp match pattern */
58 char *sr_replace; /* regexp replace pattern */
59 regex_t sr_workspace; /* workspace for regexp engine */
60 int sr_offset[SASLREGEX_REPLACE+2]; /* offsets of $1,$2... in *replace */
63 static int nSaslRegexp = 0;
64 static SaslRegexp_t *SaslRegexp = NULL;
66 /* What SASL proxy authorization policies are allowed? */
67 #define SASL_AUTHZ_NONE 0
68 #define SASL_AUTHZ_FROM 1
69 #define SASL_AUTHZ_TO 2
71 static int authz_policy = SASL_AUTHZ_NONE;
73 int slap_sasl_setpolicy( const char *arg )
75 int rc = LDAP_SUCCESS;
77 if ( strcasecmp( arg, "none" ) == 0 ) {
78 authz_policy = SASL_AUTHZ_NONE;
79 } else if ( strcasecmp( arg, "from" ) == 0 ) {
80 authz_policy = SASL_AUTHZ_FROM;
81 } else if ( strcasecmp( arg, "to" ) == 0 ) {
82 authz_policy = SASL_AUTHZ_TO;
83 } else if ( strcasecmp( arg, "both" ) == 0 ) {
84 authz_policy = SASL_AUTHZ_FROM | SASL_AUTHZ_TO;
91 static int slap_parseURI( Operation *op, struct berval *uri,
92 struct berval *base, struct berval *nbase,
93 int *scope, Filter **filter, struct berval *fstr )
99 assert( uri != NULL && uri->bv_val != NULL );
102 nbase->bv_val = NULL;
110 LDAP_LOG( TRANSPORT, ENTRY,
111 "slap_parseURI: parsing %s\n", uri->bv_val, 0, 0 );
113 Debug( LDAP_DEBUG_TRACE,
114 "slap_parseURI: parsing %s\n", uri->bv_val, 0, 0 );
117 /* If it does not look like a URI, assume it is a DN */
118 /* explicitly set to exact: will skip regcomp/regexec */
119 if( !strncasecmp( uri->bv_val, "dn.exact:", sizeof("dn.exact:")-1 ) ) {
120 bv.bv_val = uri->bv_val + sizeof("dn.exact:")-1;
121 bv.bv_val += strspn( bv.bv_val, " " );
123 is_dn_exact: bv.bv_len = uri->bv_len - (bv.bv_val - uri->bv_val);
125 rc = dnNormalize( 0, NULL, NULL, &bv, nbase, op->o_tmpmemctx );
126 if( rc == LDAP_SUCCESS ) {
127 *scope = LDAP_X_SCOPE_EXACT;
132 /* unqualified: to be liberal, it is left to the caller
133 * whether to normalize or regcomp() it */
134 } else if( !strncasecmp( uri->bv_val, "dn:", sizeof("dn:")-1 ) ) {
135 bv.bv_val = uri->bv_val + sizeof("dn:")-1;
136 bv.bv_val += strspn( bv.bv_val, " " );
138 is_dn: bv.bv_len = uri->bv_len - (bv.bv_val - uri->bv_val);
141 rc = dnNormalize( 0, NULL, NULL, &bv, nbase, op->o_tmpmemctx );
142 if( rc == LDAP_SUCCESS ) {
143 *scope = LDAP_X_SCOPE_EXACTREGEX;
146 *scope = LDAP_X_SCOPE_EXACTREGEX;
151 /* explicitly set to regex: it will be regcomp'd/regexec'd */
152 } else if ( !strncasecmp( uri->bv_val, "dn.regex:", sizeof("dn.regex:")-1 ) ) {
153 bv.bv_val = uri->bv_val + sizeof("dn.regex:")-1;
154 bv.bv_val += strspn( bv.bv_val, " " );
156 is_dn_regex: bv.bv_len = uri->bv_len - (bv.bv_val - uri->bv_val);
158 ber_dupbv_x( nbase, &bv, op->o_tmpmemctx );
159 *scope = LDAP_X_SCOPE_REGEX;
163 rc = ldap_url_parse( uri->bv_val, &ludp );
164 if ( rc == LDAP_URL_ERR_BADSCHEME ) {
165 bv.bv_val = uri->bv_val;
169 if ( rc != LDAP_URL_SUCCESS ) {
170 return LDAP_PROTOCOL_ERROR;
173 if (( ludp->lud_host && *ludp->lud_host )
174 || ludp->lud_attrs || ludp->lud_exts )
176 /* host part must be empty */
177 /* attrs and extensions parts must be empty */
178 rc = LDAP_PROTOCOL_ERROR;
183 *scope = ludp->lud_scope;
185 /* Grab the filter */
186 if ( ludp->lud_filter ) {
187 *filter = str2filter_x( op, ludp->lud_filter );
188 if ( *filter == NULL ) {
189 rc = LDAP_PROTOCOL_ERROR;
192 ber_str2bv( ludp->lud_filter, 0, 0, fstr );
195 /* Grab the searchbase */
196 ber_str2bv( ludp->lud_dn, 0, 0, base );
197 rc = dnNormalize( 0, NULL, NULL, base, nbase, op->o_tmpmemctx );
200 if( rc != LDAP_SUCCESS ) {
201 if( *filter ) filter_free_x( op, *filter );
207 /* Don't free these, return them to caller */
208 ludp->lud_filter = NULL;
212 ldap_free_urldesc( ludp );
216 static int slap_sasl_rx_off(char *rep, int *off)
221 /* Precompile replace pattern. Find the $<n> placeholders */
224 for ( c = rep; *c; c++ ) {
225 if ( *c == '\\' && c[1] ) {
230 if ( n == SASLREGEX_REPLACE ) {
232 LDAP_LOG( TRANSPORT, ERR,
233 "slap_sasl_rx_off: \"%s\" has too many $n "
234 "placeholders (max %d)\n", rep, SASLREGEX_REPLACE, 0 );
236 Debug( LDAP_DEBUG_ANY,
237 "SASL replace pattern %s has too many $n "
238 "placeholders (max %d)\n",
239 rep, SASLREGEX_REPLACE, 0 );
242 return( LDAP_OTHER );
249 /* Final placeholder, after the last $n */
253 return( LDAP_SUCCESS );
256 int slap_sasl_regexp_config( const char *match, const char *replace )
261 SaslRegexp = (SaslRegexp_t *) ch_realloc( (char *) SaslRegexp,
262 (nSaslRegexp + 1) * sizeof(SaslRegexp_t) );
264 reg = &SaslRegexp[nSaslRegexp];
266 reg->sr_match = ch_strdup( match );
267 reg->sr_replace = ch_strdup( replace );
269 /* Precompile matching pattern */
270 rc = regcomp( ®->sr_workspace, reg->sr_match, REG_EXTENDED|REG_ICASE );
273 LDAP_LOG( TRANSPORT, ERR,
274 "slap_sasl_regexp_config: \"%s\" could not be compiled.\n",
275 reg->sr_match, 0, 0 );
277 Debug( LDAP_DEBUG_ANY,
278 "SASL match pattern %s could not be compiled by regexp engine\n",
279 reg->sr_match, 0, 0 );
282 return( LDAP_OTHER );
285 rc = slap_sasl_rx_off( reg->sr_replace, reg->sr_offset );
286 if ( rc != LDAP_SUCCESS ) return rc;
289 return( LDAP_SUCCESS );
293 /* Perform replacement on regexp matches */
294 static void slap_sasl_rx_exp(
298 const char *saslname,
302 int i, n, len, insert;
304 /* Get the total length of the final URI */
308 while( off[n] >= 0 ) {
309 /* Len of next section from replacement string (x,y,z above) */
310 len += off[n] - off[n-1] - 2;
314 /* Len of string from saslname that matched next $i (b,d above) */
315 i = rep[ off[n] + 1 ] - '0';
316 len += str[i].rm_eo - str[i].rm_so;
319 out->bv_val = sl_malloc( len + 1, ctx );
322 /* Fill in URI with replace string, replacing $i as we go */
325 while( off[n] >= 0) {
326 /* Paste in next section from replacement string (x,y,z above) */
327 len = off[n] - off[n-1] - 2;
328 strncpy( out->bv_val+insert, rep + off[n-1] + 2, len);
333 /* Paste in string from saslname that matched next $i (b,d above) */
334 i = rep[ off[n] + 1 ] - '0';
335 len = str[i].rm_eo - str[i].rm_so;
336 strncpy( out->bv_val+insert, saslname + str[i].rm_so, len );
342 out->bv_val[insert] = '\0';
345 /* Take the passed in SASL name and attempt to convert it into an
346 LDAP URI to find the matching LDAP entry, using the pattern matching
347 strings given in the saslregexp config file directive(s) */
349 static int slap_sasl_regexp( struct berval *in, struct berval *out, void *ctx )
351 char *saslname = in->bv_val;
353 regmatch_t sr_strings[SASLREGEX_REPLACE]; /* strings matching $1,$2 ... */
356 memset( out, 0, sizeof( *out ) );
359 LDAP_LOG( TRANSPORT, ENTRY,
360 "slap_sasl_regexp: converting SASL name %s\n", saslname, 0, 0 );
362 Debug( LDAP_DEBUG_TRACE, "slap_sasl_regexp: converting SASL name %s\n",
366 if (( saslname == NULL ) || ( nSaslRegexp == 0 )) {
370 /* Match the normalized SASL name to the saslregexp patterns */
371 for( reg = SaslRegexp,i=0; i<nSaslRegexp; i++,reg++ ) {
372 if ( regexec( ®->sr_workspace, saslname, SASLREGEX_REPLACE,
373 sr_strings, 0) == 0 )
377 if( i >= nSaslRegexp ) return( 0 );
380 * The match pattern may have been of the form "a(b.*)c(d.*)e" and the
381 * replace pattern of the form "x$1y$2z". The returned string needs
382 * to replace the $1,$2 with the strings that matched (b.*) and (d.*)
384 slap_sasl_rx_exp( reg->sr_replace, reg->sr_offset,
385 sr_strings, saslname, out, ctx );
388 LDAP_LOG( TRANSPORT, ENTRY,
389 "slap_sasl_regexp: converted SASL name to %s\n",
390 out->bv_len ? out->bv_val : "", 0, 0 );
392 Debug( LDAP_DEBUG_TRACE,
393 "slap_sasl_regexp: converted SASL name to %s\n",
394 out->bv_len ? out->bv_val : "", 0, 0 );
400 /* This callback actually does some work...*/
401 static int sasl_sc_sasl2dn( Operation *o, SlapReply *rs )
403 struct berval *ndn = o->o_callback->sc_private;
405 if (rs->sr_type != REP_SEARCH) return 0;
407 /* We only want to be called once */
409 o->o_tmpfree(ndn->bv_val, o->o_tmpmemctx);
413 LDAP_LOG( TRANSPORT, DETAIL1,
414 "slap_sasl2dn: search DN returned more than 1 entry\n", 0, 0, 0 );
416 Debug( LDAP_DEBUG_TRACE,
417 "slap_sasl2dn: search DN returned more than 1 entry\n", 0, 0, 0 );
422 ber_dupbv_x(ndn, &rs->sr_entry->e_nname, o->o_tmpmemctx);
427 typedef struct smatch_info {
432 static int sasl_sc_smatch( Operation *o, SlapReply *rs )
434 smatch_info *sm = o->o_callback->sc_private;
436 if (rs->sr_type != REP_SEARCH) return 0;
438 if (dn_match(sm->dn, &rs->sr_entry->e_nname)) {
440 return -1; /* short-circuit the search */
447 * Map a SASL regexp rule to a DN. If the rule is just a DN or a scope=base
448 * URI, just strcmp the rule (or its searchbase) to the *assertDN. Otherwise,
449 * the rule must be used as an internal search for entries. If that search
450 * returns the *assertDN entry, the match is successful.
452 * The assertDN should not have the dn: prefix
456 int slap_sasl_match( Operation *opx, struct berval *rule,
457 struct berval *assertDN, struct berval *authc )
462 slap_callback cb = { NULL, sasl_sc_smatch, NULL, NULL };
464 SlapReply rs = {REP_RESULT};
467 LDAP_LOG( TRANSPORT, ENTRY,
468 "slap_sasl_match: comparing DN %s to rule %s\n",
469 assertDN->bv_val, rule->bv_val,0 );
471 Debug( LDAP_DEBUG_TRACE,
472 "===>slap_sasl_match: comparing DN %s to rule %s\n",
473 assertDN->bv_val, rule->bv_val, 0 );
476 rc = slap_parseURI( opx, rule, &op.o_req_dn,
477 &op.o_req_ndn, &op.oq_search.rs_scope, &op.oq_search.rs_filter,
479 if( rc != LDAP_SUCCESS ) goto CONCLUDED;
481 /* Massive shortcut: search scope == base */
482 switch ( op.oq_search.rs_scope ) {
483 case LDAP_SCOPE_BASE:
484 case LDAP_X_SCOPE_EXACT:
485 if ( dn_match( &op.o_req_ndn, assertDN ) ) {
488 rc = LDAP_INAPPROPRIATE_AUTH;
492 case LDAP_X_SCOPE_REGEX:
493 case LDAP_X_SCOPE_EXACTREGEX:
494 rc = regcomp(®, op.o_req_ndn.bv_val,
495 REG_EXTENDED|REG_ICASE|REG_NOSUB);
497 rc = regexec(®, assertDN->bv_val, 0, NULL, 0);
503 rc = LDAP_INAPPROPRIATE_AUTH;
511 /* Must run an internal search. */
512 if ( op.oq_search.rs_filter == NULL ) {
513 rc = LDAP_FILTER_ERROR;
518 LDAP_LOG( TRANSPORT, DETAIL1,
519 "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
520 op.o_req_ndn.bv_val, op.oq_search.rs_scope, 0 );
522 Debug( LDAP_DEBUG_TRACE,
523 "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
524 op.o_req_ndn.bv_val, op.oq_search.rs_scope, 0 );
527 op.o_bd = select_backend( &op.o_req_ndn, 0, 1 );
528 if(( op.o_bd == NULL ) || ( op.o_bd->be_search == NULL)) {
529 rc = LDAP_INAPPROPRIATE_AUTH;
537 op.o_tag = LDAP_REQ_SEARCH;
538 op.o_protocol = LDAP_VERSION3;
541 op.o_time = slap_get_time();
542 op.o_do_not_cache = 1;
543 op.o_is_auth_check = 1;
544 op.o_threadctx = opx->o_threadctx;
545 op.o_tmpmemctx = opx->o_tmpmemctx;
546 op.o_tmpmfuncs = opx->o_tmpmfuncs;
550 op.o_conn = opx->o_conn;
551 op.o_connid = opx->o_connid;
552 op.o_req_dn = op.o_req_ndn;
554 op.o_bd->be_search( &op, &rs );
559 rc = LDAP_INAPPROPRIATE_AUTH;
563 if( op.o_req_dn.bv_len ) ch_free( op.o_req_dn.bv_val );
564 if( op.o_req_ndn.bv_len ) sl_free( op.o_req_ndn.bv_val, opx->o_tmpmemctx );
565 if( op.oq_search.rs_filter ) filter_free_x( opx, op.oq_search.rs_filter );
566 if( op.ors_filterstr.bv_len ) ch_free( op.ors_filterstr.bv_val );
569 LDAP_LOG( TRANSPORT, ENTRY,
570 "slap_sasl_match: comparison returned %d\n", rc, 0, 0 );
572 Debug( LDAP_DEBUG_TRACE,
573 "<===slap_sasl_match: comparison returned %d\n", rc, 0, 0);
581 * This function answers the question, "Can this ID authorize to that ID?",
582 * based on authorization rules. The rules are stored in the *searchDN, in the
583 * attribute named by *attr. If any of those rules map to the *assertDN, the
584 * authorization is approved.
586 * The DNs should not have the dn: prefix
589 slap_sasl_check_authz( Operation *op,
590 struct berval *searchDN,
591 struct berval *assertDN,
592 AttributeDescription *ad,
593 struct berval *authc )
599 LDAP_LOG( TRANSPORT, ENTRY,
600 "slap_sasl_check_authz: does %s match %s rule in %s?\n",
601 assertDN->bv_val, ad->ad_cname.bv_val, searchDN->bv_val);
603 Debug( LDAP_DEBUG_TRACE,
604 "==>slap_sasl_check_authz: does %s match %s rule in %s?\n",
605 assertDN->bv_val, ad->ad_cname.bv_val, searchDN->bv_val);
608 rc = backend_attribute( op, NULL,
609 searchDN, ad, &vals );
610 if( rc != LDAP_SUCCESS ) goto COMPLETE;
612 /* Check if the *assertDN matches any **vals */
614 for( i=0; vals[i].bv_val != NULL; i++ ) {
615 rc = slap_sasl_match( op, &vals[i], assertDN, authc );
616 if ( rc == LDAP_SUCCESS ) goto COMPLETE;
619 rc = LDAP_INAPPROPRIATE_AUTH;
622 if( vals ) ber_bvarray_free_x( vals, op->o_tmpmemctx );
625 LDAP_LOG( TRANSPORT, RESULTS,
626 "slap_sasl_check_authz: %s check returning %s\n",
627 ad->ad_cname.bv_val, rc, 0 );
629 Debug( LDAP_DEBUG_TRACE,
630 "<==slap_sasl_check_authz: %s check returning %d\n",
631 ad->ad_cname.bv_val, rc, 0);
638 * Given a SASL name (e.g. "UID=name,cn=REALM,cn=MECH,cn=AUTH")
639 * return the LDAP DN to which it matches. The SASL regexp rules in the config
640 * file turn the SASL name into an LDAP URI. If the URI is just a DN (or a
641 * search with scope=base), just return the URI (or its searchbase). Otherwise
642 * an internal search must be done, and if that search returns exactly one
643 * entry, return the DN of that one entry.
645 void slap_sasl2dn( Operation *opx,
646 struct berval *saslname, struct berval *sasldn )
649 slap_callback cb = { NULL, sasl_sc_sasl2dn, NULL, NULL };
651 SlapReply rs = {REP_RESULT};
652 struct berval regout = { 0, NULL };
655 LDAP_LOG( TRANSPORT, ENTRY,
656 "slap_sasl2dn: converting SASL name %s to DN.\n",
657 saslname->bv_val, 0, 0 );
659 Debug( LDAP_DEBUG_TRACE, "==>slap_sasl2dn: "
660 "converting SASL name %s to a DN\n",
661 saslname->bv_val, 0,0 );
664 sasldn->bv_val = NULL;
666 cb.sc_private = sasldn;
668 /* Convert the SASL name into a minimal URI */
669 if( !slap_sasl_regexp( saslname, ®out, opx->o_tmpmemctx ) ) {
673 rc = slap_parseURI( opx, ®out, &op.o_req_dn,
674 &op.o_req_ndn, &op.oq_search.rs_scope, &op.oq_search.rs_filter,
676 if( regout.bv_val ) sl_free( regout.bv_val, opx->o_tmpmemctx );
677 if( rc != LDAP_SUCCESS ) {
681 /* Must do an internal search */
682 op.o_bd = select_backend( &op.o_req_ndn, 0, 1 );
684 /* Massive shortcut: search scope == base */
685 switch ( op.oq_search.rs_scope ) {
686 case LDAP_X_SCOPE_EXACTREGEX:
688 * this occurs when "dn:<dn>" was used, which means
689 * it is not specified whether the DN is an exact value
690 * or a regular expression, and thus it has not been
691 * normalized yet. slap_parseURI() clears the op.o_req_dn
692 * field and stores its result in op.o_req_ndn, so we first
693 * swap them and then normalize the value
695 assert( op.o_req_dn.bv_val == NULL );
697 op.o_req_dn = op.o_req_ndn;
698 rc = dnNormalize( 0, NULL, NULL, &op.o_req_dn, &op.o_req_ndn, opx->o_tmpmemctx );
699 op.o_req_dn.bv_len = 0;
700 op.o_req_dn.bv_val = NULL;
702 if( rc != LDAP_SUCCESS ) {
705 /* intentionally continue to next case */
707 case LDAP_SCOPE_BASE:
708 case LDAP_X_SCOPE_EXACT:
709 *sasldn = op.o_req_ndn;
710 op.o_req_ndn.bv_len = 0;
711 op.o_req_ndn.bv_val = NULL;
712 /* intentionally continue to next case */
714 case LDAP_X_SCOPE_REGEX:
723 LDAP_LOG( TRANSPORT, DETAIL1,
724 "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
725 op.o_req_ndn.bv_val, op.oq_search.rs_scope, 0 );
727 Debug( LDAP_DEBUG_TRACE,
728 "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
729 op.o_req_ndn.bv_val, op.oq_search.rs_scope, 0 );
732 if(( op.o_bd == NULL ) || ( op.o_bd->be_search == NULL)) {
736 op.o_conn = opx->o_conn;
737 op.o_connid = opx->o_connid;
738 op.o_tag = LDAP_REQ_SEARCH;
739 op.o_protocol = LDAP_VERSION3;
740 op.o_ndn = opx->o_conn->c_ndn;
742 op.o_time = slap_get_time();
743 op.o_do_not_cache = 1;
744 op.o_is_auth_check = 1;
745 op.o_threadctx = opx->o_threadctx;
746 op.o_tmpmemctx = opx->o_tmpmemctx;
747 op.o_tmpmfuncs = opx->o_tmpmfuncs;
751 op.oq_search.rs_deref = LDAP_DEREF_NEVER;
752 op.oq_search.rs_slimit = 1;
753 op.oq_search.rs_attrsonly = 1;
754 op.o_req_dn = op.o_req_ndn;
756 op.o_bd->be_search( &op, &rs );
759 if( sasldn->bv_len ) {
760 opx->o_conn->c_authz_backend = op.o_bd;
762 if( op.o_req_dn.bv_len ) ch_free( op.o_req_dn.bv_val );
763 if( op.o_req_ndn.bv_len ) sl_free( op.o_req_ndn.bv_val, opx->o_tmpmemctx );
764 if( op.oq_search.rs_filter ) filter_free_x( opx, op.oq_search.rs_filter );
765 if( op.ors_filterstr.bv_len ) ch_free( op.ors_filterstr.bv_val );
768 LDAP_LOG( TRANSPORT, ENTRY,
769 "slap_sasl2dn: Converted SASL name to %s\n",
770 sasldn->bv_len ? sasldn->bv_val : "<nothing>", 0, 0 );
772 Debug( LDAP_DEBUG_TRACE, "<==slap_sasl2dn: Converted SASL name to %s\n",
773 sasldn->bv_len ? sasldn->bv_val : "<nothing>", 0, 0 );
780 /* Check if a bind can SASL authorize to another identity.
781 * The DNs should not have the dn: prefix
784 int slap_sasl_authorized( Operation *op,
785 struct berval *authcDN, struct berval *authzDN )
787 int rc = LDAP_INAPPROPRIATE_AUTH;
789 /* User binding as anonymous */
790 if ( authzDN == NULL ) {
796 LDAP_LOG( TRANSPORT, ENTRY,
797 "slap_sasl_authorized: can %s become %s?\n",
798 authcDN->bv_val, authzDN->bv_val, 0 );
800 Debug( LDAP_DEBUG_TRACE,
801 "==>slap_sasl_authorized: can %s become %s?\n",
802 authcDN->bv_val, authzDN->bv_val, 0 );
805 /* If person is authorizing to self, succeed */
806 if ( dn_match( authcDN, authzDN ) ) {
811 /* Allow the manager to authorize as any DN. */
812 if( op->o_conn->c_authz_backend && be_isroot( op->o_conn->c_authz_backend, authcDN )) {
817 /* Check source rules */
818 if( authz_policy & SASL_AUTHZ_TO ) {
819 rc = slap_sasl_check_authz( op, authcDN, authzDN,
820 slap_schema.si_ad_saslAuthzTo, authcDN );
821 if( rc == LDAP_SUCCESS ) {
826 /* Check destination rules */
827 if( authz_policy & SASL_AUTHZ_FROM ) {
828 rc = slap_sasl_check_authz( op, authzDN, authcDN,
829 slap_schema.si_ad_saslAuthzFrom, authcDN );
830 if( rc == LDAP_SUCCESS ) {
835 rc = LDAP_INAPPROPRIATE_AUTH;
840 LDAP_LOG( TRANSPORT, RESULTS, "slap_sasl_authorized: return %d\n", rc,0,0 );
842 Debug( LDAP_DEBUG_TRACE,
843 "<== slap_sasl_authorized: return %d\n", rc, 0, 0 );