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