]> git.sur5r.net Git - openldap/blob - servers/slapd/saslauthz.c
ITS#2497, implement value-level ACLs:
[openldap] / servers / slapd / saslauthz.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 /*
7  * Copyright (c) 2000, Mark Adamson, Carnegie Mellon.  All rights reserved.
8  * This software is not subject to any license of Carnegie Mellon University.
9  *
10  * Redistribution and use in source and binary forms are permitted without 
11  * restriction or fee of any kind as long as this notice is preserved.
12  *
13  * The name "Carnegie Mellon" must not be used to endorse or promote
14  * products derived from this software without prior written permission.
15  *
16  */
17
18 #include "portable.h"
19
20 #include <stdio.h>
21
22 #include <ac/stdlib.h>
23 #include <ac/string.h>
24
25 #include "slap.h"
26
27 #include <limits.h>
28
29 #include <ldap_pvt.h>
30
31 #define SASLREGEX_REPLACE 10
32
33 typedef struct sasl_regexp {
34   char *sr_match;                                                       /* regexp match pattern */
35   char *sr_replace;                                             /* regexp replace pattern */
36   regex_t sr_workspace;                                         /* workspace for regexp engine */
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 static int slap_parseURI( Operation *op, struct berval *uri,
69         struct berval *searchbase, int *scope, Filter **filter )
70 {
71         struct berval bv;
72         int rc;
73         LDAPURLDesc *ludp;
74
75         assert( uri != NULL && uri->bv_val != NULL );
76         searchbase->bv_val = NULL;
77         searchbase->bv_len = 0;
78         *scope = -1;
79         *filter = NULL;
80
81 #ifdef NEW_LOGGING
82         LDAP_LOG( TRANSPORT, ENTRY, 
83                 "slap_parseURI: parsing %s\n", uri->bv_val, 0, 0 );
84 #else
85         Debug( LDAP_DEBUG_TRACE,
86                 "slap_parseURI: parsing %s\n", uri->bv_val, 0, 0 );
87 #endif
88
89         /* If it does not look like a URI, assume it is a DN */
90         if( !strncasecmp( uri->bv_val, "dn:", sizeof("dn:")-1 ) ) {
91                 bv.bv_val = uri->bv_val + sizeof("dn:")-1;
92                 bv.bv_val += strspn( bv.bv_val, " " );
93
94 is_dn:  bv.bv_len = uri->bv_len - (bv.bv_val - uri->bv_val);
95
96                 rc = dnNormalize( 0, NULL, NULL, &bv, searchbase, op->o_tmpmemctx );
97                 if( rc == LDAP_SUCCESS ) {
98                         *scope = LDAP_SCOPE_BASE;
99                 }
100                 return( rc );
101         }
102
103         rc = ldap_url_parse( uri->bv_val, &ludp );
104         if ( rc == LDAP_URL_ERR_BADSCHEME ) {
105                 bv.bv_val = uri->bv_val;
106                 goto is_dn;
107         }
108
109         if ( rc != LDAP_URL_SUCCESS ) {
110                 return LDAP_PROTOCOL_ERROR;
111         }
112
113         if (( ludp->lud_host && *ludp->lud_host )
114                 || ludp->lud_attrs || ludp->lud_exts )
115         {
116                 /* host part must be empty */
117                 /* attrs and extensions parts must be empty */
118                 return LDAP_PROTOCOL_ERROR;
119         }
120
121         /* Grab the scope */
122         *scope = ludp->lud_scope;
123
124         /* Grab the filter */
125         if ( ludp->lud_filter ) {
126                 *filter = str2filter_x( op, ludp->lud_filter );
127                 if ( *filter == NULL ) {
128                         rc = LDAP_PROTOCOL_ERROR;
129                         goto done;
130                 }
131         }
132
133         /* Grab the searchbase */
134         bv.bv_val = ludp->lud_dn;
135         bv.bv_len = strlen( bv.bv_val );
136         rc = dnNormalize( 0, NULL, NULL, &bv, searchbase, op->o_tmpmemctx );
137
138 done:
139         if( rc != LDAP_SUCCESS ) {
140                 if( *filter ) filter_free_x( op, *filter );
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         int rc;
190         SaslRegexp_t *reg;
191
192         SaslRegexp = (SaslRegexp_t *) ch_realloc( (char *) SaslRegexp,
193           (nSaslRegexp + 1) * sizeof(SaslRegexp_t) );
194
195         reg = &SaslRegexp[nSaslRegexp];
196
197         reg->sr_match = ch_strdup( match );
198         reg->sr_replace = ch_strdup( replace );
199
200         /* Precompile matching pattern */
201         rc = regcomp( &reg->sr_workspace, reg->sr_match, REG_EXTENDED|REG_ICASE );
202         if ( rc ) {
203 #ifdef NEW_LOGGING
204                 LDAP_LOG( TRANSPORT, ERR, 
205                         "slap_sasl_regexp_config: \"%s\" could not be compiled.\n",
206                         reg->sr_match, 0, 0 );
207 #else
208                 Debug( LDAP_DEBUG_ANY,
209                 "SASL match pattern %s could not be compiled by regexp engine\n",
210                 reg->sr_match, 0, 0 );
211 #endif
212
213                 return( LDAP_OTHER );
214         }
215
216         rc = slap_sasl_rx_off( reg->sr_replace, reg->sr_offset );
217         if ( rc != LDAP_SUCCESS ) return rc;
218
219         nSaslRegexp++;
220         return( LDAP_SUCCESS );
221 }
222
223
224 /* Perform replacement on regexp matches */
225 static void slap_sasl_rx_exp(
226         const char *rep,
227         const int *off,
228         regmatch_t *str,
229         const char *saslname,
230         struct berval *out,
231         void *ctx )
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 = sl_malloc( len + 1, ctx );
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, void *ctx )
281 {
282         char *saslname = in->bv_val;
283         SaslRegexp_t *reg;
284         regmatch_t sr_strings[SASLREGEX_REPLACE];       /* strings matching $1,$2 ... */
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
301         /* Match the normalized SASL name to the saslregexp patterns */
302         for( reg = SaslRegexp,i=0;  i<nSaslRegexp;  i++,reg++ ) {
303                 if ( regexec( &reg->sr_workspace, saslname, SASLREGEX_REPLACE,
304                   sr_strings, 0)  == 0 )
305                         break;
306         }
307
308         if( i >= nSaslRegexp ) 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                 sr_strings, saslname, out, ctx );
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 %s\n",
325                 out->bv_len ? out->bv_val : "", 0, 0 );
326 #endif
327
328         return( 1 );
329 }
330
331 /* This callback actually does some work...*/
332 static int sasl_sc_sasl2dn( Operation *o, SlapReply *rs )
333 {
334         struct berval *ndn = o->o_callback->sc_private;
335
336         if (rs->sr_type != REP_SEARCH) return 0;
337
338         /* We only want to be called once */
339         if( ndn->bv_val ) {
340                 o->o_tmpfree(ndn->bv_val, o->o_tmpmemctx);
341                 ndn->bv_val = NULL;
342
343 #ifdef NEW_LOGGING
344                 LDAP_LOG( TRANSPORT, DETAIL1,
345                         "slap_sasl2dn: search DN returned more than 1 entry\n", 0, 0, 0 );
346 #else
347                 Debug( LDAP_DEBUG_TRACE,
348                         "slap_sasl2dn: search DN returned more than 1 entry\n", 0,0,0 );
349 #endif
350                 return -1;
351         }
352
353         ber_dupbv_x(ndn, &rs->sr_entry->e_nname, o->o_tmpmemctx);
354         return 0;
355 }
356
357
358 typedef struct smatch_info {
359         struct berval *dn;
360         int match;
361 } smatch_info;
362
363 static int sasl_sc_smatch( Operation *o, SlapReply *rs )
364 {
365         smatch_info *sm = o->o_callback->sc_private;
366
367         if (rs->sr_type != REP_SEARCH) return 0;
368
369         if (dn_match(sm->dn, &rs->sr_entry->e_nname)) {
370                 sm->match = 1;
371                 return -1;      /* short-circuit the search */
372         }
373
374         return 1;
375 }
376
377 /*
378  * Map a SASL regexp rule to a DN. If the rule is just a DN or a scope=base
379  * URI, just strcmp the rule (or its searchbase) to the *assertDN. Otherwise,
380  * the rule must be used as an internal search for entries. If that search
381  * returns the *assertDN entry, the match is successful.
382  *
383  * The assertDN should not have the dn: prefix
384  */
385
386 static
387 int slap_sasl_match( Operation *opx, struct berval *rule,
388         struct berval *assertDN, struct berval *authc )
389 {
390         int rc; 
391         regex_t reg;
392         smatch_info sm;
393         slap_callback cb = { sasl_sc_smatch, NULL };
394         Operation op = {0};
395         SlapReply rs = {REP_RESULT};
396
397 #ifdef NEW_LOGGING
398         LDAP_LOG( TRANSPORT, ENTRY, 
399                 "slap_sasl_match: comparing DN %s to rule %s\n", 
400                 assertDN->bv_val, rule->bv_val,0 );
401 #else
402         Debug( LDAP_DEBUG_TRACE,
403            "===>slap_sasl_match: comparing DN %s to rule %s\n",
404                 assertDN->bv_val, rule->bv_val, 0 );
405 #endif
406
407         rc = slap_parseURI( opx, rule,
408                 &op.o_req_ndn, &op.oq_search.rs_scope, &op.oq_search.rs_filter );
409         if( rc != LDAP_SUCCESS ) goto CONCLUDED;
410
411         /* Massive shortcut: search scope == base */
412         if( op.oq_search.rs_scope == LDAP_SCOPE_BASE ) {
413                 rc = regcomp(&reg, op.o_req_ndn.bv_val,
414                         REG_EXTENDED|REG_ICASE|REG_NOSUB);
415                 if ( rc == 0 ) {
416                         rc = regexec(&reg, assertDN->bv_val, 0, NULL, 0);
417                         regfree( &reg );
418                 }
419                 if ( rc == 0 ) {
420                         rc = LDAP_SUCCESS;
421                 } else {
422                         rc = LDAP_INAPPROPRIATE_AUTH;
423                 }
424                 goto CONCLUDED;
425         }
426
427         /* Must run an internal search. */
428
429 #ifdef NEW_LOGGING
430         LDAP_LOG( TRANSPORT, DETAIL1, 
431                 "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
432                 op.o_req_ndn.bv_val, op.oq_search.rs_scope, 0 );
433 #else
434         Debug( LDAP_DEBUG_TRACE,
435            "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
436            op.o_req_ndn.bv_val, op.oq_search.rs_scope, 0 );
437 #endif
438
439         op.o_bd = select_backend( &op.o_req_ndn, 0, 1 );
440         if(( op.o_bd == NULL ) || ( op.o_bd->be_search == NULL)) {
441                 rc = LDAP_INAPPROPRIATE_AUTH;
442                 goto CONCLUDED;
443         }
444
445         sm.dn = assertDN;
446         sm.match = 0;
447         cb.sc_private = &sm;
448
449         op.o_tag = LDAP_REQ_SEARCH;
450         op.o_protocol = LDAP_VERSION3;
451         op.o_ndn = *authc;
452         op.o_callback = &cb;
453         op.o_time = slap_get_time();
454         op.o_do_not_cache = 1;
455         op.o_is_auth_check = 1;
456         op.o_threadctx = opx->o_threadctx;
457         op.o_tmpmemctx = opx->o_tmpmemctx;
458         op.o_tmpmfuncs = opx->o_tmpmfuncs;
459 #ifdef LDAP_SLAPI
460         op.o_pb = opx->o_pb;
461 #endif
462         op.o_conn = opx->o_conn;
463         op.o_connid = opx->o_connid;
464
465         op.o_bd->be_search( &op, &rs );
466
467         if (sm.match) {
468                 rc = LDAP_SUCCESS;
469         } else {
470                 rc = LDAP_INAPPROPRIATE_AUTH;
471         }
472
473 CONCLUDED:
474         if( op.o_req_ndn.bv_len ) sl_free( op.o_req_ndn.bv_val, opx->o_tmpmemctx );
475         if( op.oq_search.rs_filter ) filter_free_x( opx, op.oq_search.rs_filter );
476
477 #ifdef NEW_LOGGING
478         LDAP_LOG( TRANSPORT, ENTRY, 
479                 "slap_sasl_match: comparison returned %d\n", rc, 0, 0 );
480 #else
481         Debug( LDAP_DEBUG_TRACE,
482            "<===slap_sasl_match: comparison returned %d\n", rc, 0, 0);
483 #endif
484
485         return( rc );
486 }
487
488
489 /*
490  * This function answers the question, "Can this ID authorize to that ID?",
491  * based on authorization rules. The rules are stored in the *searchDN, in the
492  * attribute named by *attr. If any of those rules map to the *assertDN, the
493  * authorization is approved.
494  *
495  * The DNs should not have the dn: prefix
496  */
497 static int
498 slap_sasl_check_authz( Operation *op,
499         struct berval *searchDN,
500         struct berval *assertDN,
501         AttributeDescription *ad,
502         struct berval *authc )
503 {
504         int i, rc;
505         BerVarray vals=NULL;
506
507 #ifdef NEW_LOGGING
508         LDAP_LOG( TRANSPORT, ENTRY, 
509                 "slap_sasl_check_authz: does %s match %s rule in %s?\n",
510             assertDN->bv_val, ad->ad_cname.bv_val, searchDN->bv_val);
511 #else
512         Debug( LDAP_DEBUG_TRACE,
513            "==>slap_sasl_check_authz: does %s match %s rule in %s?\n",
514            assertDN->bv_val, ad->ad_cname.bv_val, searchDN->bv_val);
515 #endif
516
517         rc = backend_attribute( op, NULL,
518                 searchDN, ad, &vals );
519         if( rc != LDAP_SUCCESS ) goto COMPLETE;
520
521         /* Check if the *assertDN matches any **vals */
522         if( vals != NULL ) {
523                 for( i=0; vals[i].bv_val != NULL; i++ ) {
524                         rc = slap_sasl_match( op, &vals[i], assertDN, authc );
525                         if ( rc == LDAP_SUCCESS ) goto COMPLETE;
526                 }
527         }
528         rc = LDAP_INAPPROPRIATE_AUTH;
529
530 COMPLETE:
531         if( vals ) ber_bvarray_free_x( vals, op->o_tmpmemctx );
532
533 #ifdef NEW_LOGGING
534         LDAP_LOG( TRANSPORT, RESULTS, 
535                 "slap_sasl_check_authz: %s check returning %s\n", 
536                 ad->ad_cname.bv_val, rc, 0 );
537 #else
538         Debug( LDAP_DEBUG_TRACE,
539            "<==slap_sasl_check_authz: %s check returning %d\n",
540                 ad->ad_cname.bv_val, rc, 0);
541 #endif
542
543         return( rc );
544 }
545
546 /*
547  * Given a SASL name (e.g. "UID=name,cn=REALM,cn=MECH,cn=AUTH")
548  * return the LDAP DN to which it matches. The SASL regexp rules in the config
549  * file turn the SASL name into an LDAP URI. If the URI is just a DN (or a
550  * search with scope=base), just return the URI (or its searchbase). Otherwise
551  * an internal search must be done, and if that search returns exactly one
552  * entry, return the DN of that one entry.
553  */
554 void slap_sasl2dn( Operation *opx,
555         struct berval *saslname, struct berval *sasldn )
556 {
557         int rc;
558         slap_callback cb = { sasl_sc_sasl2dn, NULL };
559         Operation op = {0};
560         SlapReply rs = {REP_RESULT};
561         struct berval regout = { 0, NULL };
562
563 #ifdef NEW_LOGGING
564         LDAP_LOG( TRANSPORT, ENTRY, 
565                 "slap_sasl2dn: converting SASL name %s to DN.\n",
566                 saslname->bv_val, 0, 0 );
567 #else
568         Debug( LDAP_DEBUG_TRACE, "==>slap_sasl2dn: "
569                 "converting SASL name %s to a DN\n",
570                 saslname->bv_val, 0,0 );
571 #endif
572
573         sasldn->bv_val = NULL;
574         sasldn->bv_len = 0;
575         cb.sc_private = sasldn;
576
577         /* Convert the SASL name into a minimal URI */
578         if( !slap_sasl_regexp( saslname, &regout, opx->o_tmpmemctx ) ) {
579                 goto FINISHED;
580         }
581
582         rc = slap_parseURI( opx, &regout,
583                 &op.o_req_ndn, &op.oq_search.rs_scope, &op.oq_search.rs_filter );
584         if( regout.bv_val ) sl_free( regout.bv_val, opx->o_tmpmemctx );
585         if( rc != LDAP_SUCCESS ) {
586                 goto FINISHED;
587         }
588
589         /* Must do an internal search */
590         op.o_bd = select_backend( &op.o_req_ndn, 0, 1 );
591
592         /* Massive shortcut: search scope == base */
593         if( op.oq_search.rs_scope == LDAP_SCOPE_BASE ) {
594                 *sasldn = op.o_req_ndn;
595                 op.o_req_ndn.bv_len = 0;
596                 op.o_req_ndn.bv_val = NULL;
597                 goto FINISHED;
598         }
599
600 #ifdef NEW_LOGGING
601         LDAP_LOG( TRANSPORT, DETAIL1, 
602                 "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
603                 op.o_req_ndn.bv_val, op.oq_search.rs_scope, 0 );
604 #else
605         Debug( LDAP_DEBUG_TRACE,
606                 "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
607                 op.o_req_ndn.bv_val, op.oq_search.rs_scope, 0 );
608 #endif
609
610         if(( op.o_bd == NULL ) || ( op.o_bd->be_search == NULL)) {
611                 goto FINISHED;
612         }
613
614         op.o_conn = opx->o_conn;
615         op.o_connid = opx->o_connid;
616         op.o_tag = LDAP_REQ_SEARCH;
617         op.o_protocol = LDAP_VERSION3;
618         op.o_ndn = opx->o_conn->c_ndn;
619         op.o_callback = &cb;
620         op.o_time = slap_get_time();
621         op.o_do_not_cache = 1;
622         op.o_is_auth_check = 1;
623         op.o_threadctx = opx->o_threadctx;
624         op.o_tmpmemctx = opx->o_tmpmemctx;
625         op.o_tmpmfuncs = opx->o_tmpmfuncs;
626 #ifdef LDAP_SLAPI
627         op.o_pb = opx->o_pb;
628 #endif
629         op.oq_search.rs_deref = LDAP_DEREF_NEVER;
630         op.oq_search.rs_slimit = 1;
631         op.oq_search.rs_attrsonly = 1;
632
633         op.o_bd->be_search( &op, &rs );
634         
635 FINISHED:
636         if( sasldn->bv_len ) {
637                 opx->o_conn->c_authz_backend = op.o_bd;
638         }
639         if( op.o_req_ndn.bv_len ) ch_free( op.o_req_ndn.bv_val );
640         if( op.oq_search.rs_filter ) filter_free_x( opx, op.oq_search.rs_filter );
641
642 #ifdef NEW_LOGGING
643         LDAP_LOG( TRANSPORT, ENTRY, 
644                 "slap_sasl2dn: Converted SASL name to %s\n",
645                 sasldn->bv_len ? sasldn->bv_val : "<nothing>", 0, 0 );
646 #else
647         Debug( LDAP_DEBUG_TRACE, "<==slap_sasl2dn: Converted SASL name to %s\n",
648                 sasldn->bv_len ? sasldn->bv_val : "<nothing>", 0, 0 );
649 #endif
650
651         return;
652 }
653
654
655 /* Check if a bind can SASL authorize to another identity.
656  * The DNs should not have the dn: prefix
657  */
658
659 int slap_sasl_authorized( Operation *op,
660         struct berval *authcDN, struct berval *authzDN )
661 {
662         int rc = LDAP_INAPPROPRIATE_AUTH;
663
664         /* User binding as anonymous */
665         if ( authzDN == NULL ) {
666                 rc = LDAP_SUCCESS;
667                 goto DONE;
668         }
669
670 #ifdef NEW_LOGGING
671         LDAP_LOG( TRANSPORT, ENTRY, 
672                 "slap_sasl_authorized: can %s become %s?\n", 
673                 authcDN->bv_val, authzDN->bv_val, 0 );
674 #else
675         Debug( LDAP_DEBUG_TRACE,
676            "==>slap_sasl_authorized: can %s become %s?\n",
677                 authcDN->bv_val, authzDN->bv_val, 0 );
678 #endif
679
680         /* If person is authorizing to self, succeed */
681         if ( dn_match( authcDN, authzDN ) ) {
682                 rc = LDAP_SUCCESS;
683                 goto DONE;
684         }
685
686         /* Allow the manager to authorize as any DN. */
687         if( op->o_conn->c_authz_backend && be_isroot( op->o_conn->c_authz_backend, authcDN )) {
688                 rc = LDAP_SUCCESS;
689                 goto DONE;
690         }
691
692         /* Check source rules */
693         if( authz_policy & SASL_AUTHZ_TO ) {
694                 rc = slap_sasl_check_authz( op, authcDN, authzDN,
695                         slap_schema.si_ad_saslAuthzTo, authcDN );
696                 if( rc == LDAP_SUCCESS ) {
697                         goto DONE;
698                 }
699         }
700
701         /* Check destination rules */
702         if( authz_policy & SASL_AUTHZ_FROM ) {
703                 rc = slap_sasl_check_authz( op, authzDN, authcDN,
704                         slap_schema.si_ad_saslAuthzFrom, authcDN );
705                 if( rc == LDAP_SUCCESS ) {
706                         goto DONE;
707                 }
708         }
709
710         rc = LDAP_INAPPROPRIATE_AUTH;
711
712 DONE:
713
714 #ifdef NEW_LOGGING
715         LDAP_LOG( TRANSPORT, RESULTS, "slap_sasl_authorized: return %d\n", rc,0,0 );
716 #else
717         Debug( LDAP_DEBUG_TRACE,
718                 "<== slap_sasl_authorized: return %d\n", rc, 0, 0 );
719 #endif
720
721         return( rc );
722 }