]> git.sur5r.net Git - openldap/blob - libraries/libldap/cyrus.c
0f8ee6241cde3e09d775aef822239d62b0673185
[openldap] / libraries / libldap / cyrus.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1999-2002 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6
7 #include "portable.h"
8
9 #include <stdlib.h>
10 #include <stdio.h>
11
12 #include <ac/socket.h>
13 #include <ac/string.h>
14 #include <ac/time.h>
15 #include <ac/errno.h>
16 #include <ac/ctype.h>
17
18 #include "ldap-int.h"
19
20 #ifdef HAVE_CYRUS_SASL
21
22 #ifdef LDAP_R_COMPILE
23 ldap_pvt_thread_mutex_t ldap_int_sasl_mutex;
24 #endif
25
26 #include <sasl.h>
27
28 /*
29 * Various Cyrus SASL related stuff.
30 */
31
32 int ldap_int_sasl_init( void )
33 {
34         /* XXX not threadsafe */
35         static int sasl_initialized = 0;
36
37         static sasl_callback_t client_callbacks[] = {
38 #ifdef SASL_CB_GETREALM
39                 { SASL_CB_GETREALM, NULL, NULL },
40 #endif
41                 { SASL_CB_USER, NULL, NULL },
42                 { SASL_CB_AUTHNAME, NULL, NULL },
43                 { SASL_CB_PASS, NULL, NULL },
44                 { SASL_CB_ECHOPROMPT, NULL, NULL },
45                 { SASL_CB_NOECHOPROMPT, NULL, NULL },
46                 { SASL_CB_LIST_END, NULL, NULL }
47         };
48
49         if ( sasl_initialized ) {
50                 return 0;
51         }
52
53 #ifndef CSRIMALLOC
54         sasl_set_alloc(
55                 ber_memalloc,
56                 ber_memcalloc,
57                 ber_memrealloc,
58                 ber_memfree );
59 #endif /* CSRIMALLOC */
60
61 #ifdef LDAP_R_COMPILE
62         sasl_set_mutex(
63                 ldap_pvt_sasl_mutex_new,
64                 ldap_pvt_sasl_mutex_lock,
65                 ldap_pvt_sasl_mutex_unlock,    
66                 ldap_pvt_sasl_mutex_dispose );    
67
68         ldap_pvt_thread_mutex_init( &ldap_int_sasl_mutex );
69 #endif
70
71         if ( sasl_client_init( client_callbacks ) == SASL_OK ) {
72                 sasl_initialized = 1;
73                 return 0;
74         }
75
76         return -1;
77 }
78
79 /*
80  * SASL encryption support for LBER Sockbufs
81  */
82
83 struct sb_sasl_data {
84         sasl_conn_t             *sasl_context;
85         unsigned                *sasl_maxbuf;
86         Sockbuf_Buf             sec_buf_in;
87         Sockbuf_Buf             buf_in;
88         Sockbuf_Buf             buf_out;
89 };
90
91 static int
92 sb_sasl_setup( Sockbuf_IO_Desc *sbiod, void *arg )
93 {
94         struct sb_sasl_data     *p;
95
96         assert( sbiod != NULL );
97
98         p = LBER_MALLOC( sizeof( *p ) );
99         if ( p == NULL )
100                 return -1;
101         p->sasl_context = (sasl_conn_t *)arg;
102         ber_pvt_sb_buf_init( &p->sec_buf_in );
103         ber_pvt_sb_buf_init( &p->buf_in );
104         ber_pvt_sb_buf_init( &p->buf_out );
105         if ( ber_pvt_sb_grow_buffer( &p->sec_buf_in, SASL_MIN_BUFF_SIZE ) < 0 ) {
106                 LBER_FREE( p );
107                 errno = ENOMEM;
108                 return -1;
109         }
110         sasl_getprop( p->sasl_context, SASL_MAXOUTBUF,
111                 (void **) &p->sasl_maxbuf );
112
113         sbiod->sbiod_pvt = p;
114
115         return 0;
116 }
117
118 static int
119 sb_sasl_remove( Sockbuf_IO_Desc *sbiod )
120 {
121         struct sb_sasl_data     *p;
122
123         assert( sbiod != NULL );
124         
125         p = (struct sb_sasl_data *)sbiod->sbiod_pvt;
126         ber_pvt_sb_buf_destroy( &p->sec_buf_in );
127         ber_pvt_sb_buf_destroy( &p->buf_in );
128         ber_pvt_sb_buf_destroy( &p->buf_out );
129         LBER_FREE( p );
130         sbiod->sbiod_pvt = NULL;
131         return 0;
132 }
133
134 static ber_len_t
135 sb_sasl_pkt_length( const unsigned char *buf, unsigned max, int debuglevel )
136 {
137         ber_len_t               size;
138
139         assert( buf != NULL );
140
141         size = buf[0] << 24
142                 | buf[1] << 16
143                 | buf[2] << 8
144                 | buf[3];
145    
146         if ( size > max ) {
147                 /* somebody is trying to mess me up. */
148                 ber_log_printf( LDAP_DEBUG_ANY, debuglevel,
149                         "sb_sasl_pkt_length: received illegal packet length "
150                         "of %lu bytes\n", (unsigned long)size );      
151                 size = 16; /* this should lead to an error. */
152         }
153
154         return size + 4; /* include the size !!! */
155 }
156
157 /* Drop a processed packet from the input buffer */
158 static void
159 sb_sasl_drop_packet ( Sockbuf_Buf *sec_buf_in, unsigned max, int debuglevel )
160 {
161         ber_slen_t                      len;
162
163         len = sec_buf_in->buf_ptr - sec_buf_in->buf_end;
164         if ( len > 0 )
165                 memmove( sec_buf_in->buf_base, sec_buf_in->buf_base +
166                         sec_buf_in->buf_end, len );
167    
168         if ( len >= 4 ) {
169                 sec_buf_in->buf_end = sb_sasl_pkt_length( sec_buf_in->buf_base,
170                         max, debuglevel);
171         }
172         else {
173                 sec_buf_in->buf_end = 0;
174         }
175         sec_buf_in->buf_ptr = len;
176 }
177
178 static ber_slen_t
179 sb_sasl_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
180 {
181         struct sb_sasl_data     *p;
182         ber_slen_t              ret, bufptr;
183    
184         assert( sbiod != NULL );
185         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
186
187         p = (struct sb_sasl_data *)sbiod->sbiod_pvt;
188
189         /* Are there anything left in the buffer? */
190         ret = ber_pvt_sb_copy_out( &p->buf_in, buf, len );
191         bufptr = ret;
192         len -= ret;
193
194         if ( len == 0 )
195                 return bufptr;
196
197         ber_pvt_sb_buf_destroy( &p->buf_in );
198
199         /* Read the length of the packet */
200         while ( p->sec_buf_in.buf_ptr < 4 ) {
201                 ret = LBER_SBIOD_READ_NEXT( sbiod, p->sec_buf_in.buf_base,
202                         4 - p->sec_buf_in.buf_ptr );
203 #ifdef EINTR
204                 if ( ( ret < 0 ) && ( errno == EINTR ) )
205                         continue;
206 #endif
207                 if ( ret <= 0 )
208                         return ret;
209
210                 p->sec_buf_in.buf_ptr += ret;
211         }
212
213         /* The new packet always starts at p->sec_buf_in.buf_base */
214         ret = sb_sasl_pkt_length( p->sec_buf_in.buf_base,
215                 *p->sasl_maxbuf, sbiod->sbiod_sb->sb_debug );
216
217         /* Grow the packet buffer if neccessary */
218         if ( ( p->sec_buf_in.buf_size < ret ) && 
219                         ber_pvt_sb_grow_buffer( &p->sec_buf_in, ret ) < 0 ) {
220                 errno = ENOMEM;
221                 return -1;
222         }
223         p->sec_buf_in.buf_end = ret;
224
225         /* Did we read the whole encrypted packet? */
226         while ( p->sec_buf_in.buf_ptr < p->sec_buf_in.buf_end ) {
227                 /* No, we have got only a part of it */
228                 ret = p->sec_buf_in.buf_end - p->sec_buf_in.buf_ptr;
229
230                 ret = LBER_SBIOD_READ_NEXT( sbiod, p->sec_buf_in.buf_base +
231                         p->sec_buf_in.buf_ptr, ret );
232 #ifdef EINTR
233                 if ( ( ret < 0 ) && ( errno == EINTR ) )
234                         continue;
235 #endif
236                 if ( ret <= 0 )
237                         return ret;
238
239                 p->sec_buf_in.buf_ptr += ret;
240         }
241
242         /* Decode the packet */
243         ret = sasl_decode( p->sasl_context, p->sec_buf_in.buf_base,
244                 p->sec_buf_in.buf_end, &p->buf_in.buf_base,
245                 (unsigned *)&p->buf_in.buf_end );
246
247         /* Drop the packet from the input buffer */
248         sb_sasl_drop_packet( &p->sec_buf_in,
249                         *p->sasl_maxbuf, sbiod->sbiod_sb->sb_debug );
250
251         if ( ret != SASL_OK ) {
252                 ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug,
253                         "sb_sasl_read: failed to decode packet: %s\n",
254                         sasl_errstring( ret, NULL, NULL ) );
255                 errno = EIO;
256                 return -1;
257         }
258         
259         p->buf_in.buf_size = p->buf_in.buf_end;
260
261         bufptr += ber_pvt_sb_copy_out( &p->buf_in, (char*) buf + bufptr, len );
262
263         return bufptr;
264 }
265
266 static ber_slen_t
267 sb_sasl_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
268 {
269         struct sb_sasl_data     *p;
270         int                     ret;
271
272         assert( sbiod != NULL );
273         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
274
275         p = (struct sb_sasl_data *)sbiod->sbiod_pvt;
276
277         /* Are there anything left in the buffer? */
278         if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) {
279                 ret = ber_pvt_sb_do_write( sbiod, &p->buf_out );
280                 if ( ret <= 0 )
281                         return ret;
282         }
283
284         /* now encode the next packet. */
285         ber_pvt_sb_buf_destroy( &p->buf_out );
286
287         if ( len > *p->sasl_maxbuf - 100 )
288                 len = *p->sasl_maxbuf - 100;    /* For safety margin */
289         ret = sasl_encode( p->sasl_context, buf, len, &p->buf_out.buf_base,
290                 (unsigned *)&p->buf_out.buf_size );
291         if ( ret != SASL_OK ) {
292                 ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug,
293                         "sb_sasl_write: failed to encode packet: %s\n",
294                         sasl_errstring( ret, NULL, NULL ) );
295                 return -1;
296         }
297         p->buf_out.buf_end = p->buf_out.buf_size;
298
299         ret = ber_pvt_sb_do_write( sbiod, &p->buf_out );
300         if ( ret <= 0 )
301                 return ret;
302         return len;
303 }
304
305 static int
306 sb_sasl_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
307 {
308         struct sb_sasl_data     *p;
309
310         p = (struct sb_sasl_data *)sbiod->sbiod_pvt;
311
312         if ( opt == LBER_SB_OPT_DATA_READY ) {
313                 if ( p->buf_in.buf_ptr != p->buf_in.buf_end )
314                         return 1;
315         }
316         
317         return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
318 }
319
320 Sockbuf_IO ldap_pvt_sockbuf_io_sasl = {
321         sb_sasl_setup,          /* sbi_setup */
322         sb_sasl_remove,         /* sbi_remove */
323         sb_sasl_ctrl,           /* sbi_ctrl */
324         sb_sasl_read,           /* sbi_read */
325         sb_sasl_write,          /* sbi_write */
326         NULL                    /* sbi_close */
327 };
328
329 int ldap_pvt_sasl_install( Sockbuf *sb, void *ctx_arg )
330 {
331         Debug( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_install\n",
332                 0, 0, 0 );
333
334         /* don't install the stuff unless security has been negotiated */
335
336         if ( !ber_sockbuf_ctrl( sb, LBER_SB_OPT_HAS_IO,
337                         &ldap_pvt_sockbuf_io_sasl ) )
338         {
339 #ifdef LDAP_DEBUG
340                 ber_sockbuf_add_io( sb, &ber_sockbuf_io_debug,
341                         LBER_SBIOD_LEVEL_APPLICATION, (void *)"sasl_" );
342 #endif
343                 ber_sockbuf_add_io( sb, &ldap_pvt_sockbuf_io_sasl,
344                         LBER_SBIOD_LEVEL_APPLICATION, ctx_arg );
345         }
346
347         return LDAP_SUCCESS;
348 }
349
350 static int
351 sasl_err2ldap( int saslerr )
352 {
353         int rc;
354
355         switch (saslerr) {
356                 case SASL_CONTINUE:
357                         rc = LDAP_MORE_RESULTS_TO_RETURN;
358                         break;
359                 case SASL_INTERACT:
360                         rc = LDAP_LOCAL_ERROR;
361                         break;
362                 case SASL_OK:
363                         rc = LDAP_SUCCESS;
364                         break;
365                 case SASL_FAIL:
366                         rc = LDAP_LOCAL_ERROR;
367                         break;
368                 case SASL_NOMEM:
369                         rc = LDAP_NO_MEMORY;
370                         break;
371                 case SASL_NOMECH:
372                         rc = LDAP_AUTH_UNKNOWN;
373                         break;
374                 case SASL_BADAUTH:
375                         rc = LDAP_AUTH_UNKNOWN;
376                         break;
377                 case SASL_NOAUTHZ:
378                         rc = LDAP_PARAM_ERROR;
379                         break;
380                 case SASL_TOOWEAK:
381                 case SASL_ENCRYPT:
382                         rc = LDAP_AUTH_UNKNOWN;
383                         break;
384                 default:
385                         rc = LDAP_LOCAL_ERROR;
386                         break;
387         }
388
389         assert( rc == LDAP_SUCCESS || LDAP_API_ERROR( rc ) );
390         return rc;
391 }
392
393 int
394 ldap_int_sasl_open(
395         LDAP *ld, 
396         LDAPConn *lc,
397         const char * host,
398         ber_len_t ssf )
399 {
400         int rc;
401         sasl_conn_t *ctx;
402
403         sasl_callback_t *session_callbacks =
404                 ber_memcalloc( 2, sizeof( sasl_callback_t ) );
405
406         if( session_callbacks == NULL ) return LDAP_NO_MEMORY;
407
408         session_callbacks[0].id = SASL_CB_USER;
409         session_callbacks[0].proc = NULL;
410         session_callbacks[0].context = ld;
411
412         session_callbacks[1].id = SASL_CB_LIST_END;
413         session_callbacks[1].proc = NULL;
414         session_callbacks[1].context = NULL;
415
416         assert( lc->lconn_sasl_ctx == NULL );
417
418         if ( host == NULL ) {
419                 ld->ld_errno = LDAP_LOCAL_ERROR;
420                 return ld->ld_errno;
421         }
422
423         rc = sasl_client_new( "ldap", host, session_callbacks,
424                 SASL_SECURITY_LAYER, &ctx );
425         ber_memfree( session_callbacks );
426
427         if ( rc != SASL_OK ) {
428                 ld->ld_errno = sasl_err2ldap( rc );
429                 return ld->ld_errno;
430         }
431
432         Debug( LDAP_DEBUG_TRACE, "ldap_int_sasl_open: host=%s\n",
433                 host, 0, 0 );
434
435         lc->lconn_sasl_ctx = ctx;
436
437         if( ssf ) {
438                 sasl_external_properties_t extprops;
439                 memset(&extprops, 0L, sizeof(extprops));
440                 extprops.ssf = ssf;
441
442                 (void) sasl_setprop( ctx, SASL_SSF_EXTERNAL,
443                         (void *) &extprops );
444
445                 Debug( LDAP_DEBUG_TRACE, "ldap_int_sasl_open: ssf=%ld\n",
446                         (long) ssf, 0, 0 );
447         }
448
449         return LDAP_SUCCESS;
450 }
451
452 int ldap_int_sasl_close( LDAP *ld, LDAPConn *lc )
453 {
454         sasl_conn_t *ctx = lc->lconn_sasl_ctx;
455
456         if( ctx != NULL ) {
457                 sasl_dispose( &ctx );
458                 lc->lconn_sasl_ctx = NULL;
459         }
460
461         return LDAP_SUCCESS;
462 }
463
464 int
465 ldap_int_sasl_bind(
466         LDAP                    *ld,
467         const char              *dn,
468         const char              *mechs,
469         LDAPControl             **sctrls,
470         LDAPControl             **cctrls,
471         unsigned                flags,
472         LDAP_SASL_INTERACT_PROC *interact,
473         void * defaults )
474 {
475         char *data;
476         const char *mech = NULL;
477         const char *pmech = NULL;
478         int                     saslrc, rc;
479         sasl_ssf_t              *ssf = NULL;
480         sasl_conn_t     *ctx;
481         sasl_interact_t *prompts = NULL;
482         unsigned credlen;
483         struct berval ccred;
484         ber_socket_t            sd;
485
486         Debug( LDAP_DEBUG_TRACE, "ldap_int_sasl_bind: %s\n",
487                 mechs ? mechs : "<null>", 0, 0 );
488
489         /* do a quick !LDAPv3 check... ldap_sasl_bind will do the rest. */
490         if (ld->ld_version < LDAP_VERSION3) {
491                 ld->ld_errno = LDAP_NOT_SUPPORTED;
492                 return ld->ld_errno;
493         }
494
495         ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd );
496
497         if ( sd == AC_SOCKET_INVALID ) {
498                 /* not connected yet */
499                 int rc;
500
501                 rc = ldap_open_defconn( ld );
502                 if( rc < 0 ) return ld->ld_errno;
503
504                 ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd );
505
506                 if( sd == AC_SOCKET_INVALID ) {
507                         ld->ld_errno = LDAP_LOCAL_ERROR;
508                         return ld->ld_errno;
509                 }
510         }   
511
512         ctx = ld->ld_defconn->lconn_sasl_ctx;
513
514         if( ctx == NULL ) {
515                 ld->ld_errno = LDAP_LOCAL_ERROR;
516                 return ld->ld_errno;
517         }
518
519         /* (re)set security properties */
520         sasl_setprop( ctx, SASL_SEC_PROPS,
521                 &ld->ld_options.ldo_sasl_secprops );
522
523         ccred.bv_val = NULL;
524         ccred.bv_len = 0;
525
526         do {
527                 saslrc = sasl_client_start( ctx,
528                         mechs,
529                         NULL,
530                         &prompts,
531                         &ccred.bv_val,
532                         &credlen,
533                         &mech );
534
535                 if( pmech == NULL && mech != NULL ) {
536                         pmech = mech;
537
538                         if( flags != LDAP_SASL_QUIET ) {
539                                 fprintf(stderr,
540                                         "SASL/%s authentication started\n",
541                                         pmech );
542                         }
543                 }
544
545                 if( saslrc == SASL_INTERACT ) {
546                         int res;
547                         if( !interact ) break;
548                         res = (interact)( ld, flags, defaults, prompts );
549                         if( res != LDAP_SUCCESS ) {
550                                 break;
551                         }
552                 }
553         } while ( saslrc == SASL_INTERACT );
554
555         ccred.bv_len = credlen;
556
557         if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
558                 ld->ld_errno = sasl_err2ldap( saslrc );
559                 return ld->ld_errno;
560         }
561
562         do {
563                 struct berval *scred;
564                 unsigned credlen;
565
566                 scred = NULL;
567
568                 rc = ldap_sasl_bind_s( ld, dn, mech, &ccred, sctrls, cctrls, &scred );
569
570                 if ( ccred.bv_val != NULL ) {
571                         LDAP_FREE( ccred.bv_val );
572                         ccred.bv_val = NULL;
573                 }
574
575                 if ( rc != LDAP_SUCCESS && rc != LDAP_SASL_BIND_IN_PROGRESS ) {
576                         if( scred && scred->bv_len ) {
577                                 /* and server provided us with data? */
578                                 Debug( LDAP_DEBUG_TRACE,
579                                         "ldap_int_sasl_bind: rc=%d sasl=%d len=%ld\n",
580                                         rc, saslrc, scred->bv_len );
581                                 ber_bvfree( scred );
582                         }
583                         return ld->ld_errno;
584                 }
585
586                 if( rc == LDAP_SUCCESS && saslrc == SASL_OK ) {
587                         /* we're done, no need to step */
588                         if( scred && scred->bv_len ) {
589                                 /* but server provided us with data! */
590                                 Debug( LDAP_DEBUG_TRACE,
591                                         "ldap_int_sasl_bind: rc=%d sasl=%d len=%ld\n",
592                                         rc, saslrc, scred->bv_len );
593                                 ber_bvfree( scred );
594                                 return ld->ld_errno = LDAP_LOCAL_ERROR;
595                         }
596                         break;
597                 }
598
599                 do {
600                         saslrc = sasl_client_step( ctx,
601                                 (scred == NULL) ? NULL : scred->bv_val,
602                                 (scred == NULL) ? 0 : scred->bv_len,
603                                 &prompts,
604                                 &ccred.bv_val,
605                                 &credlen );
606
607                         Debug( LDAP_DEBUG_TRACE, "sasl_client_start: %d\n",
608                                 saslrc, 0, 0 );
609
610                         if( saslrc == SASL_INTERACT ) {
611                                 int res;
612                                 if( !interact ) break;
613                                 res = (interact)( ld, flags, defaults, prompts );
614                                 if( res != LDAP_SUCCESS ) {
615                                         break;
616                                 }
617                         }
618                 } while ( saslrc == SASL_INTERACT );
619
620                 ccred.bv_len = credlen;
621                 ber_bvfree( scred );
622
623                 if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
624                         ld->ld_errno = sasl_err2ldap( saslrc );
625                         return ld->ld_errno;
626                 }
627         } while ( rc == LDAP_SASL_BIND_IN_PROGRESS );
628
629         if ( rc != LDAP_SUCCESS ) {
630                 return rc;
631         }
632
633         if ( saslrc != SASL_OK ) {
634                 return ld->ld_errno = sasl_err2ldap( saslrc );
635         }
636
637         if( flags != LDAP_SASL_QUIET ) {
638                 saslrc = sasl_getprop( ctx, SASL_USERNAME, (void **) &data );
639                 if( saslrc == SASL_OK && data && *data ) {
640                         fprintf( stderr, "SASL username: %s\n", data );
641                 }
642
643                 saslrc = sasl_getprop( ctx, SASL_REALM, (void **) &data );
644                 if( saslrc == SASL_OK && data && *data ) {
645                         fprintf( stderr, "SASL realm: %s\n", data );
646                 }
647         }
648
649         saslrc = sasl_getprop( ctx, SASL_SSF, (void **) &ssf );
650         if( saslrc == SASL_OK ) {
651                 if( flags != LDAP_SASL_QUIET ) {
652                         fprintf( stderr, "SASL SSF: %lu\n",
653                                 (unsigned long) *ssf );
654                 }
655
656                 if( ssf && *ssf ) {
657                         if( flags != LDAP_SASL_QUIET ) {
658                                 fprintf( stderr, "SASL installing layers\n" );
659                         }
660                         ldap_pvt_sasl_install( ld->ld_conns->lconn_sb, ctx );
661                 }
662         }
663
664         return rc;
665 }
666
667 int
668 ldap_int_sasl_external(
669         LDAP *ld,
670         LDAPConn *conn,
671         const char * authid,
672         ber_len_t ssf )
673 {
674         int sc;
675         sasl_conn_t *ctx;
676         sasl_external_properties_t extprops;
677
678         ctx = conn->lconn_sasl_ctx;
679
680         if ( ctx == NULL ) {
681                 return LDAP_LOCAL_ERROR;
682         }
683     
684         memset( &extprops, '\0', sizeof(extprops) );
685         extprops.ssf = ssf;
686         extprops.auth_id = (char *) authid;
687     
688         sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL,
689                 (void *) &extprops );
690     
691         if ( sc != SASL_OK ) {
692                 return LDAP_LOCAL_ERROR;
693         }
694
695         return LDAP_SUCCESS;
696 }
697
698
699 int ldap_pvt_sasl_secprops(
700         const char *in,
701         sasl_security_properties_t *secprops )
702 {
703         int i;
704         char **props = ldap_str2charray( in, "," );
705         unsigned sflags = 0;
706         int got_sflags = 0;
707         sasl_ssf_t max_ssf = 0;
708         int got_max_ssf = 0;
709         sasl_ssf_t min_ssf = 0;
710         int got_min_ssf = 0;
711         unsigned maxbufsize = 0;
712         int got_maxbufsize = 0;
713
714         if( props == NULL || secprops == NULL ) {
715                 return LDAP_PARAM_ERROR;
716         }
717
718         for( i=0; props[i]; i++ ) {
719                 if( !strcasecmp(props[i], "none") ) {
720                         got_sflags++;
721
722                 } else if( !strcasecmp(props[i], "noplain") ) {
723                         got_sflags++;
724                         sflags |= SASL_SEC_NOPLAINTEXT;
725
726                 } else if( !strcasecmp(props[i], "noactive") ) {
727                         got_sflags++;
728                         sflags |= SASL_SEC_NOACTIVE;
729
730                 } else if( !strcasecmp(props[i], "nodict") ) {
731                         got_sflags++;
732                         sflags |= SASL_SEC_NODICTIONARY;
733
734                 } else if( !strcasecmp(props[i], "forwardsec") ) {
735                         got_sflags++;
736                         sflags |= SASL_SEC_FORWARD_SECRECY;
737
738                 } else if( !strcasecmp(props[i], "noanonymous")) {
739                         got_sflags++;
740                         sflags |= SASL_SEC_NOANONYMOUS;
741
742                 } else if( !strcasecmp(props[i], "passcred") ) {
743                         got_sflags++;
744                         sflags |= SASL_SEC_PASS_CREDENTIALS;
745
746                 } else if( !strncasecmp(props[i],
747                         "minssf=", sizeof("minssf")) )
748                 {
749                         if( isdigit( props[i][sizeof("minssf")] ) ) {
750                                 got_min_ssf++;
751                                 min_ssf = atoi( &props[i][sizeof("minssf")] );
752                         } else {
753                                 return LDAP_NOT_SUPPORTED;
754                         }
755
756                 } else if( !strncasecmp(props[i],
757                         "maxssf=", sizeof("maxssf")) )
758                 {
759                         if( isdigit( props[i][sizeof("maxssf")] ) ) {
760                                 got_max_ssf++;
761                                 max_ssf = atoi( &props[i][sizeof("maxssf")] );
762                         } else {
763                                 return LDAP_NOT_SUPPORTED;
764                         }
765
766                 } else if( !strncasecmp(props[i],
767                         "maxbufsize=", sizeof("maxbufsize")) )
768                 {
769                         if( isdigit( props[i][sizeof("maxbufsize")] ) ) {
770                                 got_maxbufsize++;
771                                 maxbufsize = atoi( &props[i][sizeof("maxbufsize")] );
772                         } else {
773                                 return LDAP_NOT_SUPPORTED;
774                         }
775
776                         if( maxbufsize && (( maxbufsize < SASL_MIN_BUFF_SIZE )
777                                 || (maxbufsize > SASL_MAX_BUFF_SIZE )))
778                         {
779                                 /* bad maxbufsize */
780                                 return LDAP_PARAM_ERROR;
781                         }
782
783                 } else {
784                         return LDAP_NOT_SUPPORTED;
785                 }
786         }
787
788         if(got_sflags) {
789                 secprops->security_flags = sflags;
790         }
791         if(got_min_ssf) {
792                 secprops->min_ssf = min_ssf;
793         }
794         if(got_max_ssf) {
795                 secprops->max_ssf = max_ssf;
796         }
797         if(got_maxbufsize) {
798                 secprops->maxbufsize = maxbufsize;
799         }
800
801         ldap_charray_free( props );
802         return LDAP_SUCCESS;
803 }
804
805 int
806 ldap_int_sasl_config( struct ldapoptions *lo, int option, const char *arg )
807 {
808         int rc;
809
810         switch( option ) {
811         case LDAP_OPT_X_SASL_SECPROPS:
812                 rc = ldap_pvt_sasl_secprops( arg, &lo->ldo_sasl_secprops );
813                 if( rc == LDAP_SUCCESS ) return 0;
814         }
815
816         return -1;
817 }
818
819 int
820 ldap_int_sasl_get_option( LDAP *ld, int option, void *arg )
821 {
822         if ( ld == NULL )
823                 return -1;
824
825         switch ( option ) {
826                 case LDAP_OPT_X_SASL_MECH: {
827                         *(char **)arg = ld->ld_options.ldo_def_sasl_mech
828                                 ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_mech ) : NULL;
829                 } break;
830                 case LDAP_OPT_X_SASL_REALM: {
831                         *(char **)arg = ld->ld_options.ldo_def_sasl_realm
832                                 ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_realm ) : NULL;
833                 } break;
834                 case LDAP_OPT_X_SASL_AUTHCID: {
835                         *(char **)arg = ld->ld_options.ldo_def_sasl_authcid
836                                 ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_authcid ) : NULL;
837                 } break;
838                 case LDAP_OPT_X_SASL_AUTHZID: {
839                         *(char **)arg = ld->ld_options.ldo_def_sasl_authzid
840                                 ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_authzid ) : NULL;
841                 } break;
842
843                 case LDAP_OPT_X_SASL_SSF: {
844                         int sc;
845                         sasl_ssf_t      *ssf;
846                         sasl_conn_t *ctx;
847
848                         if( ld->ld_defconn == NULL ) {
849                                 return -1;
850                         }
851
852                         ctx = ld->ld_defconn->lconn_sasl_ctx;
853
854                         if ( ctx == NULL ) {
855                                 return -1;
856                         }
857
858                         sc = sasl_getprop( ctx, SASL_SSF,
859                                 (void **) &ssf );
860
861                         if ( sc != SASL_OK ) {
862                                 return -1;
863                         }
864
865                         *(ber_len_t *)arg = *ssf;
866                 } break;
867
868                 case LDAP_OPT_X_SASL_SSF_EXTERNAL:
869                         /* this option is write only */
870                         return -1;
871
872                 case LDAP_OPT_X_SASL_SSF_MIN:
873                         *(ber_len_t *)arg = ld->ld_options.ldo_sasl_secprops.min_ssf;
874                         break;
875                 case LDAP_OPT_X_SASL_SSF_MAX:
876                         *(ber_len_t *)arg = ld->ld_options.ldo_sasl_secprops.max_ssf;
877                         break;
878                 case LDAP_OPT_X_SASL_MAXBUFSIZE:
879                         *(ber_len_t *)arg = ld->ld_options.ldo_sasl_secprops.maxbufsize;
880                         break;
881
882                 case LDAP_OPT_X_SASL_SECPROPS:
883                         /* this option is write only */
884                         return -1;
885
886                 default:
887                         return -1;
888         }
889         return 0;
890 }
891
892 int
893 ldap_int_sasl_set_option( LDAP *ld, int option, void *arg )
894 {
895         if ( ld == NULL )
896                 return -1;
897
898         switch ( option ) {
899         case LDAP_OPT_X_SASL_SSF:
900                 /* This option is read-only */
901                 return -1;
902
903         case LDAP_OPT_X_SASL_SSF_EXTERNAL: {
904                 int sc;
905                 sasl_external_properties_t extprops;
906                 sasl_conn_t *ctx;
907
908                 if( ld->ld_defconn == NULL ) {
909                         return -1;
910                 }
911
912                 ctx = ld->ld_defconn->lconn_sasl_ctx;
913
914                 if ( ctx == NULL ) {
915                         return -1;
916                 }
917
918                 memset(&extprops, 0L, sizeof(extprops));
919
920                 extprops.ssf = * (ber_len_t *) arg;
921
922                 sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL,
923                         (void *) &extprops );
924
925                 if ( sc != SASL_OK ) {
926                         return -1;
927                 }
928                 } break;
929
930         case LDAP_OPT_X_SASL_SSF_MIN:
931                 ld->ld_options.ldo_sasl_secprops.min_ssf = *(ber_len_t *)arg;
932                 break;
933         case LDAP_OPT_X_SASL_SSF_MAX:
934                 ld->ld_options.ldo_sasl_secprops.max_ssf = *(ber_len_t *)arg;
935                 break;
936         case LDAP_OPT_X_SASL_MAXBUFSIZE:
937                 ld->ld_options.ldo_sasl_secprops.maxbufsize = *(ber_len_t *)arg;
938                 break;
939
940         case LDAP_OPT_X_SASL_SECPROPS: {
941                 int sc;
942                 sc = ldap_pvt_sasl_secprops( (char *) arg,
943                         &ld->ld_options.ldo_sasl_secprops );
944
945                 return sc == LDAP_SUCCESS ? 0 : -1;
946                 }
947
948         default:
949                 return -1;
950         }
951         return 0;
952 }
953
954 #ifdef LDAP_R_COMPILE
955 void *ldap_pvt_sasl_mutex_new(void)
956 {
957         ldap_pvt_thread_mutex_t *mutex;
958
959         mutex = (ldap_pvt_thread_mutex_t *) LDAP_MALLOC(
960                 sizeof(ldap_pvt_thread_mutex_t) );
961
962         if ( ldap_pvt_thread_mutex_init( mutex ) == 0 ) {
963                 return mutex;
964         }
965         return NULL;
966 }
967
968 int ldap_pvt_sasl_mutex_lock(void *mutex)
969 {
970         return ldap_pvt_thread_mutex_lock( (ldap_pvt_thread_mutex_t *)mutex )
971                 ? SASL_FAIL : SASL_OK;
972 }
973
974 int ldap_pvt_sasl_mutex_unlock(void *mutex)
975 {
976         return ldap_pvt_thread_mutex_unlock( (ldap_pvt_thread_mutex_t *)mutex )
977                 ? SASL_FAIL : SASL_OK;
978 }
979
980 void ldap_pvt_sasl_mutex_dispose(void *mutex)
981 {
982         (void) ldap_pvt_thread_mutex_destroy( (ldap_pvt_thread_mutex_t *)mutex );
983         LDAP_FREE( mutex );
984 }
985 #endif
986
987 #else
988 int ldap_int_sasl_init( void )
989 { return LDAP_SUCCESS; }
990
991 int ldap_int_sasl_close( LDAP *ld, LDAPConn *lc )
992 { return LDAP_SUCCESS; }
993
994 int
995 ldap_int_sasl_bind(
996         LDAP                    *ld,
997         const char              *dn,
998         const char              *mechs,
999         LDAPControl             **sctrls,
1000         LDAPControl             **cctrls,
1001         unsigned                flags,
1002         LDAP_SASL_INTERACT_PROC *interact,
1003         void * defaults )
1004 { return LDAP_NOT_SUPPORTED; }
1005
1006 int
1007 ldap_int_sasl_external(
1008         LDAP *ld,
1009         LDAPConn *conn,
1010         const char * authid,
1011         ber_len_t ssf )
1012 { return LDAP_SUCCESS; }
1013
1014 #endif /* HAVE_CYRUS_SASL */