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