/************************************************************************** * 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 ); }