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