home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ldapsdk.zip / libraries / libldap / sasl.c < prev    next >
C/C++ Source or Header  |  2001-07-22  |  9KB  |  459 lines

  1. /* $OpenLDAP: pkg/ldap/libraries/libldap/sasl.c,v 1.1.4.9 2001/07/21 19:01:40 kurt Exp $ */
  2. /*
  3.  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
  4.  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
  5.  */
  6.  
  7. /*
  8.  *    BindRequest ::= SEQUENCE {
  9.  *        version        INTEGER,
  10.  *        name        DistinguishedName,     -- who
  11.  *        authentication    CHOICE {
  12.  *            simple        [0] OCTET STRING -- passwd
  13. #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
  14.  *            krbv42ldap    [1] OCTET STRING
  15.  *            krbv42dsa    [2] OCTET STRING
  16. #endif
  17.  *            sasl        [3] SaslCredentials    -- LDAPv3
  18.  *        }
  19.  *    }
  20.  *
  21.  *    BindResponse ::= SEQUENCE {
  22.  *        COMPONENTS OF LDAPResult,
  23.  *        serverSaslCreds        OCTET STRING OPTIONAL -- LDAPv3
  24.  *    }
  25.  *
  26.  */
  27.  
  28. #include "portable.h"
  29.  
  30. #include <stdlib.h>
  31. #include <stdio.h>
  32.  
  33. #include <ac/socket.h>
  34. #include <ac/string.h>
  35. #include <ac/time.h>
  36. #include <ac/errno.h>
  37.  
  38. #include "ldap-int.h"
  39.  
  40. /*
  41.  * ldap_sasl_bind - bind to the ldap server (and X.500).
  42.  * The dn (usually NULL), mechanism, and credentials are provided.
  43.  * The message id of the request initiated is provided upon successful
  44.  * (LDAP_SUCCESS) return.
  45.  *
  46.  * Example:
  47.  *    ldap_sasl_bind( ld, NULL, "mechanism",
  48.  *        cred, NULL, NULL, &msgid )
  49.  */
  50.  
  51. int
  52. ldap_sasl_bind(
  53.     LDAP            *ld,
  54.     LDAP_CONST char    *dn,
  55.     LDAP_CONST char    *mechanism,
  56.     struct berval    *cred,
  57.     LDAPControl        **sctrls,
  58.     LDAPControl        **cctrls,
  59.     int                *msgidp )
  60. {
  61.     BerElement    *ber;
  62.     int rc;
  63.  
  64.     Debug( LDAP_DEBUG_TRACE, "ldap_sasl_bind\n", 0, 0, 0 );
  65.  
  66.     assert( ld != NULL );
  67.     assert( LDAP_VALID( ld ) );
  68.     assert( msgidp != NULL );
  69.  
  70.     /* check client controls */
  71.     rc = ldap_int_client_controls( ld, cctrls );
  72.     if( rc != LDAP_SUCCESS ) return rc;
  73.  
  74.     if( msgidp == NULL ) {
  75.         ld->ld_errno = LDAP_PARAM_ERROR;
  76.         return ld->ld_errno;
  77.     }
  78.  
  79.     if( mechanism == LDAP_SASL_SIMPLE ) {
  80.         if( dn == NULL && cred != NULL ) {
  81.             /* use default binddn */
  82.             dn = ld->ld_defbinddn;
  83.         }
  84.  
  85.     } else if( ld->ld_version < LDAP_VERSION3 ) {
  86.         ld->ld_errno = LDAP_NOT_SUPPORTED;
  87.         return ld->ld_errno;
  88.     }
  89.  
  90.     if ( dn == NULL ) {
  91.         dn = "";
  92.     }
  93.  
  94.     /* create a message to send */
  95.     if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
  96.         ld->ld_errno = LDAP_NO_MEMORY;
  97.         return ld->ld_errno;
  98.     }
  99.  
  100.     assert( BER_VALID( ber ) );
  101.  
  102.     if( mechanism == LDAP_SASL_SIMPLE ) {
  103.         /* simple bind */
  104.         rc = ber_printf( ber, "{it{istON}" /*}*/,
  105.             ++ld->ld_msgid, LDAP_REQ_BIND,
  106.             ld->ld_version, dn, LDAP_AUTH_SIMPLE,
  107.             cred );
  108.         
  109.     } else if ( cred == NULL || !cred->bv_len ) {
  110.         /* SASL bind w/o creditials */
  111.         rc = ber_printf( ber, "{it{ist{sN}N}" /*}*/,
  112.             ++ld->ld_msgid, LDAP_REQ_BIND,
  113.             ld->ld_version, dn, LDAP_AUTH_SASL,
  114.             mechanism );
  115.  
  116.     } else {
  117.         /* SASL bind w/ creditials */
  118.         rc = ber_printf( ber, "{it{ist{sON}N}" /*}*/,
  119.             ++ld->ld_msgid, LDAP_REQ_BIND,
  120.             ld->ld_version, dn, LDAP_AUTH_SASL,
  121.             mechanism, cred );
  122.     }
  123.  
  124.     if( rc == -1 ) {
  125.         ld->ld_errno = LDAP_ENCODING_ERROR;
  126.         ber_free( ber, 1 );
  127.         return( -1 );
  128.     }
  129.  
  130.     /* Put Server Controls */
  131.     if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) {
  132.         ber_free( ber, 1 );
  133.         return ld->ld_errno;
  134.     }
  135.  
  136.     if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) {
  137.         ld->ld_errno = LDAP_ENCODING_ERROR;
  138.         ber_free( ber, 1 );
  139.         return ld->ld_errno;
  140.     }
  141.  
  142. #ifndef LDAP_NOCACHE
  143.     if ( ld->ld_cache != NULL ) {
  144.         ldap_flush_cache( ld );
  145.     }
  146. #endif /* !LDAP_NOCACHE */
  147.  
  148.     /* send the message */
  149.     *msgidp = ldap_send_initial_request( ld, LDAP_REQ_BIND, dn, ber );
  150.  
  151.     if(*msgidp < 0)
  152.         return ld->ld_errno;
  153.  
  154.     return LDAP_SUCCESS;
  155. }
  156.  
  157.  
  158. int
  159. ldap_sasl_bind_s(
  160.     LDAP            *ld,
  161.     LDAP_CONST char    *dn,
  162.     LDAP_CONST char    *mechanism,
  163.     struct berval    *cred,
  164.     LDAPControl        **sctrls,
  165.     LDAPControl        **cctrls,
  166.     struct berval    **servercredp )
  167. {
  168.     int    rc, msgid;
  169.     LDAPMessage    *result;
  170.     struct berval    *scredp = NULL;
  171.  
  172.     Debug( LDAP_DEBUG_TRACE, "ldap_sasl_bind_s\n", 0, 0, 0 );
  173.  
  174.     /* do a quick !LDAPv3 check... ldap_sasl_bind will do the rest. */
  175.     if( servercredp != NULL ) {
  176.         if (ld->ld_version < LDAP_VERSION3) {
  177.             ld->ld_errno = LDAP_NOT_SUPPORTED;
  178.             return ld->ld_errno;
  179.         }
  180.         *servercredp = NULL;
  181.     }
  182.  
  183.     rc = ldap_sasl_bind( ld, dn, mechanism, cred, sctrls, cctrls, &msgid );
  184.  
  185.     if ( rc != LDAP_SUCCESS ) {
  186.         return( rc );
  187.     }
  188.  
  189.     if ( ldap_result( ld, msgid, 1, NULL, &result ) == -1 ) {
  190.         return( ld->ld_errno );    /* ldap_result sets ld_errno */
  191.     }
  192.  
  193.     /* parse the results */
  194.     scredp = NULL;
  195.     if( servercredp != NULL ) {
  196.         rc = ldap_parse_sasl_bind_result( ld, result, &scredp, 0 );
  197.     }
  198.  
  199.     if ( rc != LDAP_SUCCESS && rc != LDAP_SASL_BIND_IN_PROGRESS ) {
  200.         ldap_msgfree( result );
  201.         return( rc );
  202.     }
  203.  
  204.     rc = ldap_result2error( ld, result, 1 );
  205.  
  206.     if ( rc == LDAP_SUCCESS || rc == LDAP_SASL_BIND_IN_PROGRESS ) {
  207.         if( servercredp != NULL ) {
  208.             *servercredp = scredp;
  209.             scredp = NULL;
  210.         }
  211.     }
  212.  
  213.     if ( scredp != NULL ) {
  214.         ber_bvfree(scredp);
  215.     }
  216.  
  217.     return rc;
  218. }
  219.  
  220.  
  221. /*
  222. * Parse BindResponse:
  223. *
  224. *   BindResponse ::= [APPLICATION 1] SEQUENCE {
  225. *     COMPONENTS OF LDAPResult,
  226. *     serverSaslCreds  [7] OCTET STRING OPTIONAL }
  227. *
  228. *   LDAPResult ::= SEQUENCE {
  229. *     resultCode      ENUMERATED,
  230. *     matchedDN       LDAPDN,
  231. *     errorMessage    LDAPString,
  232. *     referral        [3] Referral OPTIONAL }
  233. */
  234.  
  235. int
  236. ldap_parse_sasl_bind_result(
  237.     LDAP            *ld,
  238.     LDAPMessage        *res,
  239.     struct berval    **servercredp,
  240.     int                freeit )
  241. {
  242.     ber_int_t errcode;
  243.     struct berval* scred;
  244.  
  245.     ber_tag_t tag;
  246.     BerElement    *ber;
  247.  
  248.     Debug( LDAP_DEBUG_TRACE, "ldap_parse_sasl_bind_result\n", 0, 0, 0 );
  249.  
  250.     assert( ld != NULL );
  251.     assert( LDAP_VALID( ld ) );
  252.     assert( res != NULL );
  253.  
  254.     if ( ld == NULL || res == NULL ) {
  255.         return LDAP_PARAM_ERROR;
  256.     }
  257.  
  258.     if( servercredp != NULL ) {
  259.         if( ld->ld_version < LDAP_VERSION2 ) {
  260.             return LDAP_NOT_SUPPORTED;
  261.         }
  262.         *servercredp = NULL;
  263.     }
  264.  
  265.     if( res->lm_msgtype != LDAP_RES_BIND ) {
  266.         ld->ld_errno = LDAP_PARAM_ERROR;
  267.         return ld->ld_errno;
  268.     }
  269.  
  270.     scred = NULL;
  271.  
  272.     if ( ld->ld_error ) {
  273.         LDAP_FREE( ld->ld_error );
  274.         ld->ld_error = NULL;
  275.     }
  276.     if ( ld->ld_matched ) {
  277.         LDAP_FREE( ld->ld_matched );
  278.         ld->ld_matched = NULL;
  279.     }
  280.  
  281.     /* parse results */
  282.  
  283.     ber = ber_dup( res->lm_ber );
  284.  
  285.     if( ber == NULL ) {
  286.         ld->ld_errno = LDAP_NO_MEMORY;
  287.         return ld->ld_errno;
  288.     }
  289.  
  290.     if ( ld->ld_version < LDAP_VERSION2 ) {
  291.         tag = ber_scanf( ber, "{ia}",
  292.             &errcode, &ld->ld_error );
  293.  
  294.         if( tag == LBER_ERROR ) {
  295.             ber_free( ber, 0 );
  296.             ld->ld_errno = LDAP_DECODING_ERROR;
  297.             return ld->ld_errno;
  298.         }
  299.  
  300.     } else {
  301.         ber_len_t len;
  302.  
  303.         tag = ber_scanf( ber, "{iaa" /*}*/,
  304.             &errcode, &ld->ld_matched, &ld->ld_error );
  305.  
  306.         if( tag == LBER_ERROR ) {
  307.             ber_free( ber, 0 );
  308.             ld->ld_errno = LDAP_DECODING_ERROR;
  309.             return ld->ld_errno;
  310.         }
  311.  
  312.         tag = ber_peek_tag(ber, &len);
  313.  
  314.         if( tag == LDAP_TAG_REFERRAL ) {
  315.             /* skip 'em */
  316.             if( ber_scanf( ber, "x" ) == LBER_ERROR ) {
  317.                 ber_free( ber, 0 );
  318.                 ld->ld_errno = LDAP_DECODING_ERROR;
  319.                 return ld->ld_errno;
  320.             }
  321.  
  322.             tag = ber_peek_tag(ber, &len);
  323.         }
  324.  
  325.         if( tag == LDAP_TAG_SASL_RES_CREDS ) {
  326.             if( ber_scanf( ber, "O", &scred ) == LBER_ERROR ) {
  327.                 ber_free( ber, 0 );
  328.                 ld->ld_errno = LDAP_DECODING_ERROR;
  329.                 return ld->ld_errno;
  330.             }
  331.         }
  332.     }
  333.  
  334.     ber_free( ber, 0 );
  335.  
  336.     if ( servercredp != NULL ) {
  337.         *servercredp = scred;
  338.  
  339.     } else if ( scred != NULL ) {
  340.         ber_bvfree( scred );
  341.     }
  342.  
  343.     ld->ld_errno = errcode;
  344.  
  345.     if ( freeit ) {
  346.         ldap_msgfree( res );
  347.     }
  348.  
  349.     return( ld->ld_errno );
  350. }
  351.  
  352. int
  353. ldap_pvt_sasl_getmechs ( LDAP *ld, char **pmechlist )
  354. {
  355.     /* we need to query the server for supported mechs anyway */
  356.     LDAPMessage *res, *e;
  357.     char *attrs[] = { "supportedSASLMechanisms", NULL };
  358.     char **values, *mechlist;
  359.     int rc;
  360.  
  361.     Debug( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_getmech\n", 0, 0, 0 );
  362.  
  363.     rc = ldap_search_s( ld, "", LDAP_SCOPE_BASE,
  364.         NULL, attrs, 0, &res );
  365.  
  366.     if ( rc != LDAP_SUCCESS ) {
  367.         return ld->ld_errno;
  368.     }
  369.         
  370.     e = ldap_first_entry( ld, res );
  371.     if ( e == NULL ) {
  372.         ldap_msgfree( res );
  373.         if ( ld->ld_errno == LDAP_SUCCESS ) {
  374.             ld->ld_errno = LDAP_NO_SUCH_OBJECT;
  375.         }
  376.         return ld->ld_errno;
  377.     }
  378.  
  379.     values = ldap_get_values( ld, e, "supportedSASLMechanisms" );
  380.     if ( values == NULL ) {
  381.         ldap_msgfree( res );
  382.         ld->ld_errno = LDAP_NO_SUCH_ATTRIBUTE;
  383.         return ld->ld_errno;
  384.     }
  385.  
  386.     mechlist = ldap_charray2str( values, " " );
  387.     if ( mechlist == NULL ) {
  388.         LDAP_VFREE( values );
  389.         ldap_msgfree( res );
  390.         ld->ld_errno = LDAP_NO_MEMORY;
  391.         return ld->ld_errno;
  392.     } 
  393.  
  394.     LDAP_VFREE( values );
  395.     ldap_msgfree( res );
  396.  
  397.     *pmechlist = mechlist;
  398.  
  399.     return LDAP_SUCCESS;
  400. }
  401.  
  402. /*
  403.  * ldap_sasl_interactive_bind_s - interactive SASL authentication
  404.  *
  405.  * This routine uses interactive callbacks.
  406.  *
  407.  * LDAP_SUCCESS is returned upon success, the ldap error code
  408.  * otherwise.
  409.  */
  410. int
  411. ldap_sasl_interactive_bind_s(
  412.     LDAP *ld,
  413.     LDAP_CONST char *dn, /* usually NULL */
  414.     LDAP_CONST char *mechs,
  415.     LDAPControl **serverControls,
  416.     LDAPControl **clientControls,
  417.     unsigned flags,
  418.     LDAP_SASL_INTERACT_PROC *interact,
  419.     void *defaults )
  420. {
  421.     int rc;
  422.  
  423. #if defined( LDAP_R_COMPILE ) && defined( HAVE_CYRUS_SASL )
  424.     ldap_pvt_thread_mutex_lock( &ldap_int_sasl_mutex );
  425. #endif
  426.  
  427.     if( mechs == NULL || *mechs == '\0' ) {
  428.         char *smechs;
  429.  
  430.         rc = ldap_pvt_sasl_getmechs( ld, &smechs );
  431.  
  432.         if( rc != LDAP_SUCCESS ) {
  433.             goto done;
  434.         }
  435.  
  436.         Debug( LDAP_DEBUG_TRACE,
  437.             "ldap_interactive_sasl_bind_s: server supports: %s\n",
  438.             smechs, 0, 0 );
  439.  
  440.         mechs = smechs;
  441.  
  442.     } else {
  443.         Debug( LDAP_DEBUG_TRACE,
  444.             "ldap_interactive_sasl_bind_s: user selected: %s\n",
  445.             mechs, 0, 0 );
  446.     }
  447.  
  448.     rc = ldap_int_sasl_bind( ld, dn, mechs,
  449.         serverControls, clientControls,
  450.         flags, interact, defaults );
  451.  
  452. done:
  453. #if defined( LDAP_R_COMPILE ) && defined( HAVE_CYRUS_SASL )
  454.     ldap_pvt_thread_mutex_unlock( &ldap_int_sasl_mutex );
  455. #endif
  456.  
  457.     return rc;
  458. }
  459.