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