//Sample code file: var/ndk/webBuildengine/tmp/viewable_samples/a4ad0b48-dd95-46b6-8289-721e99c8dc76/nmas_client/saslbind.c

//Warning: This code has been marked up for HTML


/**************************************************************************
*  Novell Software Developer Kit
*
*  Copyright (C) 2002-2003 Novell, Inc. All Rights Reserved.
*
*  THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES.
*  USE AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO THE LICENSE AGREEMENT
*  ACCOMPANYING THE SOFTWARE DEVELOPER KIT (SDK) THAT CONTAINS THIS WORK.
*  PURSUANT TO THE SDK LICENSE AGREEMENT, NOVELL HEREBY GRANTS TO DEVELOPER A
*  ROYALTY-FREE, NON-EXCLUSIVE LICENSE TO INCLUDE NOVELL'S SAMPLE CODE IN ITS
*  PRODUCT. NOVELL GRANTS DEVELOPER WORLDWIDE DISTRIBUTION RIGHTS TO MARKET,
*  DISTRIBUTE, OR SELL NOVELL'S SAMPLE CODE AS A COMPONENT OF DEVELOPER'S
*  PRODUCTS. NOVELL SHALL HAVE NO OBLIGATIONS TO DEVELOPER OR DEVELOPER'S
*  CUSTOMERS WITH RESPECT TO THIS CODE.
*
***************************************************************************
   
   saslbind.c 
***************************************************************************
   Description: 
  
  This sample demonstrates authenticating to eDiretory using the Novell
  Modular Authentication Service(NMAS) LDAP SASL mechanism.  
  
    
  NMAS provides an infrastructure for adding new authentication methods for 
  authenticating a user to eDirectory.  New authentication methods can include 
  alternate passwords, smart cards, tokens, or biometric measures such as 
  finger prints. 
  
  This example uses the Novell LDAP SDK to invoke and process the "NMAS_LOGIN"
  SASL mechanism.  However, any LDAP SDK which supports SASL LDAP binds should
  work.
  
***************************************************************************/

class='cKeyword'>#include <stdio.h>
class='cKeyword'>#include <stdlib.h>
class='cKeyword'>#include <string.h>
class='cKeyword'>#include <time.h>

class='cKeyword'>#include <ldap.h>

class='cKeyword'>#include <nmasclnt.h>


typedef struct _NMAS_TransportInfo{
   LDAP  *ld;
   int    ldapRC;

} NMAS_TransportInfo;




/******************************************************************************
 * LDAP Transport callback function:
 * 
 * This routine is called by the NMAS Client to transport NMAS packets
 * between the eDirectory NMAS Service and the NMAS Client.  
 * 
 * Each NMAS packet is transmitted using the ldap_sasl_bind routine.  The NMAS 
 * Service in eDirectory registers the "NMAS_LOGIN" SASL mechanism and 
 * receives the SASL data packets.  
 *
 * The number request/reply packets is defined by the NMAS Method (LCM/LSM) 
 * which is invoked.  
 */ 
int NMAS_CALLBACK nmas_sasl_transport(
   void     *arg, 
   void     *instructionBuf,
   size_t    instructionLen,
   void     *resultBuf,
   size_t    resultLen)
{
   int              rc = NMAS_SUCCESS;

   struct berval    cred;
   struct berval   *pServerCred;

   NMAS_TransportInfo   *pInfo = (NMAS_TransportInfo*)arg;


   cred.bv_val = instructionBuf;
   cred.bv_len = instructionLen;


   pInfo->ldapRC = ldap_sasl_bind_s( 
                        pInfo->ld,
                        NULL,                // dn is in the nmas credentials
                        "NMAS_LOGIN",        // nmas sasl mechanism
                        &cred, 
                        NULL,                
                        NULL,                
                        &pServerCred );

      /* A return code of LDAP_SASL_BIND_IN_PROGRESS indicates the SASL 
       * mechanism requires more data.  A SASL mechanism may require multiple
       * client/server exchanges to complete.
      */
   if ( LDAP_SASL_BIND_IN_PROGRESS != pInfo->ldapRC && 
        LDAP_SUCCESS != pInfo->ldapRC ) 
   {
      rc = NMAS_E_TRANSPORT;
   }


      /* copy the server reply into the result buffer
      */
   if (NMAS_SUCCESS == rc )
   {
      if (NULL != resultBuf   &&
          NULL != pServerCred &&
          NULL != pServerCred->bv_val )
      {
         if ( resultLen >= pServerCred->bv_len)
            memcpy(resultBuf, pServerCred->bv_val, pServerCred->bv_len);
         else
            rc = NMAS_E_INSUFFICIENT_MEMORY;
      }
   }


      /* free memory for server credentials
      */
   if ( NULL != pServerCred )
   {
      ber_bvfree(pServerCred);
   }

   return(rc);
}




