]> git.sur5r.net Git - openldap/blobdiff - libraries/libldap/sasl.c
Update SASL code to reuse context through life of session.
[openldap] / libraries / libldap / sasl.c
index 81a97dd593d945bf7cc913ccc370a23946e99a60..3168692582dfb7655ee4d0d8c3856c7380e51eb5 100644 (file)
@@ -1,6 +1,6 @@
 /* $OpenLDAP$ */
 /*
- * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
+ * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
  */
 
@@ -10,7 +10,7 @@
  *             name            DistinguishedName,       -- who
  *             authentication  CHOICE {
  *                     simple          [0] OCTET STRING -- passwd
-#ifdef HAVE_KERBEROS
+#ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
  *                     krbv42ldap      [1] OCTET STRING
  *                     krbv42dsa       [2] OCTET STRING
 #endif
 
 #include "portable.h"
 
+#include <stdlib.h>
 #include <stdio.h>
 
 #include <ac/socket.h>
 #include <ac/string.h>
 #include <ac/time.h>
+#include <ac/errno.h>
 
 #include "ldap-int.h"
 
 
 /*
- * ldap_sasl_bind - bind to the ldap server (and X.500).  The dn, mechanism, and
- * credentials of the entry to which to bind are supplied.  The message id
- * of the request initiated is provided upon successful (LDAP_SUCCESS) return.
+ * ldap_sasl_bind - bind to the ldap server (and X.500).
+ * The dn (usually NULL), mechanism, and credentials are provided.
+ * The message id of the request initiated is provided upon successful
+ * (LDAP_SUCCESS) return.
  *
  * Example:
- *     ldap_sasl_bind( ld, "cn=manager, o=university of michigan, c=us",
- *         "mechanism", "secret", NULL, NULL, &msgid )
+ *     ldap_sasl_bind( ld, NULL, "mechanism",
+ *             cred, NULL, NULL, &msgid )
  */
 
 int
@@ -70,15 +73,20 @@ ldap_sasl_bind(
                return ld->ld_errno;
        }
 
-       if( mechanism != LDAP_SASL_SIMPLE
-               && ld->ld_version < LDAP_VERSION3)
-       {
+       if( mechanism == LDAP_SASL_SIMPLE ) {
+               if( dn == NULL && cred != NULL ) {
+                       /* use default binddn */
+                       dn = ld->ld_defbinddn;
+               }
+
+       } else if( ld->ld_version < LDAP_VERSION3 ) {
                ld->ld_errno = LDAP_NOT_SUPPORTED;
                return ld->ld_errno;
        }
 
-       if ( dn == NULL )
+       if ( dn == NULL ) {
                dn = "";
+       }
 
        /* create a message to send */
        if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
@@ -90,21 +98,21 @@ ldap_sasl_bind(
 
        if( mechanism == LDAP_SASL_SIMPLE ) {
                /* simple bind */
-               rc = ber_printf( ber, "{it{istO}" /*}*/,
+               rc = ber_printf( ber, "{it{istON}" /*}*/,
                        ++ld->ld_msgid, LDAP_REQ_BIND,
                        ld->ld_version, dn, LDAP_AUTH_SIMPLE,
                        cred );
                
        } else if ( cred == NULL ) {
                /* SASL bind w/o creditials */
-               rc = ber_printf( ber, "{it{ist{s}}" /*}*/,
+               rc = ber_printf( ber, "{it{ist{sN}N}" /*}*/,
                        ++ld->ld_msgid, LDAP_REQ_BIND,
                        ld->ld_version, dn, LDAP_AUTH_SASL,
                        mechanism );
 
        } else {
                /* SASL bind w/ creditials */
-               rc = ber_printf( ber, "{it{ist{sO}}" /*}*/,
+               rc = ber_printf( ber, "{it{ist{sON}N}" /*}*/,
                        ++ld->ld_msgid, LDAP_REQ_BIND,
                        ld->ld_version, dn, LDAP_AUTH_SASL,
                        mechanism, cred );
@@ -122,7 +130,7 @@ ldap_sasl_bind(
                return ld->ld_errno;
        }
 
-       if ( ber_printf( ber, /*{*/ "}" ) == -1 ) {
+       if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) {
                ld->ld_errno = LDAP_ENCODING_ERROR;
                ber_free( ber, 1 );
                return ld->ld_errno;
@@ -143,16 +151,6 @@ ldap_sasl_bind(
        return LDAP_SUCCESS;
 }
 
-/*
- * ldap_sasl_bind_s - bind to the ldap server (and X.500) using simple
- * authentication.  The dn and password of the entry to which to bind are
- * supplied.  LDAP_SUCCESS is returned upon success, the ldap error code
- * otherwise.
- *
- * Example:
- *     ldap_sasl_bind_s( ld, "cn=manager, o=university of michigan, c=us",
- *         "mechanism", "secret", NULL, NULL, &servercred )
- */
 
 int
 ldap_sasl_bind_s(
@@ -195,19 +193,21 @@ ldap_sasl_bind_s(
                rc = ldap_parse_sasl_bind_result( ld, result, &scredp, 0 );
        }
 
-       if( rc != LDAP_SUCCESS ) {
+       if ( rc != LDAP_SUCCESS && rc != LDAP_SASL_BIND_IN_PROGRESS ) {
                ldap_msgfree( result );
                return( rc );
        }
 
        rc = ldap_result2error( ld, result, 1 );
 
-       if( rc == LDAP_SUCCESS ) {
+       if ( rc == LDAP_SUCCESS || rc == LDAP_SASL_BIND_IN_PROGRESS ) {
                if( servercredp != NULL ) {
                        *servercredp = scredp;
+                       scredp = NULL;
                }
+       }
 
-       } else if (scredp != NULL ) {
+       if ( scredp != NULL ) {
                ber_bvfree(scredp);
        }
 
@@ -216,18 +216,18 @@ ldap_sasl_bind_s(
 
 
 /*
- * Parse BindResponse:
- *
- *   BindResponse ::= [APPLICATION 1] SEQUENCE {
- *     COMPONENTS OF LDAPResult,
- *     serverSaslCreds  [7] OCTET STRING OPTIONAL }
- *
- *   LDAPResult ::= SEQUENCE {
- *     resultCode      ENUMERATED,
- *     matchedDN       LDAPDN,
- *     errorMessage    LDAPString,
- *     referral        [3] Referral OPTIONAL }
- */
+* Parse BindResponse:
+*
+*   BindResponse ::= [APPLICATION 1] SEQUENCE {
+*     COMPONENTS OF LDAPResult,
+*     serverSaslCreds  [7] OCTET STRING OPTIONAL }
+*
+*   LDAPResult ::= SEQUENCE {
+*     resultCode      ENUMERATED,
+*     matchedDN       LDAPDN,
+*     errorMessage    LDAPString,
+*     referral        [3] Referral OPTIONAL }
+*/
 
 int
 ldap_parse_sasl_bind_result(
@@ -252,14 +252,14 @@ ldap_parse_sasl_bind_result(
                return LDAP_PARAM_ERROR;
        }
 
-       if(servercredp != NULL) {
+       if( servercredp != NULL ) {
                if( ld->ld_version < LDAP_VERSION2 ) {
                        return LDAP_NOT_SUPPORTED;
                }
                *servercredp = NULL;
        }
 
-       if( res->lm_msgtype == LDAP_RES_BIND ) {
+       if( res->lm_msgtype != LDAP_RES_BIND ) {
                ld->ld_errno = LDAP_PARAM_ERROR;
                return ld->ld_errno;
        }
@@ -345,3 +345,97 @@ ldap_parse_sasl_bind_result(
 
        return( ld->ld_errno );
 }
+
+int
+ldap_pvt_sasl_getmechs ( LDAP *ld, char **pmechlist )
+{
+       /* we need to query the server for supported mechs anyway */
+       LDAPMessage *res, *e;
+       char *attrs[] = { "supportedSASLMechanisms", NULL };
+       char **values, *mechlist;
+       int rc;
+
+       Debug( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_getmech\n", 0, 0, 0 );
+
+       rc = ldap_search_s( ld, NULL, LDAP_SCOPE_BASE,
+               NULL, attrs, 0, &res );
+
+       if ( rc != LDAP_SUCCESS ) {
+               return ld->ld_errno;
+       }
+               
+       e = ldap_first_entry( ld, res );
+       if ( e == NULL ) {
+               if ( ld->ld_errno == LDAP_SUCCESS ) {
+                       ld->ld_errno = LDAP_UNAVAILABLE;
+               }
+               return ld->ld_errno;
+       }
+
+       values = ldap_get_values( ld, e, "supportedSASLMechanisms" );
+       if ( values == NULL ) {
+               ld->ld_errno = LDAP_NO_SUCH_ATTRIBUTE;
+               ldap_msgfree( res );
+               return ld->ld_errno;
+       }
+
+       mechlist = ldap_charray2str( values, " " );
+       if ( mechlist == NULL ) {
+               ld->ld_errno = LDAP_NO_MEMORY;
+               LDAP_VFREE( values );
+               ldap_msgfree( res );
+               return ld->ld_errno;
+       } 
+
+       LDAP_VFREE( values );
+       ldap_msgfree( res );
+
+       *pmechlist = mechlist;
+
+       return LDAP_SUCCESS;
+}
+
+/*
+ * ldap_sasl_interactive_bind_s - interactive SASL authentication
+ *
+ * This routine uses interactive callbacks.
+ *
+ * LDAP_SUCCESS is returned upon success, the ldap error code
+ * otherwise.
+ */
+int
+ldap_sasl_interactive_bind_s(
+       LDAP *ld,
+       LDAP_CONST char *dn, /* usually NULL */
+       LDAP_CONST char *mechs,
+       LDAPControl **serverControls,
+       LDAPControl **clientControls)
+{
+       int rc;
+
+       if( mechs == NULL || *mechs == '\0' ) {
+               char *smechs;
+
+               rc = ldap_pvt_sasl_getmechs( ld, &smechs );
+
+               if( rc != LDAP_SUCCESS ) {
+                       return rc;
+               }
+
+               Debug( LDAP_DEBUG_TRACE,
+                       "ldap_interactive_sasl_bind_s: server supports: %s\n",
+                       smechs, 0, 0 );
+
+               mechs = smechs;
+
+       } else {
+               Debug( LDAP_DEBUG_TRACE,
+                       "ldap_interactive_sasl_bind_s: user selected: %s\n",
+                       mechs, 0, 0 );
+       }
+
+       rc = ldap_int_sasl_bind( ld, dn, mechs,
+               serverControls, clientControls );
+
+       return rc;
+}