]> git.sur5r.net Git - openldap/blob - servers/slapd/saslauthz.c
Don't use 'shtool mkln' as ln(1) replacement.
[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, &sm};
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
543         ldap_pvt_thread_mutex_init( &op.o_abandonmutex );
544         op.o_tag = LDAP_REQ_SEARCH;
545         op.o_protocol = LDAP_VERSION3;
546         op.o_ndn = *authc;
547         op.o_callback = &cb;
548         op.o_time = slap_get_time();
549
550         (*be->be_search)( be, /*conn=*/NULL, &op, /*base=*/NULL, &searchbase,
551            scope, /*deref=*/1, /*sizelimit=*/0, /*time=*/0, filter, /*fstr=*/NULL,
552            /*attrs=*/NULL, /*attrsonly=*/0 );
553
554         ldap_pvt_thread_mutex_destroy( &op.o_abandonmutex );
555
556         if (sm.match)
557                 rc = LDAP_SUCCESS;
558         else
559                 rc = LDAP_INAPPROPRIATE_AUTH;
560
561 CONCLUDED:
562         if( searchbase.bv_len ) ch_free( searchbase.bv_val );
563         if( filter ) filter_free( filter );
564 #ifdef NEW_LOGGING
565         LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
566                    "slap_sasl_match: comparison returned %d\n", rc ));
567 #else
568         Debug( LDAP_DEBUG_TRACE,
569            "<===slap_sasl_match: comparison returned %d\n", rc, 0, 0);
570 #endif
571
572         return( rc );
573 }
574
575
576 /*
577  * This function answers the question, "Can this ID authorize to that ID?",
578  * based on authorization rules. The rules are stored in the *searchDN, in the
579  * attribute named by *attr. If any of those rules map to the *assertDN, the
580  * authorization is approved.
581  *
582  * DN's passed in should have a dn: prefix
583  */
584 static int
585 slap_sasl_check_authz(struct berval *searchDN, struct berval *assertDN, struct berval *attr, struct berval *authc)
586 {
587         const char *errmsg;
588         int i, rc;
589         BerVarray vals=NULL;
590         AttributeDescription *ad=NULL;
591         struct berval bv;
592
593 #ifdef NEW_LOGGING
594         LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
595                    "slap_sasl_check_authz: does %s match %s rule in %s?\n",
596                    assertDN->bv_val, attr->bv_val, searchDN->bv_val ));
597 #else
598         Debug( LDAP_DEBUG_TRACE,
599            "==>slap_sasl_check_authz: does %s match %s rule in %s?\n",
600            assertDN->bv_val, attr->bv_val, searchDN->bv_val);
601 #endif
602
603         rc = slap_bv2ad( attr, &ad, &errmsg );
604         if( rc != LDAP_SUCCESS )
605                 goto COMPLETE;
606
607         bv.bv_val = searchDN->bv_val + 3;
608         bv.bv_len = searchDN->bv_len - 3;
609         rc = backend_attribute( NULL, NULL, NULL, NULL, &bv, ad, &vals );
610         if( rc != LDAP_SUCCESS )
611                 goto COMPLETE;
612
613         bv.bv_val = assertDN->bv_val + 3;
614         bv.bv_len = assertDN->bv_len - 3;
615         /* Check if the *assertDN matches any **vals */
616         for( i=0; vals[i].bv_val != NULL; i++ ) {
617                 rc = slap_sasl_match( vals[i].bv_val, &bv, authc );
618                 if ( rc == LDAP_SUCCESS )
619                         goto COMPLETE;
620         }
621         rc = LDAP_INAPPROPRIATE_AUTH;
622
623 COMPLETE:
624         if( vals ) ber_bvarray_free( vals );
625
626 #ifdef NEW_LOGGING
627         LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
628                    "slap_sasl_check_authz: %s check returning %s\n", attr->bv_val, rc ));
629 #else
630         Debug( LDAP_DEBUG_TRACE,
631            "<==slap_sasl_check_authz: %s check returning %d\n", attr->bv_val, rc, 0);
632 #endif
633
634         return( rc );
635 }
636 #endif  /* HAVE_CYRUS_SASL */
637
638
639 /* Check if a bind can SASL authorize to another identity.
640    Accepts authorization DN's with "dn:" prefix */
641
642 static struct berval sasl_authz_src = {
643         sizeof(SASL_AUTHZ_SOURCE_ATTR)-1, SASL_AUTHZ_SOURCE_ATTR };
644
645 static struct berval sasl_authz_dst = {
646         sizeof(SASL_AUTHZ_DEST_ATTR)-1, SASL_AUTHZ_DEST_ATTR };
647
648 int slap_sasl_authorized( struct berval *authcDN, struct berval *authzDN )
649 {
650         int rc = LDAP_INAPPROPRIATE_AUTH;
651
652 #ifdef HAVE_CYRUS_SASL
653         /* User binding as anonymous */
654         if ( authzDN == NULL ) {
655                 rc = LDAP_SUCCESS;
656                 goto DONE;
657         }
658
659 #ifdef NEW_LOGGING
660         LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
661                 "slap_sasl_authorized: can %s become %s?\n", authcDN->bv_val, authzDN->bv_val ));
662 #else
663         Debug( LDAP_DEBUG_TRACE,
664            "==>slap_sasl_authorized: can %s become %s?\n", authcDN->bv_val, authzDN->bv_val, 0 );
665 #endif
666
667         /* If person is authorizing to self, succeed */
668         if ( dn_match( authcDN, authzDN ) ) {
669                 rc = LDAP_SUCCESS;
670                 goto DONE;
671         }
672
673         /* Check source rules */
674         rc = slap_sasl_check_authz( authcDN, authzDN, &sasl_authz_src,
675            authcDN );
676         if( rc == LDAP_SUCCESS ) {
677                 goto DONE;
678         }
679
680         /* Check destination rules */
681         rc = slap_sasl_check_authz( authzDN, authcDN, &sasl_authz_dst,
682            authcDN );
683         if( rc == LDAP_SUCCESS ) {
684                 goto DONE;
685         }
686
687         rc = LDAP_INAPPROPRIATE_AUTH;
688
689 DONE:
690 #endif
691
692 #ifdef NEW_LOGGING
693         LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
694                 "slap_sasl_authorized: return %d\n", rc ));
695 #else
696         Debug( LDAP_DEBUG_TRACE,
697                 "<== slap_sasl_authorized: return %d\n", rc, 0, 0 );
698 #endif
699
700         return( rc );
701 }