]> git.sur5r.net Git - openldap/blob - servers/slapd/saslauthz.c
777cf9d6de328048bfe4560087b5d88342fb5462
[openldap] / servers / slapd / saslauthz.c
1 /*
2  * Copyright (c) 2000, Mark Adamson, Carnegie Mellon.  All rights reserved.
3  * This software is not subject to any license of Carnegie Mellon University.
4  *
5  * Redistribution and use in source and binary forms are permitted without 
6  * restriction or fee of any kind as long as this notice is preserved.
7  *
8  * The name "Carnegie Mellon" must not be used to endorse or promote
9  * products derived from this software without prior written permission.
10  *
11  */
12
13 #include "portable.h"
14
15 #include <stdio.h>
16
17 #include <ac/stdlib.h>
18 #include <ac/string.h>
19
20 #include "slap.h"
21
22 #ifdef HAVE_CYRUS_SASL
23 #include <limits.h>
24 #include <sasl.h>
25 #include <ldap_pvt.h>
26 #endif
27
28 /* URI format: ldap://<host>/<base>[?[<attrs>][?[<scope>][?[<filter>]]]] */
29
30 static int slap_parseURI( char *uri,
31         struct berval *searchbase, int *scope, Filter **filter )
32 {
33         char *start, *end;
34         struct berval bv;
35         int rc;
36
37
38         assert( uri != NULL );
39         searchbase->bv_val = NULL;
40         searchbase->bv_len = 0;
41         *scope = -1;
42         *filter = NULL;
43
44 #ifdef NEW_LOGGING
45         LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
46                 "slap_parseURI: parsing %s\n", uri ));
47 #else
48         Debug( LDAP_DEBUG_TRACE, "slap_parseURI: parsing %s\n", uri, 0, 0 );
49 #endif
50
51         /* If it does not look like a URI, assume it is a DN */
52         if( !strncasecmp( uri, "dn:", sizeof("dn:")-1 ) ) {
53                 uri += sizeof("dn:")-1;
54                 uri += strspn( uri, " " );
55                 bv.bv_val = uri;
56                 /* FIXME: if dnNormalize actually uses input bv_len we
57                  * will have to make this right.
58                  */
59 is_dn:          bv.bv_len = 1;
60                 rc = dnNormalize2( NULL, &bv, searchbase );
61                 if (rc == LDAP_SUCCESS) {
62                         *scope = LDAP_SCOPE_BASE;
63                 }
64                 return( rc );
65         }
66
67         /* FIXME: should use ldap_url_parse() */
68         if( strncasecmp( uri, "ldap://", sizeof("ldap://")-1 ) ) {
69                 bv.bv_val = uri;
70                 goto is_dn;
71         }
72
73         end = strchr( uri + (sizeof("ldap://")-1), '/' );
74         if ( end == NULL )
75                 return( LDAP_PROTOCOL_ERROR );
76
77         /* could check the hostname here */
78
79         /* Grab the searchbase */
80         start = end+1;
81         end = strchr( start, '?' );
82         bv.bv_val = start;
83         if( end == NULL ) {
84                 bv.bv_len = 1;
85                 return dnNormalize2( NULL, &bv, searchbase );
86         }
87         *end = '\0';
88         bv.bv_len = end - start;
89         rc = dnNormalize2( NULL, &bv, searchbase );
90         *end = '?';
91         if (rc != LDAP_SUCCESS)
92                 return( rc );
93
94         /* Skip the attrs */
95         start = end+1;
96         end = strchr( start, '?' );
97         if( end == NULL ) {
98                 return( LDAP_SUCCESS );
99         }
100
101         /* Grab the scope */
102         start = end+1;
103         if( !strncasecmp( start, "base?", sizeof("base?")-1 )) {
104                 *scope = LDAP_SCOPE_BASE;
105                 start += sizeof("base?")-1;
106         }
107         else if( !strncasecmp( start, "one?", sizeof("one?")-1 )) {
108                 *scope = LDAP_SCOPE_ONELEVEL;
109                 start += sizeof("one?")-1;
110         }
111         else if( !strncasecmp( start, "sub?", sizeof("sub?")-1 )) {
112                 *scope = LDAP_SCOPE_SUBTREE;
113                 start += sizeof("sub?")-1;
114         }
115         else {
116                 free( searchbase->bv_val );
117                 searchbase->bv_val = NULL;
118                 return( LDAP_PROTOCOL_ERROR );
119         }
120
121         /* Grab the filter */
122         *filter = str2filter( start );
123
124         return( LDAP_SUCCESS );
125 }
126
127
128 int slap_sasl_regexp_config( const char *match, const char *replace )
129 {
130 #ifdef HAVE_CYRUS_SASL
131         const char *c;
132         int rc, n;
133         SaslRegexp_t *reg;
134
135         SaslRegexp = (SaslRegexp_t *) ch_realloc( (char *) SaslRegexp,
136           (nSaslRegexp + 1) * sizeof(SaslRegexp_t) );
137         reg = &( SaslRegexp[nSaslRegexp] );
138         reg->match = ch_strdup( match );
139         reg->replace = ch_strdup( replace );
140         dn_normalize( reg->match );
141         dn_normalize( reg->replace );
142
143         /* Precompile matching pattern */
144         rc = regcomp( &reg->workspace, reg->match, REG_EXTENDED|REG_ICASE );
145         if ( rc ) {
146 #ifdef NEW_LOGGING
147                 LDAP_LOG(( "sasl", LDAP_LEVEL_ERR,
148                            "slap_sasl_regexp_config: \"%s\" could not be compiled.\n",
149                            reg->match ));
150 #else
151                 Debug( LDAP_DEBUG_ANY,
152                 "SASL match pattern %s could not be compiled by regexp engine\n",
153                 reg->match, 0, 0 );
154 #endif
155
156                 return( LDAP_OPERATIONS_ERROR );
157         }
158
159         /* Precompile replace pattern. Find the $<n> placeholders */
160         reg->offset[0] = -2;
161         n = 1;
162         for ( c = reg->replace;  *c;  c++ ) {
163                 if ( *c == '\\' ) {
164                         c++;
165                         continue;
166                 }
167                 if ( *c == '$' ) {
168                         if ( n == SASLREGEX_REPLACE ) {
169 #ifdef NEW_LOGGING
170                                 LDAP_LOG(( "sasl", LDAP_LEVEL_ERR,
171                                            "slap_sasl_regexp_config: \"%s\" has too many $n placeholders (max %d)\n",
172                                            reg->replace, SASLREGEX_REPLACE ));
173 #else
174                                 Debug( LDAP_DEBUG_ANY,
175                                    "SASL replace pattern %s has too many $n placeholders (max %d)\n",
176                                    reg->replace, SASLREGEX_REPLACE, 0 );
177 #endif
178
179                                 return( LDAP_OPERATIONS_ERROR );
180                         }
181                         reg->offset[n] = c - reg->replace;
182                         n++;
183                 }
184         }
185
186         /* Final placeholder, after the last $n */
187         reg->offset[n] = c - reg->replace;
188         n++;
189         reg->offset[n] = -1;
190
191         nSaslRegexp++;
192 #endif
193         return( LDAP_SUCCESS );
194 }
195
196
197 #ifdef HAVE_CYRUS_SASL
198
199 /* Take the passed in SASL name and attempt to convert it into an
200    LDAP URI to find the matching LDAP entry, using the pattern matching
201    strings given in the saslregexp config file directive(s) */
202 static
203 char *slap_sasl_regexp( char *saslname )
204 {
205         char *uri=NULL;
206         int i, n, len, insert;
207         SaslRegexp_t *reg;
208
209 #ifdef NEW_LOGGING
210         LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
211                 "slap_sasl_regexp: converting SASL name %s\n", saslname ));
212 #else
213         Debug( LDAP_DEBUG_TRACE, "slap_sasl_regexp: converting SASL name %s\n",
214            saslname, 0, 0 );
215 #endif
216
217         if (( saslname == NULL ) || ( nSaslRegexp == 0 ))
218                 return( NULL );
219
220         /* Match the normalized SASL name to the saslregexp patterns */
221         for( reg = SaslRegexp,i=0;  i<nSaslRegexp;  i++,reg++ ) {
222                 if ( regexec( &reg->workspace, saslname, SASLREGEX_REPLACE,
223                   reg->strings, 0)  == 0 )
224                         break;
225         }
226
227         if( i >= nSaslRegexp )
228                 return( NULL );
229
230         /*
231          * The match pattern may have been of the form "a(b.*)c(d.*)e" and the
232          * replace pattern of the form "x$1y$2z". The returned string needs
233          * to replace the $1,$2 with the strings that matched (b.*) and (d.*)
234          */
235
236
237         /* Get the total length of the final URI */
238
239         n=1;
240         len = 0;
241         while( reg->offset[n] >= 0 ) {
242                 /* Len of next section from replacement string (x,y,z above) */
243                 len += reg->offset[n] - reg->offset[n-1] - 2;
244                 if( reg->offset[n+1] < 0)
245                         break;
246
247                 /* Len of string from saslname that matched next $i  (b,d above) */
248                 i = reg->replace[ reg->offset[n] + 1 ]  - '0';
249                 len += reg->strings[i].rm_eo - reg->strings[i].rm_so;
250                 n++;
251         }
252         uri = ch_malloc( len + 1 );
253
254         /* Fill in URI with replace string, replacing $i as we go */
255         n=1;
256         insert = 0;
257         while( reg->offset[n] >= 0) {
258                 /* Paste in next section from replacement string (x,y,z above) */
259                 len = reg->offset[n] - reg->offset[n-1] - 2;
260                 strncpy( uri+insert, reg->replace + reg->offset[n-1] + 2, len);
261                 insert += len;
262                 if( reg->offset[n+1] < 0)
263                         break;
264
265                 /* Paste in string from saslname that matched next $i  (b,d above) */
266                 i = reg->replace[ reg->offset[n] + 1 ]  - '0';
267                 len = reg->strings[i].rm_eo - reg->strings[i].rm_so;
268                 strncpy( uri+insert, saslname + reg->strings[i].rm_so, len );
269                 insert += len;
270
271                 n++;
272         }
273
274         uri[insert] = '\0';
275 #ifdef NEW_LOGGING
276         LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
277                 "slap_sasl_regexp: converted SASL name to %s\n", uri ));
278 #else
279         Debug( LDAP_DEBUG_TRACE,
280            "slap_sasl_regexp: converted SASL name to %s\n", uri, 0, 0 );
281 #endif
282
283         return( uri );
284 }
285
286 /* Two empty callback functions to avoid sending results */
287 static void sasl_sc_r( Connection *conn, Operation *o, ber_tag_t tag,
288         ber_int_t msgid, ber_int_t err, const char *matched,
289         const char *text, BerVarray ref, const char *resoid,
290         struct berval *resdata, struct berval *sasldata, LDAPControl **c)
291 {
292 }
293
294 static void sasl_sc_s( Connection *conn, Operation *o, ber_int_t err,
295         const char *matched, const char *text, BerVarray refs, LDAPControl **c,
296         int nentries)
297 {
298 }
299
300 /* This callback actually does some work...*/
301 static int sasl_sc_sasl2dn( BackendDB *be, Connection *conn, Operation *o,
302         Entry *e, AttributeName *an, int ao, LDAPControl **c)
303 {
304         struct berval *ndn = o->o_callback->sc_private;
305
306         /* We only want to be called once */
307         if (ndn->bv_val) {
308                 free(ndn->bv_val);
309                 ndn->bv_val = NULL;
310 #ifdef NEW_LOGGING
311         LDAP_LOG(( "sasl", LDAP_LEVEL_DETAIL1,
312                    "slap_sasl2dn: search DN returned more than 1 entry\n" ));
313 #else
314         Debug( LDAP_DEBUG_TRACE,
315            "slap_sasl2dn: search DN returned more than 1 entry\n", 0,0,0 );
316 #endif
317                 return -1;
318         } else {
319                 ber_dupbv(ndn, &e->e_nname);
320                 return 0;
321         }
322 }
323
324 /*
325  * Given a SASL name (e.g. "UID=name,cn=REALM,cn=MECH,cn=AUTH")
326  * return the LDAP DN to which it matches. The SASL regexp rules in the config
327  * file turn the SASL name into an LDAP URI. If the URI is just a DN (or a
328  * search with scope=base), just return the URI (or its searchbase). Otherwise
329  * an internal search must be done, and if that search returns exactly one
330  * entry, return the DN of that one entry.
331  */
332
333 char *slap_sasl2dn( char *saslname )
334 {
335         char *uri=NULL;
336         struct berval searchbase = {0, NULL};
337         struct berval dn = {0, NULL};
338         int rc, scope;
339         Backend *be;
340         Filter *filter=NULL;
341         slap_callback cb = {sasl_sc_r, sasl_sc_s, sasl_sc_sasl2dn, &dn};
342         Operation op = {0};
343
344 #ifdef NEW_LOGGING
345         LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
346                 "slap_sasl2dn: converting SASL name %s to DN.\n", saslname ));
347 #else
348         Debug( LDAP_DEBUG_TRACE,
349                 "==>slap_sasl2dn: Converting SASL name %s to a DN\n", saslname, 0,0 );
350 #endif
351
352         /* Convert the SASL name into an LDAP URI */
353         uri = slap_sasl_regexp( saslname );
354         if( uri == NULL )
355                 goto FINISHED;
356
357         rc = slap_parseURI( uri, &searchbase, &scope, &filter );
358         if( rc ) {
359                 goto FINISHED;
360         }
361
362         /* Massive shortcut: search scope == base */
363         if( scope == LDAP_SCOPE_BASE ) {
364                 dn = searchbase;
365                 searchbase.bv_len = 0;
366                 searchbase.bv_val = NULL;
367                 goto FINISHED;
368         }
369
370         /* Must do an internal search */
371
372 #ifdef NEW_LOGGING
373         LDAP_LOG(( "sasl", LDAP_LEVEL_DETAIL1,
374                    "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
375                    searchbase.bv_val, scope ));
376 #else
377         Debug( LDAP_DEBUG_TRACE,
378            "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
379            searchbase.bv_val, scope, 0 );
380 #endif
381
382         be = select_backend( &searchbase, 0, 1 );
383         if(( be == NULL ) || ( be->be_search == NULL))
384                 goto FINISHED;
385         suffix_alias( be, &searchbase );
386
387         ldap_pvt_thread_mutex_init( &op.o_abandonmutex );
388         op.o_tag = LDAP_REQ_SEARCH;
389         op.o_protocol = LDAP_VERSION3;
390         op.o_ndn.bv_val = saslname;
391         op.o_ndn.bv_len = strlen(saslname);
392         op.o_callback = &cb;
393         op.o_time = slap_get_time();
394
395         (*be->be_search)( be, /*conn*/NULL, &op, /*base*/NULL, &searchbase,
396            scope, /*deref=*/1, /*sizelimit=*/1, /*time=*/0, filter, /*fstr=*/NULL,
397            /*attrs=*/NULL, /*attrsonly=*/0 );
398         
399         ldap_pvt_thread_mutex_destroy( &op.o_abandonmutex );
400
401 FINISHED:
402         if( searchbase.bv_len ) ch_free( searchbase.bv_val );
403         if( filter ) filter_free( filter );
404         if( uri ) ch_free( uri );
405
406 #ifdef NEW_LOGGING
407         LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
408                 "slap_sasl2dn: Converted SASL name to %s\n",
409                 dn.bv_len ? dn.bv_val : "<nothing>" ));
410 #else
411         Debug( LDAP_DEBUG_TRACE, "<==slap_sasl2dn: Converted SASL name to %s\n",
412                 dn.bv_len ? dn.bv_val : "<nothing>", 0, 0 );
413 #endif
414
415         return( dn.bv_val );
416 }
417
418 typedef struct smatch_info {
419         struct berval *dn;
420         int match;
421 } smatch_info;
422
423 static int sasl_sc_smatch( BackendDB *be, Connection *conn, Operation *o,
424         Entry *e, AttributeName *an, int ao, LDAPControl **c)
425 {
426         smatch_info *sm = o->o_callback->sc_private;
427
428         if (dn_match(sm->dn, &e->e_nname)) {
429                 sm->match = 1;
430                 return -1;      /* short-circuit the search */
431         } else {
432                 return 1;
433         }
434 }
435
436 /*
437  * Map a SASL regexp rule to a DN. If the rule is just a DN or a scope=base
438  * URI, just strcmp the rule (or its searchbase) to the *assertDN. Otherwise,
439  * the rule must be used as an internal search for entries. If that search
440  * returns the *assertDN entry, the match is successful.
441  *
442  * The assertDN should not have the dn: prefix
443  */
444
445 static
446 int slap_sasl_match( char *rule, struct berval *assertDN, char *authc )
447 {
448         struct berval searchbase = {0, NULL};
449         int rc, scope;
450         Backend *be;
451         Filter *filter=NULL;
452         regex_t reg;
453         smatch_info sm;
454         slap_callback cb = {sasl_sc_r, sasl_sc_s, sasl_sc_smatch, &sm};
455         Operation op = {0};
456
457 #ifdef NEW_LOGGING
458         LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
459                 "slap_sasl_match: comparing DN %s to rule %s\n", assertDN, rule ));
460 #else
461         Debug( LDAP_DEBUG_TRACE,
462            "===>slap_sasl_match: comparing DN %s to rule %s\n", assertDN, rule, 0 );
463 #endif
464
465         rc = slap_parseURI( rule, &searchbase, &scope, &filter );
466         if( rc != LDAP_SUCCESS )
467                 goto CONCLUDED;
468
469         /* Massive shortcut: search scope == base */
470         if( scope == LDAP_SCOPE_BASE ) {
471                 rc = regcomp(&reg, searchbase.bv_val,
472                         REG_EXTENDED|REG_ICASE|REG_NOSUB);
473                 if ( rc == 0 ) {
474                         rc = regexec(&reg, assertDN->bv_val, 0, NULL, 0);
475                         regfree( &reg );
476                 }
477                 if ( rc == 0 )
478                         rc = LDAP_SUCCESS;
479                 else
480                         rc = LDAP_INAPPROPRIATE_AUTH;
481                 goto CONCLUDED;
482         }
483
484         /* Must run an internal search. */
485
486 #ifdef NEW_LOGGING
487         LDAP_LOG(( "sasl", LDAP_LEVEL_DETAIL1,
488                 "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
489                 searchbase.bv_val, scope ));
490 #else
491         Debug( LDAP_DEBUG_TRACE,
492            "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
493            searchbase.bv_val, scope, 0 );
494 #endif
495
496         be = select_backend( &searchbase, 0, 1 );
497         if(( be == NULL ) || ( be->be_search == NULL)) {
498                 rc = LDAP_INAPPROPRIATE_AUTH;
499                 goto CONCLUDED;
500         }
501         suffix_alias( be, &searchbase );
502
503         sm.dn = assertDN;
504         sm.match = 0;
505
506         ldap_pvt_thread_mutex_init( &op.o_abandonmutex );
507         op.o_tag = LDAP_REQ_SEARCH;
508         op.o_protocol = LDAP_VERSION3;
509         op.o_ndn.bv_val = authc;
510         op.o_ndn.bv_len = strlen(authc);
511         op.o_callback = &cb;
512         op.o_time = slap_get_time();
513
514         (*be->be_search)( be, /*conn=*/NULL, &op, /*base=*/NULL, &searchbase,
515            scope, /*deref=*/1, /*sizelimit=*/0, /*time=*/0, filter, /*fstr=*/NULL,
516            /*attrs=*/NULL, /*attrsonly=*/0 );
517
518         ldap_pvt_thread_mutex_destroy( &op.o_abandonmutex );
519
520         if (sm.match)
521                 rc = LDAP_SUCCESS;
522         else
523                 rc = LDAP_INAPPROPRIATE_AUTH;
524
525 CONCLUDED:
526         if( searchbase.bv_len ) ch_free( searchbase.bv_val );
527         if( filter ) filter_free( filter );
528 #ifdef NEW_LOGGING
529         LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
530                    "slap_sasl_match: comparison returned %d\n", rc ));
531 #else
532         Debug( LDAP_DEBUG_TRACE,
533            "<===slap_sasl_match: comparison returned %d\n", rc, 0, 0);
534 #endif
535
536         return( rc );
537 }
538
539
540 /*
541  * This function answers the question, "Can this ID authorize to that ID?",
542  * based on authorization rules. The rules are stored in the *searchDN, in the
543  * attribute named by *attr. If any of those rules map to the *assertDN, the
544  * authorization is approved.
545  *
546  * DN's passed in should have a dn: prefix
547  */
548 static int
549 slap_sasl_check_authz(char *searchDN, char *assertDN, struct berval *attr, char *authc)
550 {
551         const char *errmsg;
552         int i, rc;
553         BerVarray vals=NULL;
554         AttributeDescription *ad=NULL;
555         struct berval bv;
556
557 #ifdef NEW_LOGGING
558         LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
559                    "slap_sasl_check_authz: does %s match %s rule in %s?\n",
560                    assertDN, attr, searchDN ));
561 #else
562         Debug( LDAP_DEBUG_TRACE,
563            "==>slap_sasl_check_authz: does %s match %s rule in %s?\n",
564            assertDN, attr, searchDN);
565 #endif
566
567         rc = slap_bv2ad( attr, &ad, &errmsg );
568         if( rc != LDAP_SUCCESS )
569                 goto COMPLETE;
570
571         bv.bv_val = searchDN+3;
572         bv.bv_len = strlen(bv.bv_val);
573         rc = backend_attribute( NULL, NULL, NULL, NULL, &bv, ad, &vals );
574         if( rc != LDAP_SUCCESS )
575                 goto COMPLETE;
576
577         bv.bv_val = assertDN+3;
578         bv.bv_len = strlen(bv.bv_val);
579         /* Check if the *assertDN matches any **vals */
580         for( i=0; vals[i].bv_val != NULL; i++ ) {
581                 rc = slap_sasl_match( vals[i].bv_val, &bv, authc );
582                 if ( rc == LDAP_SUCCESS )
583                         goto COMPLETE;
584         }
585         rc = LDAP_INAPPROPRIATE_AUTH;
586
587 COMPLETE:
588         if( vals ) ber_bvarray_free( vals );
589
590 #ifdef NEW_LOGGING
591         LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
592                    "slap_sasl_check_authz: %s check returning %s\n", attr, rc ));
593 #else
594         Debug( LDAP_DEBUG_TRACE,
595            "<==slap_sasl_check_authz: %s check returning %d\n", attr, rc, 0);
596 #endif
597
598         return( rc );
599 }
600 #endif  /* HAVE_CYRUS_SASL */
601
602
603 /* Check if a bind can SASL authorize to another identity.
604    Accepts authorization DN's with "dn:" prefix */
605
606 static struct berval sasl_authz_src = {
607         sizeof(SASL_AUTHZ_SOURCE_ATTR)-1, SASL_AUTHZ_SOURCE_ATTR };
608
609 static struct berval sasl_authz_dst = {
610         sizeof(SASL_AUTHZ_DEST_ATTR)-1, SASL_AUTHZ_DEST_ATTR };
611
612 int slap_sasl_authorized( char *authcDN, char *authzDN )
613 {
614         int rc = LDAP_INAPPROPRIATE_AUTH;
615
616 #ifdef HAVE_CYRUS_SASL
617         /* User binding as anonymous */
618         if ( authzDN == NULL ) {
619                 rc = LDAP_SUCCESS;
620                 goto DONE;
621         }
622
623 #ifdef NEW_LOGGING
624         LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
625                 "slap_sasl_authorized: can %s become %s?\n", authcDN, authzDN ));
626 #else
627         Debug( LDAP_DEBUG_TRACE,
628            "==>slap_sasl_authorized: can %s become %s?\n", authcDN, authzDN, 0 );
629 #endif
630
631         /* If person is authorizing to self, succeed */
632         if ( !strcmp( authcDN, authzDN ) ) {
633                 rc = LDAP_SUCCESS;
634                 goto DONE;
635         }
636
637         /* Check source rules */
638         rc = slap_sasl_check_authz( authcDN, authzDN, &sasl_authz_src,
639            authcDN );
640         if( rc == LDAP_SUCCESS ) {
641                 goto DONE;
642         }
643
644         /* Check destination rules */
645         rc = slap_sasl_check_authz( authzDN, authcDN, &sasl_authz_dst,
646            authcDN );
647         if( rc == LDAP_SUCCESS ) {
648                 goto DONE;
649         }
650
651         rc = LDAP_INAPPROPRIATE_AUTH;
652
653 DONE:
654 #endif
655
656 #ifdef NEW_LOGGING
657         LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
658                 "slap_sasl_authorized: return %d\n", rc ));
659 #else
660         Debug( LDAP_DEBUG_TRACE,
661                 "<== slap_sasl_authorized: return %d\n", rc, 0, 0 );
662 #endif
663
664         return( rc );
665 }