/*
 * The Initial Developer of the Original Code is International
 * Business Machines Corporation. Portions created by IBM
 * Corporation are Copyright (C) 2007 International Business
 * Machines Corporation. All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the Common Public License as published by
 * IBM Corporation; either version 1 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * Common Public License for more details.
 *
 * You should have received a copy of the Common Public License
 * along with this program; if not, a copy can be viewed at
 * http://www.opensource.org/licenses/cpl1.0.php.
 */

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

#include <tss/platform.h>
#include <tss/tss_defines.h>
#include <tss/tss_typedef.h>
#include <tss/tss_structs.h>
#include <tss/tss_error.h>
#include <tss/tspi.h>

#include <getopt.h>

// Local TCSD
#define SERVER    NULL

#define MAX_PCRNUM 24

/*

 TPM PCR Read

 Usage:
  tpm_pcrread -p index 
 
 */

int hex2bin(void *dest, const void *src, size_t n);
void fprinthex(FILE* fp,char *str, unsigned char *buf, int len);
void fprinthex2(FILE* fp,char *str, unsigned char *buf, int len);

/* options */
const struct option long_option[] = {
	{"help", no_argument, NULL, 'h'},
	{"pcrindex", required_argument, NULL, 'p'},
	{"all", no_argument, NULL, 'a'},
	{"kernel", no_argument, NULL, 'k'},
	{"output", required_argument, NULL, 'o'},
	{0, 0, 0, 0}
};
const char short_option[] = "p:hako:";

void usage() {
	printf("Usage: tpm_pcrread [options]\n");
	printf("\t-h, --help\n");
	printf("\t\tDisplay command usage info.\n");

	printf("\t-p, --pcrindex NUMBER\n");
	printf("\t\tPCR to read to.  Default is none.  This option can be specified multiple times to choose more than one PCR.\n");

	printf("\t-a, --all\n");
	printf("\t\tDisplay all PCRs\n");
	
	printf("\t-k, --kernel\n");
	printf("\t\tDisplay PCR same as kernel format (/sys/class/misc/tpm0/device/pcrs)\n");
	
	printf("\t-o, --output FILE\n");
	printf("\t\tFilename to write quote result to.  Default is STDOUT.\n");
}

int main(int argc, char *argv[])
{
	TSS_RESULT result;
	TSS_HCONTEXT hContext;

	TSS_HTPM hTPM;

	BYTE *blob;
	UINT32 blobLength;
	BYTE pcrSelect[MAX_PCRNUM];		// TODO
	UINT32 subCap;

	int so;
	int pcrindex;
	//int all = 0;
	int i;
	int pcrNum =16;
	int kernel = 0;
	
	char *filename = NULL;
	FILE *fp = stdout;
	
	memset(pcrSelect,0,MAX_PCRNUM);

	/* we parse the option args */

	while (1) {
		so = getopt_long(argc, argv, short_option, long_option, 0);
		if (so == -1)
			break;	// END

		switch (so) {

		case 'p':	/* PCR */
			pcrindex = atoi(optarg);
			pcrSelect[pcrindex] = 1;

			/*
			result =
			    Tspi_TPM_PcrRead(hTPM, pcrindex, &blobLength,
					     &blob);
			if (result != TSS_SUCCESS) {
				printf("ERROR: failed rc=0x%x\n", result);
				goto free;
			}
			printf("pcr.%d=", pcrindex);
			printhex("", blob, blobLength);
			Tspi_Context_FreeMemory(hContext, blob);

			pcr[pcrindex] = 1;
			*/
			
			break;
		case 'a':	/* all */
			memset(pcrSelect,1,MAX_PCRNUM);
			break;
		case 'k':	/* kernel */
			kernel = 1;
			break;
		case 'o':	/* output file name */
			filename = optarg;
			fp = fopen(filename, "w");
			break;
		case 'h':	/* help */
			usage();
			goto close;
		default:
			usage();
			goto close;
		}
	}
	

	/* Connect to TCSD */

	result = Tspi_Context_Create(&hContext);
	if (result != TSS_SUCCESS) {
		printf("ERROR: Tspi_Context_Create failed rc=0x%x\n",
		       result);
		goto close;
	}

	result = Tspi_Context_Connect(hContext, SERVER);
	if (result != TSS_SUCCESS) {
		printf("ERROR: Tspi_Context_Connect failed rc=0x%x\n",
		       result);
		goto close;
	}


	/* Get TPM handles */
	result = Tspi_Context_GetTpmObject(hContext, &hTPM);
	if (result != TSS_SUCCESS) {
		printf("ERROR: Tspi_Context_GetTpmObject failed rc=0x%x\n",
		       result);
		goto close;
	}


	
	/* get PCR num */
	subCap = TSS_TPMCAP_PROP_PCR;
	result =
		Tspi_TPM_GetCapability( 
			hTPM,
			TSS_TPMCAP_PROPERTY,
			sizeof(UINT32),
			(BYTE*) &subCap,
			&blobLength,
			&blob);
	pcrNum = (UINT32) *blob;
	
	if (result != TSS_SUCCESS) {
		printf("ERROR: Tspi_TPM_GetCapability failed rc=0x%x\n", result);
		goto free;
	}
                                                                                
	/* Print */
	for (i=0;i<pcrNum;i++){
		if (pcrSelect[i] == 1) {
			result =
			    Tspi_TPM_PcrRead(hTPM, i, &blobLength,
					     &blob);
				
			if (result != TSS_SUCCESS) {
				printf("ERROR: Tspi_TPM_PcrRead failed rc=0x%x\n", result);
				goto free;
			}
			
			if (kernel == 1) {
				fprintf(fp,"PCR-%02d:", i);
				fprinthex2(fp," ", blob, blobLength);
			}
			else {	
				fprintf(fp,"pcr.%d=", i);
				fprinthex(fp,"", blob, blobLength);
			}
			Tspi_Context_FreeMemory(hContext, blob);
		}
	}


      free:
	Tspi_Context_FreeMemory(hContext, NULL);

	/* Close TSS/TPM */
      close:
	Tspi_Context_Close(hContext);
	
	fclose(fp);

	return result;
}
