]> git.sur5r.net Git - openldap/blob - servers/slapd/saslauthz.c
Add start of discussion of strings in LDAP/X.500 and OpenLDAP.
[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 #ifdef HAVE_CYRUS_SASL
27 #include <limits.h>
28
29 #ifdef HAVE_SASL_SASL_H
30 #include <sasl/sasl.h>
31 #else
32 #include <sasl.h>
33 #endif
34
35 #include <ldap_pvt.h>
36
37 #define SASLREGEX_REPLACE 10
38
39 typedef struct sasl_regexp {
40   char *sr_match;                                                       /* regexp match pattern */
41   char *sr_replace;                                             /* regexp replace pattern */
42   regex_t sr_workspace;                                         /* workspace for regexp engine */
43   regmatch_t sr_strings[SASLREGEX_REPLACE];     /* strings matching $1,$2 ... */
44   int sr_offset[SASLREGEX_REPLACE+2];           /* offsets of $1,$2... in *replace */
45 } SaslRegexp_t;
46
47 static int nSaslRegexp = 0;
48 static SaslRegexp_t *SaslRegexp = NULL;
49
50 /* What SASL proxy authorization policies are allowed? */
51 #define SASL_AUTHZ_NONE 0
52 #define SASL_AUTHZ_FROM 1
53 #define SASL_AUTHZ_TO   2
54
55 static int authz_policy = SASL_AUTHZ_NONE;
56
57 int slap_sasl_setpolicy( const char *arg )
58 {
59         int rc = LDAP_SUCCESS;
60
61         if ( strcasecmp( arg, "none" ) == 0 )
62                 authz_policy = SASL_AUTHZ_NONE;
63         else if ( strcasecmp( arg, "from" ) == 0 )
64                 authz_policy = SASL_AUTHZ_FROM;
65         else if ( strcasecmp( arg, "to" ) == 0 )
66                 authz_policy = SASL_AUTHZ_TO;
67         else if ( strcasecmp( arg, "both" ) == 0 )
68                 authz_policy = SASL_AUTHZ_FROM | SASL_AUTHZ_TO;
69         else
70                 rc = LDAP_OTHER;
71         return rc;
72 }
73
74 /* URI format: ldap://<host>/<base>[?[<attrs>][?[<scope>][?[<filter>]]]] */
75
76 static int slap_parseURI( struct berval *uri,
77         struct berval *searchbase, int *scope, Filter **filter )
78 {
79         struct berval bv;
80         int rc;
81         LDAPURLDesc *ludp;
82
83         assert( uri != NULL && uri->bv_val != NULL );
84         searchbase->bv_val = NULL;
85         searchbase->bv_len = 0;
86         *scope = -1;
87         *filter = NULL;
88
89 #ifdef NEW_LOGGING
90         LDAP_LOG( TRANSPORT, ENTRY, 
91                 "slap_parseURI: parsing %s\n", uri->bv_val, 0, 0 );
92 #else
93         Debug( LDAP_DEBUG_TRACE, "slap_parseURI: parsing %s\n", uri->bv_val, 0, 0 );
94 #endif
95
96         /* If it does not look like a URI, assume it is a DN */
97         if( !strncasecmp( uri->bv_val, "dn:", sizeof("dn:")-1 ) ) {
98                 bv.bv_val = uri->bv_val + sizeof("dn:")-1;
99                 bv.bv_val += strspn( bv.bv_val, " " );
100
101 is_dn:          bv.bv_len = uri->bv_len - (bv.bv_val - uri->bv_val);
102
103                 rc = dnNormalize2( NULL, &bv, searchbase );
104                 if( rc == LDAP_SUCCESS ) {
105                         *scope = LDAP_SCOPE_BASE;
106                 }
107                 return( rc );
108         }
109
110         rc = ldap_url_parse( uri->bv_val, &ludp );
111         if ( rc == LDAP_URL_ERR_BADSCHEME ) {
112                 bv.bv_val = uri->bv_val;
113                 goto is_dn;
114         }
115
116         if ( rc != LDAP_URL_SUCCESS ) {
117                 return LDAP_PROTOCOL_ERROR;
118         }
119
120         if (( ludp->lud_host && *ludp->lud_host )
121                 || ludp->lud_attrs || ludp->lud_exts )
122         {
123                 /* host part should be empty */
124                 /* attrs and extensions parts should be empty */
125                 return LDAP_PROTOCOL_ERROR;
126         }
127
128         /* Grab the scope */
129         *scope = ludp->lud_scope;
130
131         /* Grab the filter */
132         if ( ludp->lud_filter ) {
133                 *filter = str2filter( ludp->lud_filter );
134                 if ( *filter == NULL ) {
135                         rc = LDAP_PROTOCOL_ERROR;
136                         goto done;
137                 }
138         }
139
140         /* Grab the searchbase */
141         bv.bv_val = ludp->lud_dn;
142         bv.bv_len = strlen( bv.bv_val );
143         rc = dnNormalize2( NULL, &bv, searchbase );
144
145 done:
146         if( rc != LDAP_SUCCESS ) {
147                 if( *filter ) filter_free( *filter );
148         }
149
150         ldap_free_urldesc( ludp );
151         return( rc );
152 }
153
154 static int slap_sasl_rx_off(char *rep, int *off)
155 {
156         const char *c;
157         int n;
158
159         /* Precompile replace pattern. Find the $<n> placeholders */
160         off[0] = -2;
161         n = 1;
162         for ( c = rep;   *c;  c++ ) {
163                 if ( *c == '\\' && c[1] ) {
164                         c++;
165                         continue;
166                 }
167                 if ( *c == '$' ) {
168                         if ( n == SASLREGEX_REPLACE ) {
169 #ifdef NEW_LOGGING
170                                 LDAP_LOG( TRANSPORT, ERR, 
171                                         "slap_sasl_rx_off: \"%s\" has too many $n "
172                                         "placeholders (max %d)\n", rep, SASLREGEX_REPLACE, 0  );
173 #else
174                                 Debug( LDAP_DEBUG_ANY,
175                                         "SASL replace pattern %s has too many $n "
176                                                 "placeholders (max %d)\n",
177                                         rep, SASLREGEX_REPLACE, 0 );
178 #endif
179
180                                 return( LDAP_OTHER );
181                         }
182                         off[n] = c - rep;
183                         n++;
184                 }
185         }
186
187         /* Final placeholder, after the last $n */
188         off[n] = c - rep;
189         n++;
190         off[n] = -1;
191         return( LDAP_SUCCESS );
192 }
193
194 int slap_sasl_regexp_config( const char *match, const char *replace )
195 {
196         int rc;
197         SaslRegexp_t *reg;
198
199         SaslRegexp = (SaslRegexp_t *) ch_realloc( (char *) SaslRegexp,
200           (nSaslRegexp + 1) * sizeof(SaslRegexp_t) );
201
202         reg->sr_match = ch_strdup( match );
203         reg->sr_replace = ch_strdup( replace );
204
205         /* Precompile matching pattern */
206         rc = regcomp( &reg->sr_workspace, reg->sr_match, REG_EXTENDED|REG_ICASE );
207         if ( rc ) {
208 #ifdef NEW_LOGGING
209                 LDAP_LOG( TRANSPORT, ERR, 
210                         "slap_sasl_regexp_config: \"%s\" could not be compiled.\n",
211                         reg->sr_match, 0, 0 );
212 #else
213                 Debug( LDAP_DEBUG_ANY,
214                 "SASL match pattern %s could not be compiled by regexp engine\n",
215                 reg->sr_match, 0, 0 );
216 #endif
217
218                 return( LDAP_OTHER );
219         }
220
221         rc = slap_sasl_rx_off( reg->sr_replace, reg->sr_offset );
222         if ( rc != LDAP_SUCCESS ) return rc;
223
224         nSaslRegexp++;
225         return( LDAP_SUCCESS );
226 }
227
228
229 /* Perform replacement on regexp matches */
230 static void slap_sasl_rx_exp(
231         const char *rep,
232         const int *off,
233         regmatch_t *str,
234         const char *saslname,
235         struct berval *out )
236 {
237         int i, n, len, insert;
238
239         /* Get the total length of the final URI */
240
241         n=1;
242         len = 0;
243         while( off[n] >= 0 ) {
244                 /* Len of next section from replacement string (x,y,z above) */
245                 len += off[n] - off[n-1] - 2;
246                 if( off[n+1] < 0)
247                         break;
248
249                 /* Len of string from saslname that matched next $i  (b,d above) */
250                 i = rep[ off[n] + 1 ]   - '0';
251                 len += str[i].rm_eo - str[i].rm_so;
252                 n++;
253         }
254         out->bv_val = ch_malloc( len + 1 );
255         out->bv_len = len;
256
257         /* Fill in URI with replace string, replacing $i as we go */
258         n=1;
259         insert = 0;
260         while( off[n] >= 0) {
261                 /* Paste in next section from replacement string (x,y,z above) */
262                 len = off[n] - off[n-1] - 2;
263                 strncpy( out->bv_val+insert, rep + off[n-1] + 2, len);
264                 insert += len;
265                 if( off[n+1] < 0)
266                         break;
267
268                 /* Paste in string from saslname that matched next $i  (b,d above) */
269                 i = rep[ off[n] + 1 ]   - '0';
270                 len = str[i].rm_eo - str[i].rm_so;
271                 strncpy( out->bv_val+insert, saslname + str[i].rm_so, len );
272                 insert += len;
273
274                 n++;
275         }
276
277         out->bv_val[insert] = '\0';
278 }
279
280 /* Take the passed in SASL name and attempt to convert it into an
281    LDAP URI to find the matching LDAP entry, using the pattern matching
282    strings given in the saslregexp config file directive(s) */
283
284 static int slap_sasl_regexp( struct berval *in, struct berval *out )
285 {
286         char *saslname = in->bv_val;
287         char *scope[] = { "base", "one", "sub" };
288         SaslRegexp_t *reg;
289         int i;
290
291         memset( out, 0, sizeof( *out ) );
292
293 #ifdef NEW_LOGGING
294         LDAP_LOG( TRANSPORT, ENTRY, 
295                 "slap_sasl_regexp: converting SASL name %s\n", saslname, 0, 0 );
296 #else
297         Debug( LDAP_DEBUG_TRACE, "slap_sasl_regexp: converting SASL name %s\n",
298            saslname, 0, 0 );
299 #endif
300
301         if (( saslname == NULL ) || ( nSaslRegexp == 0 ))
302                 return( 0 );
303
304         /* Match the normalized SASL name to the saslregexp patterns */
305         for( reg = SaslRegexp,i=0;  i<nSaslRegexp;  i++,reg++ ) {
306                 if ( regexec( &reg->sr_workspace, saslname, SASLREGEX_REPLACE,
307                   reg->sr_strings, 0)  == 0 )
308                         break;
309         }
310
311         if( i >= nSaslRegexp )
312                 return( 0 );
313
314         /*
315          * The match pattern may have been of the form "a(b.*)c(d.*)e" and the
316          * replace pattern of the form "x$1y$2z". The returned string needs
317          * to replace the $1,$2 with the strings that matched (b.*) and (d.*)
318          */
319         slap_sasl_rx_exp( reg->sr_replace, reg->sr_offset,
320                 reg->sr_strings, saslname, out );
321
322 #ifdef NEW_LOGGING
323         LDAP_LOG( TRANSPORT, ENTRY, 
324                 "slap_sasl_regexp: converted SASL name to %s\n",
325                 out->bv_len ? out->bv_val : "", 0, 0 );
326 #else
327         Debug( LDAP_DEBUG_TRACE,
328            "slap_sasl_regexp: converted SASL name to ldap:///%s??%s?%s\n",
329                 out->bv_len ? out->bv_val : "", 0, 0 );
330 #endif
331
332         return( 1 );
333 }
334
335 /* Two empty callback functions to avoid sending results */
336 static void sasl_sc_r( Connection *conn, Operation *o, ber_tag_t tag,
337         ber_int_t msgid, ber_int_t err, const char *matched,
338         const char *text, BerVarray ref, const char *resoid,
339         struct berval *resdata, struct berval *sasldata, LDAPControl **c)
340 {
341 }
342
343 static void sasl_sc_s( Connection *conn, Operation *o, ber_int_t err,
344         const char *matched, const char *text, BerVarray refs, LDAPControl **c,
345         int nentries)
346 {
347 }
348
349 /* This callback actually does some work...*/
350 static int sasl_sc_sasl2dn( BackendDB *be, Connection *conn, Operation *o,
351         Entry *e, AttributeName *an, int ao, LDAPControl **c)
352 {
353         struct berval *ndn = o->o_callback->sc_private;
354
355         /* We only want to be called once */
356         if( ndn->bv_val ) {
357                 free(ndn->bv_val);
358                 ndn->bv_val = NULL;
359
360 #ifdef NEW_LOGGING
361         LDAP_LOG( TRANSPORT, DETAIL1,
362                     "slap_sasl2dn: search DN returned more than 1 entry\n", 0, 0, 0 );
363 #else
364                 Debug( LDAP_DEBUG_TRACE,
365                         "slap_sasl2dn: search DN returned more than 1 entry\n", 0,0,0 );
366 #endif
367                 return -1;
368         }
369
370         ber_dupbv(ndn, &e->e_nname);
371         return 0;
372 }
373
374 /*
375  * Given a SASL name (e.g. "UID=name,cn=REALM,cn=MECH,cn=AUTH")
376  * return the LDAP DN to which it matches. The SASL regexp rules in the config
377  * file turn the SASL name into an LDAP URI. If the URI is just a DN (or a
378  * search with scope=base), just return the URI (or its searchbase). Otherwise
379  * an internal search must be done, and if that search returns exactly one
380  * entry, return the DN of that one entry.
381  */
382
383 void slap_sasl2dn( Connection *conn,
384         struct berval *saslname, struct berval *sasldn )
385 {
386         int rc;
387         Backend *be;
388         struct berval dn = { 0, NULL };
389         int scope = LDAP_SCOPE_BASE;
390         Filter *filter = NULL;
391         slap_callback cb = {sasl_sc_r, sasl_sc_s, sasl_sc_sasl2dn, NULL};
392         Operation op = {0};
393         struct berval regout = { 0, NULL };
394
395 #ifdef NEW_LOGGING
396         LDAP_LOG( TRANSPORT, ENTRY, 
397                 "slap_sasl2dn: converting SASL name %s to DN.\n",
398                 saslname->bv_val, 0, 0 );
399 #else
400         Debug( LDAP_DEBUG_TRACE, "==>slap_sasl2dn: "
401                 "converting SASL name %s to a DN\n",
402                 saslname->bv_val, 0,0 );
403 #endif
404
405         sasldn->bv_val = NULL;
406         sasldn->bv_len = 0;
407         cb.sc_private = sasldn;
408
409         /* Convert the SASL name into a minimal URI */
410         if( !slap_sasl_regexp( saslname, &regout ) ) {
411                 goto FINISHED;
412         }
413
414         rc = slap_parseURI( &regout, &dn, &scope, &filter );
415         if( rc != LDAP_SUCCESS ) {
416                 goto FINISHED;
417         }
418
419         /* Must do an internal search */
420         be = select_backend( &dn, 0, 1 );
421
422         /* Massive shortcut: search scope == base */
423         if( scope == LDAP_SCOPE_BASE ) {
424                 *sasldn = dn;
425                 dn.bv_len = 0;
426                 dn.bv_val = NULL;
427                 goto FINISHED;
428         }
429
430 #ifdef NEW_LOGGING
431         LDAP_LOG( TRANSPORT, DETAIL1, 
432                 "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
433                 dn.bv_val, scope, 0 );
434 #else
435         Debug( LDAP_DEBUG_TRACE,
436                 "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
437                 dn.bv_val, scope, 0 );
438 #endif
439
440         if(( be == NULL ) || ( be->be_search == NULL)) {
441                 goto FINISHED;
442         }
443         suffix_alias( be, &dn );
444
445         op.o_tag = LDAP_REQ_SEARCH;
446         op.o_protocol = LDAP_VERSION3;
447         op.o_ndn = *saslname;
448         op.o_callback = &cb;
449         op.o_time = slap_get_time();
450         op.o_do_not_cache = 1;
451
452         (*be->be_search)( be, conn, &op, NULL, &dn,
453                 scope, LDAP_DEREF_NEVER, 1, 0,
454                 filter, NULL, NULL, 1 );
455         
456 FINISHED:
457         if( sasldn->bv_len ) {
458                 conn->c_authz_backend = be;
459         }
460         if( dn.bv_len ) ch_free( dn.bv_val );
461         if( filter ) filter_free( filter );
462
463 #ifdef NEW_LOGGING
464         LDAP_LOG( TRANSPORT, ENTRY, 
465                 "slap_sasl2dn: Converted SASL name to %s\n",
466                 sasldn->bv_len ? sasldn->bv_val : "<nothing>", 0, 0 );
467 #else
468         Debug( LDAP_DEBUG_TRACE, "<==slap_sasl2dn: Converted SASL name to %s\n",
469                 sasldn->bv_len ? sasldn->bv_val : "<nothing>", 0, 0 );
470 #endif
471
472         return;
473 }
474
475 typedef struct smatch_info {
476         struct berval *dn;
477         int match;
478 } smatch_info;
479
480 static int sasl_sc_smatch( BackendDB *be, Connection *conn, Operation *o,
481         Entry *e, AttributeName *an, int ao, LDAPControl **c)
482 {
483         smatch_info *sm = o->o_callback->sc_private;
484
485         if (dn_match(sm->dn, &e->e_nname)) {
486                 sm->match = 1;
487                 return -1;      /* short-circuit the search */
488         } else {
489                 return 1;
490         }
491 }
492
493 /*
494  * Map a SASL regexp rule to a DN. If the rule is just a DN or a scope=base
495  * URI, just strcmp the rule (or its searchbase) to the *assertDN. Otherwise,
496  * the rule must be used as an internal search for entries. If that search
497  * returns the *assertDN entry, the match is successful.
498  *
499  * The assertDN should not have the dn: prefix
500  */
501
502 static
503 int slap_sasl_match(Connection *conn, struct berval *rule, struct berval *assertDN, struct berval *authc )
504 {
505         struct berval searchbase = {0, NULL};
506         int rc, scope;
507         Backend *be;
508         Filter *filter=NULL;
509         regex_t reg;
510         smatch_info sm;
511         slap_callback cb = { sasl_sc_r, sasl_sc_s, sasl_sc_smatch, NULL };
512         Operation op = {0};
513
514 #ifdef NEW_LOGGING
515         LDAP_LOG( TRANSPORT, ENTRY, 
516                 "slap_sasl_match: comparing DN %s to rule %s\n", 
517                 assertDN->bv_val, rule->bv_val,0 );
518 #else
519         Debug( LDAP_DEBUG_TRACE,
520            "===>slap_sasl_match: comparing DN %s to rule %s\n", assertDN->bv_val, rule->bv_val, 0 );
521 #endif
522
523         rc = slap_parseURI( rule, &searchbase, &scope, &filter );
524         if( rc != LDAP_SUCCESS )
525                 goto CONCLUDED;
526
527         /* Massive shortcut: search scope == base */
528         if( scope == LDAP_SCOPE_BASE ) {
529                 rc = regcomp(&reg, searchbase.bv_val,
530                         REG_EXTENDED|REG_ICASE|REG_NOSUB);
531                 if ( rc == 0 ) {
532                         rc = regexec(&reg, assertDN->bv_val, 0, NULL, 0);
533                         regfree( &reg );
534                 }
535                 if ( rc == 0 )
536                         rc = LDAP_SUCCESS;
537                 else
538                         rc = LDAP_INAPPROPRIATE_AUTH;
539                 goto CONCLUDED;
540         }
541
542         /* Must run an internal search. */
543
544 #ifdef NEW_LOGGING
545         LDAP_LOG( TRANSPORT, DETAIL1, 
546                 "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
547                 searchbase.bv_val, scope,0 );
548 #else
549         Debug( LDAP_DEBUG_TRACE,
550            "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
551            searchbase.bv_val, scope, 0 );
552 #endif
553
554         be = select_backend( &searchbase, 0, 1 );
555         if(( be == NULL ) || ( be->be_search == NULL)) {
556                 rc = LDAP_INAPPROPRIATE_AUTH;
557                 goto CONCLUDED;
558         }
559         suffix_alias( be, &searchbase );
560
561         sm.dn = assertDN;
562         sm.match = 0;
563         cb.sc_private = &sm;
564
565         op.o_tag = LDAP_REQ_SEARCH;
566         op.o_protocol = LDAP_VERSION3;
567         op.o_ndn = *authc;
568         op.o_callback = &cb;
569         op.o_time = slap_get_time();
570         op.o_do_not_cache = 1;
571
572         (*be->be_search)( be, conn, &op, /*base=*/NULL, &searchbase,
573            scope, /*deref=*/1, /*sizelimit=*/0, /*time=*/0, filter, /*fstr=*/NULL,
574            /*attrs=*/NULL, /*attrsonly=*/0 );
575
576         if (sm.match)
577                 rc = LDAP_SUCCESS;
578         else
579                 rc = LDAP_INAPPROPRIATE_AUTH;
580
581 CONCLUDED:
582         if( searchbase.bv_len ) ch_free( searchbase.bv_val );
583         if( filter ) filter_free( filter );
584 #ifdef NEW_LOGGING
585         LDAP_LOG( TRANSPORT, ENTRY, 
586                 "slap_sasl_match: comparison returned %d\n", rc, 0, 0 );
587 #else
588         Debug( LDAP_DEBUG_TRACE,
589            "<===slap_sasl_match: comparison returned %d\n", rc, 0, 0);
590 #endif
591
592         return( rc );
593 }
594
595
596 /*
597  * This function answers the question, "Can this ID authorize to that ID?",
598  * based on authorization rules. The rules are stored in the *searchDN, in the
599  * attribute named by *attr. If any of those rules map to the *assertDN, the
600  * authorization is approved.
601  *
602  * The DNs should not have the dn: prefix
603  */
604 static int
605 slap_sasl_check_authz( Connection *conn,
606         struct berval *searchDN,
607         struct berval *assertDN,
608         AttributeDescription *ad,
609         struct berval *authc )
610 {
611         int i, rc;
612         BerVarray vals=NULL;
613
614 #ifdef NEW_LOGGING
615         LDAP_LOG( TRANSPORT, ENTRY, 
616                    "slap_sasl_check_authz: does %s match %s rule in %s?\n",
617                assertDN->bv_val, ad->ad_cname.bv_val, searchDN->bv_val);
618 #else
619         Debug( LDAP_DEBUG_TRACE,
620            "==>slap_sasl_check_authz: does %s match %s rule in %s?\n",
621            assertDN->bv_val, ad->ad_cname.bv_val, searchDN->bv_val);
622 #endif
623
624         rc = backend_attribute( NULL, NULL, NULL, NULL, searchDN, ad, &vals );
625         if( rc != LDAP_SUCCESS )
626                 goto COMPLETE;
627
628         /* Check if the *assertDN matches any **vals */
629         for( i=0; vals[i].bv_val != NULL; i++ ) {
630                 rc = slap_sasl_match( conn, &vals[i], assertDN, authc );
631                 if ( rc == LDAP_SUCCESS )
632                         goto COMPLETE;
633         }
634         rc = LDAP_INAPPROPRIATE_AUTH;
635
636 COMPLETE:
637         if( vals ) ber_bvarray_free( vals );
638
639 #ifdef NEW_LOGGING
640         LDAP_LOG( TRANSPORT, RESULTS, 
641                    "slap_sasl_check_authz: %s check returning %s\n", 
642                    ad->ad_cname.bv_val, rc, 0 );
643 #else
644         Debug( LDAP_DEBUG_TRACE,
645            "<==slap_sasl_check_authz: %s check returning %d\n", ad->ad_cname.bv_val, rc, 0);
646 #endif
647
648         return( rc );
649 }
650 #endif  /* HAVE_CYRUS_SASL */
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 #ifdef HAVE_CYRUS_SASL
663         /* User binding as anonymous */
664         if ( authzDN == NULL ) {
665                 rc = LDAP_SUCCESS;
666                 goto DONE;
667         }
668
669 #ifdef NEW_LOGGING
670         LDAP_LOG( TRANSPORT, ENTRY, 
671                 "slap_sasl_authorized: can %s become %s?\n", 
672                 authcDN->bv_val, authzDN->bv_val, 0 );
673 #else
674         Debug( LDAP_DEBUG_TRACE,
675            "==>slap_sasl_authorized: can %s become %s?\n", 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         /* Check source rules */
685         if( authz_policy & SASL_AUTHZ_TO ) {
686                 rc = slap_sasl_check_authz( conn, authcDN, authzDN,
687                         slap_schema.si_ad_saslAuthzTo, authcDN );
688                 if( rc == LDAP_SUCCESS ) {
689                         goto DONE;
690                 }
691         }
692
693         /* Check destination rules */
694         if( authz_policy & SASL_AUTHZ_FROM ) {
695                 rc = slap_sasl_check_authz( conn, authzDN, authcDN,
696                         slap_schema.si_ad_saslAuthzFrom, authcDN );
697                 if( rc == LDAP_SUCCESS ) {
698                         goto DONE;
699                 }
700         }
701
702         rc = LDAP_INAPPROPRIATE_AUTH;
703
704 DONE:
705 #endif
706
707 #ifdef NEW_LOGGING
708         LDAP_LOG( TRANSPORT, RESULTS, "slap_sasl_authorized: return %d\n", rc,0,0 );
709 #else
710         Debug( LDAP_DEBUG_TRACE,
711                 "<== slap_sasl_authorized: return %d\n", rc, 0, 0 );
712 #endif
713
714         return( rc );
715 }