home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ldapsdk.zip / libraries / libldap / cyrus.c < prev    next >
C/C++ Source or Header  |  2001-09-18  |  22KB  |  1,010 lines

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