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