]> git.sur5r.net Git - openldap/blob - servers/slapd/saslauthz.c
ba3b1375738b91608642e0c2bf61e2feea143934
[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
493         (*be->be_search)( be, NULL, &op, NULL, &uri.dn,
494                 uri.scope, LDAP_DEREF_NEVER, 1, 0,
495                 filter, NULL, NULL, 1 );
496         
497 FINISHED:
498         if( dn->bv_len ) {
499                 conn->c_authz_backend = be;
500         }
501         if( uri.dn.bv_len ) ch_free( uri.dn.bv_val );
502         if( uri.filter.bv_len ) ch_free( uri.filter.bv_val );
503         if( filter ) filter_free( filter );
504
505 #ifdef NEW_LOGGING
506         LDAP_LOG( TRANSPORT, ENTRY, 
507                 "slap_sasl2dn: Converted SASL name to %s\n",
508                 dn->bv_len ? dn->bv_val : "<nothing>", 0, 0 );
509 #else
510         Debug( LDAP_DEBUG_TRACE, "<==slap_sasl2dn: Converted SASL name to %s\n",
511                 dn->bv_len ? dn->bv_val : "<nothing>", 0, 0 );
512 #endif
513
514         return;
515 }
516
517 typedef struct smatch_info {
518         struct berval *dn;
519         int match;
520 } smatch_info;
521
522 static int sasl_sc_smatch( BackendDB *be, Connection *conn, Operation *o,
523         Entry *e, AttributeName *an, int ao, LDAPControl **c)
524 {
525         smatch_info *sm = o->o_callback->sc_private;
526
527         if (dn_match(sm->dn, &e->e_nname)) {
528                 sm->match = 1;
529                 return -1;      /* short-circuit the search */
530         } else {
531                 return 1;
532         }
533 }
534
535 /*
536  * Map a SASL regexp rule to a DN. If the rule is just a DN or a scope=base
537  * URI, just strcmp the rule (or its searchbase) to the *assertDN. Otherwise,
538  * the rule must be used as an internal search for entries. If that search
539  * returns the *assertDN entry, the match is successful.
540  *
541  * The assertDN should not have the dn: prefix
542  */
543
544 static
545 int slap_sasl_match( struct berval *rule, struct berval *assertDN, struct berval *authc )
546 {
547         struct berval searchbase = {0, NULL};
548         int rc, scope;
549         Backend *be;
550         Filter *filter=NULL;
551         regex_t reg;
552         smatch_info sm;
553         slap_callback cb = { sasl_sc_r, sasl_sc_s, sasl_sc_smatch, NULL };
554         Operation op = {0};
555
556 #ifdef NEW_LOGGING
557         LDAP_LOG( TRANSPORT, ENTRY, 
558                 "slap_sasl_match: comparing DN %s to rule %s\n", 
559                 assertDN->bv_val, rule->bv_val,0 );
560 #else
561         Debug( LDAP_DEBUG_TRACE,
562            "===>slap_sasl_match: comparing DN %s to rule %s\n", assertDN->bv_val, rule->bv_val, 0 );
563 #endif
564
565         rc = slap_parseURI( rule, &searchbase, &scope, &filter, NULL );
566         if( rc != LDAP_SUCCESS )
567                 goto CONCLUDED;
568
569         /* Massive shortcut: search scope == base */
570         if( scope == LDAP_SCOPE_BASE ) {
571                 rc = regcomp(&reg, searchbase.bv_val,
572                         REG_EXTENDED|REG_ICASE|REG_NOSUB);
573                 if ( rc == 0 ) {
574                         rc = regexec(&reg, assertDN->bv_val, 0, NULL, 0);
575                         regfree( &reg );
576                 }
577                 if ( rc == 0 )
578                         rc = LDAP_SUCCESS;
579                 else
580                         rc = LDAP_INAPPROPRIATE_AUTH;
581                 goto CONCLUDED;
582         }
583
584         /* Must run an internal search. */
585
586 #ifdef NEW_LOGGING
587         LDAP_LOG( TRANSPORT, DETAIL1, 
588                 "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
589                 searchbase.bv_val, scope,0 );
590 #else
591         Debug( LDAP_DEBUG_TRACE,
592            "slap_sasl_match: performing internal search (base=%s, scope=%d)\n",
593            searchbase.bv_val, scope, 0 );
594 #endif
595
596         be = select_backend( &searchbase, 0, 1 );
597         if(( be == NULL ) || ( be->be_search == NULL)) {
598                 rc = LDAP_INAPPROPRIATE_AUTH;
599                 goto CONCLUDED;
600         }
601         suffix_alias( be, &searchbase );
602
603         sm.dn = assertDN;
604         sm.match = 0;
605         cb.sc_private = &sm;
606
607         op.o_tag = LDAP_REQ_SEARCH;
608         op.o_protocol = LDAP_VERSION3;
609         op.o_ndn = *authc;
610         op.o_callback = &cb;
611         op.o_time = slap_get_time();
612
613         (*be->be_search)( be, /*conn=*/NULL, &op, /*base=*/NULL, &searchbase,
614            scope, /*deref=*/1, /*sizelimit=*/0, /*time=*/0, filter, /*fstr=*/NULL,
615            /*attrs=*/NULL, /*attrsonly=*/0 );
616
617         if (sm.match)
618                 rc = LDAP_SUCCESS;
619         else
620                 rc = LDAP_INAPPROPRIATE_AUTH;
621
622 CONCLUDED:
623         if( searchbase.bv_len ) ch_free( searchbase.bv_val );
624         if( filter ) filter_free( filter );
625 #ifdef NEW_LOGGING
626         LDAP_LOG( TRANSPORT, ENTRY, 
627                 "slap_sasl_match: comparison returned %d\n", rc, 0, 0 );
628 #else
629         Debug( LDAP_DEBUG_TRACE,
630            "<===slap_sasl_match: comparison returned %d\n", rc, 0, 0);
631 #endif
632
633         return( rc );
634 }
635
636
637 /*
638  * This function answers the question, "Can this ID authorize to that ID?",
639  * based on authorization rules. The rules are stored in the *searchDN, in the
640  * attribute named by *attr. If any of those rules map to the *assertDN, the
641  * authorization is approved.
642  *
643  * The DNs should not have the dn: prefix
644  */
645 static int
646 slap_sasl_check_authz(struct berval *searchDN, struct berval *assertDN, AttributeDescription *ad, struct berval *authc)
647 {
648         int i, rc;
649         BerVarray vals=NULL;
650
651 #ifdef NEW_LOGGING
652         LDAP_LOG( TRANSPORT, ENTRY, 
653                    "slap_sasl_check_authz: does %s match %s rule in %s?\n",
654                assertDN->bv_val, ad->ad_cname.bv_val, searchDN->bv_val);
655 #else
656         Debug( LDAP_DEBUG_TRACE,
657            "==>slap_sasl_check_authz: does %s match %s rule in %s?\n",
658            assertDN->bv_val, ad->ad_cname.bv_val, searchDN->bv_val);
659 #endif
660
661         rc = backend_attribute( NULL, NULL, NULL, NULL, searchDN, ad, &vals );
662         if( rc != LDAP_SUCCESS )
663                 goto COMPLETE;
664
665         /* Check if the *assertDN matches any **vals */
666         for( i=0; vals[i].bv_val != NULL; i++ ) {
667                 rc = slap_sasl_match( &vals[i], assertDN, authc );
668                 if ( rc == LDAP_SUCCESS )
669                         goto COMPLETE;
670         }
671         rc = LDAP_INAPPROPRIATE_AUTH;
672
673 COMPLETE:
674         if( vals ) ber_bvarray_free( vals );
675
676 #ifdef NEW_LOGGING
677         LDAP_LOG( TRANSPORT, RESULTS, 
678                    "slap_sasl_check_authz: %s check returning %s\n", 
679                    ad->ad_cname.bv_val, rc, 0 );
680 #else
681         Debug( LDAP_DEBUG_TRACE,
682            "<==slap_sasl_check_authz: %s check returning %d\n", ad->ad_cname.bv_val, rc, 0);
683 #endif
684
685         return( rc );
686 }
687 #endif  /* HAVE_CYRUS_SASL */
688
689
690 /* Check if a bind can SASL authorize to another identity.
691  * The DNs should not have the dn: prefix
692  */
693
694 int slap_sasl_authorized( struct berval *authcDN, struct berval *authzDN )
695 {
696         int rc = LDAP_INAPPROPRIATE_AUTH;
697
698 #ifdef HAVE_CYRUS_SASL
699         /* User binding as anonymous */
700         if ( authzDN == NULL ) {
701                 rc = LDAP_SUCCESS;
702                 goto DONE;
703         }
704
705 #ifdef NEW_LOGGING
706         LDAP_LOG( TRANSPORT, ENTRY, 
707                 "slap_sasl_authorized: can %s become %s?\n", 
708                 authcDN->bv_val, authzDN->bv_val, 0 );
709 #else
710         Debug( LDAP_DEBUG_TRACE,
711            "==>slap_sasl_authorized: can %s become %s?\n", authcDN->bv_val, authzDN->bv_val, 0 );
712 #endif
713
714         /* If person is authorizing to self, succeed */
715         if ( dn_match( authcDN, authzDN ) ) {
716                 rc = LDAP_SUCCESS;
717                 goto DONE;
718         }
719
720         /* Check source rules */
721         if( authz_policy & SASL_AUTHZ_TO ) {
722                 rc = slap_sasl_check_authz( authcDN, authzDN,
723                         slap_schema.si_ad_saslAuthzTo, authcDN );
724                 if( rc == LDAP_SUCCESS ) {
725                         goto DONE;
726                 }
727         }
728
729         /* Check destination rules */
730         if( authz_policy & SASL_AUTHZ_FROM ) {
731                 rc = slap_sasl_check_authz( authzDN, authcDN,
732                         slap_schema.si_ad_saslAuthzFrom, authcDN );
733                 if( rc == LDAP_SUCCESS ) {
734                         goto DONE;
735                 }
736         }
737
738         rc = LDAP_INAPPROPRIATE_AUTH;
739
740 DONE:
741 #endif
742
743 #ifdef NEW_LOGGING
744         LDAP_LOG( TRANSPORT, RESULTS, "slap_sasl_authorized: return %d\n", rc,0,0 );
745 #else
746         Debug( LDAP_DEBUG_TRACE,
747                 "<== slap_sasl_authorized: return %d\n", rc, 0, 0 );
748 #endif
749
750         return( rc );
751 }