]> git.sur5r.net Git - openldap/blob - servers/slapd/saslauthz.c
Allow the root DN to switch to any authorization identity.
[openldap] / servers / slapd / saslauthz.c
1 /*
2  * Copyright 1998-2002 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         return rc;
65 }
66
67 /* URI format: ldap://<host>/<base>[?[<attrs>][?[<scope>][?[<filter>]]]] */
68
69 static int slap_parseURI( struct berval *uri,
70         struct berval *searchbase, int *scope, Filter **filter )
71 {
72         struct berval bv;
73         int rc;
74         LDAPURLDesc *ludp;
75
76         assert( uri != NULL && uri->bv_val != NULL );
77         searchbase->bv_val = NULL;
78         searchbase->bv_len = 0;
79         *scope = -1;
80         *filter = NULL;
81
82 #ifdef NEW_LOGGING
83         LDAP_LOG( TRANSPORT, ENTRY, 
84                 "slap_parseURI: parsing %s\n", uri->bv_val, 0, 0 );
85 #else
86         Debug( LDAP_DEBUG_TRACE, "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 = dnNormalize2( NULL, &bv, searchbase );
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 should be empty */
117                 /* attrs and extensions parts should 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( 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 = dnNormalize2( NULL, &bv, searchbase );
137
138 done:
139         if( rc != LDAP_SUCCESS ) {
140                 if( *filter ) filter_free( *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 {
232         int i, n, len, insert;
233
234         /* Get the total length of the final URI */
235
236         n=1;
237         len = 0;
238         while( off[n] >= 0 ) {
239                 /* Len of next section from replacement string (x,y,z above) */
240                 len += off[n] - off[n-1] - 2;
241                 if( off[n+1] < 0)
242                         break;
243
244                 /* Len of string from saslname that matched next $i  (b,d above) */
245                 i = rep[ off[n] + 1 ]   - '0';
246                 len += str[i].rm_eo - str[i].rm_so;
247                 n++;
248         }
249         out->bv_val = ch_malloc( len + 1 );
250         out->bv_len = len;
251
252         /* Fill in URI with replace string, replacing $i as we go */
253         n=1;
254         insert = 0;
255         while( off[n] >= 0) {
256                 /* Paste in next section from replacement string (x,y,z above) */
257                 len = off[n] - off[n-1] - 2;
258                 strncpy( out->bv_val+insert, rep + off[n-1] + 2, len);
259                 insert += len;
260                 if( off[n+1] < 0)
261                         break;
262
263                 /* Paste in string from saslname that matched next $i  (b,d above) */
264                 i = rep[ off[n] + 1 ]   - '0';
265                 len = str[i].rm_eo - str[i].rm_so;
266                 strncpy( out->bv_val+insert, saslname + str[i].rm_so, len );
267                 insert += len;
268
269                 n++;
270         }
271
272         out->bv_val[insert] = '\0';
273 }
274
275 /* Take the passed in SASL name and attempt to convert it into an
276    LDAP URI to find the matching LDAP entry, using the pattern matching
277    strings given in the saslregexp config file directive(s) */
278
279 static int slap_sasl_regexp( struct berval *in, struct berval *out )
280 {
281         char *saslname = in->bv_val;
282         SaslRegexp_t *reg;
283         int i;
284
285         memset( out, 0, sizeof( *out ) );
286
287 #ifdef NEW_LOGGING
288         LDAP_LOG( TRANSPORT, ENTRY, 
289                 "slap_sasl_regexp: converting SASL name %s\n", saslname, 0, 0 );
290 #else
291         Debug( LDAP_DEBUG_TRACE, "slap_sasl_regexp: converting SASL name %s\n",
292            saslname, 0, 0 );
293 #endif
294
295         if (( saslname == NULL ) || ( nSaslRegexp == 0 ))
296                 return( 0 );
297
298         /* Match the normalized SASL name to the saslregexp patterns */
299         for( reg = SaslRegexp,i=0;  i<nSaslRegexp;  i++,reg++ ) {
300                 if ( regexec( &reg->sr_workspace, saslname, SASLREGEX_REPLACE,
301                   reg->sr_strings, 0)  == 0 )
302                         break;
303         }
304
305         if( i >= nSaslRegexp )
306                 return( 0 );
307
308         /*
309          * The match pattern may have been of the form "a(b.*)c(d.*)e" and the
310          * replace pattern of the form "x$1y$2z". The returned string needs
311          * to replace the $1,$2 with the strings that matched (b.*) and (d.*)
312          */
313         slap_sasl_rx_exp( reg->sr_replace, reg->sr_offset,
314                 reg->sr_strings, saslname, out );
315
316 #ifdef NEW_LOGGING
317         LDAP_LOG( TRANSPORT, ENTRY, 
318                 "slap_sasl_regexp: converted SASL name to %s\n",
319                 out->bv_len ? out->bv_val : "", 0, 0 );
320 #else
321         Debug( LDAP_DEBUG_TRACE,
322                 "slap_sasl_regexp: converted SASL name to %s\n",
323                 out->bv_len ? out->bv_val : "", 0, 0 );
324 #endif
325
326         return( 1 );
327 }
328
329 /* Two empty callback functions to avoid sending results */
330 void slap_cb_null_response( Connection *conn, Operation *o, ber_tag_t tag,
331         ber_int_t msgid, ber_int_t err, const char *matched,
332         const char *text, BerVarray ref, const char *resoid,
333         struct berval *resdata, struct berval *sasldata, LDAPControl **c)
334 {
335 }
336
337 void slap_cb_null_sresult( Connection *conn, Operation *o, ber_int_t err,
338         const char *matched, const char *text, BerVarray refs, LDAPControl **c,
339         int nentries)
340 {
341 }
342
343 /* This callback actually does some work...*/
344 static int sasl_sc_sasl2dn( BackendDB *be, Connection *conn, Operation *o,
345         Entry *e, AttributeName *an, int ao, LDAPControl **c)
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, &e->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( BackendDB *be, Connection *conn, Operation *o,
375         Entry *e, AttributeName *an, int ao, LDAPControl **c)
376 {
377         smatch_info *sm = o->o_callback->sc_private;
378
379         if (dn_match(sm->dn, &e->e_nname)) {
380                 sm->match = 1;
381                 return -1;      /* short-circuit the search */
382         } else {
383                 return 1;
384         }
385 }
386
387 /*
388  * Map a SASL regexp rule to a DN. If the rule is just a DN or a scope=base
389  * URI, just strcmp the rule (or its searchbase) to the *assertDN. Otherwise,
390  * the rule must be used as an internal search for entries. If that search
391  * returns the *assertDN entry, the match is successful.
392  *
393  * The assertDN should not have the dn: prefix
394  */
395
396 static
397 int slap_sasl_match(Connection *conn, struct berval *rule, struct berval *assertDN, struct berval *authc )
398 {
399         struct berval searchbase = {0, NULL};
400         int rc, scope;
401         Backend *be;
402         Filter *filter=NULL;
403         regex_t reg;
404         smatch_info sm;
405         slap_callback cb = { slap_cb_null_response, slap_cb_null_sresult, sasl_sc_smatch, NULL };
406         Operation op = {0};
407
408 #ifdef NEW_LOGGING
409         LDAP_LOG( TRANSPORT, ENTRY, 
410                 "slap_sasl_match: comparing DN %s to rule %s\n", 
411                 assertDN->bv_val, rule->bv_val,0 );
412 #else
413         Debug( LDAP_DEBUG_TRACE,
414            "===>slap_sasl_match: comparing DN %s to rule %s\n", assertDN->bv_val, rule->bv_val, 0 );
415 #endif
416
417         rc = slap_parseURI( rule, &searchbase, &scope, &filter );
418         if( rc != LDAP_SUCCESS )
419                 goto CONCLUDED;
420
421         /* Massive shortcut: search scope == base */
422         if( scope == LDAP_SCOPE_BASE ) {
423                 rc = regcomp(&reg, searchbase.bv_val,
424                         REG_EXTENDED|REG_ICASE|REG_NOSUB);
425                 if ( rc == 0 ) {
426                         rc = regexec(&reg, assertDN->bv_val, 0, NULL, 0);
427                         regfree( &reg );
428                 }
429                 if ( rc == 0 )
430                         rc = LDAP_SUCCESS;
431                 else
432                         rc = LDAP_INAPPROPRIATE_AUTH;
433                 goto CONCLUDED;
434         }
435
436         /* Must run an internal search. */
437
438 #ifdef NEW_LOGGING
439         LDAP_LOG( TRANSPORT, DETAIL1, 
440                 "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
441                 searchbase.bv_val, scope,0 );
442 #else
443         Debug( LDAP_DEBUG_TRACE,
444            "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
445            searchbase.bv_val, scope, 0 );
446 #endif
447
448         be = select_backend( &searchbase, 0, 1 );
449         if(( be == NULL ) || ( be->be_search == NULL)) {
450                 rc = LDAP_INAPPROPRIATE_AUTH;
451                 goto CONCLUDED;
452         }
453         suffix_alias( be, &searchbase );
454
455         sm.dn = assertDN;
456         sm.match = 0;
457         cb.sc_private = &sm;
458
459         op.o_tag = LDAP_REQ_SEARCH;
460         op.o_protocol = LDAP_VERSION3;
461         op.o_ndn = *authc;
462         op.o_callback = &cb;
463         op.o_time = slap_get_time();
464         op.o_do_not_cache = 1;
465         op.o_threadctx = conn->c_sasl_bindop->o_threadctx;
466
467         (*be->be_search)( be, conn, &op, /*base=*/NULL, &searchbase,
468            scope, /*deref=*/1, /*sizelimit=*/0, /*time=*/0, filter, /*fstr=*/NULL,
469            /*attrs=*/NULL, /*attrsonly=*/0 );
470
471         if (sm.match)
472                 rc = LDAP_SUCCESS;
473         else
474                 rc = LDAP_INAPPROPRIATE_AUTH;
475
476 CONCLUDED:
477         if( searchbase.bv_len ) ch_free( searchbase.bv_val );
478         if( filter ) filter_free( filter );
479 #ifdef NEW_LOGGING
480         LDAP_LOG( TRANSPORT, ENTRY, 
481                 "slap_sasl_match: comparison returned %d\n", rc, 0, 0 );
482 #else
483         Debug( LDAP_DEBUG_TRACE,
484            "<===slap_sasl_match: comparison returned %d\n", rc, 0, 0);
485 #endif
486
487         return( rc );
488 }
489
490
491 /*
492  * This function answers the question, "Can this ID authorize to that ID?",
493  * based on authorization rules. The rules are stored in the *searchDN, in the
494  * attribute named by *attr. If any of those rules map to the *assertDN, the
495  * authorization is approved.
496  *
497  * The DNs should not have the dn: prefix
498  */
499 static int
500 slap_sasl_check_authz( Connection *conn,
501         struct berval *searchDN,
502         struct berval *assertDN,
503         AttributeDescription *ad,
504         struct berval *authc )
505 {
506         int i, rc;
507         BerVarray vals=NULL;
508
509 #ifdef NEW_LOGGING
510         LDAP_LOG( TRANSPORT, ENTRY, 
511                 "slap_sasl_check_authz: does %s match %s rule in %s?\n",
512             assertDN->bv_val, ad->ad_cname.bv_val, searchDN->bv_val);
513 #else
514         Debug( LDAP_DEBUG_TRACE,
515            "==>slap_sasl_check_authz: does %s match %s rule in %s?\n",
516            assertDN->bv_val, ad->ad_cname.bv_val, searchDN->bv_val);
517 #endif
518
519         rc = backend_attribute( NULL, NULL, conn->c_sasl_bindop, NULL,
520                 searchDN, ad, &vals );
521         if( rc != LDAP_SUCCESS )
522                 goto COMPLETE;
523
524         /* Check if the *assertDN matches any **vals */
525         for( i=0; vals[i].bv_val != NULL; i++ ) {
526                 rc = slap_sasl_match( conn, &vals[i], assertDN, authc );
527                 if ( rc == LDAP_SUCCESS )
528                         goto COMPLETE;
529         }
530         rc = LDAP_INAPPROPRIATE_AUTH;
531
532 COMPLETE:
533         if( vals ) ber_bvarray_free( vals );
534
535 #ifdef NEW_LOGGING
536         LDAP_LOG( TRANSPORT, RESULTS, 
537                 "slap_sasl_check_authz: %s check returning %s\n", 
538                 ad->ad_cname.bv_val, rc, 0 );
539 #else
540         Debug( LDAP_DEBUG_TRACE,
541            "<==slap_sasl_check_authz: %s check returning %d\n",
542                 ad->ad_cname.bv_val, rc, 0);
543 #endif
544
545         return( rc );
546 }
547
548 /*
549  * Given a SASL name (e.g. "UID=name,cn=REALM,cn=MECH,cn=AUTH")
550  * return the LDAP DN to which it matches. The SASL regexp rules in the config
551  * file turn the SASL name into an LDAP URI. If the URI is just a DN (or a
552  * search with scope=base), just return the URI (or its searchbase). Otherwise
553  * an internal search must be done, and if that search returns exactly one
554  * entry, return the DN of that one entry.
555  */
556 void slap_sasl2dn( Connection *conn,
557         struct berval *saslname, struct berval *sasldn )
558 {
559         int rc;
560         Backend *be = NULL;
561         struct berval dn = { 0, NULL };
562         int scope = LDAP_SCOPE_BASE;
563         Filter *filter = NULL;
564         slap_callback cb = { slap_cb_null_response,
565                 slap_cb_null_sresult, sasl_sc_sasl2dn, NULL};
566         Operation op = {0};
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, &dn, &scope, &filter );
589         if( rc != LDAP_SUCCESS ) {
590                 goto FINISHED;
591         }
592
593         /* Must do an internal search */
594         be = select_backend( &dn, 0, 1 );
595
596         /* Massive shortcut: search scope == base */
597         if( scope == LDAP_SCOPE_BASE ) {
598                 *sasldn = dn;
599                 dn.bv_len = 0;
600                 dn.bv_val = NULL;
601                 goto FINISHED;
602         }
603
604 #ifdef NEW_LOGGING
605         LDAP_LOG( TRANSPORT, DETAIL1, 
606                 "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
607                 dn.bv_val, scope, 0 );
608 #else
609         Debug( LDAP_DEBUG_TRACE,
610                 "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
611                 dn.bv_val, scope, 0 );
612 #endif
613
614         if(( be == NULL ) || ( be->be_search == NULL)) {
615                 goto FINISHED;
616         }
617         suffix_alias( be, &dn );
618
619         op.o_tag = LDAP_REQ_SEARCH;
620         op.o_protocol = LDAP_VERSION3;
621         op.o_ndn = conn->c_ndn;
622         op.o_callback = &cb;
623         op.o_time = slap_get_time();
624         op.o_do_not_cache = 1;
625         op.o_threadctx = conn->c_sasl_bindop->o_threadctx;
626
627         (*be->be_search)( be, conn, &op, NULL, &dn,
628                 scope, LDAP_DEREF_NEVER, 1, 0,
629                 filter, NULL, NULL, 1 );
630         
631 FINISHED:
632         if( sasldn->bv_len ) {
633                 conn->c_authz_backend = be;
634         }
635         if( dn.bv_len ) ch_free( dn.bv_val );
636         if( filter ) filter_free( filter );
637
638 #ifdef NEW_LOGGING
639         LDAP_LOG( TRANSPORT, ENTRY, 
640                 "slap_sasl2dn: Converted SASL name to %s\n",
641                 sasldn->bv_len ? sasldn->bv_val : "<nothing>", 0, 0 );
642 #else
643         Debug( LDAP_DEBUG_TRACE, "<==slap_sasl2dn: Converted SASL name to %s\n",
644                 sasldn->bv_len ? sasldn->bv_val : "<nothing>", 0, 0 );
645 #endif
646
647         return;
648 }
649
650
651 /* Check if a bind can SASL authorize to another identity.
652  * The DNs should not have the dn: prefix
653  */
654
655 int slap_sasl_authorized( Connection *conn,
656         struct berval *authcDN, struct berval *authzDN )
657 {
658         int rc = LDAP_INAPPROPRIATE_AUTH;
659
660         /* User binding as anonymous */
661         if ( authzDN == NULL ) {
662                 rc = LDAP_SUCCESS;
663                 goto DONE;
664         }
665
666 #ifdef NEW_LOGGING
667         LDAP_LOG( TRANSPORT, ENTRY, 
668                 "slap_sasl_authorized: can %s become %s?\n", 
669                 authcDN->bv_val, authzDN->bv_val, 0 );
670 #else
671         Debug( LDAP_DEBUG_TRACE,
672            "==>slap_sasl_authorized: can %s become %s?\n",
673                 authcDN->bv_val, authzDN->bv_val, 0 );
674 #endif
675
676         /* If person is authorizing to self, succeed */
677         if ( dn_match( authcDN, authzDN ) ) {
678                 rc = LDAP_SUCCESS;
679                 goto DONE;
680         }
681
682         /* Allow the manager to authorize as any DN. */
683         if( be_isroot( conn->c_authz_backend, authcDN )) {
684                 rc = LDAP_SUCCESS;
685                 goto DONE;
686         }
687
688         /* Check source rules */
689         if( authz_policy & SASL_AUTHZ_TO ) {
690                 rc = slap_sasl_check_authz( conn, authcDN, authzDN,
691                         slap_schema.si_ad_saslAuthzTo, authcDN );
692                 if( rc == LDAP_SUCCESS ) {
693                         goto DONE;
694                 }
695         }
696
697         /* Check destination rules */
698         if( authz_policy & SASL_AUTHZ_FROM ) {
699                 rc = slap_sasl_check_authz( conn, authzDN, authcDN,
700                         slap_schema.si_ad_saslAuthzFrom, authcDN );
701                 if( rc == LDAP_SUCCESS ) {
702                         goto DONE;
703                 }
704         }
705
706         rc = LDAP_INAPPROPRIATE_AUTH;
707
708 DONE:
709
710 #ifdef NEW_LOGGING
711         LDAP_LOG( TRANSPORT, RESULTS, "slap_sasl_authorized: return %d\n", rc,0,0 );
712 #else
713         Debug( LDAP_DEBUG_TRACE,
714                 "<== slap_sasl_authorized: return %d\n", rc, 0, 0 );
715 #endif
716
717         return( rc );
718 }