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