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