]> git.sur5r.net Git - openldap/blob - servers/slapd/sasl.c
251098fb981d7fb89e19a260d556119c6c1434dd
[openldap] / servers / slapd / sasl.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6
7 #include "portable.h"
8
9 #include <stdio.h>
10 #include <ac/stdlib.h>
11 #include <ac/string.h>
12
13 #include <lber.h>
14 #include <ldap_log.h>
15
16 #include "slap.h"
17
18 #ifdef HAVE_CYRUS_SASL
19 #include <limits.h>
20 #include <sasl.h>
21
22 #include <ldap_pvt.h>
23
24 #ifdef SLAPD_SPASSWD
25 #include <lutil.h>
26 #endif
27
28 /* Flags for telling slap_sasl_getdn() what type of identity is being passed */
29 #define FLAG_GETDN_FINAL   1
30 #define FLAG_GETDN_AUTHCID 2
31 #define FLAG_GETDN_AUTHZID 4
32
33 static sasl_security_properties_t sasl_secprops;
34
35 static int
36 slap_sasl_log(
37         void *context,
38         int priority,
39         const char *message) 
40 {
41         Connection *conn = context;
42         int level;
43         const char * label;
44
45         if ( message == NULL ) {
46                 return SASL_BADPARAM;
47         }
48
49         switch (priority) {
50         case SASL_LOG_ERR:
51                 level = LDAP_DEBUG_ANY;
52                 label = "Error";
53                 break;
54         case SASL_LOG_WARNING:
55                 level = LDAP_DEBUG_TRACE;
56                 label = "Warning";
57                 break;
58         case SASL_LOG_INFO:
59                 level = LDAP_DEBUG_TRACE;
60                 label = "Info";
61                 break;
62         default:
63                 return SASL_BADPARAM;
64         }
65
66 #ifdef NEW_LOGGING
67         LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
68                 "SASL [conn=%ld] %s: %s\n",
69                 conn ? conn->c_connid : -1,
70                 label, message ));
71 #else
72         Debug( level, "SASL [conn=%ld] %s: %s\n",
73                 conn ? conn->c_connid: -1,
74                 label, message );
75 #endif
76
77
78         return SASL_OK;
79 }
80
81
82 /* Take any sort of identity string and return a DN with the "dn:" prefix. The
83    string returned in *dn is in its own allocated memory, and must be free'd 
84    by the calling process.
85    -Mark Adamson, Carnegie Mellon
86 */
87
88 #define SET_DN  1
89 #define SET_U   2
90
91 static struct berval ext_bv = { sizeof("EXTERNAL")-1, "EXTERNAL" };
92
93 int slap_sasl_getdn( Connection *conn, char *id, struct berval *dn, int flags )
94 {
95         char *c=NULL, *c1;
96         int rc, len, is_dn = 0;
97         sasl_conn_t *ctx;
98         struct berval dn2;
99
100 #ifdef NEW_LOGGING
101         LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
102                 "slap_sasl_getdn: conn %d id=%s\n",
103                 conn ? conn->c_connid : -1,
104                 id ? (*id ? id : "<empty>") : "NULL" ));
105 #else
106         Debug( LDAP_DEBUG_ARGS, "slap_sasl_getdn: id=%s\n", 
107       id?(*id?id:"<empty>"):"NULL",0,0 );
108 #endif
109
110         dn->bv_val = NULL;
111         dn->bv_len = 0;
112
113         /* Blatantly anonymous ID */
114         if( id &&
115                 ( id[sizeof( "anonymous" )-1] == '\0'
116                         || id[sizeof( "anonymous" )-1] == '@' ) &&
117                 !strncasecmp( id, "anonymous", sizeof( "anonymous" )-1) ) {
118                 return( LDAP_SUCCESS );
119         }
120         ctx = conn->c_sasl_context;
121         len = strlen( id );
122
123         /* An authcID needs to be converted to authzID form */
124         if( flags & FLAG_GETDN_AUTHCID ) {
125                 if( sasl_external_x509dn_convert
126                         && conn->c_sasl_bind_mech.bv_len == ext_bv.bv_len
127                         && ( strcasecmp( ext_bv.bv_val, conn->c_sasl_bind_mech.bv_val ) == 0 ) 
128                         && id[0] == '/' )
129                 {
130                         /* check SASL external for X.509 style DN and */
131                         /* convert to dn:<dn> form */
132                         dn->bv_val = ldap_dcedn2dn( id );
133                         dn->bv_len = strlen(dn->bv_val);
134                         is_dn = SET_DN;
135
136                 } else {
137                         /* convert to u:<username> form */
138                         ber_str2bv( id, len, 1, dn );
139                         is_dn = SET_U;
140                 }
141         }
142         if( !is_dn ) {
143                 if( !strncasecmp( id, "u:", sizeof("u:")-1 )) {
144                         is_dn = SET_U;
145                         ber_str2bv( id+2, len-2, 1, dn );
146                 } else if ( !strncasecmp( id, "dn:", sizeof("dn:")-1) ) {
147                         is_dn = SET_DN;
148                         ber_str2bv( id+3, len-3, 1, dn );
149                 }
150         }
151
152         /* An authzID must be properly prefixed */
153         if( (flags & FLAG_GETDN_AUTHZID) && !is_dn ) {
154                 free( dn->bv_val );
155                 dn->bv_val = NULL;
156                 dn->bv_len = 0;
157                 return( LDAP_INAPPROPRIATE_AUTH );
158         }
159
160         /* Username strings */
161         if( is_dn == SET_U ) {
162                 char *p;
163                 len = dn->bv_len + sizeof("uid=")-1 + sizeof(",cn=auth")-1;
164
165                 /* Figure out how much data we have for the dn */
166                 rc = sasl_getprop( ctx, SASL_REALM, (void **)&c );
167                 if( rc != SASL_OK && rc != SASL_NOTDONE ) {
168 #ifdef NEW_LOGGING
169                         LDAP_LOG(( "sasl", LDAP_LEVEL_ERR,
170                                 "slap_sasl_getdn: getprop(REALM) failed.\n" ));
171 #else
172                         Debug(LDAP_DEBUG_TRACE,
173                                 "getdn: getprop(REALM) failed!\n", 0,0,0);
174 #endif
175
176                         ch_free( dn->bv_val );
177                         *dn = slap_empty_bv;
178                         return( LDAP_OPERATIONS_ERROR );
179                 }
180
181                 if( c && *c ) {
182                         len += strlen( c ) + sizeof(",cn=")-1;
183                 }
184
185                 if( conn->c_sasl_bind_mech.bv_len ) {
186                         len += conn->c_sasl_bind_mech.bv_len + sizeof(",cn=")-1;
187                 }
188
189                 /* Build the new dn */
190                 c1 = dn->bv_val;
191                 dn->bv_val = ch_malloc( len );
192                 p = slap_strcopy( dn->bv_val, "uid=" );
193                 p = slap_strcopy( p, c1 );
194                 ch_free( c1 );
195
196                 if( c ) {
197                         p = slap_strcopy( p, ",cn=" );
198                         p = slap_strcopy( p, c );
199                 }
200                 if( conn->c_sasl_bind_mech.bv_len ) {
201                         p = slap_strcopy( p, ",cn=" );
202                         p = slap_strcopy( p, conn->c_sasl_bind_mech.bv_val );
203                 }
204                 p = slap_strcopy( p, ",cn=auth" );
205                 dn->bv_len = p - dn->bv_val;
206                 is_dn = SET_DN;
207
208 #ifdef NEW_LOGGING
209                 LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
210                         "slap_sasl_getdn: u:id converted to %s.\n", dn->bv_val ));
211 #else
212                 Debug( LDAP_DEBUG_TRACE, "getdn: u:id converted to %s\n", dn->bv_val,0,0 );
213 #endif
214         }
215
216         /* DN strings that are a cn=auth identity to run through regexp */
217         if( is_dn == SET_DN && ( ( flags & FLAG_GETDN_FINAL ) == 0 ) )
218         {
219                 slap_sasl2dn( dn, &dn2 );
220                 if( dn2.bv_val ) {
221                         ch_free( dn->bv_val );
222                         *dn = dn2;
223 #ifdef NEW_LOGGING
224                         LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
225                                 "slap_sasl_getdn: dn:id converted to %s.\n", dn->bv_val ));
226 #else
227                         Debug( LDAP_DEBUG_TRACE, "getdn: dn:id converted to %s\n",
228                                 dn->bv_val, 0, 0 );
229 #endif
230                 }
231         }
232
233         if( flags & FLAG_GETDN_FINAL ) {
234                 /* omit "dn:" prefix */
235                 is_dn = 0;
236         } else {
237                 rc = dnNormalize2( NULL, dn, &dn2 );
238                 free(dn->bv_val);
239                 if ( rc != LDAP_SUCCESS ) {
240                         *dn = slap_empty_bv;
241                         return rc;
242                 }
243                 *dn = dn2;
244         }
245
246         /* Attach the "dn:" prefix if needed */
247         if ( is_dn == SET_DN ) {
248                 c1 = ch_malloc( dn->bv_len + sizeof("dn:") );
249                 strcpy( c1, "dn:" );
250                 strcpy( c1 + 3, dn->bv_val );
251                 free( dn->bv_val );
252                 dn->bv_val = c1;
253                 dn->bv_len += 3;
254         }
255
256         return( LDAP_SUCCESS );
257 }
258
259
260
261 static int
262 slap_sasl_authorize(
263         void *context,
264         const char *authcid,
265         const char *authzid,
266         const char **user,
267         const char **errstr)
268 {
269         struct berval authcDN, authzDN;
270         int rc;
271         Connection *conn = context;
272
273         *user = NULL;
274
275 #ifdef NEW_LOGGING
276         LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
277                    "slap_sas_authorize: conn %d  authcid=\"%s\" authzid=\"%s\"\n",
278                    conn ? conn->c_connid : -1,
279                    authcid ? authcid : "<empty>",
280                    authzid ? authzid : "<empty>" ));
281 #else
282         Debug( LDAP_DEBUG_ARGS, "SASL Authorize [conn=%ld]: "
283                 "authcid=\"%s\" authzid=\"%s\"\n",
284                 (long) (conn ? conn->c_connid : -1),
285                 authcid ? authcid : "<empty>",
286                 authzid ? authzid : "<empty>" );
287 #endif
288
289
290         /* Convert the identities to DN's. If no authzid was given, client will
291            be bound as the DN matching their username */
292         rc = slap_sasl_getdn( conn, (char *)authcid, &authcDN, FLAG_GETDN_AUTHCID );
293         if( rc != LDAP_SUCCESS ) {
294                 *errstr = ldap_err2string( rc );
295                 return SASL_NOAUTHZ;
296         }
297         if( ( authzid == NULL ) || !strcmp( authcid,authzid ) ) {
298 #ifdef NEW_LOGGING
299                 LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
300                            "slap_sasl_authorize: conn %d  Using authcDN=%s\n",
301                            conn ? conn->c_connid : -1, authcDN.bv_val ));
302 #else
303                 Debug( LDAP_DEBUG_TRACE, "SASL Authorize [conn=%ld]: "
304                  "Using authcDN=%s\n", (long) (conn ? conn->c_connid : -1), authcDN.bv_val,0 );
305 #endif
306
307                 *user = authcDN.bv_val;
308                 *errstr = NULL;
309                 return SASL_OK;
310         }
311         rc = slap_sasl_getdn( conn, (char *)authzid, &authzDN, FLAG_GETDN_AUTHZID );
312         if( rc != LDAP_SUCCESS ) {
313                 ch_free( authcDN.bv_val );
314                 *errstr = ldap_err2string( rc );
315                 return SASL_NOAUTHZ;
316         }
317
318         rc = slap_sasl_authorized( &authcDN, &authzDN );
319         if( rc ) {
320 #ifdef NEW_LOGGING
321                 LDAP_LOG(( "sasl", LDAP_LEVEL_INFO,
322                            "slap_sasl_authorize: conn %ld  authorization disallowed (%d)\n",
323                            (long)(conn ? conn->c_connid : -1), rc ));
324 #else
325                 Debug( LDAP_DEBUG_TRACE, "SASL Authorize [conn=%ld]: "
326                         " authorization disallowed (%d)\n",
327                         (long) (conn ? conn->c_connid : -1), rc, 0 );
328 #endif
329
330                 *errstr = "not authorized";
331                 ch_free( authcDN.bv_val );
332                 ch_free( authzDN.bv_val );
333                 return SASL_NOAUTHZ;
334         }
335
336 #ifdef NEW_LOGGING
337         LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
338                    "slap_sasl_authorize: conn %d authorization allowed\n",
339                    (long)(conn ? conn->c_connid : -1 ) ));
340 #else
341         Debug( LDAP_DEBUG_TRACE, "SASL Authorize [conn=%ld]: "
342                 " authorization allowed\n",
343                 (long) (conn ? conn->c_connid : -1), 0, 0 );
344 #endif
345
346
347         ch_free( authcDN.bv_val );
348         *user = authzDN.bv_val;
349         *errstr = NULL;
350         return SASL_OK;
351 }
352
353
354 static int
355 slap_sasl_err2ldap( int saslerr )
356 {
357         int rc;
358
359         switch (saslerr) {
360                 case SASL_CONTINUE:
361                         rc = LDAP_SASL_BIND_IN_PROGRESS;
362                         break;
363                 case SASL_FAIL:
364                         rc = LDAP_OTHER;
365                         break;
366                 case SASL_NOMEM:
367                         rc = LDAP_OTHER;
368                         break;
369                 case SASL_NOMECH:
370                         rc = LDAP_AUTH_METHOD_NOT_SUPPORTED;
371                         break;
372                 case SASL_BADAUTH:
373                         rc = LDAP_INVALID_CREDENTIALS;
374                         break;
375                 case SASL_NOAUTHZ:
376                         rc = LDAP_INSUFFICIENT_ACCESS;
377                         break;
378                 case SASL_TOOWEAK:
379                 case SASL_ENCRYPT:
380                         rc = LDAP_INAPPROPRIATE_AUTH;
381                         break;
382                 default:
383                         rc = LDAP_OTHER;
384                         break;
385         }
386
387         return rc;
388 }
389 #endif
390
391
392 int slap_sasl_init( void )
393 {
394 #ifdef HAVE_CYRUS_SASL
395         int rc;
396         static sasl_callback_t server_callbacks[] = {
397                 { SASL_CB_LOG, &slap_sasl_log, NULL },
398                 { SASL_CB_LIST_END, NULL, NULL }
399         };
400
401         sasl_set_alloc(
402                 ch_malloc,
403                 ch_calloc,
404                 ch_realloc,
405                 ch_free ); 
406
407         sasl_set_mutex(
408                 ldap_pvt_sasl_mutex_new,
409                 ldap_pvt_sasl_mutex_lock,
410                 ldap_pvt_sasl_mutex_unlock,
411                 ldap_pvt_sasl_mutex_dispose );
412
413         /* should provide callbacks for logging */
414         /* server name should be configurable */
415         rc = sasl_server_init( server_callbacks, "slapd" );
416
417         if( rc != SASL_OK ) {
418 #ifdef NEW_LOGGING
419                 LDAP_LOG(( "sasl", LDAP_LEVEL_INFO,
420                            "slap_sasl_init: init failed.\n" ));
421 #else
422                 Debug( LDAP_DEBUG_ANY, "sasl_server_init failed\n",
423                         0, 0, 0 );
424 #endif
425
426                 return -1;
427         }
428
429 #ifdef NEW_LOGGING
430         LDAP_LOG(( "sasl", LDAP_LEVEL_INFO,
431                    "slap_sasl_init: initialized!\n"));
432 #else
433         Debug( LDAP_DEBUG_TRACE, "slap_sasl_init: initialized!\n",
434                 0, 0, 0 );
435 #endif
436
437
438         /* default security properties */
439         memset( &sasl_secprops, '\0', sizeof(sasl_secprops) );
440     sasl_secprops.max_ssf = INT_MAX;
441     sasl_secprops.maxbufsize = 65536;
442     sasl_secprops.security_flags = SASL_SEC_NOPLAINTEXT|SASL_SEC_NOANONYMOUS;
443 #endif
444
445         return 0;
446 }
447
448 int slap_sasl_destroy( void )
449 {
450 #ifdef HAVE_CYRUS_SASL
451         sasl_done();
452 #endif
453         free( global_host );
454         global_host = NULL;
455
456         return 0;
457 }
458
459 int slap_sasl_open( Connection *conn )
460 {
461         int sc = LDAP_SUCCESS;
462
463 #ifdef HAVE_CYRUS_SASL
464         sasl_conn_t *ctx = NULL;
465         sasl_callback_t *session_callbacks;
466
467         assert( conn->c_sasl_context == NULL );
468         assert( conn->c_sasl_extra == NULL );
469
470         conn->c_sasl_layers = 0;
471
472         session_callbacks =
473                 ch_calloc( 3, sizeof(sasl_callback_t));
474         conn->c_sasl_extra = session_callbacks;
475
476         session_callbacks[0].id = SASL_CB_LOG;
477         session_callbacks[0].proc = &slap_sasl_log;
478         session_callbacks[0].context = conn;
479
480         session_callbacks[1].id = SASL_CB_PROXY_POLICY;
481         session_callbacks[1].proc = &slap_sasl_authorize;
482         session_callbacks[1].context = conn;
483
484         session_callbacks[2].id = SASL_CB_LIST_END;
485         session_callbacks[2].proc = NULL;
486         session_callbacks[2].context = NULL;
487
488         if( global_host == NULL ) {
489                 global_host = ldap_pvt_get_fqdn( NULL );
490         }
491
492         /* create new SASL context */
493         sc = sasl_server_new( "ldap", global_host, global_realm,
494                 session_callbacks, SASL_SECURITY_LAYER, &ctx );
495
496         if( sc != SASL_OK ) {
497 #ifdef NEW_LOGGING
498                 LDAP_LOG(( "sasl", LDAP_LEVEL_ERR,
499                            "slap_sasl_open: sasl_server_new failed: %d\n", sc ));
500 #else
501                 Debug( LDAP_DEBUG_ANY, "sasl_server_new failed: %d\n",
502                         sc, 0, 0 );
503 #endif
504
505                 return -1;
506         }
507
508         conn->c_sasl_context = ctx;
509
510         if( sc == SASL_OK ) {
511                 sc = sasl_setprop( ctx,
512                         SASL_SEC_PROPS, &sasl_secprops );
513
514                 if( sc != SASL_OK ) {
515 #ifdef NEW_LOGGING
516                         LDAP_LOG(( "sasl", LDAP_LEVEL_ERR,
517                                    "slap_sasl_open: sasl_setprop failed: %d \n", sc ));
518 #else
519                         Debug( LDAP_DEBUG_ANY, "sasl_setprop failed: %d\n",
520                                 sc, 0, 0 );
521 #endif
522
523                         slap_sasl_close( conn );
524                         return -1;
525                 }
526         }
527
528         sc = slap_sasl_err2ldap( sc );
529 #endif
530         return sc;
531 }
532
533 int slap_sasl_external(
534         Connection *conn,
535         slap_ssf_t ssf,
536         const char *auth_id )
537 {
538 #ifdef HAVE_CYRUS_SASL
539         int sc;
540         sasl_conn_t *ctx = conn->c_sasl_context;
541         sasl_external_properties_t extprops;
542
543         if ( ctx == NULL ) {
544                 return LDAP_UNAVAILABLE;
545         }
546
547         memset( &extprops, '\0', sizeof(extprops) );
548         extprops.ssf = ssf;
549         extprops.auth_id = (char *) auth_id;
550
551         sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL,
552                 (void *) &extprops );
553
554         if ( sc != SASL_OK ) {
555                 return LDAP_OTHER;
556         }
557 #endif
558
559         return LDAP_SUCCESS;
560 }
561
562 int slap_sasl_reset( Connection *conn )
563 {
564 #ifdef HAVE_CYRUS_SASL
565         sasl_conn_t *ctx = conn->c_sasl_context;
566
567         if( ctx != NULL ) {
568         }
569 #endif
570         /* must return "anonymous" */
571         return LDAP_SUCCESS;
572 }
573
574 char ** slap_sasl_mechs( Connection *conn )
575 {
576         char **mechs = NULL;
577
578 #ifdef HAVE_CYRUS_SASL
579         sasl_conn_t *ctx = conn->c_sasl_context;
580
581         if( ctx != NULL ) {
582                 int sc;
583                 char *mechstr;
584
585                 sc = sasl_listmech( ctx,
586                         NULL, NULL, ",", NULL,
587                         &mechstr, NULL, NULL );
588
589                 if( sc != SASL_OK ) {
590 #ifdef NEW_LOGGING
591                         LDAP_LOG(( "sasl", LDAP_LEVEL_ERR,
592                                 "slap_sasl_mechs: sasl_listmech failed: %d\n", sc ));
593 #else
594                         Debug( LDAP_DEBUG_ANY, "slap_sasl_listmech failed: %d\n",
595                                 sc, 0, 0 );
596 #endif
597
598                         return NULL;
599                 }
600
601                 mechs = str2charray( mechstr, "," );
602
603                 ch_free( mechstr );
604         }
605 #endif
606
607         return mechs;
608 }
609
610 int slap_sasl_close( Connection *conn )
611 {
612 #ifdef HAVE_CYRUS_SASL
613         sasl_conn_t *ctx = conn->c_sasl_context;
614
615         if( ctx != NULL ) {
616                 sasl_dispose( &ctx );
617         }
618
619         conn->c_sasl_context = NULL;
620
621         free( conn->c_sasl_extra );
622         conn->c_sasl_extra = NULL;
623 #endif
624
625         return LDAP_SUCCESS;
626 }
627
628 int slap_sasl_bind(
629     Connection          *conn,
630     Operation           *op,  
631     struct berval       *dn,  
632     struct berval       *ndn,
633     struct berval       *cred,
634         struct berval                   *edn,
635         slap_ssf_t              *ssfp )
636 {
637         int rc = 1;
638
639 #ifdef HAVE_CYRUS_SASL
640         sasl_conn_t *ctx = conn->c_sasl_context;
641         struct berval response;
642         unsigned reslen = 0;
643         const char *errstr;
644         int sc;
645
646 #ifdef NEW_LOGGING
647         LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
648                 "sasl_bind: conn %ld dn=\"%s\" mech=%s datalen=%ld\n",
649                 conn->c_connid,
650                 dn->bv_len ? dn->bv_val : "",
651                 conn->c_sasl_bind_in_progress ? "<continuing>" : conn->c_sasl_bind_mech.bv_val,
652                 cred ? cred->bv_len : 0 ));
653 #else
654         Debug(LDAP_DEBUG_ARGS,
655                 "==> sasl_bind: dn=\"%s\" mech=%s datalen=%ld\n",
656                 dn->bv_len ? dn->bv_val : "",
657                 conn->c_sasl_bind_in_progress ? "<continuing>":conn->c_sasl_bind_mech.bv_val,
658                 cred ? cred->bv_len : 0 );
659 #endif
660
661
662         if( ctx == NULL ) {
663                 send_ldap_result( conn, op, LDAP_UNAVAILABLE,
664                         NULL, "SASL unavailable on this session", NULL, NULL );
665                 return rc;
666         }
667
668         if ( !conn->c_sasl_bind_in_progress ) {
669                 sc = sasl_server_start( ctx,
670                         conn->c_sasl_bind_mech.bv_val,
671                         cred->bv_len ? cred->bv_val : "",
672                         cred->bv_len,
673                         (char **)&response.bv_val, &reslen, &errstr );
674
675         } else {
676                 sc = sasl_server_step( ctx,
677                         cred->bv_val, cred->bv_len,
678                         (char **)&response.bv_val, &reslen, &errstr );
679         }
680
681         response.bv_len = reslen;
682
683         if ( sc == SASL_OK ) {
684                 char *username = NULL;
685
686                 sc = sasl_getprop( ctx,
687                         SASL_USERNAME, (void **)&username );
688
689                 if ( sc != SASL_OK ) {
690 #ifdef NEW_LOGGING
691                         LDAP_LOG(( "sasl", LDAP_LEVEL_ERR,
692                                 "slap_sasl_bind: getprop(USERNAME) failed: %d\n", sc ));
693 #else
694                         Debug(LDAP_DEBUG_TRACE,
695                                 "slap_sasl_bind: getprop(USERNAME) failed!\n",
696                                 0, 0, 0);
697 #endif
698
699
700                         send_ldap_result( conn, op, rc = slap_sasl_err2ldap( sc ),
701                                 NULL, "no SASL username", NULL, NULL );
702
703                 } else {
704                         rc = slap_sasl_getdn( conn, username, edn, FLAG_GETDN_FINAL );
705
706                         if( rc == LDAP_SUCCESS ) {
707                                 int i;
708                                 sasl_ssf_t *ssf = NULL;
709                                 (void) sasl_getprop( ctx, SASL_SSF, (void *)&ssf );
710                                 *ssfp = ssf ? *ssf : 0;
711
712                                 if( *ssfp ) {
713                                         ldap_pvt_thread_mutex_lock( &conn->c_mutex );
714                                         conn->c_sasl_layers++;
715                                         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
716                                 }
717
718                                 send_ldap_sasl( conn, op, rc,
719                                         NULL, NULL, NULL, NULL,
720                                         response.bv_len ? &response : NULL );
721
722                         } else {
723                                 send_ldap_result( conn, op, rc,
724                                         NULL, errstr, NULL, NULL );
725                         }
726                 }
727
728         } else if ( sc == SASL_CONTINUE ) {
729                 send_ldap_sasl( conn, op, rc = LDAP_SASL_BIND_IN_PROGRESS,
730                         NULL, NULL, NULL, NULL, &response );
731
732         } else {
733                 send_ldap_result( conn, op, rc = slap_sasl_err2ldap( sc ),
734                         NULL, errstr, NULL, NULL );
735         }
736
737         if( response.bv_len ) {
738                 ch_free( response.bv_val );
739         }
740
741 #ifdef NEW_LOGGING
742         LDAP_LOG(( "sasl", LDAP_LEVEL_ENTRY,
743                 "slap_sasl_bind: rc=%d\n", rc ));
744 #else
745         Debug(LDAP_DEBUG_TRACE, "<== slap_sasl_bind: rc=%d\n", rc, 0, 0);
746 #endif
747
748
749 #else
750         send_ldap_result( conn, op, rc = LDAP_UNAVAILABLE,
751                 NULL, "SASL not supported", NULL, NULL );
752 #endif
753
754         return rc;
755 }
756
757 char* slap_sasl_secprops( const char *in )
758 {
759 #ifdef HAVE_CYRUS_SASL
760         int rc = ldap_pvt_sasl_secprops( in, &sasl_secprops );
761
762         return rc == LDAP_SUCCESS ? NULL : "Invalid security properties";
763 #else
764         return "SASL not supported";
765 #endif
766 }