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