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