]> git.sur5r.net Git - openldap/blob - servers/slapd/saslauthz.c
Commit of the Proxy Cache contribution (ITS#2062)
[openldap] / servers / slapd / saslauthz.c
1 /*
2  * Copyright 1998-2003 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 #include <limits.h>
27
28 #include <ldap_pvt.h>
29
30 #define SASLREGEX_REPLACE 10
31
32 typedef struct sasl_regexp {
33   char *sr_match;                                                       /* regexp match pattern */
34   char *sr_replace;                                             /* regexp replace pattern */
35   regex_t sr_workspace;                                         /* workspace for regexp engine */
36   regmatch_t sr_strings[SASLREGEX_REPLACE];     /* strings matching $1,$2 ... */
37   int sr_offset[SASLREGEX_REPLACE+2];           /* offsets of $1,$2... in *replace */
38 } SaslRegexp_t;
39
40 static int nSaslRegexp = 0;
41 static SaslRegexp_t *SaslRegexp = NULL;
42
43 /* What SASL proxy authorization policies are allowed? */
44 #define SASL_AUTHZ_NONE 0
45 #define SASL_AUTHZ_FROM 1
46 #define SASL_AUTHZ_TO   2
47
48 static int authz_policy = SASL_AUTHZ_NONE;
49
50 int slap_sasl_setpolicy( const char *arg )
51 {
52         int rc = LDAP_SUCCESS;
53
54         if ( strcasecmp( arg, "none" ) == 0 ) {
55                 authz_policy = SASL_AUTHZ_NONE;
56         } else if ( strcasecmp( arg, "from" ) == 0 ) {
57                 authz_policy = SASL_AUTHZ_FROM;
58         } else if ( strcasecmp( arg, "to" ) == 0 ) {
59                 authz_policy = SASL_AUTHZ_TO;
60         } else if ( strcasecmp( arg, "both" ) == 0 ) {
61                 authz_policy = SASL_AUTHZ_FROM | SASL_AUTHZ_TO;
62         } else {
63                 rc = LDAP_OTHER;
64         }
65         return rc;
66 }
67
68 /* URI format: ldap://<host>/<base>[?[<attrs>][?[<scope>][?[<filter>]]]] */
69
70 static int slap_parseURI( struct berval *uri,
71         struct berval *searchbase, int *scope, Filter **filter )
72 {
73         struct berval bv;
74         int rc;
75         LDAPURLDesc *ludp;
76
77         assert( uri != NULL && uri->bv_val != NULL );
78         searchbase->bv_val = NULL;
79         searchbase->bv_len = 0;
80         *scope = -1;
81         *filter = NULL;
82
83 #ifdef NEW_LOGGING
84         LDAP_LOG( TRANSPORT, ENTRY, 
85                 "slap_parseURI: parsing %s\n", uri->bv_val, 0, 0 );
86 #else
87         Debug( LDAP_DEBUG_TRACE, "slap_parseURI: parsing %s\n", uri->bv_val, 0, 0 );
88 #endif
89
90         /* If it does not look like a URI, assume it is a DN */
91         if( !strncasecmp( uri->bv_val, "dn:", sizeof("dn:")-1 ) ) {
92                 bv.bv_val = uri->bv_val + sizeof("dn:")-1;
93                 bv.bv_val += strspn( bv.bv_val, " " );
94
95 is_dn:  bv.bv_len = uri->bv_len - (bv.bv_val - uri->bv_val);
96
97                 rc = dnNormalize2( NULL, &bv, searchbase );
98                 if( rc == LDAP_SUCCESS ) {
99                         *scope = LDAP_SCOPE_BASE;
100                 }
101                 return( rc );
102         }
103
104         rc = ldap_url_parse( uri->bv_val, &ludp );
105         if ( rc == LDAP_URL_ERR_BADSCHEME ) {
106                 bv.bv_val = uri->bv_val;
107                 goto is_dn;
108         }
109
110         if ( rc != LDAP_URL_SUCCESS ) {
111                 return LDAP_PROTOCOL_ERROR;
112         }
113
114         if (( ludp->lud_host && *ludp->lud_host )
115                 || ludp->lud_attrs || ludp->lud_exts )
116         {
117                 /* host part should be empty */
118                 /* attrs and extensions parts should be empty */
119                 return LDAP_PROTOCOL_ERROR;
120         }
121
122         /* Grab the scope */
123         *scope = ludp->lud_scope;
124
125         /* Grab the filter */
126         if ( ludp->lud_filter ) {
127                 *filter = str2filter( ludp->lud_filter );
128                 if ( *filter == NULL ) {
129                         rc = LDAP_PROTOCOL_ERROR;
130                         goto done;
131                 }
132         }
133
134         /* Grab the searchbase */
135         bv.bv_val = ludp->lud_dn;
136         bv.bv_len = strlen( bv.bv_val );
137         rc = dnNormalize2( NULL, &bv, searchbase );
138
139 done:
140         if( rc != LDAP_SUCCESS ) {
141                 if( *filter ) filter_free( *filter );
142         }
143
144         ldap_free_urldesc( ludp );
145         return( rc );
146 }
147
148 static int slap_sasl_rx_off(char *rep, int *off)
149 {
150         const char *c;
151         int n;
152
153         /* Precompile replace pattern. Find the $<n> placeholders */
154         off[0] = -2;
155         n = 1;
156         for ( c = rep;   *c;  c++ ) {
157                 if ( *c == '\\' && c[1] ) {
158                         c++;
159                         continue;
160                 }
161                 if ( *c == '$' ) {
162                         if ( n == SASLREGEX_REPLACE ) {
163 #ifdef NEW_LOGGING
164                                 LDAP_LOG( TRANSPORT, ERR, 
165                                         "slap_sasl_rx_off: \"%s\" has too many $n "
166                                         "placeholders (max %d)\n", rep, SASLREGEX_REPLACE, 0  );
167 #else
168                                 Debug( LDAP_DEBUG_ANY,
169                                         "SASL replace pattern %s has too many $n "
170                                                 "placeholders (max %d)\n",
171                                         rep, SASLREGEX_REPLACE, 0 );
172 #endif
173
174                                 return( LDAP_OTHER );
175                         }
176                         off[n] = c - rep;
177                         n++;
178                 }
179         }
180
181         /* Final placeholder, after the last $n */
182         off[n] = c - rep;
183         n++;
184         off[n] = -1;
185         return( LDAP_SUCCESS );
186 }
187
188 int slap_sasl_regexp_config( const char *match, const char *replace )
189 {
190         int rc;
191         SaslRegexp_t *reg;
192
193         SaslRegexp = (SaslRegexp_t *) ch_realloc( (char *) SaslRegexp,
194           (nSaslRegexp + 1) * sizeof(SaslRegexp_t) );
195
196         reg = &SaslRegexp[nSaslRegexp];
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         SaslRegexp_t *reg;
284         int i;
285
286         memset( out, 0, sizeof( *out ) );
287
288 #ifdef NEW_LOGGING
289         LDAP_LOG( TRANSPORT, ENTRY, 
290                 "slap_sasl_regexp: converting SASL name %s\n", saslname, 0, 0 );
291 #else
292         Debug( LDAP_DEBUG_TRACE, "slap_sasl_regexp: converting SASL name %s\n",
293            saslname, 0, 0 );
294 #endif
295
296         if (( saslname == NULL ) || ( nSaslRegexp == 0 )) {
297                 return( 0 );
298         }
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 ) return( 0 );
308
309         /*
310          * The match pattern may have been of the form "a(b.*)c(d.*)e" and the
311          * replace pattern of the form "x$1y$2z". The returned string needs
312          * to replace the $1,$2 with the strings that matched (b.*) and (d.*)
313          */
314         slap_sasl_rx_exp( reg->sr_replace, reg->sr_offset,
315                 reg->sr_strings, saslname, out );
316
317 #ifdef NEW_LOGGING
318         LDAP_LOG( TRANSPORT, ENTRY, 
319                 "slap_sasl_regexp: converted SASL name to %s\n",
320                 out->bv_len ? out->bv_val : "", 0, 0 );
321 #else
322         Debug( LDAP_DEBUG_TRACE,
323                 "slap_sasl_regexp: converted SASL name to %s\n",
324                 out->bv_len ? out->bv_val : "", 0, 0 );
325 #endif
326
327         return( 1 );
328 }
329
330 /* Two empty callback functions to avoid sending results */
331 void slap_cb_null_response( Connection *conn, Operation *o, ber_tag_t tag,
332         ber_int_t msgid, ber_int_t err, const char *matched,
333         const char *text, BerVarray ref, const char *resoid,
334         struct berval *resdata, struct berval *sasldata, LDAPControl **c)
335 {
336 }
337
338 void slap_cb_null_sresult( Connection *conn, Operation *o, ber_int_t err,
339         const char *matched, const char *text, BerVarray refs, LDAPControl **c,
340         int nentries)
341 {
342 }
343
344 int slap_cb_null_sreference( BackendDB *db, Connection *conn, Operation *o, 
345         Entry *e, BerVarray r, LDAPControl **c, BerVarray *v2)
346 {
347         return 0;
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 typedef struct smatch_info {
377         struct berval *dn;
378         int match;
379 } smatch_info;
380
381 static int sasl_sc_smatch( BackendDB *be, Connection *conn, Operation *o,
382         Entry *e, AttributeName *an, int ao, LDAPControl **c)
383 {
384         smatch_info *sm = o->o_callback->sc_private;
385
386         if (dn_match(sm->dn, &e->e_nname)) {
387                 sm->match = 1;
388                 return -1;      /* short-circuit the search */
389         }
390
391         return 1;
392 }
393
394 /*
395  * Map a SASL regexp rule to a DN. If the rule is just a DN or a scope=base
396  * URI, just strcmp the rule (or its searchbase) to the *assertDN. Otherwise,
397  * the rule must be used as an internal search for entries. If that search
398  * returns the *assertDN entry, the match is successful.
399  *
400  * The assertDN should not have the dn: prefix
401  */
402
403 static
404 int slap_sasl_match(Connection *conn, struct berval *rule, struct berval *assertDN, struct berval *authc )
405 {
406         struct berval searchbase = {0, NULL};
407         int rc, scope;
408         Backend *be;
409         Filter *filter=NULL;
410         regex_t reg;
411         smatch_info sm;
412         slap_callback cb = {
413                 slap_cb_null_response,
414                 slap_cb_null_sresult,
415                 sasl_sc_smatch,
416                 NULL
417         };
418         Operation op = {0};
419
420 #ifdef NEW_LOGGING
421         LDAP_LOG( TRANSPORT, ENTRY, 
422                 "slap_sasl_match: comparing DN %s to rule %s\n", 
423                 assertDN->bv_val, rule->bv_val,0 );
424 #else
425         Debug( LDAP_DEBUG_TRACE,
426            "===>slap_sasl_match: comparing DN %s to rule %s\n",
427                 assertDN->bv_val, rule->bv_val, 0 );
428 #endif
429
430         rc = slap_parseURI( rule, &searchbase, &scope, &filter );
431         if( rc != LDAP_SUCCESS ) goto CONCLUDED;
432
433         /* Massive shortcut: search scope == base */
434         if( scope == LDAP_SCOPE_BASE ) {
435                 rc = regcomp(&reg, searchbase.bv_val,
436                         REG_EXTENDED|REG_ICASE|REG_NOSUB);
437                 if ( rc == 0 ) {
438                         rc = regexec(&reg, assertDN->bv_val, 0, NULL, 0);
439                         regfree( &reg );
440                 }
441                 if ( rc == 0 ) {
442                         rc = LDAP_SUCCESS;
443                 } else {
444                         rc = LDAP_INAPPROPRIATE_AUTH;
445                 }
446                 goto CONCLUDED;
447         }
448
449         /* Must run an internal search. */
450
451 #ifdef NEW_LOGGING
452         LDAP_LOG( TRANSPORT, DETAIL1, 
453                 "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
454                 searchbase.bv_val, scope,0 );
455 #else
456         Debug( LDAP_DEBUG_TRACE,
457            "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
458            searchbase.bv_val, scope, 0 );
459 #endif
460
461         be = select_backend( &searchbase, 0, 1 );
462         if(( be == NULL ) || ( be->be_search == NULL)) {
463                 rc = LDAP_INAPPROPRIATE_AUTH;
464                 goto CONCLUDED;
465         }
466
467         sm.dn = assertDN;
468         sm.match = 0;
469         cb.sc_private = &sm;
470
471         op.o_tag = LDAP_REQ_SEARCH;
472         op.o_protocol = LDAP_VERSION3;
473         op.o_ndn = *authc;
474         op.o_callback = &cb;
475         op.o_time = slap_get_time();
476         op.o_do_not_cache = 1;
477         op.o_threadctx = conn->c_sasl_bindop->o_threadctx;
478
479         (*be->be_search)( be, conn, &op, /*base=*/NULL, &searchbase,
480            scope, /*deref=*/1, /*sizelimit=*/0, /*time=*/0, filter, /*fstr=*/NULL,
481            /*attrs=*/NULL, /*attrsonly=*/0 );
482
483         if (sm.match) {
484                 rc = LDAP_SUCCESS;
485         } else {
486                 rc = LDAP_INAPPROPRIATE_AUTH;
487         }
488
489 CONCLUDED:
490         if( searchbase.bv_len ) ch_free( searchbase.bv_val );
491         if( filter ) filter_free( filter );
492
493 #ifdef NEW_LOGGING
494         LDAP_LOG( TRANSPORT, ENTRY, 
495                 "slap_sasl_match: comparison returned %d\n", rc, 0, 0 );
496 #else
497         Debug( LDAP_DEBUG_TRACE,
498            "<===slap_sasl_match: comparison returned %d\n", rc, 0, 0);
499 #endif
500
501         return( rc );
502 }
503
504
505 /*
506  * This function answers the question, "Can this ID authorize to that ID?",
507  * based on authorization rules. The rules are stored in the *searchDN, in the
508  * attribute named by *attr. If any of those rules map to the *assertDN, the
509  * authorization is approved.
510  *
511  * The DNs should not have the dn: prefix
512  */
513 static int
514 slap_sasl_check_authz( Connection *conn,
515         struct berval *searchDN,
516         struct berval *assertDN,
517         AttributeDescription *ad,
518         struct berval *authc )
519 {
520         int i, rc;
521         BerVarray vals=NULL;
522
523 #ifdef NEW_LOGGING
524         LDAP_LOG( TRANSPORT, ENTRY, 
525                 "slap_sasl_check_authz: does %s match %s rule in %s?\n",
526             assertDN->bv_val, ad->ad_cname.bv_val, searchDN->bv_val);
527 #else
528         Debug( LDAP_DEBUG_TRACE,
529            "==>slap_sasl_check_authz: does %s match %s rule in %s?\n",
530            assertDN->bv_val, ad->ad_cname.bv_val, searchDN->bv_val);
531 #endif
532
533         rc = backend_attribute( NULL, NULL, conn->c_sasl_bindop, NULL,
534                 searchDN, ad, &vals );
535         if( rc != LDAP_SUCCESS ) goto COMPLETE;
536
537         /* Check if the *assertDN matches any **vals */
538         for( i=0; vals[i].bv_val != NULL; i++ ) {
539                 rc = slap_sasl_match( conn, &vals[i], assertDN, authc );
540                 if ( rc == LDAP_SUCCESS ) goto COMPLETE;
541         }
542         rc = LDAP_INAPPROPRIATE_AUTH;
543
544 COMPLETE:
545         if( vals ) ber_bvarray_free( vals );
546
547 #ifdef NEW_LOGGING
548         LDAP_LOG( TRANSPORT, RESULTS, 
549                 "slap_sasl_check_authz: %s check returning %s\n", 
550                 ad->ad_cname.bv_val, rc, 0 );
551 #else
552         Debug( LDAP_DEBUG_TRACE,
553            "<==slap_sasl_check_authz: %s check returning %d\n",
554                 ad->ad_cname.bv_val, rc, 0);
555 #endif
556
557         return( rc );
558 }
559
560 /*
561  * Given a SASL name (e.g. "UID=name,cn=REALM,cn=MECH,cn=AUTH")
562  * return the LDAP DN to which it matches. The SASL regexp rules in the config
563  * file turn the SASL name into an LDAP URI. If the URI is just a DN (or a
564  * search with scope=base), just return the URI (or its searchbase). Otherwise
565  * an internal search must be done, and if that search returns exactly one
566  * entry, return the DN of that one entry.
567  */
568 void slap_sasl2dn( Connection *conn,
569         struct berval *saslname, struct berval *sasldn )
570 {
571         int rc;
572         Backend *be = NULL;
573         struct berval dn = { 0, NULL };
574         int scope = LDAP_SCOPE_BASE;
575         Filter *filter = NULL;
576         slap_callback cb = { slap_cb_null_response,
577                 slap_cb_null_sresult, sasl_sc_sasl2dn, slap_cb_null_sreference, NULL};
578         Operation op = {0};
579         struct berval regout = { 0, NULL };
580
581 #ifdef NEW_LOGGING
582         LDAP_LOG( TRANSPORT, ENTRY, 
583                 "slap_sasl2dn: converting SASL name %s to DN.\n",
584                 saslname->bv_val, 0, 0 );
585 #else
586         Debug( LDAP_DEBUG_TRACE, "==>slap_sasl2dn: "
587                 "converting SASL name %s to a DN\n",
588                 saslname->bv_val, 0,0 );
589 #endif
590
591         sasldn->bv_val = NULL;
592         sasldn->bv_len = 0;
593         cb.sc_private = sasldn;
594
595         /* Convert the SASL name into a minimal URI */
596         if( !slap_sasl_regexp( saslname, &regout ) ) {
597                 goto FINISHED;
598         }
599
600         rc = slap_parseURI( &regout, &dn, &scope, &filter );
601         if( regout.bv_val ) ch_free( regout.bv_val );
602         if( rc != LDAP_SUCCESS ) {
603                 goto FINISHED;
604         }
605
606         /* Must do an internal search */
607         be = select_backend( &dn, 0, 1 );
608
609         /* Massive shortcut: search scope == base */
610         if( scope == LDAP_SCOPE_BASE ) {
611                 *sasldn = dn;
612                 dn.bv_len = 0;
613                 dn.bv_val = NULL;
614                 goto FINISHED;
615         }
616
617 #ifdef NEW_LOGGING
618         LDAP_LOG( TRANSPORT, DETAIL1, 
619                 "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
620                 dn.bv_val, scope, 0 );
621 #else
622         Debug( LDAP_DEBUG_TRACE,
623                 "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
624                 dn.bv_val, scope, 0 );
625 #endif
626
627         if(( be == NULL ) || ( be->be_search == NULL)) {
628                 goto FINISHED;
629         }
630
631         op.o_tag = LDAP_REQ_SEARCH;
632         op.o_protocol = LDAP_VERSION3;
633         op.o_ndn = conn->c_ndn;
634         op.o_callback = &cb;
635         op.o_time = slap_get_time();
636         op.o_do_not_cache = 1;
637         op.o_threadctx = conn->c_sasl_bindop ? conn->c_sasl_bindop->o_threadctx:
638                 ldap_pvt_thread_pool_context( &connection_pool );
639
640         (*be->be_search)( be, conn, &op, NULL, &dn,
641                 scope, LDAP_DEREF_NEVER, 1, 0,
642                 filter, NULL, NULL, 1 );
643         
644 FINISHED:
645         if( sasldn->bv_len ) {
646                 conn->c_authz_backend = be;
647         }
648         if( dn.bv_len ) ch_free( dn.bv_val );
649         if( filter ) filter_free( filter );
650
651 #ifdef NEW_LOGGING
652         LDAP_LOG( TRANSPORT, ENTRY, 
653                 "slap_sasl2dn: Converted SASL name to %s\n",
654                 sasldn->bv_len ? sasldn->bv_val : "<nothing>", 0, 0 );
655 #else
656         Debug( LDAP_DEBUG_TRACE, "<==slap_sasl2dn: Converted SASL name to %s\n",
657                 sasldn->bv_len ? sasldn->bv_val : "<nothing>", 0, 0 );
658 #endif
659
660         return;
661 }
662
663
664 /* Check if a bind can SASL authorize to another identity.
665  * The DNs should not have the dn: prefix
666  */
667
668 int slap_sasl_authorized( Connection *conn,
669         struct berval *authcDN, struct berval *authzDN )
670 {
671         int rc = LDAP_INAPPROPRIATE_AUTH;
672
673         /* User binding as anonymous */
674         if ( authzDN == NULL ) {
675                 rc = LDAP_SUCCESS;
676                 goto DONE;
677         }
678
679 #ifdef NEW_LOGGING
680         LDAP_LOG( TRANSPORT, ENTRY, 
681                 "slap_sasl_authorized: can %s become %s?\n", 
682                 authcDN->bv_val, authzDN->bv_val, 0 );
683 #else
684         Debug( LDAP_DEBUG_TRACE,
685            "==>slap_sasl_authorized: can %s become %s?\n",
686                 authcDN->bv_val, authzDN->bv_val, 0 );
687 #endif
688
689         /* If person is authorizing to self, succeed */
690         if ( dn_match( authcDN, authzDN ) ) {
691                 rc = LDAP_SUCCESS;
692                 goto DONE;
693         }
694
695         /* Allow the manager to authorize as any DN. */
696         if( conn->c_authz_backend && be_isroot( conn->c_authz_backend, authcDN )) {
697                 rc = LDAP_SUCCESS;
698                 goto DONE;
699         }
700
701         /* Check source rules */
702         if( authz_policy & SASL_AUTHZ_TO ) {
703                 rc = slap_sasl_check_authz( conn, authcDN, authzDN,
704                         slap_schema.si_ad_saslAuthzTo, authcDN );
705                 if( rc == LDAP_SUCCESS ) {
706                         goto DONE;
707                 }
708         }
709
710         /* Check destination rules */
711         if( authz_policy & SASL_AUTHZ_FROM ) {
712                 rc = slap_sasl_check_authz( conn, authzDN, authcDN,
713                         slap_schema.si_ad_saslAuthzFrom, authcDN );
714                 if( rc == LDAP_SUCCESS ) {
715                         goto DONE;
716                 }
717         }
718
719         rc = LDAP_INAPPROPRIATE_AUTH;
720
721 DONE:
722
723 #ifdef NEW_LOGGING
724         LDAP_LOG( TRANSPORT, RESULTS, "slap_sasl_authorized: return %d\n", rc,0,0 );
725 #else
726         Debug( LDAP_DEBUG_TRACE,
727                 "<== slap_sasl_authorized: return %d\n", rc, 0, 0 );
728 #endif
729
730         return( rc );
731 }