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