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