]> git.sur5r.net Git - openldap/blob - servers/slapd/saslauthz.c
Added comment for future reference re: in-directory secrets
[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 == '\\' && c[1] ) {
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         /* FIXME: move this check to after select_backend, and set
373          * the selected backend in conn->c_authz_backend, to allow
374          * passwd_extop to be used on in-directory SASL secrets.
375          *   ... when all of that gets implemented...
376          */
377         /* Massive shortcut: search scope == base */
378         if( scope == LDAP_SCOPE_BASE ) {
379                 *dn = searchbase;
380                 searchbase.bv_len = 0;
381                 searchbase.bv_val = NULL;
382                 goto FINISHED;
383         }
384
385         /* Must do an internal search */
386
387 #ifdef NEW_LOGGING
388         LDAP_LOG(( "sasl", LDAP_LEVEL_DETAIL1,
389                    "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
390                    searchbase.bv_val, scope ));
391 #else
392         Debug( LDAP_DEBUG_TRACE,
393            "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
394            searchbase.bv_val, scope, 0 );
395 #endif
396
397         be = select_backend( &searchbase, 0, 1 );
398         if(( be == NULL ) || ( be->be_search == NULL))
399                 goto FINISHED;
400         suffix_alias( be, &searchbase );
401
402         op.o_tag = LDAP_REQ_SEARCH;
403         op.o_protocol = LDAP_VERSION3;
404         op.o_ndn = *saslname;
405         op.o_callback = &cb;
406         op.o_time = slap_get_time();
407
408         (*be->be_search)( be, /*conn*/NULL, &op, /*base*/NULL, &searchbase,
409            scope, /*deref=*/1, /*sizelimit=*/1, /*time=*/0, filter, /*fstr=*/NULL,
410            /*attrs=*/NULL, /*attrsonly=*/0 );
411         
412 FINISHED:
413         if( searchbase.bv_len ) ch_free( searchbase.bv_val );
414         if( filter ) filter_free( filter );
415         if( uri.bv_val ) ch_free( uri.bv_val );
416
417 #ifdef NEW_LOGGING
418         LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
419                 "slap_sasl2dn: Converted SASL name to %s\n",
420                 dn->bv_len ? dn->bv_val : "<nothing>" ));
421 #else
422         Debug( LDAP_DEBUG_TRACE, "<==slap_sasl2dn: Converted SASL name to %s\n",
423                 dn->bv_len ? dn->bv_val : "<nothing>", 0, 0 );
424 #endif
425
426         return;
427 }
428
429 typedef struct smatch_info {
430         struct berval *dn;
431         int match;
432 } smatch_info;
433
434 static int sasl_sc_smatch( BackendDB *be, Connection *conn, Operation *o,
435         Entry *e, AttributeName *an, int ao, LDAPControl **c)
436 {
437         smatch_info *sm = o->o_callback->sc_private;
438
439         if (dn_match(sm->dn, &e->e_nname)) {
440                 sm->match = 1;
441                 return -1;      /* short-circuit the search */
442         } else {
443                 return 1;
444         }
445 }
446
447 /*
448  * Map a SASL regexp rule to a DN. If the rule is just a DN or a scope=base
449  * URI, just strcmp the rule (or its searchbase) to the *assertDN. Otherwise,
450  * the rule must be used as an internal search for entries. If that search
451  * returns the *assertDN entry, the match is successful.
452  *
453  * The assertDN should not have the dn: prefix
454  */
455
456 static
457 int slap_sasl_match( struct berval *rule, struct berval *assertDN, struct berval *authc )
458 {
459         struct berval searchbase = {0, NULL};
460         int rc, scope;
461         Backend *be;
462         Filter *filter=NULL;
463         regex_t reg;
464         smatch_info sm;
465         slap_callback cb = { sasl_sc_r, sasl_sc_s, sasl_sc_smatch, NULL };
466         Operation op = {0};
467
468 #ifdef NEW_LOGGING
469         LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
470                 "slap_sasl_match: comparing DN %s to rule %s\n", assertDN->bv_val, rule->bv_val ));
471 #else
472         Debug( LDAP_DEBUG_TRACE,
473            "===>slap_sasl_match: comparing DN %s to rule %s\n", assertDN->bv_val, rule->bv_val, 0 );
474 #endif
475
476         rc = slap_parseURI( rule, &searchbase, &scope, &filter );
477         if( rc != LDAP_SUCCESS )
478                 goto CONCLUDED;
479
480         /* Massive shortcut: search scope == base */
481         if( scope == LDAP_SCOPE_BASE ) {
482                 rc = regcomp(&reg, searchbase.bv_val,
483                         REG_EXTENDED|REG_ICASE|REG_NOSUB);
484                 if ( rc == 0 ) {
485                         rc = regexec(&reg, assertDN->bv_val, 0, NULL, 0);
486                         regfree( &reg );
487                 }
488                 if ( rc == 0 )
489                         rc = LDAP_SUCCESS;
490                 else
491                         rc = LDAP_INAPPROPRIATE_AUTH;
492                 goto CONCLUDED;
493         }
494
495         /* Must run an internal search. */
496
497 #ifdef NEW_LOGGING
498         LDAP_LOG(( "sasl", LDAP_LEVEL_DETAIL1,
499                 "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
500                 searchbase.bv_val, scope ));
501 #else
502         Debug( LDAP_DEBUG_TRACE,
503            "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
504            searchbase.bv_val, scope, 0 );
505 #endif
506
507         be = select_backend( &searchbase, 0, 1 );
508         if(( be == NULL ) || ( be->be_search == NULL)) {
509                 rc = LDAP_INAPPROPRIATE_AUTH;
510                 goto CONCLUDED;
511         }
512         suffix_alias( be, &searchbase );
513
514         sm.dn = assertDN;
515         sm.match = 0;
516         cb.sc_private = &sm;
517
518         op.o_tag = LDAP_REQ_SEARCH;
519         op.o_protocol = LDAP_VERSION3;
520         op.o_ndn = *authc;
521         op.o_callback = &cb;
522         op.o_time = slap_get_time();
523
524         (*be->be_search)( be, /*conn=*/NULL, &op, /*base=*/NULL, &searchbase,
525            scope, /*deref=*/1, /*sizelimit=*/0, /*time=*/0, filter, /*fstr=*/NULL,
526            /*attrs=*/NULL, /*attrsonly=*/0 );
527
528         if (sm.match)
529                 rc = LDAP_SUCCESS;
530         else
531                 rc = LDAP_INAPPROPRIATE_AUTH;
532
533 CONCLUDED:
534         if( searchbase.bv_len ) ch_free( searchbase.bv_val );
535         if( filter ) filter_free( filter );
536 #ifdef NEW_LOGGING
537         LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
538                    "slap_sasl_match: comparison returned %d\n", rc ));
539 #else
540         Debug( LDAP_DEBUG_TRACE,
541            "<===slap_sasl_match: comparison returned %d\n", rc, 0, 0);
542 #endif
543
544         return( rc );
545 }
546
547
548 /*
549  * This function answers the question, "Can this ID authorize to that ID?",
550  * based on authorization rules. The rules are stored in the *searchDN, in the
551  * attribute named by *attr. If any of those rules map to the *assertDN, the
552  * authorization is approved.
553  *
554  * The DNs should not have the dn: prefix
555  */
556 static int
557 slap_sasl_check_authz(struct berval *searchDN, struct berval *assertDN, struct berval *attr, struct berval *authc)
558 {
559         const char *errmsg;
560         int i, rc;
561         BerVarray vals=NULL;
562         AttributeDescription *ad=NULL;
563
564 #ifdef NEW_LOGGING
565         LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
566                    "slap_sasl_check_authz: does %s match %s rule in %s?\n",
567                    assertDN->bv_val, attr->bv_val, searchDN->bv_val ));
568 #else
569         Debug( LDAP_DEBUG_TRACE,
570            "==>slap_sasl_check_authz: does %s match %s rule in %s?\n",
571            assertDN->bv_val, attr->bv_val, searchDN->bv_val);
572 #endif
573
574         rc = slap_bv2ad( attr, &ad, &errmsg );
575         if( rc != LDAP_SUCCESS )
576                 goto COMPLETE;
577
578         rc = backend_attribute( NULL, NULL, NULL, NULL, searchDN, ad, &vals );
579         if( rc != LDAP_SUCCESS )
580                 goto COMPLETE;
581
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], assertDN, 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  * The DNs should not have the dn: prefix
608  */
609
610 static struct berval sasl_authz_src = {
611         sizeof(SASL_AUTHZ_SOURCE_ATTR)-1, SASL_AUTHZ_SOURCE_ATTR };
612
613 static struct berval sasl_authz_dst = {
614         sizeof(SASL_AUTHZ_DEST_ATTR)-1, SASL_AUTHZ_DEST_ATTR };
615
616 int slap_sasl_authorized( struct berval *authcDN, struct berval *authzDN )
617 {
618         int rc = LDAP_INAPPROPRIATE_AUTH;
619
620 #ifdef HAVE_CYRUS_SASL
621         /* User binding as anonymous */
622         if ( authzDN == NULL ) {
623                 rc = LDAP_SUCCESS;
624                 goto DONE;
625         }
626
627 #ifdef NEW_LOGGING
628         LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
629                 "slap_sasl_authorized: can %s become %s?\n", authcDN->bv_val, authzDN->bv_val ));
630 #else
631         Debug( LDAP_DEBUG_TRACE,
632            "==>slap_sasl_authorized: can %s become %s?\n", authcDN->bv_val, authzDN->bv_val, 0 );
633 #endif
634
635         /* If person is authorizing to self, succeed */
636         if ( dn_match( authcDN, authzDN ) ) {
637                 rc = LDAP_SUCCESS;
638                 goto DONE;
639         }
640
641         /* Check source rules */
642         rc = slap_sasl_check_authz( authcDN, authzDN, &sasl_authz_src,
643            authcDN );
644         if( rc == LDAP_SUCCESS ) {
645                 goto DONE;
646         }
647
648         /* Check destination rules */
649         rc = slap_sasl_check_authz( authzDN, authcDN, &sasl_authz_dst,
650            authcDN );
651         if( rc == LDAP_SUCCESS ) {
652                 goto DONE;
653         }
654
655         rc = LDAP_INAPPROPRIATE_AUTH;
656
657 DONE:
658 #endif
659
660 #ifdef NEW_LOGGING
661         LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
662                 "slap_sasl_authorized: return %d\n", rc ));
663 #else
664         Debug( LDAP_DEBUG_TRACE,
665                 "<== slap_sasl_authorized: return %d\n", rc, 0, 0 );
666 #endif
667
668         return( rc );
669 }