]> git.sur5r.net Git - openldap/blob - libraries/libldap/cyrus.c
ITS#837: fix server down abandon bug
[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                 errno = ENOMEM;
215                 return -1;
216         }
217         p->sec_buf_in.buf_end = ret;
218
219         /* Did we read the whole encrypted packet? */
220         while ( p->sec_buf_in.buf_ptr < p->sec_buf_in.buf_end ) {
221                 /* No, we have got only a part of it */
222                 ret = p->sec_buf_in.buf_end - p->sec_buf_in.buf_ptr;
223
224                 ret = LBER_SBIOD_READ_NEXT( sbiod, p->sec_buf_in.buf_base +
225                         p->sec_buf_in.buf_ptr, ret );
226 #ifdef EINTR
227                 if ( ( ret < 0 ) && ( errno == EINTR ) )
228                         continue;
229 #endif
230                 if ( ret <= 0 )
231                         return ret;
232
233                 p->sec_buf_in.buf_ptr += ret;
234         }
235
236         /* Decode the packet */
237         ret = sasl_decode( p->sasl_context, p->sec_buf_in.buf_base,
238                 p->sec_buf_in.buf_end, &p->buf_in.buf_base,
239                 (unsigned *)&p->buf_in.buf_end );
240         if ( ret != SASL_OK ) {
241                 ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug,
242                         "sb_sasl_read: failed to decode packet: %s\n",
243                         sasl_errstring( ret, NULL, NULL ) );
244                 sb_sasl_drop_packet( &p->sec_buf_in,
245                         sbiod->sbiod_sb->sb_debug );
246                 errno = EIO;
247                 return -1;
248         }
249         
250         /* Drop the packet from the input buffer */
251         sb_sasl_drop_packet( &p->sec_buf_in, sbiod->sbiod_sb->sb_debug );
252
253         p->buf_in.buf_size = p->buf_in.buf_end;
254
255         bufptr += ber_pvt_sb_copy_out( &p->buf_in, (char*) buf + bufptr, len );
256
257         return bufptr;
258 }
259
260 static ber_slen_t
261 sb_sasl_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
262 {
263         struct sb_sasl_data     *p;
264         int                     ret;
265
266         assert( sbiod != NULL );
267         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
268
269         p = (struct sb_sasl_data *)sbiod->sbiod_pvt;
270
271         /* Are there anything left in the buffer? */
272         if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) {
273                 ret = ber_pvt_sb_do_write( sbiod, &p->buf_out );
274                 if ( ret <= 0 )
275                         return ret;
276         }
277
278         /* now encode the next packet. */
279         ber_pvt_sb_buf_destroy( &p->buf_out );
280         ret = sasl_encode( p->sasl_context, buf, len, &p->buf_out.buf_base,
281                 (unsigned *)&p->buf_out.buf_size );
282         if ( ret != SASL_OK ) {
283                 ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug,
284                         "sb_sasl_write: failed to encode packet: %s\n",
285                         sasl_errstring( ret, NULL, NULL ) );
286                 return -1;
287         }
288         p->buf_out.buf_end = p->buf_out.buf_size;
289
290         ret = ber_pvt_sb_do_write( sbiod, &p->buf_out );
291         if ( ret <= 0 )
292                 return ret;
293         return len;
294 }
295
296 static int
297 sb_sasl_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
298 {
299         struct sb_sasl_data     *p;
300
301         p = (struct sb_sasl_data *)sbiod->sbiod_pvt;
302
303         if ( opt == LBER_SB_OPT_DATA_READY ) {
304                 if ( p->buf_in.buf_ptr != p->buf_in.buf_end )
305                         return 1;
306         }
307         
308         return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
309 }
310
311 Sockbuf_IO ldap_pvt_sockbuf_io_sasl = {
312         sb_sasl_setup,          /* sbi_setup */
313         sb_sasl_remove,         /* sbi_remove */
314         sb_sasl_ctrl,           /* sbi_ctrl */
315         sb_sasl_read,           /* sbi_read */
316         sb_sasl_write,          /* sbi_write */
317         NULL                    /* sbi_close */
318 };
319
320 int ldap_pvt_sasl_install( Sockbuf *sb, void *ctx_arg )
321 {
322         Debug( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_install\n",
323                 0, 0, 0 );
324
325         /* don't install the stuff unless security has been negotiated */
326
327         if ( !ber_sockbuf_ctrl( sb, LBER_SB_OPT_HAS_IO,
328                         &ldap_pvt_sockbuf_io_sasl ) )
329         {
330 #ifdef LDAP_DEBUG
331                 ber_sockbuf_add_io( sb, &ber_sockbuf_io_debug,
332                         LBER_SBIOD_LEVEL_APPLICATION, (void *)"sasl_" );
333 #endif
334                 ber_sockbuf_add_io( sb, &ldap_pvt_sockbuf_io_sasl,
335                         LBER_SBIOD_LEVEL_APPLICATION, ctx_arg );
336         }
337
338         return LDAP_SUCCESS;
339 }
340
341 static int
342 sasl_err2ldap( int saslerr )
343 {
344         int rc;
345
346         switch (saslerr) {
347                 case SASL_CONTINUE:
348                         rc = LDAP_MORE_RESULTS_TO_RETURN;
349                         break;
350                 case SASL_INTERACT:
351                         rc = LDAP_LOCAL_ERROR;
352                         break;
353                 case SASL_OK:
354                         rc = LDAP_SUCCESS;
355                         break;
356                 case SASL_FAIL:
357                         rc = LDAP_LOCAL_ERROR;
358                         break;
359                 case SASL_NOMEM:
360                         rc = LDAP_NO_MEMORY;
361                         break;
362                 case SASL_NOMECH:
363                         rc = LDAP_AUTH_UNKNOWN;
364                         break;
365                 case SASL_BADAUTH:
366                         rc = LDAP_AUTH_UNKNOWN;
367                         break;
368                 case SASL_NOAUTHZ:
369                         rc = LDAP_PARAM_ERROR;
370                         break;
371                 case SASL_TOOWEAK:
372                 case SASL_ENCRYPT:
373                         rc = LDAP_AUTH_UNKNOWN;
374                         break;
375                 default:
376                         rc = LDAP_LOCAL_ERROR;
377                         break;
378         }
379
380         assert( rc == LDAP_SUCCESS || LDAP_API_ERROR( rc ) );
381         return rc;
382 }
383
384 int
385 ldap_int_sasl_open(
386         LDAP *ld, 
387         LDAPConn *lc,
388         const char * host,
389         ber_len_t ssf )
390 {
391         int rc;
392         sasl_conn_t *ctx;
393
394         sasl_callback_t *session_callbacks =
395                 ber_memcalloc( 2, sizeof( sasl_callback_t ) );
396
397         if( session_callbacks == NULL ) return LDAP_NO_MEMORY;
398
399         session_callbacks[0].id = SASL_CB_USER;
400         session_callbacks[0].proc = NULL;
401         session_callbacks[0].context = ld;
402
403         session_callbacks[1].id = SASL_CB_LIST_END;
404         session_callbacks[1].proc = NULL;
405         session_callbacks[1].context = NULL;
406
407         assert( lc->lconn_sasl_ctx == NULL );
408
409         if ( host == NULL ) {
410                 ld->ld_errno = LDAP_LOCAL_ERROR;
411                 return ld->ld_errno;
412         }
413
414         rc = sasl_client_new( "ldap", host, session_callbacks,
415                 SASL_SECURITY_LAYER, &ctx );
416
417         if ( rc != SASL_OK ) {
418                 ld->ld_errno = sasl_err2ldap( rc );
419                 return ld->ld_errno;
420         }
421
422         Debug( LDAP_DEBUG_TRACE, "ldap_int_sasl_open: %s\n",
423                 host, 0, 0 );
424
425         lc->lconn_sasl_ctx = ctx;
426
427         if( ssf ) {
428                 sasl_external_properties_t extprops;
429                 memset(&extprops, 0L, sizeof(extprops));
430                 extprops.ssf = ssf;
431
432                 (void) sasl_setprop( ctx, SASL_SSF_EXTERNAL,
433                         (void *) &extprops );
434
435                 Debug( LDAP_DEBUG_TRACE, "ldap_int_sasl_open: ssf=%ld\n",
436                         (long) ssf, 0, 0 );
437         }
438
439         return LDAP_SUCCESS;
440 }
441
442 int ldap_int_sasl_close( LDAP *ld, LDAPConn *lc )
443 {
444         sasl_conn_t *ctx = lc->lconn_sasl_ctx;
445
446         if( ctx != NULL ) {
447                 sasl_dispose( &ctx );
448                 lc->lconn_sasl_ctx = NULL;
449         }
450
451         return LDAP_SUCCESS;
452 }
453
454 int
455 ldap_int_sasl_bind(
456         LDAP                    *ld,
457         const char              *dn,
458         const char              *mechs,
459         LDAPControl             **sctrls,
460         LDAPControl             **cctrls,
461         unsigned                flags,
462         LDAP_SASL_INTERACT_PROC *interact,
463         void * defaults )
464 {
465         char *data;
466         const char *mech = NULL;
467         const char *pmech = NULL;
468         int                     saslrc, rc;
469         sasl_ssf_t              *ssf = NULL;
470         sasl_conn_t     *ctx;
471         sasl_interact_t *prompts = NULL;
472         unsigned credlen;
473         struct berval ccred;
474         ber_socket_t            sd;
475
476         Debug( LDAP_DEBUG_TRACE, "ldap_int_sasl_bind: %s\n",
477                 mechs ? mechs : "<null>", 0, 0 );
478
479         /* do a quick !LDAPv3 check... ldap_sasl_bind will do the rest. */
480         if (ld->ld_version < LDAP_VERSION3) {
481                 ld->ld_errno = LDAP_NOT_SUPPORTED;
482                 return ld->ld_errno;
483         }
484
485         ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd );
486
487         if ( sd == AC_SOCKET_INVALID ) {
488                 /* not connected yet */
489                 int rc;
490
491                 rc = ldap_open_defconn( ld );
492                 if( rc < 0 ) return ld->ld_errno;
493
494                 ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd );
495
496                 if( sd == AC_SOCKET_INVALID ) {
497                         ld->ld_errno = LDAP_LOCAL_ERROR;
498                         return ld->ld_errno;
499                 }
500         }   
501
502         ctx = ld->ld_defconn->lconn_sasl_ctx;
503
504         if( ctx == NULL ) {
505                 ld->ld_errno = LDAP_LOCAL_ERROR;
506                 return ld->ld_errno;
507         }
508
509         /* (re)set security properties */
510         sasl_setprop( ctx, SASL_SEC_PROPS,
511                 &ld->ld_options.ldo_sasl_secprops );
512
513         ccred.bv_val = NULL;
514         ccred.bv_len = 0;
515
516         do {
517                 saslrc = sasl_client_start( ctx,
518                         mechs,
519                         NULL,
520                         &prompts,
521                         &ccred.bv_val,
522                         &credlen,
523                         &mech );
524
525                 if( pmech == NULL && mech != NULL ) {
526                         pmech = mech;
527
528                         if( flags != LDAP_SASL_QUIET ) {
529                                 fprintf(stderr,
530                                         "SASL/%s authentication started\n",
531                                         pmech );
532                         }
533                 }
534
535                 if( saslrc == SASL_INTERACT ) {
536                         int res;
537                         if( !interact ) break;
538                         res = (interact)( ld, flags, defaults, prompts );
539                         if( res != LDAP_SUCCESS ) {
540                                 break;
541                         }
542                 }
543         } while ( saslrc == SASL_INTERACT );
544
545         ccred.bv_len = credlen;
546
547         if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
548                 ld->ld_errno = sasl_err2ldap( saslrc );
549                 return ld->ld_errno;
550         }
551
552         do {
553                 struct berval *scred;
554                 unsigned credlen;
555
556                 scred = NULL;
557
558                 rc = ldap_sasl_bind_s( ld, dn, mech, &ccred, sctrls, cctrls, &scred );
559
560                 if ( ccred.bv_val != NULL ) {
561                         LDAP_FREE( ccred.bv_val );
562                         ccred.bv_val = NULL;
563                 }
564
565                 if ( rc != LDAP_SUCCESS && rc != LDAP_SASL_BIND_IN_PROGRESS ) {
566                         if( scred ) {
567                                 /* and server provided us with data? */
568                                 Debug( LDAP_DEBUG_TRACE,
569                                         "ldap_int_sasl_bind: rc=%d sasl=%d len=%ld\n",
570                                         rc, saslrc, scred->bv_len );
571                                 ber_bvfree( scred );
572                         }
573                         return ld->ld_errno;
574                 }
575
576                 if( rc == LDAP_SUCCESS && saslrc == SASL_OK ) {
577                         /* we're done, no need to step */
578                         if( scred ) {
579                                 /* but server provided us with data! */
580                                 Debug( LDAP_DEBUG_TRACE,
581                                         "ldap_int_sasl_bind: rc=%d sasl=%d len=%ld\n",
582                                         rc, saslrc, scred->bv_len );
583                                 ber_bvfree( scred );
584                                 return ld->ld_errno = LDAP_LOCAL_ERROR;
585                         }
586                         break;
587                 }
588
589                 do {
590                         saslrc = sasl_client_step( ctx,
591                                 (scred == NULL) ? NULL : scred->bv_val,
592                                 (scred == NULL) ? 0 : scred->bv_len,
593                                 &prompts,
594                                 &ccred.bv_val,
595                                 &credlen );
596
597                         Debug( LDAP_DEBUG_TRACE, "sasl_client_start: %d\n",
598                                 saslrc, 0, 0 );
599
600                         if( saslrc == SASL_INTERACT ) {
601                                 int res;
602                                 if( !interact ) break;
603                                 res = (interact)( ld, flags, defaults, prompts );
604                                 if( res != LDAP_SUCCESS ) {
605                                         break;
606                                 }
607                         }
608                 } while ( saslrc == SASL_INTERACT );
609
610                 ccred.bv_len = credlen;
611                 ber_bvfree( scred );
612
613                 if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
614                         ld->ld_errno = sasl_err2ldap( saslrc );
615                         return ld->ld_errno;
616                 }
617         } while ( rc == LDAP_SASL_BIND_IN_PROGRESS );
618
619         if ( rc != LDAP_SUCCESS ) {
620                 return rc;
621         }
622
623         if ( saslrc != SASL_OK ) {
624                 return ld->ld_errno = sasl_err2ldap( saslrc );
625         }
626
627         if( flags != LDAP_SASL_QUIET ) {
628                 saslrc = sasl_getprop( ctx, SASL_USERNAME, (void **) &data );
629                 if( saslrc == SASL_OK && data && *data ) {
630                         fprintf( stderr, "SASL username: %s\n", data );
631                 }
632
633                 saslrc = sasl_getprop( ctx, SASL_REALM, (void **) &data );
634                 if( saslrc == SASL_OK && data && *data ) {
635                         fprintf( stderr, "SASL realm: %s\n", data );
636                 }
637         }
638
639         saslrc = sasl_getprop( ctx, SASL_SSF, (void **) &ssf );
640         if( saslrc == SASL_OK ) {
641                 if( flags != LDAP_SASL_QUIET ) {
642                         fprintf( stderr, "SASL SSF: %lu\n",
643                                 (unsigned long) *ssf );
644                 }
645
646                 if( ssf && *ssf ) {
647                         if( flags != LDAP_SASL_QUIET ) {
648                                 fprintf( stderr, "SASL installing layers\n" );
649                         }
650                         ldap_pvt_sasl_install( ld->ld_sb, ctx );
651                 }
652         }
653
654         return rc;
655 }
656
657 int ldap_pvt_sasl_secprops(
658         const char *in,
659         sasl_security_properties_t *secprops )
660 {
661         int i;
662         char **props = ldap_str2charray( in, "," );
663         unsigned sflags = 0;
664         int got_sflags = 0;
665         sasl_ssf_t max_ssf = 0;
666         int got_max_ssf = 0;
667         sasl_ssf_t min_ssf = 0;
668         int got_min_ssf = 0;
669         unsigned maxbufsize = 0;
670         int got_maxbufsize = 0;
671
672         if( props == NULL || secprops == NULL ) {
673                 return LDAP_PARAM_ERROR;
674         }
675
676         for( i=0; props[i]; i++ ) {
677                 if( !strcasecmp(props[i], "none") ) {
678                         got_sflags++;
679
680                 } else if( !strcasecmp(props[i], "noplain") ) {
681                         got_sflags++;
682                         sflags |= SASL_SEC_NOPLAINTEXT;
683
684                 } else if( !strcasecmp(props[i], "noactive") ) {
685                         got_sflags++;
686                         sflags |= SASL_SEC_NOACTIVE;
687
688                 } else if( !strcasecmp(props[i], "nodict") ) {
689                         got_sflags++;
690                         sflags |= SASL_SEC_NODICTIONARY;
691
692                 } else if( !strcasecmp(props[i], "forwardsec") ) {
693                         got_sflags++;
694                         sflags |= SASL_SEC_FORWARD_SECRECY;
695
696                 } else if( !strcasecmp(props[i], "noanonymous")) {
697                         got_sflags++;
698                         sflags |= SASL_SEC_NOANONYMOUS;
699
700                 } else if( !strcasecmp(props[i], "passcred") ) {
701                         got_sflags++;
702                         sflags |= SASL_SEC_PASS_CREDENTIALS;
703
704                 } else if( !strncasecmp(props[i],
705                         "minssf=", sizeof("minssf")) )
706                 {
707                         if( isdigit( props[i][sizeof("minssf")] ) ) {
708                                 got_min_ssf++;
709                                 min_ssf = atoi( &props[i][sizeof("minssf")] );
710                         } else {
711                                 return LDAP_NOT_SUPPORTED;
712                         }
713
714                 } else if( !strncasecmp(props[i],
715                         "maxssf=", sizeof("maxssf")) )
716                 {
717                         if( isdigit( props[i][sizeof("maxssf")] ) ) {
718                                 got_max_ssf++;
719                                 max_ssf = atoi( &props[i][sizeof("maxssf")] );
720                         } else {
721                                 return LDAP_NOT_SUPPORTED;
722                         }
723
724                 } else if( !strncasecmp(props[i],
725                         "maxbufsize=", sizeof("maxbufsize")) )
726                 {
727                         if( isdigit( props[i][sizeof("maxbufsize")] ) ) {
728                                 got_maxbufsize++;
729                                 maxbufsize = atoi( &props[i][sizeof("maxbufsize")] );
730                         } else {
731                                 return LDAP_NOT_SUPPORTED;
732                         }
733
734                 } else {
735                         return LDAP_NOT_SUPPORTED;
736                 }
737         }
738
739         if(got_sflags) {
740                 secprops->security_flags = sflags;
741         }
742         if(got_min_ssf) {
743                 secprops->min_ssf = min_ssf;
744         }
745         if(got_max_ssf) {
746                 secprops->max_ssf = max_ssf;
747         }
748         if(got_maxbufsize) {
749                 secprops->maxbufsize = maxbufsize;
750         }
751
752         ldap_charray_free( props );
753         return LDAP_SUCCESS;
754 }
755
756 int
757 ldap_int_sasl_config( struct ldapoptions *lo, int option, const char *arg )
758 {
759         int rc;
760
761         switch( option ) {
762         case LDAP_OPT_X_SASL_SECPROPS:
763                 rc = ldap_pvt_sasl_secprops( arg, &lo->ldo_sasl_secprops );
764                 if( rc == LDAP_SUCCESS ) return 0;
765         }
766
767         return -1;
768 }
769
770 int
771 ldap_int_sasl_get_option( LDAP *ld, int option, void *arg )
772 {
773         if ( ld == NULL )
774                 return -1;
775
776         switch ( option ) {
777                 case LDAP_OPT_X_SASL_MECH: {
778                         *(char **)arg = ld->ld_options.ldo_def_sasl_mech
779                                 ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_mech ) : NULL;
780                 } break;
781                 case LDAP_OPT_X_SASL_REALM: {
782                         *(char **)arg = ld->ld_options.ldo_def_sasl_realm
783                                 ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_realm ) : NULL;
784                 } break;
785                 case LDAP_OPT_X_SASL_AUTHCID: {
786                         *(char **)arg = ld->ld_options.ldo_def_sasl_authcid
787                                 ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_authcid ) : NULL;
788                 } break;
789                 case LDAP_OPT_X_SASL_AUTHZID: {
790                         *(char **)arg = ld->ld_options.ldo_def_sasl_authzid
791                                 ? LDAP_STRDUP( ld->ld_options.ldo_def_sasl_authzid ) : NULL;
792                 } break;
793
794                 case LDAP_OPT_X_SASL_SSF: {
795                         int sc;
796                         sasl_ssf_t      *ssf;
797                         sasl_conn_t *ctx;
798
799                         if( ld->ld_defconn == NULL ) {
800                                 return -1;
801                         }
802
803                         ctx = ld->ld_defconn->lconn_sasl_ctx;
804
805                         if ( ctx == NULL ) {
806                                 return -1;
807                         }
808
809                         sc = sasl_getprop( ctx, SASL_SSF,
810                                 (void **) &ssf );
811
812                         if ( sc != SASL_OK ) {
813                                 return -1;
814                         }
815
816                         *(ber_len_t *)arg = *ssf;
817                 } break;
818
819                 case LDAP_OPT_X_SASL_SSF_EXTERNAL:
820                         /* this option is write only */
821                         return -1;
822
823                 case LDAP_OPT_X_SASL_SSF_MIN:
824                         *(ber_len_t *)arg = ld->ld_options.ldo_sasl_secprops.min_ssf;
825                         break;
826                 case LDAP_OPT_X_SASL_SSF_MAX:
827                         *(ber_len_t *)arg = ld->ld_options.ldo_sasl_secprops.max_ssf;
828                         break;
829                 case LDAP_OPT_X_SASL_MAXBUFSIZE:
830                         *(ber_len_t *)arg = ld->ld_options.ldo_sasl_secprops.maxbufsize;
831                         break;
832
833                 case LDAP_OPT_X_SASL_SECPROPS:
834                         /* this option is write only */
835                         return -1;
836
837                 default:
838                         return -1;
839         }
840         return 0;
841 }
842
843 int
844 ldap_int_sasl_set_option( LDAP *ld, int option, void *arg )
845 {
846         if ( ld == NULL )
847                 return -1;
848
849         switch ( option ) {
850         case LDAP_OPT_X_SASL_SSF:
851                 /* This option is read-only */
852                 return -1;
853
854         case LDAP_OPT_X_SASL_SSF_EXTERNAL: {
855                 int sc;
856                 sasl_external_properties_t extprops;
857                 sasl_conn_t *ctx;
858
859                 if( ld->ld_defconn == NULL ) {
860                         return -1;
861                 }
862
863                 ctx = ld->ld_defconn->lconn_sasl_ctx;
864
865                 if ( ctx == NULL ) {
866                         return -1;
867                 }
868
869                 memset(&extprops, 0L, sizeof(extprops));
870
871                 extprops.ssf = * (ber_len_t *) arg;
872
873                 sc = sasl_setprop( ctx, SASL_SSF_EXTERNAL,
874                         (void *) &extprops );
875
876                 if ( sc != SASL_OK ) {
877                         return -1;
878                 }
879                 } break;
880
881         case LDAP_OPT_X_SASL_SSF_MIN:
882                 ld->ld_options.ldo_sasl_secprops.min_ssf = *(ber_len_t *)arg;
883                 break;
884         case LDAP_OPT_X_SASL_SSF_MAX:
885                 ld->ld_options.ldo_sasl_secprops.max_ssf = *(ber_len_t *)arg;
886                 break;
887         case LDAP_OPT_X_SASL_MAXBUFSIZE:
888                 ld->ld_options.ldo_sasl_secprops.maxbufsize = *(ber_len_t *)arg;
889                 break;
890
891         case LDAP_OPT_X_SASL_SECPROPS: {
892                 int sc;
893                 sc = ldap_pvt_sasl_secprops( (char *) arg,
894                         &ld->ld_options.ldo_sasl_secprops );
895
896                 return sc == LDAP_SUCCESS ? 0 : -1;
897                 }
898
899         default:
900                 return -1;
901         }
902         return 0;
903 }
904
905 #ifdef LDAP_R_COMPILE
906 void *ldap_pvt_sasl_mutex_new(void)
907 {
908         ldap_pvt_thread_mutex_t *mutex;
909
910         mutex = (ldap_pvt_thread_mutex_t *) LDAP_MALLOC(
911                 sizeof(ldap_pvt_thread_mutex_t) );
912
913         if ( ldap_pvt_thread_mutex_init( mutex ) == 0 ) {
914                 return mutex;
915         }
916         return NULL;
917 }
918
919 int ldap_pvt_sasl_mutex_lock(void *mutex)
920 {
921         return ldap_pvt_thread_mutex_lock( (ldap_pvt_thread_mutex_t *)mutex )
922                 ? SASL_FAIL : SASL_OK;
923 }
924
925 int ldap_pvt_sasl_mutex_unlock(void *mutex)
926 {
927         return ldap_pvt_thread_mutex_unlock( (ldap_pvt_thread_mutex_t *)mutex )
928                 ? SASL_FAIL : SASL_OK;
929 }
930
931 void ldap_pvt_sasl_mutex_dispose(void *mutex)
932 {
933         (void) ldap_pvt_thread_mutex_destroy( (ldap_pvt_thread_mutex_t *)mutex );
934         LDAP_FREE( mutex );
935 }
936 #endif
937
938 #else
939 int ldap_int_sasl_init( void )
940 { return LDAP_SUCCESS; }
941
942 int ldap_int_sasl_close( LDAP *ld, LDAPConn *lc )
943 { return LDAP_SUCCESS; }
944
945 int
946 ldap_int_sasl_bind(
947         LDAP                    *ld,
948         const char              *dn,
949         const char              *mechs,
950         LDAPControl             **sctrls,
951         LDAPControl             **cctrls,
952         unsigned                flags,
953         LDAP_SASL_INTERACT_PROC *interact,
954         void * defaults )
955 { return LDAP_NOT_SUPPORTED; }
956 #endif /* HAVE_CYRUS_SASL */