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 will be regcomp'd/regexec'd */
133 } else if( !strncasecmp( uri->bv_val, "dn:", sizeof("dn:")-1 ) ) {
134 bv.bv_val = uri->bv_val + sizeof("dn:")-1;
135 bv.bv_val += strspn( bv.bv_val, " " );
137 is_dn: bv.bv_len = uri->bv_len - (bv.bv_val - uri->bv_val);
139 rc = dnNormalize( 0, NULL, NULL, &bv, nbase, op->o_tmpmemctx );
140 if( rc == LDAP_SUCCESS ) {
141 *scope = LDAP_X_SCOPE_EXACTREGEX;
146 /* explicitly set to regex: it will be regcomp'd/regexec'd */
147 } else if ( !strncasecmp( uri->bv_val, "dn.regex:", sizeof("dn.regex:")-1 ) ) {
148 bv.bv_val = uri->bv_val + sizeof("dn.regex:")-1;
149 bv.bv_val += strspn( bv.bv_val, " " );
151 is_dn_regex: bv.bv_len = uri->bv_len - (bv.bv_val - uri->bv_val);
153 ber_dupbv_x( nbase, &bv, op->o_tmpmemctx );
154 *scope = LDAP_X_SCOPE_REGEX;
158 rc = ldap_url_parse( uri->bv_val, &ludp );
159 if ( rc == LDAP_URL_ERR_BADSCHEME ) {
160 bv.bv_val = uri->bv_val;
164 if ( rc != LDAP_URL_SUCCESS ) {
165 return LDAP_PROTOCOL_ERROR;
168 if (( ludp->lud_host && *ludp->lud_host )
169 || ludp->lud_attrs || ludp->lud_exts )
171 /* host part must be empty */
172 /* attrs and extensions parts must be empty */
173 rc = LDAP_PROTOCOL_ERROR;
178 *scope = ludp->lud_scope;
180 /* Grab the filter */
181 if ( ludp->lud_filter ) {
182 *filter = str2filter_x( op, ludp->lud_filter );
183 if ( *filter == NULL ) {
184 rc = LDAP_PROTOCOL_ERROR;
187 ber_str2bv( ludp->lud_filter, 0, 0, fstr );
190 /* Grab the searchbase */
191 ber_str2bv( ludp->lud_dn, 0, 0, base );
192 rc = dnNormalize( 0, NULL, NULL, base, nbase, op->o_tmpmemctx );
195 if( rc != LDAP_SUCCESS ) {
196 if( *filter ) filter_free_x( op, *filter );
202 /* Don't free these, return them to caller */
203 ludp->lud_filter = NULL;
207 ldap_free_urldesc( ludp );
211 static int slap_sasl_rx_off(char *rep, int *off)
216 /* Precompile replace pattern. Find the $<n> placeholders */
219 for ( c = rep; *c; c++ ) {
220 if ( *c == '\\' && c[1] ) {
225 if ( n == SASLREGEX_REPLACE ) {
227 LDAP_LOG( TRANSPORT, ERR,
228 "slap_sasl_rx_off: \"%s\" has too many $n "
229 "placeholders (max %d)\n", rep, SASLREGEX_REPLACE, 0 );
231 Debug( LDAP_DEBUG_ANY,
232 "SASL replace pattern %s has too many $n "
233 "placeholders (max %d)\n",
234 rep, SASLREGEX_REPLACE, 0 );
237 return( LDAP_OTHER );
244 /* Final placeholder, after the last $n */
248 return( LDAP_SUCCESS );
251 int slap_sasl_regexp_config( const char *match, const char *replace )
256 SaslRegexp = (SaslRegexp_t *) ch_realloc( (char *) SaslRegexp,
257 (nSaslRegexp + 1) * sizeof(SaslRegexp_t) );
259 reg = &SaslRegexp[nSaslRegexp];
261 reg->sr_match = ch_strdup( match );
262 reg->sr_replace = ch_strdup( replace );
264 /* Precompile matching pattern */
265 rc = regcomp( ®->sr_workspace, reg->sr_match, REG_EXTENDED|REG_ICASE );
268 LDAP_LOG( TRANSPORT, ERR,
269 "slap_sasl_regexp_config: \"%s\" could not be compiled.\n",
270 reg->sr_match, 0, 0 );
272 Debug( LDAP_DEBUG_ANY,
273 "SASL match pattern %s could not be compiled by regexp engine\n",
274 reg->sr_match, 0, 0 );
277 return( LDAP_OTHER );
280 rc = slap_sasl_rx_off( reg->sr_replace, reg->sr_offset );
281 if ( rc != LDAP_SUCCESS ) return rc;
284 return( LDAP_SUCCESS );
288 /* Perform replacement on regexp matches */
289 static void slap_sasl_rx_exp(
293 const char *saslname,
297 int i, n, len, insert;
299 /* Get the total length of the final URI */
303 while( off[n] >= 0 ) {
304 /* Len of next section from replacement string (x,y,z above) */
305 len += off[n] - off[n-1] - 2;
309 /* Len of string from saslname that matched next $i (b,d above) */
310 i = rep[ off[n] + 1 ] - '0';
311 len += str[i].rm_eo - str[i].rm_so;
314 out->bv_val = sl_malloc( len + 1, ctx );
317 /* Fill in URI with replace string, replacing $i as we go */
320 while( off[n] >= 0) {
321 /* Paste in next section from replacement string (x,y,z above) */
322 len = off[n] - off[n-1] - 2;
323 strncpy( out->bv_val+insert, rep + off[n-1] + 2, len);
328 /* Paste in string from saslname that matched next $i (b,d above) */
329 i = rep[ off[n] + 1 ] - '0';
330 len = str[i].rm_eo - str[i].rm_so;
331 strncpy( out->bv_val+insert, saslname + str[i].rm_so, len );
337 out->bv_val[insert] = '\0';
340 /* Take the passed in SASL name and attempt to convert it into an
341 LDAP URI to find the matching LDAP entry, using the pattern matching
342 strings given in the saslregexp config file directive(s) */
344 static int slap_sasl_regexp( struct berval *in, struct berval *out, void *ctx )
346 char *saslname = in->bv_val;
348 regmatch_t sr_strings[SASLREGEX_REPLACE]; /* strings matching $1,$2 ... */
351 memset( out, 0, sizeof( *out ) );
354 LDAP_LOG( TRANSPORT, ENTRY,
355 "slap_sasl_regexp: converting SASL name %s\n", saslname, 0, 0 );
357 Debug( LDAP_DEBUG_TRACE, "slap_sasl_regexp: converting SASL name %s\n",
361 if (( saslname == NULL ) || ( nSaslRegexp == 0 )) {
365 /* Match the normalized SASL name to the saslregexp patterns */
366 for( reg = SaslRegexp,i=0; i<nSaslRegexp; i++,reg++ ) {
367 if ( regexec( ®->sr_workspace, saslname, SASLREGEX_REPLACE,
368 sr_strings, 0) == 0 )
372 if( i >= nSaslRegexp ) return( 0 );
375 * The match pattern may have been of the form "a(b.*)c(d.*)e" and the
376 * replace pattern of the form "x$1y$2z". The returned string needs
377 * to replace the $1,$2 with the strings that matched (b.*) and (d.*)
379 slap_sasl_rx_exp( reg->sr_replace, reg->sr_offset,
380 sr_strings, saslname, out, ctx );
383 LDAP_LOG( TRANSPORT, ENTRY,
384 "slap_sasl_regexp: converted SASL name to %s\n",
385 out->bv_len ? out->bv_val : "", 0, 0 );
387 Debug( LDAP_DEBUG_TRACE,
388 "slap_sasl_regexp: converted SASL name to %s\n",
389 out->bv_len ? out->bv_val : "", 0, 0 );
395 /* This callback actually does some work...*/
396 static int sasl_sc_sasl2dn( Operation *o, SlapReply *rs )
398 struct berval *ndn = o->o_callback->sc_private;
400 if (rs->sr_type != REP_SEARCH) return 0;
402 /* We only want to be called once */
404 o->o_tmpfree(ndn->bv_val, o->o_tmpmemctx);
408 LDAP_LOG( TRANSPORT, DETAIL1,
409 "slap_sasl2dn: search DN returned more than 1 entry\n", 0, 0, 0 );
411 Debug( LDAP_DEBUG_TRACE,
412 "slap_sasl2dn: search DN returned more than 1 entry\n", 0,0,0 );
417 ber_dupbv_x(ndn, &rs->sr_entry->e_nname, o->o_tmpmemctx);
422 typedef struct smatch_info {
427 static int sasl_sc_smatch( Operation *o, SlapReply *rs )
429 smatch_info *sm = o->o_callback->sc_private;
431 if (rs->sr_type != REP_SEARCH) return 0;
433 if (dn_match(sm->dn, &rs->sr_entry->e_nname)) {
435 return -1; /* short-circuit the search */
442 * Map a SASL regexp rule to a DN. If the rule is just a DN or a scope=base
443 * URI, just strcmp the rule (or its searchbase) to the *assertDN. Otherwise,
444 * the rule must be used as an internal search for entries. If that search
445 * returns the *assertDN entry, the match is successful.
447 * The assertDN should not have the dn: prefix
451 int slap_sasl_match( Operation *opx, struct berval *rule,
452 struct berval *assertDN, struct berval *authc )
457 slap_callback cb = { sasl_sc_smatch, NULL };
459 SlapReply rs = {REP_RESULT};
462 LDAP_LOG( TRANSPORT, ENTRY,
463 "slap_sasl_match: comparing DN %s to rule %s\n",
464 assertDN->bv_val, rule->bv_val,0 );
466 Debug( LDAP_DEBUG_TRACE,
467 "===>slap_sasl_match: comparing DN %s to rule %s\n",
468 assertDN->bv_val, rule->bv_val, 0 );
471 rc = slap_parseURI( opx, rule, &op.o_req_dn,
472 &op.o_req_ndn, &op.oq_search.rs_scope, &op.oq_search.rs_filter,
474 if( rc != LDAP_SUCCESS ) goto CONCLUDED;
476 /* Massive shortcut: search scope == base */
477 switch ( op.oq_search.rs_scope ) {
478 case LDAP_SCOPE_BASE:
479 case LDAP_X_SCOPE_EXACT:
480 if ( dn_match( &op.o_req_ndn, assertDN ) ) {
483 rc = LDAP_INAPPROPRIATE_AUTH;
487 case LDAP_X_SCOPE_REGEX:
488 case LDAP_X_SCOPE_EXACTREGEX:
489 rc = regcomp(®, op.o_req_ndn.bv_val,
490 REG_EXTENDED|REG_ICASE|REG_NOSUB);
492 rc = regexec(®, assertDN->bv_val, 0, NULL, 0);
498 rc = LDAP_INAPPROPRIATE_AUTH;
506 /* Must run an internal search. */
507 if ( op.oq_search.rs_filter == NULL ) {
508 rc = LDAP_FILTER_ERROR;
513 LDAP_LOG( TRANSPORT, DETAIL1,
514 "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
515 op.o_req_ndn.bv_val, op.oq_search.rs_scope, 0 );
517 Debug( LDAP_DEBUG_TRACE,
518 "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
519 op.o_req_ndn.bv_val, op.oq_search.rs_scope, 0 );
522 op.o_bd = select_backend( &op.o_req_ndn, 0, 1 );
523 if(( op.o_bd == NULL ) || ( op.o_bd->be_search == NULL)) {
524 rc = LDAP_INAPPROPRIATE_AUTH;
532 op.o_tag = LDAP_REQ_SEARCH;
533 op.o_protocol = LDAP_VERSION3;
536 op.o_time = slap_get_time();
537 op.o_do_not_cache = 1;
538 op.o_is_auth_check = 1;
539 op.o_threadctx = opx->o_threadctx;
540 op.o_tmpmemctx = opx->o_tmpmemctx;
541 op.o_tmpmfuncs = opx->o_tmpmfuncs;
545 op.o_conn = opx->o_conn;
546 op.o_connid = opx->o_connid;
547 op.o_req_dn = op.o_req_ndn;
549 op.o_bd->be_search( &op, &rs );
554 rc = LDAP_INAPPROPRIATE_AUTH;
558 if( op.o_req_dn.bv_len ) ch_free( op.o_req_dn.bv_val );
559 if( op.o_req_ndn.bv_len ) sl_free( op.o_req_ndn.bv_val, opx->o_tmpmemctx );
560 if( op.oq_search.rs_filter ) filter_free_x( opx, op.oq_search.rs_filter );
561 if( op.ors_filterstr.bv_len ) ch_free( op.ors_filterstr.bv_val );
564 LDAP_LOG( TRANSPORT, ENTRY,
565 "slap_sasl_match: comparison returned %d\n", rc, 0, 0 );
567 Debug( LDAP_DEBUG_TRACE,
568 "<===slap_sasl_match: comparison returned %d\n", rc, 0, 0);
576 * This function answers the question, "Can this ID authorize to that ID?",
577 * based on authorization rules. The rules are stored in the *searchDN, in the
578 * attribute named by *attr. If any of those rules map to the *assertDN, the
579 * authorization is approved.
581 * The DNs should not have the dn: prefix
584 slap_sasl_check_authz( Operation *op,
585 struct berval *searchDN,
586 struct berval *assertDN,
587 AttributeDescription *ad,
588 struct berval *authc )
594 LDAP_LOG( TRANSPORT, ENTRY,
595 "slap_sasl_check_authz: does %s match %s rule in %s?\n",
596 assertDN->bv_val, ad->ad_cname.bv_val, searchDN->bv_val);
598 Debug( LDAP_DEBUG_TRACE,
599 "==>slap_sasl_check_authz: does %s match %s rule in %s?\n",
600 assertDN->bv_val, ad->ad_cname.bv_val, searchDN->bv_val);
603 rc = backend_attribute( op, NULL,
604 searchDN, ad, &vals );
605 if( rc != LDAP_SUCCESS ) goto COMPLETE;
607 /* Check if the *assertDN matches any **vals */
609 for( i=0; vals[i].bv_val != NULL; i++ ) {
610 rc = slap_sasl_match( op, &vals[i], assertDN, authc );
611 if ( rc == LDAP_SUCCESS ) goto COMPLETE;
614 rc = LDAP_INAPPROPRIATE_AUTH;
617 if( vals ) ber_bvarray_free_x( vals, op->o_tmpmemctx );
620 LDAP_LOG( TRANSPORT, RESULTS,
621 "slap_sasl_check_authz: %s check returning %s\n",
622 ad->ad_cname.bv_val, rc, 0 );
624 Debug( LDAP_DEBUG_TRACE,
625 "<==slap_sasl_check_authz: %s check returning %d\n",
626 ad->ad_cname.bv_val, rc, 0);
633 * Given a SASL name (e.g. "UID=name,cn=REALM,cn=MECH,cn=AUTH")
634 * return the LDAP DN to which it matches. The SASL regexp rules in the config
635 * file turn the SASL name into an LDAP URI. If the URI is just a DN (or a
636 * search with scope=base), just return the URI (or its searchbase). Otherwise
637 * an internal search must be done, and if that search returns exactly one
638 * entry, return the DN of that one entry.
640 void slap_sasl2dn( Operation *opx,
641 struct berval *saslname, struct berval *sasldn )
644 slap_callback cb = { sasl_sc_sasl2dn, NULL };
646 SlapReply rs = {REP_RESULT};
647 struct berval regout = { 0, NULL };
650 LDAP_LOG( TRANSPORT, ENTRY,
651 "slap_sasl2dn: converting SASL name %s to DN.\n",
652 saslname->bv_val, 0, 0 );
654 Debug( LDAP_DEBUG_TRACE, "==>slap_sasl2dn: "
655 "converting SASL name %s to a DN\n",
656 saslname->bv_val, 0,0 );
659 sasldn->bv_val = NULL;
661 cb.sc_private = sasldn;
663 /* Convert the SASL name into a minimal URI */
664 if( !slap_sasl_regexp( saslname, ®out, opx->o_tmpmemctx ) ) {
668 rc = slap_parseURI( opx, ®out, &op.o_req_dn,
669 &op.o_req_ndn, &op.oq_search.rs_scope, &op.oq_search.rs_filter,
671 if( regout.bv_val ) sl_free( regout.bv_val, opx->o_tmpmemctx );
672 if( rc != LDAP_SUCCESS ) {
676 /* Must do an internal search */
677 op.o_bd = select_backend( &op.o_req_ndn, 0, 1 );
679 /* Massive shortcut: search scope == base */
680 switch ( op.oq_search.rs_scope ) {
681 case LDAP_SCOPE_BASE:
682 case LDAP_X_SCOPE_EXACT:
683 case LDAP_X_SCOPE_EXACTREGEX:
684 *sasldn = op.o_req_ndn;
685 op.o_req_ndn.bv_len = 0;
686 op.o_req_ndn.bv_val = NULL;
687 /* intentionally continue to next case */
689 case LDAP_X_SCOPE_REGEX:
698 LDAP_LOG( TRANSPORT, DETAIL1,
699 "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
700 op.o_req_ndn.bv_val, op.oq_search.rs_scope, 0 );
702 Debug( LDAP_DEBUG_TRACE,
703 "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
704 op.o_req_ndn.bv_val, op.oq_search.rs_scope, 0 );
707 if(( op.o_bd == NULL ) || ( op.o_bd->be_search == NULL)) {
711 op.o_conn = opx->o_conn;
712 op.o_connid = opx->o_connid;
713 op.o_tag = LDAP_REQ_SEARCH;
714 op.o_protocol = LDAP_VERSION3;
715 op.o_ndn = opx->o_conn->c_ndn;
717 op.o_time = slap_get_time();
718 op.o_do_not_cache = 1;
719 op.o_is_auth_check = 1;
720 op.o_threadctx = opx->o_threadctx;
721 op.o_tmpmemctx = opx->o_tmpmemctx;
722 op.o_tmpmfuncs = opx->o_tmpmfuncs;
726 op.oq_search.rs_deref = LDAP_DEREF_NEVER;
727 op.oq_search.rs_slimit = 1;
728 op.oq_search.rs_attrsonly = 1;
729 op.o_req_dn = op.o_req_ndn;
731 op.o_bd->be_search( &op, &rs );
734 if( sasldn->bv_len ) {
735 opx->o_conn->c_authz_backend = op.o_bd;
737 if( op.o_req_dn.bv_len ) ch_free( op.o_req_dn.bv_val );
738 if( op.o_req_ndn.bv_len ) sl_free( op.o_req_ndn.bv_val, opx->o_tmpmemctx );
739 if( op.oq_search.rs_filter ) filter_free_x( opx, op.oq_search.rs_filter );
740 if( op.ors_filterstr.bv_len ) ch_free( op.ors_filterstr.bv_val );
743 LDAP_LOG( TRANSPORT, ENTRY,
744 "slap_sasl2dn: Converted SASL name to %s\n",
745 sasldn->bv_len ? sasldn->bv_val : "<nothing>", 0, 0 );
747 Debug( LDAP_DEBUG_TRACE, "<==slap_sasl2dn: Converted SASL name to %s\n",
748 sasldn->bv_len ? sasldn->bv_val : "<nothing>", 0, 0 );
755 /* Check if a bind can SASL authorize to another identity.
756 * The DNs should not have the dn: prefix
759 int slap_sasl_authorized( Operation *op,
760 struct berval *authcDN, struct berval *authzDN )
762 int rc = LDAP_INAPPROPRIATE_AUTH;
764 /* User binding as anonymous */
765 if ( authzDN == NULL ) {
771 LDAP_LOG( TRANSPORT, ENTRY,
772 "slap_sasl_authorized: can %s become %s?\n",
773 authcDN->bv_val, authzDN->bv_val, 0 );
775 Debug( LDAP_DEBUG_TRACE,
776 "==>slap_sasl_authorized: can %s become %s?\n",
777 authcDN->bv_val, authzDN->bv_val, 0 );
780 /* If person is authorizing to self, succeed */
781 if ( dn_match( authcDN, authzDN ) ) {
786 /* Allow the manager to authorize as any DN. */
787 if( op->o_conn->c_authz_backend && be_isroot( op->o_conn->c_authz_backend, authcDN )) {
792 /* Check source rules */
793 if( authz_policy & SASL_AUTHZ_TO ) {
794 rc = slap_sasl_check_authz( op, authcDN, authzDN,
795 slap_schema.si_ad_saslAuthzTo, authcDN );
796 if( rc == LDAP_SUCCESS ) {
801 /* Check destination rules */
802 if( authz_policy & SASL_AUTHZ_FROM ) {
803 rc = slap_sasl_check_authz( op, authzDN, authcDN,
804 slap_schema.si_ad_saslAuthzFrom, authcDN );
805 if( rc == LDAP_SUCCESS ) {
810 rc = LDAP_INAPPROPRIATE_AUTH;
815 LDAP_LOG( TRANSPORT, RESULTS, "slap_sasl_authorized: return %d\n", rc,0,0 );
817 Debug( LDAP_DEBUG_TRACE,
818 "<== slap_sasl_authorized: return %d\n", rc, 0, 0 );