]> git.sur5r.net Git - openldap/blob - libraries/libldap/cyrus.c
skeleton of ldap_str2nd/dn2str; works with most of the simple cases, but there's...
[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: host=%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         LDAPConn *conn,
667         const char * authid,
668         ber_len_t ssf )
669 {
670         int sc;
671         sasl_conn_t *ctx;
672         sasl_external_properties_t extprops;
673
674         ctx = conn->lconn_sasl_ctx;
675
676         if ( ctx == NULL ) {
677                 return LDAP_LOCAL_ERROR;
678         }
679     
680         memset( &extprops, '\0', sizeof(extprops) );
681         extprops.ssf = ssf;
682         extprops.auth_id = (char *) authid;
683     
684         sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL,
685                 (void *) &extprops );
686     
687         if ( sc != SASL_OK ) {
688                 return LDAP_LOCAL_ERROR;
689         }
690
691         return LDAP_SUCCESS;
692 }
693
694
695 int ldap_pvt_sasl_secprops(
696         const char *in,
697         sasl_security_properties_t *secprops )
698 {
699         int i;
700         char **props = ldap_str2charray( in, "," );
701         unsigned sflags = 0;
702         int got_sflags = 0;
703         sasl_ssf_t max_ssf = 0;
704         int got_max_ssf = 0;
705         sasl_ssf_t min_ssf = 0;
706         int got_min_ssf = 0;
707         unsigned maxbufsize = 0;
708         int got_maxbufsize = 0;
709
710         if( props == NULL || secprops == NULL ) {
711                 return LDAP_PARAM_ERROR;
712         }
713
714         for( i=0; props[i]; i++ ) {
715                 if( !strcasecmp(props[i], "none") ) {
716                         got_sflags++;
717
718                 } else if( !strcasecmp(props[i], "noplain") ) {
719                         got_sflags++;
720                         sflags |= SASL_SEC_NOPLAINTEXT;
721
722                 } else if( !strcasecmp(props[i], "noactive") ) {
723                         got_sflags++;
724                         sflags |= SASL_SEC_NOACTIVE;
725
726                 } else if( !strcasecmp(props[i], "nodict") ) {
727                         got_sflags++;
728                         sflags |= SASL_SEC_NODICTIONARY;
729
730                 } else if( !strcasecmp(props[i], "forwardsec") ) {
731                         got_sflags++;
732                         sflags |= SASL_SEC_FORWARD_SECRECY;
733
734                 } else if( !strcasecmp(props[i], "noanonymous")) {
735                         got_sflags++;
736                         sflags |= SASL_SEC_NOANONYMOUS;
737
738                 } else if( !strcasecmp(props[i], "passcred") ) {
739                         got_sflags++;
740                         sflags |= SASL_SEC_PASS_CREDENTIALS;
741
742                 } else if( !strncasecmp(props[i],
743                         "minssf=", sizeof("minssf")) )
744                 {
745                         if( isdigit( props[i][sizeof("minssf")] ) ) {
746                                 got_min_ssf++;
747                                 min_ssf = atoi( &props[i][sizeof("minssf")] );
748                         } else {
749                                 return LDAP_NOT_SUPPORTED;
750                         }
751
752                 } else if( !strncasecmp(props[i],
753                         "maxssf=", sizeof("maxssf")) )
754                 {
755                         if( isdigit( props[i][sizeof("maxssf")] ) ) {
756                                 got_max_ssf++;
757                                 max_ssf = atoi( &props[i][sizeof("maxssf")] );
758                         } else {
759                                 return LDAP_NOT_SUPPORTED;
760                         }
761
762                 } else if( !strncasecmp(props[i],
763                         "maxbufsize=", sizeof("maxbufsize")) )
764                 {
765                         if( isdigit( props[i][sizeof("maxbufsize")] ) ) {
766                                 got_maxbufsize++;
767                                 maxbufsize = atoi( &props[i][sizeof("maxbufsize")] );
768                         } else {
769                                 return LDAP_NOT_SUPPORTED;
770                         }
771
772                         if( maxbufsize && (( maxbufsize < SASL_MIN_BUFF_SIZE )
773                                 || (maxbufsize > SASL_MAX_BUFF_SIZE )))
774                         {
775                                 /* bad maxbufsize */
776                                 return LDAP_PARAM_ERROR;
777                         }
778
779                 } else {
780                         return LDAP_NOT_SUPPORTED;
781                 }
782         }
783
784         if(got_sflags) {
785                 secprops->security_flags = sflags;
786         }
787         if(got_min_ssf) {
788                 secprops->min_ssf = min_ssf;
789         }
790         if(got_max_ssf) {
791                 secprops->max_ssf = max_ssf;
792         }
793         if(got_maxbufsize) {
794                 secprops->maxbufsize = maxbufsize;
795         }
796
797         ldap_charray_free( props );
798         return LDAP_SUCCESS;
799 }
800
801 int
802 ldap_int_sasl_config( struct ldapoptions *lo, int option, const char *arg )
803 {
804         int rc;
805
806         switch( option ) {
807         case LDAP_OPT_X_SASL_SECPROPS:
808                 rc = ldap_pvt_sasl_secprops( arg, &lo->ldo_sasl_secprops );
809                 if( rc == LDAP_SUCCESS ) return 0;
810         }
811
812         return -1;
813 }
814
815 int
816 ldap_int_sasl_get_option( LDAP *ld, int option, void *arg )
817 {
818         if ( ld == NULL )
819                 return -1;
820
821         switch ( option ) {
822                 case LDAP_OPT_X_SASL_MECH: {
823                         *(char **)arg = ld->ld_options.ldo_def_sasl_mech
824                                 ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_mech ) : NULL;
825                 } break;
826                 case LDAP_OPT_X_SASL_REALM: {
827                         *(char **)arg = ld->ld_options.ldo_def_sasl_realm
828                                 ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_realm ) : NULL;
829                 } break;
830                 case LDAP_OPT_X_SASL_AUTHCID: {
831                         *(char **)arg = ld->ld_options.ldo_def_sasl_authcid
832                                 ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_authcid ) : NULL;
833                 } break;
834                 case LDAP_OPT_X_SASL_AUTHZID: {
835                         *(char **)arg = ld->ld_options.ldo_def_sasl_authzid
836                                 ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_authzid ) : NULL;
837                 } break;
838
839                 case LDAP_OPT_X_SASL_SSF: {
840                         int sc;
841                         sasl_ssf_t      *ssf;
842                         sasl_conn_t *ctx;
843
844                         if( ld->ld_defconn == NULL ) {
845                                 return -1;
846                         }
847
848                         ctx = ld->ld_defconn->lconn_sasl_ctx;
849
850                         if ( ctx == NULL ) {
851                                 return -1;
852                         }
853
854                         sc = sasl_getprop( ctx, SASL_SSF,
855                                 (void **) &ssf );
856
857                         if ( sc != SASL_OK ) {
858                                 return -1;
859                         }
860
861                         *(ber_len_t *)arg = *ssf;
862                 } break;
863
864                 case LDAP_OPT_X_SASL_SSF_EXTERNAL:
865                         /* this option is write only */
866                         return -1;
867
868                 case LDAP_OPT_X_SASL_SSF_MIN:
869                         *(ber_len_t *)arg = ld->ld_options.ldo_sasl_secprops.min_ssf;
870                         break;
871                 case LDAP_OPT_X_SASL_SSF_MAX:
872                         *(ber_len_t *)arg = ld->ld_options.ldo_sasl_secprops.max_ssf;
873                         break;
874                 case LDAP_OPT_X_SASL_MAXBUFSIZE:
875                         *(ber_len_t *)arg = ld->ld_options.ldo_sasl_secprops.maxbufsize;
876                         break;
877
878                 case LDAP_OPT_X_SASL_SECPROPS:
879                         /* this option is write only */
880                         return -1;
881
882                 default:
883                         return -1;
884         }
885         return 0;
886 }
887
888 int
889 ldap_int_sasl_set_option( LDAP *ld, int option, void *arg )
890 {
891         if ( ld == NULL )
892                 return -1;
893
894         switch ( option ) {
895         case LDAP_OPT_X_SASL_SSF:
896                 /* This option is read-only */
897                 return -1;
898
899         case LDAP_OPT_X_SASL_SSF_EXTERNAL: {
900                 int sc;
901                 sasl_external_properties_t extprops;
902                 sasl_conn_t *ctx;
903
904                 if( ld->ld_defconn == NULL ) {
905                         return -1;
906                 }
907
908                 ctx = ld->ld_defconn->lconn_sasl_ctx;
909
910                 if ( ctx == NULL ) {
911                         return -1;
912                 }
913
914                 memset(&extprops, 0L, sizeof(extprops));
915
916                 extprops.ssf = * (ber_len_t *) arg;
917
918                 sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL,
919                         (void *) &extprops );
920
921                 if ( sc != SASL_OK ) {
922                         return -1;
923                 }
924                 } break;
925
926         case LDAP_OPT_X_SASL_SSF_MIN:
927                 ld->ld_options.ldo_sasl_secprops.min_ssf = *(ber_len_t *)arg;
928                 break;
929         case LDAP_OPT_X_SASL_SSF_MAX:
930                 ld->ld_options.ldo_sasl_secprops.max_ssf = *(ber_len_t *)arg;
931                 break;
932         case LDAP_OPT_X_SASL_MAXBUFSIZE:
933                 ld->ld_options.ldo_sasl_secprops.maxbufsize = *(ber_len_t *)arg;
934                 break;
935
936         case LDAP_OPT_X_SASL_SECPROPS: {
937                 int sc;
938                 sc = ldap_pvt_sasl_secprops( (char *) arg,
939                         &ld->ld_options.ldo_sasl_secprops );
940
941                 return sc == LDAP_SUCCESS ? 0 : -1;
942                 }
943
944         default:
945                 return -1;
946         }
947         return 0;
948 }
949
950 #ifdef LDAP_R_COMPILE
951 void *ldap_pvt_sasl_mutex_new(void)
952 {
953         ldap_pvt_thread_mutex_t *mutex;
954
955         mutex = (ldap_pvt_thread_mutex_t *) LDAP_MALLOC(
956                 sizeof(ldap_pvt_thread_mutex_t) );
957
958         if ( ldap_pvt_thread_mutex_init( mutex ) == 0 ) {
959                 return mutex;
960         }
961         return NULL;
962 }
963
964 int ldap_pvt_sasl_mutex_lock(void *mutex)
965 {
966         return ldap_pvt_thread_mutex_lock( (ldap_pvt_thread_mutex_t *)mutex )
967                 ? SASL_FAIL : SASL_OK;
968 }
969
970 int ldap_pvt_sasl_mutex_unlock(void *mutex)
971 {
972         return ldap_pvt_thread_mutex_unlock( (ldap_pvt_thread_mutex_t *)mutex )
973                 ? SASL_FAIL : SASL_OK;
974 }
975
976 void ldap_pvt_sasl_mutex_dispose(void *mutex)
977 {
978         (void) ldap_pvt_thread_mutex_destroy( (ldap_pvt_thread_mutex_t *)mutex );
979         LDAP_FREE( mutex );
980 }
981 #endif
982
983 #else
984 int ldap_int_sasl_init( void )
985 { return LDAP_SUCCESS; }
986
987 int ldap_int_sasl_close( LDAP *ld, LDAPConn *lc )
988 { return LDAP_SUCCESS; }
989
990 int
991 ldap_int_sasl_bind(
992         LDAP                    *ld,
993         const char              *dn,
994         const char              *mechs,
995         LDAPControl             **sctrls,
996         LDAPControl             **cctrls,
997         unsigned                flags,
998         LDAP_SASL_INTERACT_PROC *interact,
999         void * defaults )
1000 { return LDAP_NOT_SUPPORTED; }
1001
1002 int
1003 ldap_int_sasl_external(
1004         LDAP *ld,
1005         LDAPConn *conn,
1006         const char * authid,
1007         ber_len_t ssf )
1008 { return LDAP_SUCCESS; }
1009
1010 #endif /* HAVE_CYRUS_SASL */