]> git.sur5r.net Git - openldap/blob - servers/slapd/saslauthz.c
Import ITS#2007 and ITS#2009 bug fixes from HEAD
[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_regexp_config: \"%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_OPERATIONS_ERROR );
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, nbv;
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         rc = dnNormalize2( NULL, &bv, &nbv );
214         if ( rc ) {
215 #ifdef NEW_LOGGING
216                 LDAP_LOG( TRANSPORT, ERR, 
217                         "slap_sasl_regexp_config: \"%s\" could not be normalized.\n",
218                         match, 0, 0 );
219 #else
220                 Debug( LDAP_DEBUG_ANY,
221                 "SASL match pattern %s could not be normalized.\n",
222                 match, 0, 0 );
223 #endif
224                 return( rc );
225         }
226         reg->sr_match = nbv.bv_val;
227
228         ber_str2bv( replace, 0, 0, &bv );
229         rc = slap_parseURI( &bv, &reg->sr_replace.dn, &reg->sr_replace.scope,
230                 &filter, &reg->sr_replace.filter );
231         if ( filter ) filter_free( filter );
232         if ( rc ) {
233 #ifdef NEW_LOGGING
234                 LDAP_LOG( TRANSPORT, ERR, 
235                         "slap_sasl_regexp_config: \"%s\" could not be parsed.\n",
236                         replace, 0, 0 );
237 #else
238                 Debug( LDAP_DEBUG_ANY,
239                 "SASL replace pattern %s could not be parsed.\n",
240                 replace, 0, 0 );
241 #endif
242                 return( rc );
243         }
244
245         /* Precompile matching pattern */
246         rc = regcomp( &reg->sr_workspace, reg->sr_match, REG_EXTENDED|REG_ICASE );
247         if ( rc ) {
248 #ifdef NEW_LOGGING
249                 LDAP_LOG( TRANSPORT, ERR, 
250                         "slap_sasl_regexp_config: \"%s\" could not be compiled.\n",
251                         reg->sr_match, 0, 0 );
252 #else
253                 Debug( LDAP_DEBUG_ANY,
254                 "SASL match pattern %s could not be compiled by regexp engine\n",
255                 reg->sr_match, 0, 0 );
256 #endif
257
258                 return( LDAP_OPERATIONS_ERROR );
259         }
260
261         rc = slap_sasl_rx_off( reg->sr_replace.dn.bv_val, reg->sr_dn_offset );
262         if ( rc != LDAP_SUCCESS ) return rc;
263
264         if (reg->sr_replace.filter.bv_val ) {
265                 rc = slap_sasl_rx_off( reg->sr_replace.filter.bv_val, reg->sr_fi_offset );
266                 if ( rc != LDAP_SUCCESS ) return rc;
267         }
268
269         nSaslRegexp++;
270         return( LDAP_SUCCESS );
271 }
272
273
274 /* Perform replacement on regexp matches */
275 static void slap_sasl_rx_exp( char *rep, int *off, regmatch_t *str,
276         char *saslname, struct berval *out )
277 {
278         int i, n, len, insert;
279
280         /* Get the total length of the final URI */
281
282         n=1;
283         len = 0;
284         while( off[n] >= 0 ) {
285                 /* Len of next section from replacement string (x,y,z above) */
286                 len += off[n] - off[n-1] - 2;
287                 if( off[n+1] < 0)
288                         break;
289
290                 /* Len of string from saslname that matched next $i  (b,d above) */
291                 i = rep[ off[n] + 1 ]   - '0';
292                 len += str[i].rm_eo - str[i].rm_so;
293                 n++;
294         }
295         out->bv_val = ch_malloc( len + 1 );
296         out->bv_len = len;
297
298         /* Fill in URI with replace string, replacing $i as we go */
299         n=1;
300         insert = 0;
301         while( off[n] >= 0) {
302                 /* Paste in next section from replacement string (x,y,z above) */
303                 len = off[n] - off[n-1] - 2;
304                 strncpy( out->bv_val+insert, rep + off[n-1] + 2, len);
305                 insert += len;
306                 if( off[n+1] < 0)
307                         break;
308
309                 /* Paste in string from saslname that matched next $i  (b,d above) */
310                 i = rep[ off[n] + 1 ]   - '0';
311                 len = str[i].rm_eo - str[i].rm_so;
312                 strncpy( out->bv_val+insert, saslname + str[i].rm_so, len );
313                 insert += len;
314
315                 n++;
316         }
317
318         out->bv_val[insert] = '\0';
319 }
320
321 /* Take the passed in SASL name and attempt to convert it into an
322    LDAP URI to find the matching LDAP entry, using the pattern matching
323    strings given in the saslregexp config file directive(s) */
324
325 static int slap_sasl_regexp( struct berval *in, SaslUri_t *out )
326 {
327         char *saslname = in->bv_val;
328         char *scope[] = { "base", "one", "sub" };
329         SaslRegexp_t *reg;
330         int i;
331
332         memset( out, 0, sizeof( *out ) );
333
334 #ifdef NEW_LOGGING
335         LDAP_LOG( TRANSPORT, ENTRY, 
336                 "slap_sasl_regexp: converting SASL name %s\n", saslname, 0, 0 );
337 #else
338         Debug( LDAP_DEBUG_TRACE, "slap_sasl_regexp: converting SASL name %s\n",
339            saslname, 0, 0 );
340 #endif
341
342         if (( saslname == NULL ) || ( nSaslRegexp == 0 ))
343                 return( 0 );
344
345         /* Match the normalized SASL name to the saslregexp patterns */
346         for( reg = SaslRegexp,i=0;  i<nSaslRegexp;  i++,reg++ ) {
347                 if ( regexec( &reg->sr_workspace, saslname, SASLREGEX_REPLACE,
348                   reg->sr_strings, 0)  == 0 )
349                         break;
350         }
351
352         if( i >= nSaslRegexp )
353                 return( 0 );
354
355         /*
356          * The match pattern may have been of the form "a(b.*)c(d.*)e" and the
357          * replace pattern of the form "x$1y$2z". The returned string needs
358          * to replace the $1,$2 with the strings that matched (b.*) and (d.*)
359          */
360         slap_sasl_rx_exp( reg->sr_replace.dn.bv_val, reg->sr_dn_offset,
361                 reg->sr_strings, saslname, &out->dn );
362
363         if ( reg->sr_replace.filter.bv_val )
364                 slap_sasl_rx_exp( reg->sr_replace.filter.bv_val,
365                         reg->sr_fi_offset, reg->sr_strings, saslname, &out->filter );
366         
367         out->scope = reg->sr_replace.scope;
368
369 #ifdef NEW_LOGGING
370         LDAP_LOG( TRANSPORT, ENTRY, 
371                 "slap_sasl_regexp: converted SASL name to ldap:///%s??%s?%s\n",
372                 out->dn.bv_val, scope[out->scope], out->filter.bv_val ?
373                 out->filter.bv_val : ""  );
374 #else
375         Debug( LDAP_DEBUG_TRACE,
376            "slap_sasl_regexp: converted SASL name to ldap:///%s??%s?%s\n",
377                 out->dn.bv_val, scope[out->scope], out->filter.bv_val ?
378                 out->filter.bv_val : "" );
379 #endif
380
381         return( 1 );
382 }
383
384 /* Two empty callback functions to avoid sending results */
385 static void sasl_sc_r( Connection *conn, Operation *o, ber_tag_t tag,
386         ber_int_t msgid, ber_int_t err, const char *matched,
387         const char *text, BerVarray ref, const char *resoid,
388         struct berval *resdata, struct berval *sasldata, LDAPControl **c)
389 {
390 }
391
392 static void sasl_sc_s( Connection *conn, Operation *o, ber_int_t err,
393         const char *matched, const char *text, BerVarray refs, LDAPControl **c,
394         int nentries)
395 {
396 }
397
398 /* This callback actually does some work...*/
399 static int sasl_sc_sasl2dn( BackendDB *be, Connection *conn, Operation *o,
400         Entry *e, AttributeName *an, int ao, LDAPControl **c)
401 {
402         struct berval *ndn = o->o_callback->sc_private;
403
404         /* We only want to be called once */
405         if( ndn->bv_val ) {
406                 free(ndn->bv_val);
407                 ndn->bv_val = NULL;
408
409 #ifdef NEW_LOGGING
410         LDAP_LOG( TRANSPORT, DETAIL1,
411                     "slap_sasl2dn: search DN returned more than 1 entry\n", 0, 0, 0 );
412 #else
413                 Debug( LDAP_DEBUG_TRACE,
414                         "slap_sasl2dn: search DN returned more than 1 entry\n", 0,0,0 );
415 #endif
416                 return -1;
417         }
418
419         ber_dupbv(ndn, &e->e_nname);
420         return 0;
421 }
422
423 /*
424  * Given a SASL name (e.g. "UID=name,cn=REALM,cn=MECH,cn=AUTH")
425  * return the LDAP DN to which it matches. The SASL regexp rules in the config
426  * file turn the SASL name into an LDAP URI. If the URI is just a DN (or a
427  * search with scope=base), just return the URI (or its searchbase). Otherwise
428  * an internal search must be done, and if that search returns exactly one
429  * entry, return the DN of that one entry.
430  */
431
432 void slap_sasl2dn( Connection *conn, struct berval *saslname, struct berval *dn )
433 {
434         int rc;
435         Backend *be;
436         Filter *filter=NULL;
437         slap_callback cb = {sasl_sc_r, sasl_sc_s, sasl_sc_sasl2dn, NULL};
438         Operation op = {0};
439         SaslUri_t uri;
440
441 #ifdef NEW_LOGGING
442         LDAP_LOG( TRANSPORT, ENTRY, 
443                 "slap_sasl2dn: converting SASL name %s to DN.\n", saslname->bv_val, 0, 0 );
444 #else
445         Debug( LDAP_DEBUG_TRACE, "==>slap_sasl2dn: "
446                 "converting SASL name %s to a DN\n", saslname->bv_val, 0,0 );
447 #endif
448
449         dn->bv_val = NULL;
450         dn->bv_len = 0;
451         cb.sc_private = dn;
452
453         /* Convert the SASL name into a minimal URI */
454         if( !slap_sasl_regexp( saslname, &uri ) )
455                 goto FINISHED;
456
457         if ( uri.filter.bv_val )
458                 filter = str2filter( uri.filter.bv_val );
459
460         /* Must do an internal search */
461
462         be = select_backend( &uri.dn, 0, 1 );
463
464         /* Massive shortcut: search scope == base */
465         if( uri.scope == LDAP_SCOPE_BASE ) {
466                 *dn = uri.dn;
467                 uri.dn.bv_len = 0;
468                 uri.dn.bv_val = NULL;
469                 goto FINISHED;
470         }
471
472 #ifdef NEW_LOGGING
473         LDAP_LOG( TRANSPORT, DETAIL1, 
474                 "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
475                 uri.dn.bv_val, uri.scope, 0 );
476 #else
477         Debug( LDAP_DEBUG_TRACE,
478            "slap_sasl2dn: performing internal search (base=%s, scope=%d)\n",
479            uri.dn.bv_val, uri.scope, 0 );
480 #endif
481
482         if(( be == NULL ) || ( be->be_search == NULL)) {
483                 goto FINISHED;
484         }
485         suffix_alias( be, &uri.dn );
486
487         op.o_tag = LDAP_REQ_SEARCH;
488         op.o_protocol = LDAP_VERSION3;
489         op.o_ndn = *saslname;
490         op.o_callback = &cb;
491         op.o_time = slap_get_time();
492         op.o_do_not_cache = 1;
493
494         (*be->be_search)( be, conn, &op, NULL, &uri.dn,
495                 uri.scope, LDAP_DEREF_NEVER, 1, 0,
496                 filter, NULL, NULL, 1 );
497         
498 FINISHED:
499         if( dn->bv_len ) {
500                 conn->c_authz_backend = be;
501         }
502         if( uri.dn.bv_len ) ch_free( uri.dn.bv_val );
503         if( uri.filter.bv_len ) ch_free( uri.filter.bv_val );
504         if( filter ) filter_free( filter );
505
506 #ifdef NEW_LOGGING
507         LDAP_LOG( TRANSPORT, ENTRY, 
508                 "slap_sasl2dn: Converted SASL name to %s\n",
509                 dn->bv_len ? dn->bv_val : "<nothing>", 0, 0 );
510 #else
511         Debug( LDAP_DEBUG_TRACE, "<==slap_sasl2dn: Converted SASL name to %s\n",
512                 dn->bv_len ? dn->bv_val : "<nothing>", 0, 0 );
513 #endif
514
515         return;
516 }
517
518 typedef struct smatch_info {
519         struct berval *dn;
520         int match;
521 } smatch_info;
522
523 static int sasl_sc_smatch( BackendDB *be, Connection *conn, Operation *o,
524         Entry *e, AttributeName *an, int ao, LDAPControl **c)
525 {
526         smatch_info *sm = o->o_callback->sc_private;
527
528         if (dn_match(sm->dn, &e->e_nname)) {
529                 sm->match = 1;
530                 return -1;      /* short-circuit the search */
531         } else {
532                 return 1;
533         }
534 }
535
536 /*
537  * Map a SASL regexp rule to a DN. If the rule is just a DN or a scope=base
538  * URI, just strcmp the rule (or its searchbase) to the *assertDN. Otherwise,
539  * the rule must be used as an internal search for entries. If that search
540  * returns the *assertDN entry, the match is successful.
541  *
542  * The assertDN should not have the dn: prefix
543  */
544
545 static
546 int slap_sasl_match(Connection *conn, struct berval *rule, struct berval *assertDN, struct berval *authc )
547 {
548         struct berval searchbase = {0, NULL};
549         int rc, scope;
550         Backend *be;
551         Filter *filter=NULL;
552         regex_t reg;
553         smatch_info sm;
554         slap_callback cb = { sasl_sc_r, sasl_sc_s, sasl_sc_smatch, NULL };
555         Operation op = {0};
556
557 #ifdef NEW_LOGGING
558         LDAP_LOG( TRANSPORT, ENTRY, 
559                 "slap_sasl_match: comparing DN %s to rule %s\n", 
560                 assertDN->bv_val, rule->bv_val,0 );
561 #else
562         Debug( LDAP_DEBUG_TRACE,
563            "===>slap_sasl_match: comparing DN %s to rule %s\n", assertDN->bv_val, rule->bv_val, 0 );
564 #endif
565
566         rc = slap_parseURI( rule, &searchbase, &scope, &filter, NULL );
567         if( rc != LDAP_SUCCESS )
568                 goto CONCLUDED;
569
570         /* Massive shortcut: search scope == base */
571         if( scope == LDAP_SCOPE_BASE ) {
572                 rc = regcomp(&reg, searchbase.bv_val,
573                         REG_EXTENDED|REG_ICASE|REG_NOSUB);
574                 if ( rc == 0 ) {
575                         rc = regexec(&reg, assertDN->bv_val, 0, NULL, 0);
576                         regfree( &reg );
577                 }
578                 if ( rc == 0 )
579                         rc = LDAP_SUCCESS;
580                 else
581                         rc = LDAP_INAPPROPRIATE_AUTH;
582                 goto CONCLUDED;
583         }
584
585         /* Must run an internal search. */
586
587 #ifdef NEW_LOGGING
588         LDAP_LOG( TRANSPORT, DETAIL1, 
589                 "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
590                 searchbase.bv_val, scope,0 );
591 #else
592         Debug( LDAP_DEBUG_TRACE,
593            "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
594            searchbase.bv_val, scope, 0 );
595 #endif
596
597         be = select_backend( &searchbase, 0, 1 );
598         if(( be == NULL ) || ( be->be_search == NULL)) {
599                 rc = LDAP_INAPPROPRIATE_AUTH;
600                 goto CONCLUDED;
601         }
602         suffix_alias( be, &searchbase );
603
604         sm.dn = assertDN;
605         sm.match = 0;
606         cb.sc_private = &sm;
607
608         op.o_tag = LDAP_REQ_SEARCH;
609         op.o_protocol = LDAP_VERSION3;
610         op.o_ndn = *authc;
611         op.o_callback = &cb;
612         op.o_time = slap_get_time();
613         op.o_do_not_cache = 1;
614
615         (*be->be_search)( be, conn, &op, /*base=*/NULL, &searchbase,
616            scope, /*deref=*/1, /*sizelimit=*/0, /*time=*/0, filter, /*fstr=*/NULL,
617            /*attrs=*/NULL, /*attrsonly=*/0 );
618
619         if (sm.match)
620                 rc = LDAP_SUCCESS;
621         else
622                 rc = LDAP_INAPPROPRIATE_AUTH;
623
624 CONCLUDED:
625         if( searchbase.bv_len ) ch_free( searchbase.bv_val );
626         if( filter ) filter_free( filter );
627 #ifdef NEW_LOGGING
628         LDAP_LOG( TRANSPORT, ENTRY, 
629                 "slap_sasl_match: comparison returned %d\n", rc, 0, 0 );
630 #else
631         Debug( LDAP_DEBUG_TRACE,
632            "<===slap_sasl_match: comparison returned %d\n", rc, 0, 0);
633 #endif
634
635         return( rc );
636 }
637
638
639 /*
640  * This function answers the question, "Can this ID authorize to that ID?",
641  * based on authorization rules. The rules are stored in the *searchDN, in the
642  * attribute named by *attr. If any of those rules map to the *assertDN, the
643  * authorization is approved.
644  *
645  * The DNs should not have the dn: prefix
646  */
647 static int
648 slap_sasl_check_authz( Connection *conn,
649         struct berval *searchDN,
650         struct berval *assertDN,
651         AttributeDescription *ad,
652         struct berval *authc )
653 {
654         int i, rc;
655         BerVarray vals=NULL;
656
657 #ifdef NEW_LOGGING
658         LDAP_LOG( TRANSPORT, ENTRY, 
659                    "slap_sasl_check_authz: does %s match %s rule in %s?\n",
660                assertDN->bv_val, ad->ad_cname.bv_val, searchDN->bv_val);
661 #else
662         Debug( LDAP_DEBUG_TRACE,
663            "==>slap_sasl_check_authz: does %s match %s rule in %s?\n",
664            assertDN->bv_val, ad->ad_cname.bv_val, searchDN->bv_val);
665 #endif
666
667         rc = backend_attribute( NULL, NULL, NULL, NULL, searchDN, ad, &vals );
668         if( rc != LDAP_SUCCESS )
669                 goto COMPLETE;
670
671         /* Check if the *assertDN matches any **vals */
672         for( i=0; vals[i].bv_val != NULL; i++ ) {
673                 rc = slap_sasl_match( conn, &vals[i], assertDN, authc );
674                 if ( rc == LDAP_SUCCESS )
675                         goto COMPLETE;
676         }
677         rc = LDAP_INAPPROPRIATE_AUTH;
678
679 COMPLETE:
680         if( vals ) ber_bvarray_free( vals );
681
682 #ifdef NEW_LOGGING
683         LDAP_LOG( TRANSPORT, RESULTS, 
684                    "slap_sasl_check_authz: %s check returning %s\n", 
685                    ad->ad_cname.bv_val, rc, 0 );
686 #else
687         Debug( LDAP_DEBUG_TRACE,
688            "<==slap_sasl_check_authz: %s check returning %d\n", ad->ad_cname.bv_val, rc, 0);
689 #endif
690
691         return( rc );
692 }
693 #endif  /* HAVE_CYRUS_SASL */
694
695
696 /* Check if a bind can SASL authorize to another identity.
697  * The DNs should not have the dn: prefix
698  */
699
700 int slap_sasl_authorized( Connection *conn,
701         struct berval *authcDN, struct berval *authzDN )
702 {
703         int rc = LDAP_INAPPROPRIATE_AUTH;
704
705 #ifdef HAVE_CYRUS_SASL
706         /* User binding as anonymous */
707         if ( authzDN == NULL ) {
708                 rc = LDAP_SUCCESS;
709                 goto DONE;
710         }
711
712 #ifdef NEW_LOGGING
713         LDAP_LOG( TRANSPORT, ENTRY, 
714                 "slap_sasl_authorized: can %s become %s?\n", 
715                 authcDN->bv_val, authzDN->bv_val, 0 );
716 #else
717         Debug( LDAP_DEBUG_TRACE,
718            "==>slap_sasl_authorized: can %s become %s?\n", authcDN->bv_val, authzDN->bv_val, 0 );
719 #endif
720
721         /* If person is authorizing to self, succeed */
722         if ( dn_match( authcDN, authzDN ) ) {
723                 rc = LDAP_SUCCESS;
724                 goto DONE;
725         }
726
727         /* Check source rules */
728         if( authz_policy & SASL_AUTHZ_TO ) {
729                 rc = slap_sasl_check_authz( conn, authcDN, authzDN,
730                         slap_schema.si_ad_saslAuthzTo, authcDN );
731                 if( rc == LDAP_SUCCESS ) {
732                         goto DONE;
733                 }
734         }
735
736         /* Check destination rules */
737         if( authz_policy & SASL_AUTHZ_FROM ) {
738                 rc = slap_sasl_check_authz( conn, authzDN, authcDN,
739                         slap_schema.si_ad_saslAuthzFrom, authcDN );
740                 if( rc == LDAP_SUCCESS ) {
741                         goto DONE;
742                 }
743         }
744
745         rc = LDAP_INAPPROPRIATE_AUTH;
746
747 DONE:
748 #endif
749
750 #ifdef NEW_LOGGING
751         LDAP_LOG( TRANSPORT, RESULTS, "slap_sasl_authorized: return %d\n", rc,0,0 );
752 #else
753         Debug( LDAP_DEBUG_TRACE,
754                 "<== slap_sasl_authorized: return %d\n", rc, 0, 0 );
755 #endif
756
757         return( rc );
758 }