/* * This is a part of the Microsoft Source Code Samples. * Copyright 1996-1997 Microsoft Corporation. * All rights reserved. * * The following example demonstrates how license updates are made and * how the challenge mechanism is used at request and update times. The * application developer should analyze the application to determine the * appropriate time to perform an update. For example, this application * prints a message 20 times and the appropriate time to do an update * was decided to be done after every 5th message was printed. */ #include #include #include #include "windows.h" /* * Include the MD4 header for computing the challenge. */ #include "md4.h" /* * Include the LSAPI header file. */ #include "lsapi.h" /* * Define the product name, product version, and publisher name for * use with the licensing calls. */ #define MYAPP_PRODUCT_NAME "sample_product" #define MYAPP_PRODUCT_VERSION "2.0" #define MYAPP_PUBLISHER_NAME "sample_publishers" /* * Define the strings used to log a comment with the license system. */ #define MYAPP_REQUEST_LOG_COMMENT "Comment for the LSRequest call" #define MYAPP_RELEASE_LOG_COMMENT "Comment for the LSRelease call" #define MYAPP_UPDATE_LOG_COMMENT "Comment for the LSUpdate call" /* * The digest length is defined to be 16 according to the LSAPI spec. */ #define DIGESTLEN 16 /* * Define the number of secrets */ #define NUMBER_OF_SECRETS 4 /* * Define macros to indicate to the challenge routines whether we are * doing an LSRequest or an LSUpdate */ #define LS_REQUEST 0 #define LS_UPDATE 1 /* * Global variable used to determine if we are on a little endian machine * or not. */ int littleEndian = 0; /* * Forward declarations. */ void PrintErrors( LS_HANDLE handle, LS_STATUS_CODE errorCode ); LS_STATUS_CODE getChallenge( LS_CHALLENGE FAR *challenge, LS_STR FAR *theString, LS_ULONG unitsConsumed, LS_ULONG unitsReserved, LS_STR FAR *logcomment, LS_ULONG R, LS_ULONG X, LS_ULONG typeOfCall); int checkChallenge( LS_CHALLENGE FAR *challenge, LS_STR FAR *theString, LS_ULONG unitsConsumed , LS_ULONG unitsReserved , LS_STR FAR *logComment , LS_ULONG unitsGranted , LS_STATUS_CODE status , LS_ULONG R, LS_ULONG X, LS_ULONG typeOfCall); void swap( LS_STR FAR *byte1, LS_STR FAR *byte2 ); int PlaceInt( char FAR *buffer, LS_ULONG value ); __cdecl main() { LS_STATUS_CODE status; unsigned long unitsGranted = 0; LS_CHALLENGE challenge; LS_HANDLE licenseHandle = (LS_HANDLE) NULL; LS_ULONG R; LS_ULONG X; int i; int endianTester = 1 ; LS_STR challengeString[100]; char FAR *endianChar = NULL; LS_ULONG Secrets[4] = { 0x7778797A, 0x31323334, 1633837924, 926431536 }; /************ the following code is for the LSAPI beta only! ************/ char szProviderPath[ MAX_PATH ]; UINT nChars; /* install if necessary */ nChars = GetSystemDirectory( szProviderPath, sizeof( szProviderPath ) ); if ( 0 == nChars ) { printf( "Can't get system directory, error %d.\n", GetLastError() ); } lstrcat( szProviderPath, "\\mslsp32.dll" ); status = LSInstall( szProviderPath ); if ( LS_SUCCESS != status ) { printf( "Cannot install LSAPI, error 0x%08lx.\n", status ); } /* add licenses for our product */ status = LSLicenseUnitsSet( LS_ANY, MYAPP_PUBLISHER_NAME, MYAPP_PRODUCT_NAME, MYAPP_PRODUCT_VERSION, LS_LICENSE_TYPE_NODE, LS_NULL, 1, sizeof( Secrets ) / sizeof( *Secrets ), Secrets ); if ( LS_SUCCESS != status ) { printf( "Cannot install licenses, error 0x%lx.\n", status ); } /************ the above code is for the LSAPI beta only! ************/ /* * test endianness and set global variable by casting an int * as bytes and look at the first byte */ endianChar = (char FAR *) &endianTester ; if ( *endianChar ) littleEndian = 1 ; /* * Calculate the string for the challenge on the LSRequest call. */ sprintf( challengeString, "%s%s%s%s%s", "LSRequest", LS_ANY, MYAPP_PUBLISHER_NAME, MYAPP_PRODUCT_NAME, MYAPP_PRODUCT_VERSION ); /* * Pick the random number R and randomly pick a number for the index X * between 1 and the number of secrets. */ srand( (unsigned)time( NULL ) ); R = rand(); X = (int)(NUMBER_OF_SECRETS * ((float)rand()/(float)RAND_MAX)) + 1; /* * Calculate the message digest for the challenge argument. */ status = getChallenge( &challenge, challengeString, 0, /* Unused argument for LSRequest call */ LS_DEFAULT_UNITS, MYAPP_REQUEST_LOG_COMMENT, R, X, LS_REQUEST ); if ( LS_SUCCESS != status ) { PrintErrors( licenseHandle, status ); return(1); } /* * Make the grant request call */ status = LSRequest( (LS_STR FAR *) LS_ANY, (LS_STR FAR *) MYAPP_PUBLISHER_NAME, (LS_STR FAR *) MYAPP_PRODUCT_NAME, (LS_STR FAR *) MYAPP_PRODUCT_VERSION, LS_DEFAULT_UNITS, (LS_STR FAR *) MYAPP_REQUEST_LOG_COMMENT, &challenge, &unitsGranted, &licenseHandle); if ( LS_SUCCESS != status ) { PrintErrors( licenseHandle, status ); LSFreeHandle( licenseHandle ); return(1); } /* * Check whether the challenge succeeded. */ if ( !checkChallenge( &challenge, challengeString, 0, /* Unused argument for LSRequest call */ LS_DEFAULT_UNITS, MYAPP_REQUEST_LOG_COMMENT, unitsGranted, status, R, X, LS_REQUEST ) ) { printf("Challenge failed!!!\n"); /* * Since we failed, we should still release the grant and free * the license handle. */ status = LSRelease( licenseHandle, LS_DEFAULT_UNITS, (LS_STR FAR *) MYAPP_RELEASE_LOG_COMMENT); if ( LS_SUCCESS != status ) PrintErrors( licenseHandle, status ); LSFreeHandle( licenseHandle ); return(1); } /* * Now we can start the application. Print "Hello, World" 20 times * performing an update after every 5th time. */ for ( i = 0; i<20; i++ ) { printf("Hello, World.\n"); if ( 0 == i%5 ) { /* * Calculate the challenge string for the challenge on * the LSUpdate call. */ sprintf( challengeString, "%s", "LSUpdate"); /* * Pick the random number R using the process id for the seed * to the random number generator. Also randomly pick a number * for the index X between 1 and NUMBER_OF_SECRETS. */ srand( (unsigned)time( NULL ) ); R = rand(); X = (int)(NUMBER_OF_SECRETS * ((float)rand()/(float)RAND_MAX)) + 1; /* * Calculate the message digest for the challenge argument. */ status = getChallenge( &challenge, challengeString, LS_DEFAULT_UNITS, LS_DEFAULT_UNITS, MYAPP_UPDATE_LOG_COMMENT, R, X, LS_UPDATE ); if ( LS_SUCCESS != status ) { PrintErrors( licenseHandle, status ); status = LSRelease( licenseHandle, LS_DEFAULT_UNITS, (LS_STR FAR *) MYAPP_RELEASE_LOG_COMMENT); LSFreeHandle( licenseHandle ); return(1); } /* * Make the update call. */ status = LSUpdate( licenseHandle, LS_DEFAULT_UNITS, LS_DEFAULT_UNITS, (LS_STR FAR *) MYAPP_UPDATE_LOG_COMMENT, &challenge, &unitsGranted); if ( LS_SUCCESS != status ) { PrintErrors( licenseHandle, status ); status = LSRelease( licenseHandle, LS_DEFAULT_UNITS, (LS_STR FAR *) MYAPP_RELEASE_LOG_COMMENT); LSFreeHandle( licenseHandle ); return( 1 ); } /* * Check whether the challenge succeeded. */ if ( !checkChallenge( &challenge, challengeString, LS_DEFAULT_UNITS, LS_DEFAULT_UNITS, MYAPP_UPDATE_LOG_COMMENT, unitsGranted, status, R, X, LS_UPDATE ) ) { printf("Challenge failed!!!\n"); /* * Release the grant. */ status = LSRelease( licenseHandle, LS_DEFAULT_UNITS, (LS_STR FAR *) MYAPP_RELEASE_LOG_COMMENT); if ( LS_SUCCESS != status ) PrintErrors( licenseHandle, status ); LSFreeHandle( licenseHandle ); return(1); } } /* End of if ( 0 == i%5 ) */ } /* End of for loop. */ /* * Release the grant. */ status = LSRelease( licenseHandle, LS_DEFAULT_UNITS, (LS_STR FAR *) MYAPP_RELEASE_LOG_COMMENT); if ( LS_SUCCESS != status ) { PrintErrors( licenseHandle, status ); LSFreeHandle( licenseHandle ); return( 1 ); } /* * Free the license handle. */ LSFreeHandle( licenseHandle ); return(0); } /* * Print the error message. */ void PrintErrors( LS_HANDLE handle, LS_STATUS_CODE errorCode ) { LS_STATUS_CODE status; char errorText[200]; status = LSGetMessage( handle, errorCode, (LS_STR FAR *)errorText, 200); if ( LS_TEXT_UNAVAILABLE == status ) printf("Error: No message catalog available.\n"); else if ( LS_UNKNOWN_STATUS == status ) printf("Error: Unknown error code was used.\n"); else printf("Error: %s\n", errorText); } /* * Use the algorithmic approach to calculate the message digest to send * to the server. */ LS_STATUS_CODE getChallenge( LS_CHALLENGE FAR *challenge, LS_STR FAR *theString, LS_ULONG unitsConsumed, LS_ULONG unitsReserved, LS_STR FAR *logComment, LS_ULONG R, LS_ULONG X, LS_ULONG typeOfCall) { MD4_CTX MD; char secret[4]; LS_STR hashString[200], FAR *hashStringPtr; int bufferLen, bytes, i; /* * Set the protocol, index, random number, and size on the challenge * argument. */ challenge->Protocol = LS_BASIC_PROTOCOL; challenge->ChallengeData.SecretIndex = X; challenge->ChallengeData.Random = R; /* * Get the secret. NOTE: Greater steps should be taken to obsure the * secrets than is shown. Also, more secrets should be used than 4. * Several methods are shown on how the secret can be specified. */ switch ( X ) { case 1: PlaceInt( secret, 0x7778797A ); break; case 2: PlaceInt( secret, 0x31323334 ); break; case 3: PlaceInt( secret, 1633837924 ); break; case 4: PlaceInt( secret, 926431536 ); break; default: printf("Index out of range\n"); return( 0 ); break; } /* * Compute the hash string to be used on input to the MD4 algorithm. */ strcpy( hashString, theString ); hashStringPtr = hashString + strlen( theString ); bufferLen = strlen( theString ); /* * Add units consumed only for LSUpdate call */ if ( LS_UPDATE == typeOfCall ) { bytes = PlaceInt( hashStringPtr, (LS_ULONG) unitsConsumed ); hashStringPtr += bytes; bufferLen += bytes; } bytes = PlaceInt( hashStringPtr, (LS_ULONG) unitsReserved ); hashStringPtr += bytes; bufferLen += bytes; strcpy( hashStringPtr, logComment ); bufferLen += strlen( logComment ); hashStringPtr += strlen( logComment ); bytes = PlaceInt( hashStringPtr, (LS_ULONG) R ); hashStringPtr += bytes; bufferLen += bytes; bytes = PlaceInt( hashStringPtr, (LS_ULONG) X ); hashStringPtr += bytes; bufferLen += bytes; for ( i=0; i<4; i++ ) { *hashStringPtr = secret[i]; hashStringPtr++; bufferLen++; } /* * Make the MD4 calls. */ MD4Init(&MD); MD4Update( (MD4_CTX *) &MD, (unsigned char *) hashString, (unsigned int) bufferLen ); MD4Final( challenge->ChallengeData.MsgDigest.MessageDigest, (MD4_CTX *) &MD); challenge->Size = sizeof( challenge->ChallengeData ); return( LS_SUCCESS ); } /* * Check the return challenge argument. */ int checkChallenge( LS_CHALLENGE FAR *challenge, LS_STR FAR *theString, LS_ULONG unitsConsumed , LS_ULONG unitsReserved , LS_STR FAR *logComment , LS_ULONG unitsGranted , LS_STATUS_CODE status , LS_ULONG R, LS_ULONG X, LS_ULONG typeOfCall) { char secret[4]; MD4_CTX MD; LS_STR hashString[200]; LS_STR digest[DIGESTLEN], FAR *hashStringPtr; int i, bufferLen, bytes, j; /* * Get the secret. NOTE: Greater steps should be taken to obsure the * secrets than is shown. Also, more secrets should be used than 4. * Several methods are shown on how the secret can be specified. */ switch ( X ) { case 1: PlaceInt( secret, 0x7778797A ); break; case 2: PlaceInt( secret, 0x31323334 ); break; case 3: PlaceInt( secret, 1633837924 ); break; case 4: PlaceInt( secret, 926431536 ); break; default: printf("Index out of range\n"); return( 0 ); break; } /* * Compute the hash string. */ strcpy( hashString, theString ); hashStringPtr = hashString + strlen( theString ); bufferLen = strlen( theString ); /* * Add units consumed only for LSUpdate call */ if ( LS_UPDATE == typeOfCall ) { bytes = PlaceInt( hashStringPtr, (LS_ULONG) unitsConsumed ); hashStringPtr += bytes; bufferLen += bytes; } bytes = PlaceInt( hashStringPtr, (LS_ULONG) unitsReserved ); hashStringPtr += bytes; bufferLen += bytes; strcpy( hashStringPtr, logComment ); bufferLen += strlen( logComment ); hashStringPtr += strlen( logComment ); bytes = PlaceInt( hashStringPtr, (LS_ULONG) unitsGranted ); hashStringPtr += bytes; bufferLen += bytes; bytes = PlaceInt( hashStringPtr, (LS_ULONG) status ); hashStringPtr += bytes; bufferLen += bytes; bytes = PlaceInt( hashStringPtr, (LS_ULONG) R ); hashStringPtr += bytes; bufferLen += bytes; bytes = PlaceInt( hashStringPtr, (LS_ULONG) X ); hashStringPtr += bytes; bufferLen += bytes; for ( i=0; i<4; i++ ) { *hashStringPtr = secret[i]; hashStringPtr++; bufferLen++; } /* * Compute the message digest. */ MD4Init(&MD); MD4Update( (MD4_CTX *) &MD, (unsigned char *) hashString, (unsigned int) bufferLen ); MD4Final( digest, (MD4_CTX *) &MD); /* * Compare the digest with the one on the challenge */ j = 0 ; for( i = 0; i < DIGESTLEN; i++ ) { if( digest[i] != challenge->ChallengeData.MsgDigest.MessageDigest[i] ) break ; j++ ; } if( j == DIGESTLEN ) return( 1 ); return( 0 ); } /* * swap bytes */ void swap( LS_STR FAR *byte1, LS_STR FAR *byte2 ) { LS_STR tmp; tmp = *byte2; *byte2 = *byte1; *byte1 = tmp; } /* * Places integer in byte buffer, swapping bytes if necessary */ int PlaceInt( char FAR *buffer, LS_ULONG value ) { if ( littleEndian ) { swap(&(((char FAR *) &value)[0]), &(((char FAR *) &value)[3])); swap(&(((char FAR *) &value)[1]), &(((char FAR *) &value)[2])); } memcpy( buffer, &value, sizeof( LS_ULONG ) ); return( (int) sizeof( LS_ULONG ) ); }