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