]> git.sur5r.net Git - openldap/blob - servers/slapd/saslauthz.c
Experimental cruft to propagate valid Operation to SASL callbacks.
[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         SaslRegexp_t *reg;
290         int i;
291
292         memset( out, 0, sizeof( *out ) );
293
294 #ifdef NEW_LOGGING
295         LDAP_LOG( TRANSPORT, ENTRY, 
296                 "slap_sasl_regexp: converting SASL name %s\n", saslname, 0, 0 );
297 #else
298         Debug( LDAP_DEBUG_TRACE, "slap_sasl_regexp: converting SASL name %s\n",
299            saslname, 0, 0 );
300 #endif
301
302         if (( saslname == NULL ) || ( nSaslRegexp == 0 ))
303                 return( 0 );
304
305         /* Match the normalized SASL name to the saslregexp patterns */
306         for( reg = SaslRegexp,i=0;  i<nSaslRegexp;  i++,reg++ ) {
307                 if ( regexec( &reg->sr_workspace, saslname, SASLREGEX_REPLACE,
308                   reg->sr_strings, 0)  == 0 )
309                         break;
310         }
311
312         if( i >= nSaslRegexp )
313                 return( 0 );
314
315         /*
316          * The match pattern may have been of the form "a(b.*)c(d.*)e" and the
317          * replace pattern of the form "x$1y$2z". The returned string needs
318          * to replace the $1,$2 with the strings that matched (b.*) and (d.*)
319          */
320         slap_sasl_rx_exp( reg->sr_replace, reg->sr_offset,
321                 reg->sr_strings, saslname, out );
322
323 #ifdef NEW_LOGGING
324         LDAP_LOG( TRANSPORT, ENTRY, 
325                 "slap_sasl_regexp: converted SASL name to %s\n",
326                 out->bv_len ? out->bv_val : "", 0, 0 );
327 #else
328         Debug( LDAP_DEBUG_TRACE,
329            "slap_sasl_regexp: converted SASL name to ldap:///%s??%s?%s\n",
330                 out->bv_len ? out->bv_val : "", 0, 0 );
331 #endif
332
333         return( 1 );
334 }
335
336 /* Two empty callback functions to avoid sending results */
337 void slap_cb_null_response( Connection *conn, Operation *o, ber_tag_t tag,
338         ber_int_t msgid, ber_int_t err, const char *matched,
339         const char *text, BerVarray ref, const char *resoid,
340         struct berval *resdata, struct berval *sasldata, LDAPControl **c)
341 {
342 }
343
344 void slap_cb_null_sresult( Connection *conn, Operation *o, ber_int_t err,
345         const char *matched, const char *text, BerVarray refs, LDAPControl **c,
346         int nentries)
347 {
348 }
349
350 /* This callback actually does some work...*/
351 static int sasl_sc_sasl2dn( BackendDB *be, Connection *conn, Operation *o,
352         Entry *e, AttributeName *an, int ao, LDAPControl **c)
353 {
354         struct berval *ndn = o->o_callback->sc_private;
355
356         /* We only want to be called once */
357         if( ndn->bv_val ) {
358                 free(ndn->bv_val);
359                 ndn->bv_val = NULL;
360
361 #ifdef NEW_LOGGING
362         LDAP_LOG( TRANSPORT, DETAIL1,
363                     "slap_sasl2dn: search DN returned more than 1 entry\n", 0, 0, 0 );
364 #else
365                 Debug( LDAP_DEBUG_TRACE,
366                         "slap_sasl2dn: search DN returned more than 1 entry\n", 0,0,0 );
367 #endif
368                 return -1;
369         }
370
371         ber_dupbv(ndn, &e->e_nname);
372         return 0;
373 }
374
375 /*
376  * Given a SASL name (e.g. "UID=name,cn=REALM,cn=MECH,cn=AUTH")
377  * return the LDAP DN to which it matches. The SASL regexp rules in the config
378  * file turn the SASL name into an LDAP URI. If the URI is just a DN (or a
379  * search with scope=base), just return the URI (or its searchbase). Otherwise
380  * an internal search must be done, and if that search returns exactly one
381  * entry, return the DN of that one entry.
382  */
383
384 void slap_sasl2dn( Connection *conn,
385         struct berval *saslname, struct berval *sasldn )
386 {
387         int rc;
388         Backend *be = NULL;
389         struct berval dn = { 0, NULL };
390         int scope = LDAP_SCOPE_BASE;
391         Filter *filter = NULL;
392         slap_callback cb = {slap_cb_null_response, slap_cb_null_sresult, sasl_sc_sasl2dn, NULL};
393         Operation op = {0};
394         struct berval regout = { 0, NULL };
395
396 #ifdef NEW_LOGGING
397         LDAP_LOG( TRANSPORT, ENTRY, 
398                 "slap_sasl2dn: converting SASL name %s to DN.\n",
399                 saslname->bv_val, 0, 0 );
400 #else
401         Debug( LDAP_DEBUG_TRACE, "==>slap_sasl2dn: "
402                 "converting SASL name %s to a DN\n",
403                 saslname->bv_val, 0,0 );
404 #endif
405
406         sasldn->bv_val = NULL;
407         sasldn->bv_len = 0;
408         cb.sc_private = sasldn;
409
410         /* Convert the SASL name into a minimal URI */
411         if( !slap_sasl_regexp( saslname, &regout ) ) {
412                 goto FINISHED;
413         }
414
415         rc = slap_parseURI( &regout, &dn, &scope, &filter );
416         if( rc != LDAP_SUCCESS ) {
417                 goto FINISHED;
418         }
419
420         /* Must do an internal search */
421         be = select_backend( &dn, 0, 1 );
422
423         /* Massive shortcut: search scope == base */
424         if( scope == LDAP_SCOPE_BASE ) {
425                 *sasldn = dn;
426                 dn.bv_len = 0;
427                 dn.bv_val = NULL;
428                 goto FINISHED;
429         }
430
431 #ifdef NEW_LOGGING
432         LDAP_LOG( TRANSPORT, DETAIL1, 
433                 "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
434                 dn.bv_val, scope, 0 );
435 #else
436         Debug( LDAP_DEBUG_TRACE,
437                 "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
438                 dn.bv_val, scope, 0 );
439 #endif
440
441         if(( be == NULL ) || ( be->be_search == NULL)) {
442                 goto FINISHED;
443         }
444         suffix_alias( be, &dn );
445
446         op.o_tag = LDAP_REQ_SEARCH;
447         op.o_protocol = LDAP_VERSION3;
448         op.o_ndn = *saslname;
449         op.o_callback = &cb;
450         op.o_time = slap_get_time();
451         op.o_do_not_cache = 1;
452         op.o_threadctx = conn->c_sasl_bindop->o_threadctx;
453
454         (*be->be_search)( be, conn, &op, NULL, &dn,
455                 scope, LDAP_DEREF_NEVER, 1, 0,
456                 filter, NULL, NULL, 1 );
457         
458 FINISHED:
459         if( sasldn->bv_len ) {
460                 conn->c_authz_backend = be;
461         }
462         if( dn.bv_len ) ch_free( dn.bv_val );
463         if( filter ) filter_free( filter );
464
465 #ifdef NEW_LOGGING
466         LDAP_LOG( TRANSPORT, ENTRY, 
467                 "slap_sasl2dn: Converted SASL name to %s\n",
468                 sasldn->bv_len ? sasldn->bv_val : "<nothing>", 0, 0 );
469 #else
470         Debug( LDAP_DEBUG_TRACE, "<==slap_sasl2dn: Converted SASL name to %s\n",
471                 sasldn->bv_len ? sasldn->bv_val : "<nothing>", 0, 0 );
472 #endif
473
474         return;
475 }
476
477 typedef struct smatch_info {
478         struct berval *dn;
479         int match;
480 } smatch_info;
481
482 static int sasl_sc_smatch( BackendDB *be, Connection *conn, Operation *o,
483         Entry *e, AttributeName *an, int ao, LDAPControl **c)
484 {
485         smatch_info *sm = o->o_callback->sc_private;
486
487         if (dn_match(sm->dn, &e->e_nname)) {
488                 sm->match = 1;
489                 return -1;      /* short-circuit the search */
490         } else {
491                 return 1;
492         }
493 }
494
495 /*
496  * Map a SASL regexp rule to a DN. If the rule is just a DN or a scope=base
497  * URI, just strcmp the rule (or its searchbase) to the *assertDN. Otherwise,
498  * the rule must be used as an internal search for entries. If that search
499  * returns the *assertDN entry, the match is successful.
500  *
501  * The assertDN should not have the dn: prefix
502  */
503
504 static
505 int slap_sasl_match(Connection *conn, struct berval *rule, struct berval *assertDN, struct berval *authc )
506 {
507         struct berval searchbase = {0, NULL};
508         int rc, scope;
509         Backend *be;
510         Filter *filter=NULL;
511         regex_t reg;
512         smatch_info sm;
513         slap_callback cb = { slap_cb_null_response, slap_cb_null_sresult, sasl_sc_smatch, NULL };
514         Operation op = {0};
515
516 #ifdef NEW_LOGGING
517         LDAP_LOG( TRANSPORT, ENTRY, 
518                 "slap_sasl_match: comparing DN %s to rule %s\n", 
519                 assertDN->bv_val, rule->bv_val,0 );
520 #else
521         Debug( LDAP_DEBUG_TRACE,
522            "===>slap_sasl_match: comparing DN %s to rule %s\n", assertDN->bv_val, rule->bv_val, 0 );
523 #endif
524
525         rc = slap_parseURI( rule, &searchbase, &scope, &filter );
526         if( rc != LDAP_SUCCESS )
527                 goto CONCLUDED;
528
529         /* Massive shortcut: search scope == base */
530         if( scope == LDAP_SCOPE_BASE ) {
531                 rc = regcomp(&reg, searchbase.bv_val,
532                         REG_EXTENDED|REG_ICASE|REG_NOSUB);
533                 if ( rc == 0 ) {
534                         rc = regexec(&reg, assertDN->bv_val, 0, NULL, 0);
535                         regfree( &reg );
536                 }
537                 if ( rc == 0 )
538                         rc = LDAP_SUCCESS;
539                 else
540                         rc = LDAP_INAPPROPRIATE_AUTH;
541                 goto CONCLUDED;
542         }
543
544         /* Must run an internal search. */
545
546 #ifdef NEW_LOGGING
547         LDAP_LOG( TRANSPORT, DETAIL1, 
548                 "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
549                 searchbase.bv_val, scope,0 );
550 #else
551         Debug( LDAP_DEBUG_TRACE,
552            "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
553            searchbase.bv_val, scope, 0 );
554 #endif
555
556         be = select_backend( &searchbase, 0, 1 );
557         if(( be == NULL ) || ( be->be_search == NULL)) {
558                 rc = LDAP_INAPPROPRIATE_AUTH;
559                 goto CONCLUDED;
560         }
561         suffix_alias( be, &searchbase );
562
563         sm.dn = assertDN;
564         sm.match = 0;
565         cb.sc_private = &sm;
566
567         op.o_tag = LDAP_REQ_SEARCH;
568         op.o_protocol = LDAP_VERSION3;
569         op.o_ndn = *authc;
570         op.o_callback = &cb;
571         op.o_time = slap_get_time();
572         op.o_do_not_cache = 1;
573         op.o_threadctx = conn->c_sasl_bindop->o_threadctx;
574
575         (*be->be_search)( be, conn, &op, /*base=*/NULL, &searchbase,
576            scope, /*deref=*/1, /*sizelimit=*/0, /*time=*/0, filter, /*fstr=*/NULL,
577            /*attrs=*/NULL, /*attrsonly=*/0 );
578
579         if (sm.match)
580                 rc = LDAP_SUCCESS;
581         else
582                 rc = LDAP_INAPPROPRIATE_AUTH;
583
584 CONCLUDED:
585         if( searchbase.bv_len ) ch_free( searchbase.bv_val );
586         if( filter ) filter_free( filter );
587 #ifdef NEW_LOGGING
588         LDAP_LOG( TRANSPORT, ENTRY, 
589                 "slap_sasl_match: comparison returned %d\n", rc, 0, 0 );
590 #else
591         Debug( LDAP_DEBUG_TRACE,
592            "<===slap_sasl_match: comparison returned %d\n", rc, 0, 0);
593 #endif
594
595         return( rc );
596 }
597
598
599 /*
600  * This function answers the question, "Can this ID authorize to that ID?",
601  * based on authorization rules. The rules are stored in the *searchDN, in the
602  * attribute named by *attr. If any of those rules map to the *assertDN, the
603  * authorization is approved.
604  *
605  * The DNs should not have the dn: prefix
606  */
607 static int
608 slap_sasl_check_authz( Connection *conn,
609         struct berval *searchDN,
610         struct berval *assertDN,
611         AttributeDescription *ad,
612         struct berval *authc )
613 {
614         int i, rc;
615         BerVarray vals=NULL;
616
617 #ifdef NEW_LOGGING
618         LDAP_LOG( TRANSPORT, ENTRY, 
619                    "slap_sasl_check_authz: does %s match %s rule in %s?\n",
620                assertDN->bv_val, ad->ad_cname.bv_val, searchDN->bv_val);
621 #else
622         Debug( LDAP_DEBUG_TRACE,
623            "==>slap_sasl_check_authz: does %s match %s rule in %s?\n",
624            assertDN->bv_val, ad->ad_cname.bv_val, searchDN->bv_val);
625 #endif
626
627         rc = backend_attribute( NULL, NULL, conn->c_sasl_bindop, NULL, searchDN, ad, &vals );
628         if( rc != LDAP_SUCCESS )
629                 goto COMPLETE;
630
631         /* Check if the *assertDN matches any **vals */
632         for( i=0; vals[i].bv_val != NULL; i++ ) {
633                 rc = slap_sasl_match( conn, &vals[i], assertDN, authc );
634                 if ( rc == LDAP_SUCCESS )
635                         goto COMPLETE;
636         }
637         rc = LDAP_INAPPROPRIATE_AUTH;
638
639 COMPLETE:
640         if( vals ) ber_bvarray_free( vals );
641
642 #ifdef NEW_LOGGING
643         LDAP_LOG( TRANSPORT, RESULTS, 
644                    "slap_sasl_check_authz: %s check returning %s\n", 
645                    ad->ad_cname.bv_val, rc, 0 );
646 #else
647         Debug( LDAP_DEBUG_TRACE,
648            "<==slap_sasl_check_authz: %s check returning %d\n", ad->ad_cname.bv_val, rc, 0);
649 #endif
650
651         return( rc );
652 }
653 #endif  /* HAVE_CYRUS_SASL */
654
655
656 /* Check if a bind can SASL authorize to another identity.
657  * The DNs should not have the dn: prefix
658  */
659
660 int slap_sasl_authorized( Connection *conn,
661         struct berval *authcDN, struct berval *authzDN )
662 {
663         int rc = LDAP_INAPPROPRIATE_AUTH;
664
665 #ifdef HAVE_CYRUS_SASL
666         /* User binding as anonymous */
667         if ( authzDN == NULL ) {
668                 rc = LDAP_SUCCESS;
669                 goto DONE;
670         }
671
672 #ifdef NEW_LOGGING
673         LDAP_LOG( TRANSPORT, ENTRY, 
674                 "slap_sasl_authorized: can %s become %s?\n", 
675                 authcDN->bv_val, authzDN->bv_val, 0 );
676 #else
677         Debug( LDAP_DEBUG_TRACE,
678            "==>slap_sasl_authorized: can %s become %s?\n", authcDN->bv_val, authzDN->bv_val, 0 );
679 #endif
680
681         /* If person is authorizing to self, succeed */
682         if ( dn_match( authcDN, authzDN ) ) {
683                 rc = LDAP_SUCCESS;
684                 goto DONE;
685         }
686
687         /* Check source rules */
688         if( authz_policy & SASL_AUTHZ_TO ) {
689                 rc = slap_sasl_check_authz( conn, authcDN, authzDN,
690                         slap_schema.si_ad_saslAuthzTo, authcDN );
691                 if( rc == LDAP_SUCCESS ) {
692                         goto DONE;
693                 }
694         }
695
696         /* Check destination rules */
697         if( authz_policy & SASL_AUTHZ_FROM ) {
698                 rc = slap_sasl_check_authz( conn, authzDN, authcDN,
699                         slap_schema.si_ad_saslAuthzFrom, authcDN );
700                 if( rc == LDAP_SUCCESS ) {
701                         goto DONE;
702                 }
703         }
704
705         rc = LDAP_INAPPROPRIATE_AUTH;
706
707 DONE:
708 #endif
709
710 #ifdef NEW_LOGGING
711         LDAP_LOG( TRANSPORT, RESULTS, "slap_sasl_authorized: return %d\n", rc,0,0 );
712 #else
713         Debug( LDAP_DEBUG_TRACE,
714                 "<== slap_sasl_authorized: return %d\n", rc, 0, 0 );
715 #endif
716
717         return( rc );
718 }