/**************************************************************************
 %name: sstst.c %
 %version: 8 %
 %date_modified: Tue May 17 16:47:34 2005 %

 Copyright (c) 1997-2007 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 DEVELOPMENT 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.
**************************************************************************/


/***************************************************************
 *** This code is available at "www.developer.novell.com/ndk/ **
 ***************************************************************/


/* Sample NCP client code for SecretStore Service APIs */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <time.h>

#include "nssscl.h"
#include "nssbldno.h"



/*
 * Global data
 */
int		optErr = 1;			//* if error message should be printed
int   	optIdx = 1;	   		//* index into parent argv vector
int   	optionString = 1;	//* character checked for validity
char 		*optArg = NULL;		//* argument associated with option

#define BADCHAR 	(int)'?'
#define ERRMSG  	""

/* interactive flag */
static int	aFlag = 1;

/*  *
/*
 * NAME - sss_GetOpt
 *
 * DESCRIPTION
 *	An implementation of the Unix getopt() function.
 *
 */
int sss_GetOpt( int nArgc, char **nArgv, char *optStr )
{ /* beginning of the call */
/* ########################## DECLARATIONS START HERE ######################### */

	static	char		*place = ERRMSG;
			char		*nxtOpt;

/* ############################## CODE STARTS HERE ############################ */

	if(!*place)  
	{
		if((optIdx >= nArgc) ||
			((*(place = nArgv[optIdx]) != '-')
				&& (*(place = nArgv[optIdx]) != '/')) ||
					(!*++place))
		{
			return(-1);
		}

		if((*place == '-') || (*place == '/'))
		{
			++optIdx;
			return(-1);
		}
	}

	if((optionString = (int)*place++) == (int)'=' || 
			!(nxtOpt = strchr(optStr, optionString))) 
	{
		if(!*place) 
		{
			++optIdx;
		}

		return(BADCHAR);
	}

	if(*++nxtOpt != '=') 
	{
		optArg = NULL;
		if(!*place) 
		{
			++optIdx;
		}
	}
	else 
	{
		if(*place)
		{
			optArg = place + 1;
		}
		else if(nArgc <= ++optIdx) 
		{
			place = ERRMSG;
			return(BADCHAR);
		}
	 	else 
		{
	 		optArg = nArgv[optIdx];
		}

		place = ERRMSG;
		++optIdx;
	}

	return(optionString);

/* ########################## CODE ENDS HERE ######################### */
} /* end of GetOPt */




void Pause()
{ /* beginning of the call */
/* ############################## CODE STARTS HERE ############################ */

	if(aFlag)
	{
		printf("\nPress a key ==>\n");
		getch();
	}
/* ########################## CODE ENDS HERE ######################### */
} /* end of Pause */






/*  */
/*
 * NAME - PrintFlags
 *
 * DESCRIPTION
 *	This function will print the 
 *	status flags read form a secret.		   
 *		   
 */
void PrintFlags(char *msg, unsigned long	statFlags)
{ /* beginning of the call */
/* ############################## CODE STARTS HERE ############################ */

	if(aFlag)
	{
		printf("%s", msg);

		if(statFlags & NSSS_ENHANCED_PROTECT_INFO_F)
			printf("\tENHANCED PROTECTION...\n");

		if(statFlags & NSSS_STORE_NOT_SYNCED_F)
			printf("\tSTORE NOT SYNCED...\n");

		if(statFlags & NSSS_SECRET_NOT_INITIALIZED_F)
			printf("\tSECRET NOT INITIALIZED...\n");

		if(statFlags & NSSS_SECRET_LOCKED_F)
			printf("\tSECRET LOCKED...\n");

		/* doesn't apply to the server */
		if(strcmp(msg, "SecretStore Flags:\n"))
		{
			if(statFlags & NSSS_ADMIN_LAST_MOD_F)
				printf("\tADMIN MODIFIED LAST...\n");
			else
				printf("\tOWNER MODIFIED LAST...\n");
		}

		if(statFlags & NSSS_EP_PWORD_PRESENT_F)
			printf("\tEP PWORD PRESENT...\n");

		if(statFlags & NSSS_EP_MASTER_PWORD_PRESENT_F)
			printf("\tMASTER PWORD PRESENT...\n");
		
		if(statFlags & NSSS_MP_NOT_ALLOWED_F)
			printf("\tMASTER PWORD NOT ALLOWED...\n");

		if(statFlags & NSSS_HIDDEN_SECRET_F)
			printf("\tHIDDEN SECRET IN SECRETSTORE...\n");

		if(statFlags & NSSS_ADMIN_UNLOCKED_F)
			printf("\tADMIN LAST UNLOCKED THE SECRETSTORE...\n");
	}

/* ########################## CODE ENDS HERE ######################### */
} /* end of PrintFlags */





/*  */
/*
 * NAME - main
 *
 * DESCRIPTION
 *	SecretStore NCP test program.		   
 *		   
 */