/******************************************************************************
 * NMAS SASL bind function:
 * 
 * This routine demonstrates calling NMAS_ClientLoginEx and providing a 
 * ldap transport callback function.
 * 
 * NMAS_ClientLoginEx accepts login information formated as 
 *    1) UTF8 strings
 *    2) wchar_t strings
 *    3) unicode strings - (Novell defined 2 byte unicode characters)
 *
 * NOTE: For simplicity purposes, this example uses UTF8 strings assuming all 
 *       inputs are 7-bit ASCII characters.  
 * 
 *       This works as a trivial example, but is not recommended.  
 *       Applications should properly convert data to UTF8, wchar_t, or  
 *       unicode strings before calling NMAS_ClientLoginEx.  
 */ 
int nmas_sasl_bind( LDAP *ld,
                    class='cKeyword'>char *userDN,
                    class='cKeyword'>char *nmasSeq,
                    class='cKeyword'>char *pwd )
{
   int rc;
   int options;

   NMAS_utf8LoginInfo   loginInfo;

   NMAS_TransportInfo   transportArg;



   /* initialize login information structure */

   loginInfo.utf8Tree      = NULL;              // optional - eDir tree name, not required for ldap
   loginInfo.utf8UserDN    = userDN;            // ldap user name
   loginInfo.dnType        = NMAS_DN_TYPE_LDAP; // using ldap names
   loginInfo.utf8Password  = pwd;               // optional - based on sequence
   loginInfo.utf8Sequence  = nmasSeq;           // nmas sequence
   loginInfo.utf8Clearance = NULL;              // optional - used for graded authentication
   loginInfo.uiHandle      = NULL;              // optional 
   loginInfo.uiTimeout     = 0;                 // optional 



   /* intialize transport callback argument */

   transportArg.ld      = ld;
   transportArg.ldapRC  = 0;



   /* initialize options */
   /* NOTE:  Options are available to the nmas methods (LCMs).  However,
   *         methods are not required to utilize the options.
   */

   if (NULL != pwd)
      options = NMAS_OPT_NO_PROMPT_FOR_PWD;
   else
      options = 0;

   rc = NMAS_ClientLoginEx( &loginInfo,            // login information
                            NMAS_LOGIN_INFO_UTF8,  // UTF8 Info structure used
                            nmas_sasl_transport,   // sasl callback transport function
                            &transportArg,         // transport function argument
                            NULL,                  // optional - atEnd function callback, called at end of sasl processing
                            NULL,                  // optional - atEnd function arg
                            options                // options 
                          );


      /* return the ldap error if available */
      
   if (0 != rc && 0 != transportArg.ldapRC )
      rc = transportArg.ldapRC;

   return(rc);
}




/******************************************************************************
 * Main example program driver:
 * 
 * 1) Processes the command line arguments
 *
 * 2) initializes the ldap session
 *
 * 3) calls nmas_sasl_bind routine to peform bind operation
 *
 */
static class='cKeyword'>char usage[] =
"\n Usage:   saslbind <host> <port> <login dn> <sequence> [<password>]"
"\n Example: saslbind xyz.com 389 cn=user,o=my_org NDS\n";

int main( int argc, class='cKeyword'>char **argv )
{
   int          rc;
   int          version    = LDAP_VERSION3;

   class='cKeyword'>char         *host      = NULL;
   int           port;
   class='cKeyword'>char         *userDN    = NULL;
   class='cKeyword'>char         *nmasSeq   = NULL;
   class='cKeyword'>char         *pwd       = NULL;

   LDAP         *ld;

   struct timeval timeOut = {10,0};   /* 10 second connection timeout */


   if ((argc != 5) && (argc != 6))
   {
      printf("%s", usage);
      return(1);
   }

   host      = argv[1];
   port      = atoi(argv[2]);
   userDN    = argv[3];
   nmasSeq   = argv[4];

   if (6 == argc)
      pwd = argv[5];

   /* Set LDAP version to 3 and set connection timeout. */
   ldap_set_option( NULL, LDAP_OPT_PROTOCOL_VERSION, &version);
   ldap_set_option( NULL, LDAP_OPT_NETWORK_TIMEOUT, &timeOut);


   /* create ldap session handle */
   if (( ld = ldap_init(host, port)) == NULL)
   {
      printf ( "\nError in ldap_init\n");
      return( 1 );
   }


   /* perform nmas sasl bind */
   rc = nmas_sasl_bind( ld,
                        userDN,
                        nmasSeq,
                        pwd);


   printf("NMAS SASL Bind:\n"
          "   ldap host     : %s\n"
          "   ldap port     : %d\n"
          "   ldap bind DN  : %s\n"
          "   nmas sequence : %s\n"
          "   password      : %s\n\n",
          host,
          port,
          userDN,
          nmasSeq,
          (NULL != pwd ? pwd : ""));


   if ( LDAP_INVALID_CREDENTIALS == rc )
   {
      printf("NMAS SASL Bind failed: Invalid password or other credentials\n");
   }
   else if ( LDAP_AUTH_METHOD_NOT_SUPPORTED == rc )
   {
      printf("NMAS SASL Bind failed: Invalid NMAS sequence or clearance\n");
   }
   else if ( LDAP_SUCCESS != rc )
   {
      printf("NMAS SASL Bind Error: %d, %s\n", 
             rc, ldap_err2string(rc));
   }
   else
   {
      printf("NMAS SASL Bind was successful\n");
   }


   ldap_unbind( ld );  

   return( 0 );
}