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