]> git.sur5r.net Git - openldap/blob - servers/slapd/saslauthz.c
More memory context tweaks
[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( Operation *op, 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, op->o_tmpmemctx );
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_x( op, 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, op->o_tmpmemctx );
138
139 done:
140         if( rc != LDAP_SUCCESS ) {
141                 if( *filter ) filter_free_x( op, *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 /* This callback actually does some work...*/
331 static int sasl_sc_sasl2dn( Operation *o, SlapReply *rs )
332 {
333         struct berval *ndn = o->o_callback->sc_private;
334
335         if (rs->sr_type != REP_SEARCH) return 0;
336
337         /* We only want to be called once */
338         if( ndn->bv_val ) {
339                 free(ndn->bv_val);
340                 ndn->bv_val = NULL;
341
342 #ifdef NEW_LOGGING
343                 LDAP_LOG( TRANSPORT, DETAIL1,
344                         "slap_sasl2dn: search DN returned more than 1 entry\n", 0, 0, 0 );
345 #else
346                 Debug( LDAP_DEBUG_TRACE,
347                         "slap_sasl2dn: search DN returned more than 1 entry\n", 0,0,0 );
348 #endif
349                 return -1;
350         }
351
352         ber_dupbv(ndn, &rs->sr_entry->e_nname);
353         return 0;
354 }
355
356
357 typedef struct smatch_info {
358         struct berval *dn;
359         int match;
360 } smatch_info;
361
362 static int sasl_sc_smatch( Operation *o, SlapReply *rs )
363 {
364         smatch_info *sm = o->o_callback->sc_private;
365
366         if (rs->sr_type != REP_SEARCH) return 0;
367
368         if (dn_match(sm->dn, &rs->sr_entry->e_nname)) {
369                 sm->match = 1;
370                 return -1;      /* short-circuit the search */
371         }
372
373         return 1;
374 }
375
376 /*
377  * Map a SASL regexp rule to a DN. If the rule is just a DN or a scope=base
378  * URI, just strcmp the rule (or its searchbase) to the *assertDN. Otherwise,
379  * the rule must be used as an internal search for entries. If that search
380  * returns the *assertDN entry, the match is successful.
381  *
382  * The assertDN should not have the dn: prefix
383  */
384
385 static
386 int slap_sasl_match(Operation *opx, struct berval *rule, struct berval *assertDN, struct berval *authc )
387 {
388         int rc; 
389         regex_t reg;
390         smatch_info sm;
391         slap_callback cb = { sasl_sc_smatch };
392         Operation op = {0};
393         SlapReply rs = {REP_RESULT};
394
395 #ifdef NEW_LOGGING
396         LDAP_LOG( TRANSPORT, ENTRY, 
397                 "slap_sasl_match: comparing DN %s to rule %s\n", 
398                 assertDN->bv_val, rule->bv_val,0 );
399 #else
400         Debug( LDAP_DEBUG_TRACE,
401            "===>slap_sasl_match: comparing DN %s to rule %s\n",
402                 assertDN->bv_val, rule->bv_val, 0 );
403 #endif
404
405         rc = slap_parseURI( opx, rule, &op.o_req_ndn, &op.oq_search.rs_scope, &op.oq_search.rs_filter );
406         if( rc != LDAP_SUCCESS ) goto CONCLUDED;
407
408         /* Massive shortcut: search scope == base */
409         if( op.oq_search.rs_scope == LDAP_SCOPE_BASE ) {
410                 rc = regcomp(&reg, op.o_req_ndn.bv_val,
411                         REG_EXTENDED|REG_ICASE|REG_NOSUB);
412                 if ( rc == 0 ) {
413                         rc = regexec(&reg, assertDN->bv_val, 0, NULL, 0);
414                         regfree( &reg );
415                 }
416                 if ( rc == 0 ) {
417                         rc = LDAP_SUCCESS;
418                 } else {
419                         rc = LDAP_INAPPROPRIATE_AUTH;
420                 }
421                 goto CONCLUDED;
422         }
423
424         /* Must run an internal search. */
425
426 #ifdef NEW_LOGGING
427         LDAP_LOG( TRANSPORT, DETAIL1, 
428                 "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
429                 op.o_req_ndn.bv_val, op.oq_search.rs_scope, 0 );
430 #else
431         Debug( LDAP_DEBUG_TRACE,
432            "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
433            op.o_req_ndn.bv_val, op.oq_search.rs_scope, 0 );
434 #endif
435
436         op.o_bd = select_backend( &op.o_req_ndn, 0, 1 );
437         if(( op.o_bd == NULL ) || ( op.o_bd->be_search == NULL)) {
438                 rc = LDAP_INAPPROPRIATE_AUTH;
439                 goto CONCLUDED;
440         }
441
442         sm.dn = assertDN;
443         sm.match = 0;
444         cb.sc_private = &sm;
445
446         op.o_tag = LDAP_REQ_SEARCH;
447         op.o_protocol = LDAP_VERSION3;
448         op.o_ndn = *authc;
449         op.o_callback = &cb;
450         op.o_time = slap_get_time();
451         op.o_do_not_cache = 1;
452         op.o_is_auth_check = 1;
453         op.o_threadctx = opx->o_threadctx;
454         op.o_tmpmemctx = opx->o_tmpmemctx;
455         op.o_tmpmfuncs = opx->o_tmpmfuncs;
456         op.o_conn = opx->o_conn;
457         op.o_connid = opx->o_connid;
458
459         op.o_bd->be_search( &op, &rs );
460
461         if (sm.match) {
462                 rc = LDAP_SUCCESS;
463         } else {
464                 rc = LDAP_INAPPROPRIATE_AUTH;
465         }
466
467 CONCLUDED:
468         if( op.o_req_ndn.bv_len ) ch_free( op.o_req_ndn.bv_val );
469         if( op.oq_search.rs_filter ) filter_free_x( opx, op.oq_search.rs_filter );
470
471 #ifdef NEW_LOGGING
472         LDAP_LOG( TRANSPORT, ENTRY, 
473                 "slap_sasl_match: comparison returned %d\n", rc, 0, 0 );
474 #else
475         Debug( LDAP_DEBUG_TRACE,
476            "<===slap_sasl_match: comparison returned %d\n", rc, 0, 0);
477 #endif
478
479         return( rc );
480 }
481
482
483 /*
484  * This function answers the question, "Can this ID authorize to that ID?",
485  * based on authorization rules. The rules are stored in the *searchDN, in the
486  * attribute named by *attr. If any of those rules map to the *assertDN, the
487  * authorization is approved.
488  *
489  * The DNs should not have the dn: prefix
490  */
491 static int
492 slap_sasl_check_authz( Connection *conn,
493         struct berval *searchDN,
494         struct berval *assertDN,
495         AttributeDescription *ad,
496         struct berval *authc )
497 {
498         int i, rc;
499         BerVarray vals=NULL;
500
501 #ifdef NEW_LOGGING
502         LDAP_LOG( TRANSPORT, ENTRY, 
503                 "slap_sasl_check_authz: does %s match %s rule in %s?\n",
504             assertDN->bv_val, ad->ad_cname.bv_val, searchDN->bv_val);
505 #else
506         Debug( LDAP_DEBUG_TRACE,
507            "==>slap_sasl_check_authz: does %s match %s rule in %s?\n",
508            assertDN->bv_val, ad->ad_cname.bv_val, searchDN->bv_val);
509 #endif
510
511         rc = backend_attribute( conn->c_sasl_bindop, NULL,
512                 searchDN, ad, &vals );
513         if( rc != LDAP_SUCCESS ) goto COMPLETE;
514
515         /* Check if the *assertDN matches any **vals */
516         for( i=0; vals[i].bv_val != NULL; i++ ) {
517                 rc = slap_sasl_match( conn->c_sasl_bindop, &vals[i], assertDN, authc );
518                 if ( rc == LDAP_SUCCESS ) goto COMPLETE;
519         }
520         rc = LDAP_INAPPROPRIATE_AUTH;
521
522 COMPLETE:
523         if( vals ) ber_bvarray_free( vals );
524
525 #ifdef NEW_LOGGING
526         LDAP_LOG( TRANSPORT, RESULTS, 
527                 "slap_sasl_check_authz: %s check returning %s\n", 
528                 ad->ad_cname.bv_val, rc, 0 );
529 #else
530         Debug( LDAP_DEBUG_TRACE,
531            "<==slap_sasl_check_authz: %s check returning %d\n",
532                 ad->ad_cname.bv_val, rc, 0);
533 #endif
534
535         return( rc );
536 }
537
538 /*
539  * Given a SASL name (e.g. "UID=name,cn=REALM,cn=MECH,cn=AUTH")
540  * return the LDAP DN to which it matches. The SASL regexp rules in the config
541  * file turn the SASL name into an LDAP URI. If the URI is just a DN (or a
542  * search with scope=base), just return the URI (or its searchbase). Otherwise
543  * an internal search must be done, and if that search returns exactly one
544  * entry, return the DN of that one entry.
545  */
546 void slap_sasl2dn( Operation *opx,
547         struct berval *saslname, struct berval *sasldn )
548 {
549         int rc;
550         slap_callback cb = { sasl_sc_sasl2dn };
551         Operation op = {0};
552         SlapReply rs = {REP_RESULT};
553         struct berval regout = { 0, NULL };
554
555 #ifdef NEW_LOGGING
556         LDAP_LOG( TRANSPORT, ENTRY, 
557                 "slap_sasl2dn: converting SASL name %s to DN.\n",
558                 saslname->bv_val, 0, 0 );
559 #else
560         Debug( LDAP_DEBUG_TRACE, "==>slap_sasl2dn: "
561                 "converting SASL name %s to a DN\n",
562                 saslname->bv_val, 0,0 );
563 #endif
564
565         sasldn->bv_val = NULL;
566         sasldn->bv_len = 0;
567         cb.sc_private = sasldn;
568
569         /* Convert the SASL name into a minimal URI */
570         if( !slap_sasl_regexp( saslname, &regout ) ) {
571                 goto FINISHED;
572         }
573
574         rc = slap_parseURI( opx, &regout, &op.o_req_ndn, &op.oq_search.rs_scope, &op.oq_search.rs_filter );
575         if( regout.bv_val ) ch_free( regout.bv_val );
576         if( rc != LDAP_SUCCESS ) {
577                 goto FINISHED;
578         }
579
580         /* Must do an internal search */
581         op.o_bd = select_backend( &op.o_req_ndn, 0, 1 );
582
583         /* Massive shortcut: search scope == base */
584         if( op.oq_search.rs_scope == LDAP_SCOPE_BASE ) {
585                 *sasldn = op.o_req_ndn;
586                 op.o_req_ndn.bv_len = 0;
587                 op.o_req_ndn.bv_val = NULL;
588                 goto FINISHED;
589         }
590
591 #ifdef NEW_LOGGING
592         LDAP_LOG( TRANSPORT, DETAIL1, 
593                 "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
594                 op.o_req_ndn.bv_val, op.oq_search.rs_scope, 0 );
595 #else
596         Debug( LDAP_DEBUG_TRACE,
597                 "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
598                 op.o_req_ndn.bv_val, op.oq_search.rs_scope, 0 );
599 #endif
600
601         if(( op.o_bd == NULL ) || ( op.o_bd->be_search == NULL)) {
602                 goto FINISHED;
603         }
604
605         op.o_conn = opx->o_conn;
606         op.o_connid = opx->o_connid;
607         op.o_tag = LDAP_REQ_SEARCH;
608         op.o_protocol = LDAP_VERSION3;
609         op.o_ndn = opx->o_conn->c_ndn;
610         op.o_callback = &cb;
611         op.o_time = slap_get_time();
612         op.o_do_not_cache = 1;
613         op.o_is_auth_check = 1;
614         op.o_threadctx = opx->o_threadctx;
615         op.o_tmpmemctx = opx->o_tmpmemctx;
616         op.o_tmpmfuncs = opx->o_tmpmfuncs;
617         op.oq_search.rs_deref = LDAP_DEREF_NEVER;
618         op.oq_search.rs_slimit = 1;
619         op.oq_search.rs_attrsonly = 1;
620
621         op.o_bd->be_search( &op, &rs );
622         
623 FINISHED:
624         if( sasldn->bv_len ) {
625                 opx->o_conn->c_authz_backend = op.o_bd;
626         }
627         if( op.o_req_ndn.bv_len ) ch_free( op.o_req_ndn.bv_val );
628         if( op.oq_search.rs_filter ) filter_free_x( opx, op.oq_search.rs_filter );
629
630 #ifdef NEW_LOGGING
631         LDAP_LOG( TRANSPORT, ENTRY, 
632                 "slap_sasl2dn: Converted SASL name to %s\n",
633                 sasldn->bv_len ? sasldn->bv_val : "<nothing>", 0, 0 );
634 #else
635         Debug( LDAP_DEBUG_TRACE, "<==slap_sasl2dn: Converted SASL name to %s\n",
636                 sasldn->bv_len ? sasldn->bv_val : "<nothing>", 0, 0 );
637 #endif
638
639         return;
640 }
641
642
643 /* Check if a bind can SASL authorize to another identity.
644  * The DNs should not have the dn: prefix
645  */
646
647 int slap_sasl_authorized( Connection *conn,
648         struct berval *authcDN, struct berval *authzDN )
649 {
650         int rc = LDAP_INAPPROPRIATE_AUTH;
651
652         /* User binding as anonymous */
653         if ( authzDN == NULL ) {
654                 rc = LDAP_SUCCESS;
655                 goto DONE;
656         }
657
658 #ifdef NEW_LOGGING
659         LDAP_LOG( TRANSPORT, ENTRY, 
660                 "slap_sasl_authorized: can %s become %s?\n", 
661                 authcDN->bv_val, authzDN->bv_val, 0 );
662 #else
663         Debug( LDAP_DEBUG_TRACE,
664            "==>slap_sasl_authorized: can %s become %s?\n",
665                 authcDN->bv_val, authzDN->bv_val, 0 );
666 #endif
667
668         /* If person is authorizing to self, succeed */
669         if ( dn_match( authcDN, authzDN ) ) {
670                 rc = LDAP_SUCCESS;
671                 goto DONE;
672         }
673
674         /* Allow the manager to authorize as any DN. */
675         if( conn->c_authz_backend && be_isroot( conn->c_authz_backend, authcDN )) {
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
702 #ifdef NEW_LOGGING
703         LDAP_LOG( TRANSPORT, RESULTS, "slap_sasl_authorized: return %d\n", rc,0,0 );
704 #else
705         Debug( LDAP_DEBUG_TRACE,
706                 "<== slap_sasl_authorized: return %d\n", rc, 0, 0 );
707 #endif
708
709         return( rc );
710 }