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