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