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