]> git.sur5r.net Git - openldap/blob - servers/slapd/saslauthz.c
Plug memleak in slap_parseURI
[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                 rc =  LDAP_PROTOCOL_ERROR;
119                 goto done;
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 = dnNormalize( 0, NULL, 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         void *ctx )
233 {
234         int i, n, len, insert;
235
236         /* Get the total length of the final URI */
237
238         n=1;
239         len = 0;
240         while( off[n] >= 0 ) {
241                 /* Len of next section from replacement string (x,y,z above) */
242                 len += off[n] - off[n-1] - 2;
243                 if( off[n+1] < 0)
244                         break;
245
246                 /* Len of string from saslname that matched next $i  (b,d above) */
247                 i = rep[ off[n] + 1 ]   - '0';
248                 len += str[i].rm_eo - str[i].rm_so;
249                 n++;
250         }
251         out->bv_val = sl_malloc( len + 1, ctx );
252         out->bv_len = len;
253
254         /* Fill in URI with replace string, replacing $i as we go */
255         n=1;
256         insert = 0;
257         while( off[n] >= 0) {
258                 /* Paste in next section from replacement string (x,y,z above) */
259                 len = off[n] - off[n-1] - 2;
260                 strncpy( out->bv_val+insert, rep + off[n-1] + 2, len);
261                 insert += len;
262                 if( off[n+1] < 0)
263                         break;
264
265                 /* Paste in string from saslname that matched next $i  (b,d above) */
266                 i = rep[ off[n] + 1 ]   - '0';
267                 len = str[i].rm_eo - str[i].rm_so;
268                 strncpy( out->bv_val+insert, saslname + str[i].rm_so, len );
269                 insert += len;
270
271                 n++;
272         }
273
274         out->bv_val[insert] = '\0';
275 }
276
277 /* Take the passed in SASL name and attempt to convert it into an
278    LDAP URI to find the matching LDAP entry, using the pattern matching
279    strings given in the saslregexp config file directive(s) */
280
281 static int slap_sasl_regexp( struct berval *in, struct berval *out, void *ctx )
282 {
283         char *saslname = in->bv_val;
284         SaslRegexp_t *reg;
285         regmatch_t sr_strings[SASLREGEX_REPLACE];       /* strings matching $1,$2 ... */
286         int i;
287
288         memset( out, 0, sizeof( *out ) );
289
290 #ifdef NEW_LOGGING
291         LDAP_LOG( TRANSPORT, ENTRY, 
292                 "slap_sasl_regexp: converting SASL name %s\n", saslname, 0, 0 );
293 #else
294         Debug( LDAP_DEBUG_TRACE, "slap_sasl_regexp: converting SASL name %s\n",
295            saslname, 0, 0 );
296 #endif
297
298         if (( saslname == NULL ) || ( nSaslRegexp == 0 )) {
299                 return( 0 );
300         }
301
302         /* Match the normalized SASL name to the saslregexp patterns */
303         for( reg = SaslRegexp,i=0;  i<nSaslRegexp;  i++,reg++ ) {
304                 if ( regexec( &reg->sr_workspace, saslname, SASLREGEX_REPLACE,
305                   sr_strings, 0)  == 0 )
306                         break;
307         }
308
309         if( i >= nSaslRegexp ) return( 0 );
310
311         /*
312          * The match pattern may have been of the form "a(b.*)c(d.*)e" and the
313          * replace pattern of the form "x$1y$2z". The returned string needs
314          * to replace the $1,$2 with the strings that matched (b.*) and (d.*)
315          */
316         slap_sasl_rx_exp( reg->sr_replace, reg->sr_offset,
317                 sr_strings, saslname, out, ctx );
318
319 #ifdef NEW_LOGGING
320         LDAP_LOG( TRANSPORT, ENTRY, 
321                 "slap_sasl_regexp: converted SASL name to %s\n",
322                 out->bv_len ? out->bv_val : "", 0, 0 );
323 #else
324         Debug( LDAP_DEBUG_TRACE,
325                 "slap_sasl_regexp: converted SASL name to %s\n",
326                 out->bv_len ? out->bv_val : "", 0, 0 );
327 #endif
328
329         return( 1 );
330 }
331
332 /* This callback actually does some work...*/
333 static int sasl_sc_sasl2dn( Operation *o, SlapReply *rs )
334 {
335         struct berval *ndn = o->o_callback->sc_private;
336
337         if (rs->sr_type != REP_SEARCH) return 0;
338
339         /* We only want to be called once */
340         if( ndn->bv_val ) {
341                 o->o_tmpfree(ndn->bv_val, o->o_tmpmemctx);
342                 ndn->bv_val = NULL;
343
344 #ifdef NEW_LOGGING
345                 LDAP_LOG( TRANSPORT, DETAIL1,
346                         "slap_sasl2dn: search DN returned more than 1 entry\n", 0, 0, 0 );
347 #else
348                 Debug( LDAP_DEBUG_TRACE,
349                         "slap_sasl2dn: search DN returned more than 1 entry\n", 0,0,0 );
350 #endif
351                 return -1;
352         }
353
354         ber_dupbv_x(ndn, &rs->sr_entry->e_nname, o->o_tmpmemctx);
355         return 0;
356 }
357
358
359 typedef struct smatch_info {
360         struct berval *dn;
361         int match;
362 } smatch_info;
363
364 static int sasl_sc_smatch( Operation *o, SlapReply *rs )
365 {
366         smatch_info *sm = o->o_callback->sc_private;
367
368         if (rs->sr_type != REP_SEARCH) return 0;
369
370         if (dn_match(sm->dn, &rs->sr_entry->e_nname)) {
371                 sm->match = 1;
372                 return -1;      /* short-circuit the search */
373         }
374
375         return 1;
376 }
377
378 /*
379  * Map a SASL regexp rule to a DN. If the rule is just a DN or a scope=base
380  * URI, just strcmp the rule (or its searchbase) to the *assertDN. Otherwise,
381  * the rule must be used as an internal search for entries. If that search
382  * returns the *assertDN entry, the match is successful.
383  *
384  * The assertDN should not have the dn: prefix
385  */
386
387 static
388 int slap_sasl_match( Operation *opx, struct berval *rule,
389         struct berval *assertDN, struct berval *authc )
390 {
391         int rc; 
392         regex_t reg;
393         smatch_info sm;
394         slap_callback cb = { sasl_sc_smatch, NULL };
395         Operation op = {0};
396         SlapReply rs = {REP_RESULT};
397
398 #ifdef NEW_LOGGING
399         LDAP_LOG( TRANSPORT, ENTRY, 
400                 "slap_sasl_match: comparing DN %s to rule %s\n", 
401                 assertDN->bv_val, rule->bv_val,0 );
402 #else
403         Debug( LDAP_DEBUG_TRACE,
404            "===>slap_sasl_match: comparing DN %s to rule %s\n",
405                 assertDN->bv_val, rule->bv_val, 0 );
406 #endif
407
408         rc = slap_parseURI( opx, rule,
409                 &op.o_req_ndn, &op.oq_search.rs_scope, &op.oq_search.rs_filter );
410         if( rc != LDAP_SUCCESS ) goto CONCLUDED;
411
412         /* Massive shortcut: search scope == base */
413         if( op.oq_search.rs_scope == LDAP_SCOPE_BASE ) {
414                 rc = regcomp(&reg, op.o_req_ndn.bv_val,
415                         REG_EXTENDED|REG_ICASE|REG_NOSUB);
416                 if ( rc == 0 ) {
417                         rc = regexec(&reg, assertDN->bv_val, 0, NULL, 0);
418                         regfree( &reg );
419                 }
420                 if ( rc == 0 ) {
421                         rc = LDAP_SUCCESS;
422                 } else {
423                         rc = LDAP_INAPPROPRIATE_AUTH;
424                 }
425                 goto CONCLUDED;
426         }
427
428         /* Must run an internal search. */
429
430 #ifdef NEW_LOGGING
431         LDAP_LOG( TRANSPORT, DETAIL1, 
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 #else
435         Debug( LDAP_DEBUG_TRACE,
436            "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
437            op.o_req_ndn.bv_val, op.oq_search.rs_scope, 0 );
438 #endif
439
440         op.o_bd = select_backend( &op.o_req_ndn, 0, 1 );
441         if(( op.o_bd == NULL ) || ( op.o_bd->be_search == NULL)) {
442                 rc = LDAP_INAPPROPRIATE_AUTH;
443                 goto CONCLUDED;
444         }
445
446         sm.dn = assertDN;
447         sm.match = 0;
448         cb.sc_private = &sm;
449
450         op.o_tag = LDAP_REQ_SEARCH;
451         op.o_protocol = LDAP_VERSION3;
452         op.o_ndn = *authc;
453         op.o_callback = &cb;
454         op.o_time = slap_get_time();
455         op.o_do_not_cache = 1;
456         op.o_is_auth_check = 1;
457         op.o_threadctx = opx->o_threadctx;
458         op.o_tmpmemctx = opx->o_tmpmemctx;
459         op.o_tmpmfuncs = opx->o_tmpmfuncs;
460 #ifdef LDAP_SLAPI
461         op.o_pb = opx->o_pb;
462 #endif
463         op.o_conn = opx->o_conn;
464         op.o_connid = opx->o_connid;
465
466         op.o_bd->be_search( &op, &rs );
467
468         if (sm.match) {
469                 rc = LDAP_SUCCESS;
470         } else {
471                 rc = LDAP_INAPPROPRIATE_AUTH;
472         }
473
474 CONCLUDED:
475         if( op.o_req_ndn.bv_len ) sl_free( op.o_req_ndn.bv_val, opx->o_tmpmemctx );
476         if( op.oq_search.rs_filter ) filter_free_x( opx, op.oq_search.rs_filter );
477
478 #ifdef NEW_LOGGING
479         LDAP_LOG( TRANSPORT, ENTRY, 
480                 "slap_sasl_match: comparison returned %d\n", rc, 0, 0 );
481 #else
482         Debug( LDAP_DEBUG_TRACE,
483            "<===slap_sasl_match: comparison returned %d\n", rc, 0, 0);
484 #endif
485
486         return( rc );
487 }
488
489
490 /*
491  * This function answers the question, "Can this ID authorize to that ID?",
492  * based on authorization rules. The rules are stored in the *searchDN, in the
493  * attribute named by *attr. If any of those rules map to the *assertDN, the
494  * authorization is approved.
495  *
496  * The DNs should not have the dn: prefix
497  */
498 static int
499 slap_sasl_check_authz( Operation *op,
500         struct berval *searchDN,
501         struct berval *assertDN,
502         AttributeDescription *ad,
503         struct berval *authc )
504 {
505         int i, rc;
506         BerVarray vals=NULL;
507
508 #ifdef NEW_LOGGING
509         LDAP_LOG( TRANSPORT, ENTRY, 
510                 "slap_sasl_check_authz: does %s match %s rule in %s?\n",
511             assertDN->bv_val, ad->ad_cname.bv_val, searchDN->bv_val);
512 #else
513         Debug( LDAP_DEBUG_TRACE,
514            "==>slap_sasl_check_authz: does %s match %s rule in %s?\n",
515            assertDN->bv_val, ad->ad_cname.bv_val, searchDN->bv_val);
516 #endif
517
518         rc = backend_attribute( op, NULL,
519                 searchDN, ad, &vals );
520         if( rc != LDAP_SUCCESS ) goto COMPLETE;
521
522         /* Check if the *assertDN matches any **vals */
523         if( vals != NULL ) {
524                 for( i=0; vals[i].bv_val != NULL; i++ ) {
525                         rc = slap_sasl_match( op, &vals[i], assertDN, authc );
526                         if ( rc == LDAP_SUCCESS ) goto COMPLETE;
527                 }
528         }
529         rc = LDAP_INAPPROPRIATE_AUTH;
530
531 COMPLETE:
532         if( vals ) ber_bvarray_free_x( vals, op->o_tmpmemctx );
533
534 #ifdef NEW_LOGGING
535         LDAP_LOG( TRANSPORT, RESULTS, 
536                 "slap_sasl_check_authz: %s check returning %s\n", 
537                 ad->ad_cname.bv_val, rc, 0 );
538 #else
539         Debug( LDAP_DEBUG_TRACE,
540            "<==slap_sasl_check_authz: %s check returning %d\n",
541                 ad->ad_cname.bv_val, rc, 0);
542 #endif
543
544         return( rc );
545 }
546
547 /*
548  * Given a SASL name (e.g. "UID=name,cn=REALM,cn=MECH,cn=AUTH")
549  * return the LDAP DN to which it matches. The SASL regexp rules in the config
550  * file turn the SASL name into an LDAP URI. If the URI is just a DN (or a
551  * search with scope=base), just return the URI (or its searchbase). Otherwise
552  * an internal search must be done, and if that search returns exactly one
553  * entry, return the DN of that one entry.
554  */
555 void slap_sasl2dn( Operation *opx,
556         struct berval *saslname, struct berval *sasldn )
557 {
558         int rc;
559         slap_callback cb = { sasl_sc_sasl2dn, NULL };
560         Operation op = {0};
561         SlapReply rs = {REP_RESULT};
562         struct berval regout = { 0, NULL };
563
564 #ifdef NEW_LOGGING
565         LDAP_LOG( TRANSPORT, ENTRY, 
566                 "slap_sasl2dn: converting SASL name %s to DN.\n",
567                 saslname->bv_val, 0, 0 );
568 #else
569         Debug( LDAP_DEBUG_TRACE, "==>slap_sasl2dn: "
570                 "converting SASL name %s to a DN\n",
571                 saslname->bv_val, 0,0 );
572 #endif
573
574         sasldn->bv_val = NULL;
575         sasldn->bv_len = 0;
576         cb.sc_private = sasldn;
577
578         /* Convert the SASL name into a minimal URI */
579         if( !slap_sasl_regexp( saslname, &regout, opx->o_tmpmemctx ) ) {
580                 goto FINISHED;
581         }
582
583         rc = slap_parseURI( opx, &regout,
584                 &op.o_req_ndn, &op.oq_search.rs_scope, &op.oq_search.rs_filter );
585         if( regout.bv_val ) sl_free( regout.bv_val, opx->o_tmpmemctx );
586         if( rc != LDAP_SUCCESS ) {
587                 goto FINISHED;
588         }
589
590         /* Must do an internal search */
591         op.o_bd = select_backend( &op.o_req_ndn, 0, 1 );
592
593         /* Massive shortcut: search scope == base */
594         if( op.oq_search.rs_scope == LDAP_SCOPE_BASE ) {
595                 *sasldn = op.o_req_ndn;
596                 op.o_req_ndn.bv_len = 0;
597                 op.o_req_ndn.bv_val = NULL;
598                 goto FINISHED;
599         }
600
601 #ifdef NEW_LOGGING
602         LDAP_LOG( TRANSPORT, DETAIL1, 
603                 "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
604                 op.o_req_ndn.bv_val, op.oq_search.rs_scope, 0 );
605 #else
606         Debug( LDAP_DEBUG_TRACE,
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 #endif
610
611         if(( op.o_bd == NULL ) || ( op.o_bd->be_search == NULL)) {
612                 goto FINISHED;
613         }
614
615         op.o_conn = opx->o_conn;
616         op.o_connid = opx->o_connid;
617         op.o_tag = LDAP_REQ_SEARCH;
618         op.o_protocol = LDAP_VERSION3;
619         op.o_ndn = opx->o_conn->c_ndn;
620         op.o_callback = &cb;
621         op.o_time = slap_get_time();
622         op.o_do_not_cache = 1;
623         op.o_is_auth_check = 1;
624         op.o_threadctx = opx->o_threadctx;
625         op.o_tmpmemctx = opx->o_tmpmemctx;
626         op.o_tmpmfuncs = opx->o_tmpmfuncs;
627 #ifdef LDAP_SLAPI
628         op.o_pb = opx->o_pb;
629 #endif
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                 opx->o_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_x( opx, 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( Operation *op,
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( op->o_conn->c_authz_backend && be_isroot( op->o_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( op, 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( op, 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 }