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