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