void	main
(
	int 		argc, 
	char 		**argv
)
{ /* beginning of the call */
/* ########################## DECLARATIONS START HERE ######################### */

	SSS_CONTEXT_T			ctx = {0};
	SSS_GSINFOEXT_T			gsInfo = {0};
	SSS_READEXT_T			rInfo = {0};
	SS_SECRET_T				secretIDList = {0};
	char					srchStr[] = "*";
	SS_OBJECT_DN_T			targetObjDN = {0};
	char					*nameStr;

	char			*passwordSS[15] = 
					{
						"NCP test01_password", "NCP test02_password",
						"NCP test03_password", "NCP test04_password",
						"NCP test05_password", "NCP test06_password",
						"NCP test07_password", "NCP test08_password",
						"NCP test09_password", "NCP test10_password",
						"NCP test11_password", "NCP test12_password",
						"NCP test13_password", "NCP test14_password",
						"NCP test15_password"
					};

	/* Test secret IDs. */

	char			*appNames[15] =
					{
						"//novell.com/NCP SSS NDK Test APP01", 
						"//novell.com/NCP SSS NDK Test APP02", 
						"//novell.com/NCP SSS NDK Test APP03", 
						"//novell.com/NCP SSS NDK Test APP04", 
						"//novell.com/NCP SSS NDK Test APP05", 
						"//novell.com/NCP SSS NDK Test APP06", 
						"//novell.com/NCP SSS NDK Test APP07", 
						"//novell.com/NCP SSS NDK Test APP08", 
						"//novell.com/NCP SSS NDK Test APP09", 
						"//novell.com/NCP SSS NDK Test APP10", 
						"//novell.com/NCP SSS NDK Test APP11", 
						"//novell.com/NCP SSS NDK Test APP12", 
						"//novell.com/NCP SSS NDK Test APP13", 
						"//novell.com/NCP SSS NDK Test APP14", 
						"//novell.com/NCP SSS NDK Test APP15"
					};


	int						rcode = NSSS_SUCCESS, nslFlag = 0, repairFlag = 0, c, nslCount = 0,
							exCount = 1, i, j, remLock = 0, unlock = 0,
							master = 0, k, rCount = 1;
	SS_SECRET_T				readSecret = {0}, writeSecret = {0};
	long					opCount, bufSize = strlen(passwordSS[0])+1;
	unsigned long			startTime, endTime, pFlag = 0L, count = 0;

	struct tm				*latStamp, *crtStamp, *lmtStamp, *unlockTStamp;
	SS_PWORD_T				mPassword = {8, "Pyramid"}, masterPword = {0}, pword = {0}, 
							ePassword = {12, "ep_password"};
	SS_HINT_T				mpHint = {0}, hint = {28, "My Key To The SecretStore!!"};
	SS_SECRET_ID_T			secretID = {0};

/* ############################## CODE STARTS HERE ############################ */

	printf("\nSecretStore NDK NCP Test Program version %s ...\n\n", GSS_BLD_STR);

	//** Process command-line arguments.
	if(argc > 1)
	{
		while((c = sss_GetOpt(argc, argv, "dDnNaAbBmMsSc=C=r=R=?hH")) != -1)
		{
			switch(c)
			{
				//* repair
				case 'd':
				case 'D':
					repairFlag = 1;
					break;

				//* NSL mode
				case 'n':
				case 'N':
					nslFlag = 1;
					break;
				
				//* 512k Secret
				case 'a':
				case 'A':
					bufSize = 512; //* bytes
					break;

				case 'b':
				case 'B':
					/* Big secret buffer */
					bufSize = NSSS_MID_SECRET_BUF_LEN;
					break;

				case 'm':
				case 'M':
					/* Minimum secret buffer */
					bufSize = NSSS_MIN_SECRET_BUF_LEN; 
					break;

				case 's':
				case 'S':
					/* set active flag to FALSE */
					aFlag = 0;
					printf("Silent Running Mode Active...\n");
					break;

				case 'c':
				case 'C':

					/* Run count */
					exCount = atoi(optArg);
					break;

				case 'r':
				case 'R':

					/* Read count */
					rCount = atoi(optArg);
					break;

				default:

					//* case '?':
					//* case 'h':
					//*case 'H':

					printf("\nUsage: sstst [/n][/m]|[/d][/b][/a]|[/s /c=[count] /r=[rcount] | /? | /h ]\n");
					printf("\tOptions: [ /n | /N ] for 128 Bytes Secrets 5 Minutes Run Emulating NSL.\n");
					printf("\tOptions: [ /a | /A ] for Average 512k Secret Buffer Size.\n");
					printf("\tOptions: [ /m | /M ] for Medium 4k Secret Buffer Size.\n");
					printf("\tOptions: [ /b | /B ] for Big 32k Secret Buffer Size.\n");
					printf("\tOptions: [ /d | /D ] for Deleting Corrupted SecretStore.\n");
					printf("\tOptions: [ /s | /S ] for Silent Running.\n");
					printf("\t\tSilent sub-Option [ /c | /C ] for number of times to run.\n");
					printf("\t\tSilent sub-Option [ /r | /R ] for number of times to Read data.\n");
					printf("\tExample: sstst /s /c=1000 /r=100\n");
					printf("\tOption: [ /h | /H  | /? ] for Help.\n");
					printf("\tNo command line options will activate interactive running.\n\n");
					printf("\tFor options \"/\" and \"-\" are interchangeable.\n\n");
					exit(0);
			}
		} 
	}
	else
	{
 		printf("Full Interactive Running Mode Active...\n");
	}

	printf("[%d]k secret size buffer chosen...\n", bufSize);
	printf("Execution Count Set to: [%d]\n", exCount);
	printf("Read Count Set to: [%d]\n", rCount);
	printf("Initializing...\n");

	if(nslFlag)
	{
		aFlag = 0;
		exCount = 1;
		rCount = 1000000;
		bufSize = 128;		
	}

	if(repairFlag)
	{
		aFlag = 0;
		exCount = 1;
		rCount = 1;
	}

	/* Allocate the buffer used for writing secrets. */
	if(!(writeSecret.data = (char *) malloc(bufSize)))
	{
		printf("Error:secret MALLOC FAILED!\n");
		goto ERROR_1;
	}
	memset(writeSecret.data, 0, bufSize);
	writeSecret.len = bufSize;

	/* Allocate and initialize the buffer used for reading secrets. */
	if(!(readSecret.data = (char *)malloc(NSSS_MAX_SECRET_BUF_LEN)))
	{
		printf("Error:readSecret MALLOC FAILED!\n");
		goto ERROR_1;
	}
	memset(readSecret.data, 0, NSSS_MAX_SECRET_BUF_LEN);
	readSecret.len = NSSS_MAX_SECRET_BUF_LEN;

	/* allocate and initialize the enumSecIDBuf for ENUM */
	if(!(secretIDList.data = (char *)malloc(NSSS_MAX_IDLIST_BUF_LEN)))
	{
		printf("Error: secretIDList MALLOC FAILED!\n");
		goto ERROR_1;
	}

	secretIDList.len = NSSS_MAX_IDLIST_BUF_LEN;

	startTime = time(NULL);
	printf("Done...\n");
	Pause();

	//** Query the SecretStore service to determine version, etc.  Note that
	//** we get and save the callerDN.
	if(rcode = NSSSGetServiceInformation(&ctx, NULL, (pFlag | NSSS_GET_CONTEXT_F), &gsInfo, NULL))
	{
		//* Call failed.
		printf("\nError [%d] NSSSGetContexts\n", rcode);
		goto ERROR_1;
	}
	else
	{
		//* Print out service information.
		printf("\nClient Version = [%d.%d.%d]\n",
			((gsInfo.clientVersion >> 16)  & 0x000000FF) , 
				((gsInfo.clientVersion >> 8) & 0x000000FF), 
					(gsInfo.clientVersion & 0x000000FF));

		printf("\nServer Version = [%d.%d.%d]\n",
			((gsInfo.serverVersion >> 16)  & 0x000000FF) , 
				((gsInfo.serverVersion >> 8) & 0x000000FF), 
					(gsInfo.serverVersion & 0x000000FF));

		if(gsInfo.serverCryptoStrength == NSSS_NICI_DOMESTIC_ENGINE)
		{
			printf("Server Crypto Strength = DOMESTIC\n");
		}
		else
		{
			printf("Server Crypto Strength = EXPORT\n");
		}
		
		if(gsInfo.clientCryptoStrength == NSSS_NICI_DOMESTIC_ENGINE)
		{
			printf("Client Crypto Strength = DOMESTIC\n");
		}
		else
		{
			printf("Client Crypto Strength = EXPORT\n");
		}

		printf("\nSecret Count = %d\n", gsInfo.secretCount);
		printf("\nHidden Secret Count = %d\n", gsInfo.hidSecCount);

		if(gsInfo.lockCount)
		{
			printf("Lock Count = %d\n", gsInfo.lockCount);
		}

		printf("\nSecretStore's NDS Tree = %s\n", ctx.ssServerInfo.treeName);
		printf("\nSecretStore's Server = %s\n", ctx.ssServerInfo.ssServerDN);

		if(gsInfo.hintLen)
		{
			printf("\nMaster Password Hint = %s\n", gsInfo.hint);
		}

		if(gsInfo.secretCount)
		{
		  PrintFlags("\nSecretStore Flags:\n", gsInfo.statusFlags);
		}

		if(gsInfo.enumBufLen)
		{
			printf("\nEnumeration Buffer Length in Chars = %d\n", gsInfo.enumBufLen);
		}

		if(gsInfo.statusFlags & NSSS_ADMIN_UNLOCKED_F)
		{
			unlockTStamp = localtime((long *)&gsInfo.unlockTStamp);
	 		if(unlockTStamp)
			{
				printf("\nLast Admin Unlock time stamp: %s", asctime(unlockTStamp));
			}

			printf("\nLast Admin Unlock DN = %s\n", gsInfo.admnDN);
		}

		if(strlen(ctx.ssServerInfo.sssConfigDN))
		{
			printf("\nNSSS Configuration Container = %s\n", ctx.ssServerInfo.sssConfigDN);
		}

		printf("\nCaller DN = %s\n", ctx.callerDN.id);

		if(gsInfo.hintLen)
		{
			printf("\nMaster Password Hint = %s\n", gsInfo.hint);
		}
	}

	targetObjDN = ctx.callerDN;
	//* reset the flag
	pFlag &= ~NSSS_GET_CONTEXT_F;
	startTime = time(NULL);

	//* Query the user to continue.
	if(aFlag)
	{
		printf("\nDo you want to CONTINUE (y/n)? ");
		c = getch();
		putchar(c);
		printf("\n\n");
	}
	else
	{
		 c = 'y';
	}

	if(!((c == 'y') || (c == 'Y')))
	{
		aFlag = 0;
		goto ERROR_1;
	}

	//* Run the tests as many times as specified by the user.
	for(j = 0, opCount = 0; j < exCount; j++)
	{
		if(aFlag)
		{
			printf("\nDo you want to CREATE/WRITE the secrets (y/n)? ");
			c = getch();
			putchar(c);
			printf("\n\n");
		}
		else
		{
			if(repairFlag)
			{
				c = 'n';
			}
			else
			{
				c = 'y';
			}
		}

		if(c == 'y' || c == 'Y')
		{
			for(i = 1; i <= 15; i++)
			{

				/* initialize the app secret buffers */
				memset(writeSecret.data, 0, bufSize);
				strcpy(writeSecret.data, passwordSS[i-1]);

				/* initialize the secret ID buffers */
				strcpy(secretID.id, appNames[i-1]);
				secretID.len = strlen(secretID.id)+1;

				if(i % 2)
				{
					//* Create the secret's ID first...
					printf("\nCreating secret ID [%s] in SS\n", secretID.id);
					//* writing secret here
					if(rcode = NSSSWriteSecret(&ctx, &targetObjDN, pFlag | NSSS_CHK_SID_FOR_COLISION_F, 
							NULL, &secretID, &writeSecret, NULL))
					{
						printf("Error [%d] NSSSWriteSecret\n", rcode);
						printf("Secret[%d] = [%s], len [%d]\n", i, writeSecret.data, writeSecret.len);
						Pause();
					}
					else
					{
						printf("Wrote Secret[%d] = [%s], len [%d]\n", i, writeSecret.data, writeSecret.len);
					}	
					opCount++;
				}
				else
				{
					if(rcode = NSSSWriteSecret(&ctx, &targetObjDN, 
							(pFlag | NSSS_ENHANCED_PROTECTION_F | NSSS_EP_PASSWORD_USED_F), 
							 &ePassword, &secretID, &writeSecret, NULL))
					{
						//* The write operation failed.
						printf("\nError [%d] NSSSWriteSecret\n", rcode);
						printf("Long Version Secret[%d] = [%s], len [%d]\n",
							i, writeSecret.data, writeSecret.len);
						Pause();
					}
					else
					{
						//* The write operation succeeded.
						printf("\nWrote Long Version Secret[%d] = [%s], len [%d]\n",
							i, writeSecret.data, writeSecret.len);
					}
					opCount++;
				}
			} /* end for ... */

			gsInfo.statusFlags |= NSSS_ENHANCED_PROTECT_INFO_F;
		}

		//* Set the enhanced protection master password, if desired.
		if((gsInfo.statusFlags & NSSS_ENHANCED_PROTECT_INFO_F ) && (!repairFlag))
		{
			if(!(gsInfo.statusFlags & NSSS_EP_MASTER_PWORD_PRESENT_F))
			{
				if(aFlag)
				{
					printf("\nDo you want to SET the Master Password(y/n)(n for default...)? ");
					c = getch();
					putchar(c);
					printf("\n");
				}
				else
				{
					c = 'n';
				}

				if(c == 'y' || c == 'Y')
				{
					printf("Enter your Master password (64 chars max): ");
					gets(masterPword.pword);
					printf("\n");
					masterPword.pwordLen = strlen(masterPword.pword) + 1;

					printf("\nEnter your Master password Hint(64 chars max): ");
					gets(mpHint.hint);
					printf("\n");
					mpHint.hintLen = strlen(mpHint.hint) + 1;

					if(rcode = NSSSSetEPMasterPassword(&ctx, &targetObjDN,
							pFlag, &masterPword, &mpHint, NULL))
					{
						printf("Error [%d] NSSSSetEPMasterPassword Failed!\n", rcode);
					}		
					else
					{
						printf("\nNSSSSetEPMasterPassword succeeded...\n", rcode);
						printf("Your Master Password was set to: %s\n", masterPword.pword);
						printf("Your Master Password Hint was set to: %s\n\n", mpHint.hint);
					}
				}
				else
				{
					if(aFlag)
					{
						 printf("\nDo you want to Use the default Master Password(y/n)? ");
						 c = getch();
						 putchar(c);
						 printf("\n");
					}
					else
					{
						c = 'y';
					}

					if(c == 'y' || c == 'Y')
					{
						masterPword = mPassword;
						mpHint = hint;
						if(rcode = NSSSSetEPMasterPassword(&ctx, &targetObjDN,
							pFlag, &masterPword, &mpHint, NULL))
						{
							printf("Error [%d] NSSSSetEPMasterPassword Failed!\n", rcode);
						}		
						else
						{
							printf("\nNSSSSetEPMasterPassword succeeded...\n", rcode);

							printf("Your Master Password was set to: %s\n", masterPword.pword);
							printf("Your Master Password Hint was set to: %s\n\n", hint.hint);
						}
					}
					else
					{
						printf("\nNO MasterPassword present!!\n");
					}
				}
			}
			else
			{
				printf("\nMasterPassword Already present...\n");
				if(aFlag)
				{
					 printf("Did you use the default Master password:(y/n)? ");
					 c = getch();
					 putchar(c);
					 printf("\n");
				}
				else
				{
					c = 'y';
				}

				if((c != 'y') && (c != 'Y'))
				{
					printf("Enter your Master password (64 chars max): ");
					gets(masterPword.pword);
					printf("\n");
					masterPword.pwordLen = strlen(masterPword.pword)+1;
				}
				else
				{
					masterPword = mPassword;

				}
			}
			opCount++;
		}
		
		if(nslFlag)
		{
			printf("\n<<=============== STARTING NSL OPS ======================>>\n");
			startTime = time(NULL);
		}

		//* Read the secrets as many times as the user has specified.
		for(k = 0; k < rCount; k++)
		{
			if(aFlag)
			{
				printf("\nDo you want to Read the secrets (y/n)? ");
				c = getch();
				putchar(c);
				printf("\n\n");
			}
			else
			{
				if(repairFlag)
				{
					c = 'n';
				}
				else
				{
					c = 'y';
				}
			}

			if(nslFlag)
			{
				
				//* do a GetServiceInfo
				memset(&gsInfo, 0, sizeof(SSS_GSINFOEXT_T));

				if(rcode = NSSSGetServiceInformation(&ctx, &targetObjDN, pFlag, &gsInfo, NULL))
				{
					//* Call failed.
					printf("\nError [%d] NSSSGetServiceInformation\n", rcode);
					goto ERROR_1;
				}
				else
				{
					printf("\nSecretStore GetService Info Succeeded...\n");
				}

				nslCount++;
				opCount++;

				strcpy(pword.pword, masterPword.pword);
				pword.pwordLen = masterPword.pwordLen;	
				// unlock the secret store
				if(rcode = NSSSUnlockSecrets(&ctx, &targetObjDN, 
						(pFlag | NSSS_EP_MASTER_PWORD_USED_F), &pword, NULL))
				{
					printf("Error [%d] NSSSUnlockSecrets\n", rcode);
					Pause();
				}
				else
				{
					printf("SecretStore Unlocked...\n");
				}
				nslCount++;
				opCount++;
			}

			/* enumerate the secrets */
			count = 0;
			secretIDList.len = NSSS_MAX_IDLIST_BUF_LEN;

			if(rcode = NSSSEnumerateSecretIDs(&ctx, &targetObjDN, pFlag,
				srchStr, &count, &secretIDList, NULL))
			{
				printf("Error [%d] NSSSEnumerateSecretIDs\n", rcode);
				secretIDList.len = 0;
				Pause();
			}
			else
			{
				if(nslFlag)
				{
					printf("SecretStore Enumerate Seceret IDs Succeeded...\n\n");
				}
				else
				{
					printf("\nNumber of Secrets = [%d]\nRaw Secret ID Buffer from SS [%s]\n", 
						count, (char*)secretIDList.data);
				}
			}
			
			opCount++;
			nslCount++;

			if(c == 'y' || c == 'Y')
			{
				if(secretIDList.len)
				{
					//* Try to read each secret separately.
					nameStr = strtok((char *)secretIDList.data, "*");

					for(i = 1; i <= (int)count; i++)
					{
						readSecret.len = NSSS_MAX_SECRET_BUF_LEN;
						rInfo.statFlags = 0;

						if(nslFlag)
						{
							strcpy(secretID.id, appNames[i-1]);
							secretID.len = strlen(secretID.id)+1;
							if(i % 2)
							{
								/* for read the length should be initialized */
								if(rcode = NSSSReadSecret(&ctx, &targetObjDN, pFlag,
										NULL, &rInfo, &secretID, &readSecret, NULL))
								{
									printf("Read SecretID[%d] [%s] Failed = [%d]!!!\n", i, secretID.id, rcode);
								}
								else
								{
									printf("Read SecretID[%d] [%s] Succeeded...\n", i, secretID.id);
								}
								nslCount++;
								opCount++;

							}
							else
							{
								/* for read the length should be initialized */
								if(rcode = NSSSReadSecret(&ctx, &targetObjDN, 
								(pFlag | NSSS_ENHANCED_PROTECTION_F | NSSS_EP_MASTER_PWORD_USED_F),
									&masterPword, &rInfo, &secretID, &readSecret, NULL))
								{
									printf("Read SecretID[%d] [%s] Failed = [%d]!!!\n", i, secretID.id, rcode);
								}
								else
								{
									printf("Read SecretID[%d] [%s] Succeeded...\n", i, secretID.id);
								}
					  			nslCount++;
					  			opCount++;
							}
						}
						else
						{
							strcpy(secretID.id, nameStr);
							secretID.len = strlen(secretID.id) + 1;
					
							//* For a read operation the length should be initialized.
							rcode = NSSSReadSecret(&ctx, &targetObjDN, pFlag, NULL,
								&rInfo, &secretID, &readSecret, NULL);

							if(rcode == NSSS_E_NDS_PWORD_CHANGED)
							{
								//* The users NDS passord has changed.
								unlock = 1;
								printf("Status Flags = [0x%x]\n", rInfo.statFlags);
								PrintFlags("Secret Flags:\n", rInfo.statFlags);
								Pause();
								opCount++;
								goto Unlock_label;
							}
							
							if(rcode == NSSS_E_EP_ACCESS_DENIED)
							{
								if(master)
								{
									//* Try to read the secret with the master password.
									/* for read the length should be initialized */
									if(rcode = NSSSReadSecret(&ctx, &targetObjDN,
											 (pFlag | NSSS_EP_MASTER_PWORD_USED_F), &masterPword,
											 &rInfo, &secretID, (SS_SECRET_T *)&readSecret, NULL))
									{
										printf("Read SecretID[%d] : [%s]\n", i, secretID.id);
										printf("Status Flags : [0x%x]\n", rInfo.statFlags);
										printf("Error [%d] NSSSReadSecret\n", rcode);
										PrintFlags("Secret Flags:\n", rInfo.statFlags);
										Pause();
						  				opCount++;
										goto ExtractNextToken_Unlocked;
									}
									else
									{
										master = 0;
									}
								}
								else
								{
									//** Try to read the secret using the enhanced protection password.
									/* for read the length should be initialized */
									if(rcode = NSSSReadSecret(&ctx, &targetObjDN,
											(pFlag | NSSS_EP_PASSWORD_USED_F), &ePassword, 
											&rInfo, &secretID, (SS_SECRET_T *)&readSecret, NULL))
									{
										printf("Read SecretID[%d] : [%s]\n", i, secretID.id);
										printf("Status Flags : [0x%x]\n", rInfo.statFlags);
										printf("Error [%d] NSSSReadSecret\n", rcode);
										PrintFlags("Secret Flags:\n", rInfo.statFlags);
										Pause();
						  				opCount++;
										goto ExtractNextToken_Unlocked;
									}
									else
									{
										master = 1;
									}
								}
							}
							
							if(rcode == NSSS_SUCCESS)
							{
								printf("Read SecretID[%d] : [%s]\n", i, secretID.id);
						  		printf("Status Flags : [0x%x]\n", rInfo.statFlags);
						  		PrintFlags("Secret Flags:\n", rInfo.statFlags);
						  		printf
						  		(
						  			"Secret data : length = [%d], data = [%s]\n", 
									readSecret.len,
									readSecret.data
								);
						  		if(aFlag)
						  		{
						  			crtStamp = localtime((long *)&rInfo.crtStamp);
						  			if(crtStamp)
						  			{
						  				printf("Creation time stamp: %s", asctime(crtStamp));
						  			}

						  			latStamp = localtime((long *)&rInfo.latStamp);
						  			if(latStamp && rInfo.latStamp)
						  			{	
						  				printf("Last accessed time stamp: %s", asctime(latStamp));
						  			}

						  			lmtStamp = localtime((long *)&rInfo.lmtStamp);
						  			if(lmtStamp)
						  			{
						  				printf("Last modified time stamp: %s\n", asctime(lmtStamp));
						  			}
						  		}								
						  		opCount++;
							}

							//* Get the secret ID of the next secret to be read.
ExtractNextToken_Unlocked:
							nameStr = strtok(NULL, "*");
						}
					} /* end for  read secret count...*/
				}
			} /* endif y */

			if(nslFlag)
			{
				endTime = time(NULL);
				if(endTime < startTime+300)
				{
					continue;
				}
				else
				{
					break;
				}
			}

		} /* end for */

Unlock_label:
		if(unlock)
		{
			/*
			** There are two ways to handle a locked SecretStore:
			**
			**    1) Remove the locked secrets (destroy the data), or
			**    2) Unlock the SecretStore using the master enhanced
			**       protection password (preservce the data)
			*/
			printf("\nDo you want to REMOVE LOCKED SECRETS(y/n)? ");
			c = getch();
			putchar(c);
			printf("\n\n");

			if((c == 'y') || (c == 'Y'))
			{
				//* Remove the locked secrets from the SecretStore.
				remLock = 1;
				if(rcode = NSSSUnlockSecrets(&ctx, &targetObjDN,
						(pFlag | NSSS_REMOVE_LOCK_FROM_STORE_F), NULL, NULL))
				{
					printf("Error [%d] NSSSUnlockSecrets\n", rcode);
					Pause();
				}
				else
				{
					printf("SecretStore Unlocked by removing the lock...\n"); 
					opCount++;
				}
			}
			else
			{		
				printf("\nDo you want to use Master Password to Unlock (y/n)? ");
				c = getch();
				putchar(c);
				printf("\n");

				if((c == 'y') || (c == 'Y'))
				{
					if(gsInfo.statusFlags & NSSS_EP_MASTER_PWORD_PRESENT_F)
					{
						strcpy(pword.pword, masterPword.pword);
						pword.pwordLen = masterPword.pwordLen;	
						// unlock the secret store
						if(rcode = NSSSUnlockSecrets(&ctx, &targetObjDN, 
							(pFlag | NSSS_EP_MASTER_PWORD_USED_F),
						 		&pword, NULL))
						{
							printf("Error [%d] NSSSUnlockSecrets\n", rcode);
							Pause();
						}
						else
						{
							printf("SecretStore Unlocked...\n");
							opCount++;
						}

					}
					else
					{
						printf("Master password not set!! ");
						Pause();									
						goto ERROR_1;
					}
					opCount++;
				}
				else
				{
					/* try the NDS password */
					/* not very secure but good for sample code demonstration */
					printf("Enter your previous valid NDS password: ");
	 				gets(pword.pword);
					pword.pwordLen = strlen(pword.pword)+1;
	 				printf("\n");
					//* Unlock the SecretStore.
					if(rcode = NSSSUnlockSecrets(&ctx, &targetObjDN, pFlag, &pword, NULL))
					{
						printf("Error [%d] NSSSUnlockSecrets\n", rcode);
						Pause();
					}
					else
					{
						printf("SecretStore Unlocked...\n");
					}

					opCount++;
				}
			}

			if(secretIDList.len)
			{
				//* Now read the secrets again.
				secretIDList.len = NSSS_MAX_IDLIST_BUF_LEN;
				if(rcode = NSSSEnumerateSecretIDs(&ctx, &targetObjDN, pFlag,
						srchStr, &count, &secretIDList, NULL))
				{
					printf("Error [%d] NSSSEnumerateSecretIDs\n", rcode);
				}

				opCount++;
				nameStr = strtok((char *)secretIDList.data, "*");

				for(i = 1; i <= (int)count; i++)
				{
					readSecret.len = NSSS_MAX_SECRET_BUF_LEN;
					strcpy(secretID.id, nameStr);
					secretID.len = strlen(secretID.id) + 1;

					rInfo.statFlags = 0;
					if(remLock)
					{
						/* for read the length should be initialized */
						if(rcode = NSSSReadSecret(&ctx, &targetObjDN,
								pFlag, NULL, &rInfo, &secretID, 
								(SS_SECRET_T *)&readSecret, NULL))
						{
							printf("Read SecretID[%d] : [%s]\n", i, secretID.id);
							printf("Status Flags : [0x%x]\n", rInfo.statFlags);
							printf("Error [%d] NSSSReadSecret\n", rcode);
							Pause();
						}
						opCount++;
						goto ExtractNextToken_Locked;
					}
					else
					{
						/* do the test read */
						if(rcode = NSSSReadSecret(&ctx, &targetObjDN, pFlag, NULL,
								&rInfo, &secretID, (SS_SECRET_T *)&readSecret, NULL))
						{
							if(rcode != NSSS_E_EP_ACCESS_DENIED)
							{
								printf("Read SecretID[%d] : [%s]\n", i, secretID.id);
								printf("Status Flags : [0x%x]\n", rInfo.statFlags);
								printf("Error [%d] NSSSReadSecret\n", rcode);
								Pause();
							}
							opCount++;
							goto ExtractNextToken_Locked;
						}
						
						if(rcode == NSSS_E_EP_ACCESS_DENIED)
						{
							if(rInfo.statFlags & NSSS_EP_PWORD_PRESENT_F)
							{
								//** Read the secret again, this time using the
								//** master password to override the lock.
								/* for a read the length should be initialized */
								if(rcode = NSSSReadSecret(&ctx, &targetObjDN,
								(pFlag | NSSS_EP_MASTER_PWORD_USED_F), &masterPword, 
								&rInfo, &secretID, (SS_SECRET_T *)&readSecret, NULL))
								{
									printf("Read SecretID[%d] : [%s]\n", i, secretID.id);
									printf("Status Flags : [0x%x]\n", rInfo.statFlags);
									printf("Error [%d] NSSSReadSecret\n", rcode);
									PrintFlags("Secret Flags:\n", rInfo.statFlags);
									Pause();
								}
								goto ExtractNextToken_Locked;
								opCount++;
							}
						}
					}
					
					if(rcode == NSSS_SUCCESS)
					{
						printf("Read SecretID[%d] : [%s]\n", i, secretID.id);
						printf("Status Flags : [0x%x]\n", rInfo.statFlags);
						PrintFlags("Secret Flags:\n", rInfo.statFlags);
						printf("Secret data : len = [%d], data = [%s]\n", 
							readSecret.len, readSecret.data);
						if(aFlag)
						{
							crtStamp = localtime((long *)&rInfo.crtStamp);
							if(crtStamp)
							{
								printf("Creation time stamp: %s", asctime(crtStamp));
							}

							latStamp = localtime((long *)&rInfo.latStamp);
							if(latStamp && rInfo.latStamp)
							{
								printf("Last accessed time stamp: %s", asctime(latStamp));
							}

							lmtStamp = localtime((long *)&rInfo.lmtStamp);
							if(lmtStamp)
							{
								printf("Last modified time stamp: %s\n", asctime(lmtStamp));
							}
						}
					}

ExtractNextToken_Locked:
					nameStr = strtok(NULL, "*");
				} /* end for ... */
			}
		} /* if unlock */

		if(nslFlag)
		{
			printf("\n<<=============== ENDING NSL OPS ======================>\n");
		}

		//** Remove the test secrets from the SecretStore.  There are two ways
		//** to do this: all at once (remove the entire SecretStore), or
		//** individually (remove only specific secrets).
		if(aFlag)
		{
			printf("\nDo you want to REMOVE the secrets(y/n)? ");
			c = getch();
			putchar(c);
			printf("\n\n");
		}
		else
		{
			c = 'y';
		}

		if(c == 'y' || c == 'Y')
		{
			if(aFlag)
			{
				printf("\nOne at a time(y/n)? ");
				c = getch();
				putchar(c);
				printf("\n");
			}
			else
			{
				if(repairFlag)
				{
					c = 'n';
				}
				else
				{
					c = 'y';
				}
			}

			if(c == 'y' || c == 'Y')
			{
				if(secretIDList.len)
				{
					//* Remove only the secrets we added.
					for(i = 1; i < 16; i++)
					{
						strcpy(secretID.id, appNames[ i - 1 ]);
						secretID.len = strlen(secretID.id) + 1;

						/* can remove one secret at a time */
						if((i == 15) && (j == exCount -1))
						{
							pFlag |= NSSS_DESTROY_CONTEXT_F;
						}

						/* can remove one secret at a time */
						if(rcode = NSSSRemoveSecret(&ctx, &targetObjDN, pFlag, &secretID, NULL))
						{
							printf("\nError [%d] NSSSRemoveSecret\n", rcode);
							printf("SecretID[%d] = [%s]\n", i, secretID.id);
							Pause();
						}
						else
						{
							printf("\nRemoved secret[%d] = \n[%s] from SS\n", i, secretID.id);
							opCount++;
						}
					}
				}

			}
			else
			{
				if(j == exCount -1)
				{
					/* remove the SecretStore */
					pFlag |= NSSS_DESTROY_CONTEXT_F;
				}

				//* Remove the entire SecretStore.
				if(rcode = NSSSRemoveSecretStore(&ctx, &targetObjDN, pFlag, NULL))
				{
					printf("\nError [%d] NSSSRemoveSecretStore\n", rcode);
				}
				else
				{
					printf("\nRemoved SecretStore\n");
					opCount++;
				}
			}
		}

		printf("\n\n\n");

		if(!nslFlag)
		{
			printf("NUMBER OF THE LOOPS = %d\n", j+1);
			printf("NUMBER OF OPERATIONS COMPLETED = %d\n", opCount);
		}

	} /* end for */

	if(!nslFlag)
	{
		endTime = time(NULL);
	}
	else
	{
		printf("\nNUMBER OF THE NSL USERS = %d\n", k+1);
		printf("TOTAL NUMBER OF OPERATIONS COMPLETED = %d\n", opCount);
		printf("NUMBER OF NSL COMPLETED OPERATIONS = %d\n", nslCount);
		printf("\nNSL START TIME = [%ld]\n", startTime);
		printf("NSL FINISH TIME = [%ld]\n\n", endTime);
	}

	printf("ELAPSED TIME IN SECONDS = [%ld]\n\n", (endTime - startTime));

/* ########################## CODE EXITS HERE ##################### */

ERROR_1:

	NSSSGetServiceInformation(&ctx, NULL, (pFlag | NSSS_DESTROY_CONTEXT_F), &gsInfo, NULL);

	if(secretIDList.data)
	{
		free(secretIDList.data);
	}

	if(readSecret.data)
	{
		free(readSecret.data);
	}

	if(writeSecret.data)
	{
		free(writeSecret.data);
	}

	Pause();

	exit(0);


/* ########################## CODE ENDS HERE ##################### */
}

