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