Index: utility/tpmc.c |
diff --git a/utility/tpmc.c b/utility/tpmc.c |
index 86db829ab17793e8fe061bbfd87e41c6f65eae0d..b74bf1c4c307d794ce3de5ef45e59bdda5e8ffbf 100644 |
--- a/utility/tpmc.c |
+++ b/utility/tpmc.c |
@@ -12,6 +12,7 @@ |
#include "tlcl.h" |
#include "tpm_error_messages.h" |
+#include "tss_constants.h" |
typedef struct command_record { |
const char* name; |
@@ -20,9 +21,62 @@ typedef struct command_record { |
uint32_t (*handler)(void); |
} command_record; |
-/* Handler functions. These wouldn't exist if C had closures. |
+/* Set in main, consumed by handler functions below. We use global variables |
+ * so we can also choose to call Tlcl*() functions directly; they don't take |
+ * argv/argc. |
+ */ |
+int nargs; |
+char** args; |
+ |
+/* Converts a string in the form 0x[0-9a-f]+ to a 32-bit value. Returns 0 for |
+ * success, non-zero for failure. |
+ */ |
+int HexStringToUint32(const char* string, uint32_t* value) { |
+ char tail[1]; |
+ /* strtoul is not as good because it overflows silently */ |
+ char* format = strncmp(string, "0x", 2) ? "%8x%s" : "0x%8x%s"; |
+ int n = sscanf(string, format, value, tail); |
+ return n != 1; |
+} |
+ |
+/* Converts a string in the form [0-9a-f]+ to an 8-bit value. Returns 0 for |
+ * success, non-zero for failure. |
*/ |
+int HexStringToUint8(const char* string, uint8_t* value) { |
+ char* end; |
+ uint32_t large_value = strtoul(string, &end, 16); |
+ if (*end != '\0' || large_value > 0xff) { |
+ return 1; |
+ } |
+ *value = large_value; |
+ return 0; |
+} |
+/* TPM error check and reporting. Returns 0 if |result| is 0 (TPM_SUCCESS). |
+ * Otherwise looks up a TPM error in the error table and prints the error if |
+ * found. |
+ */ |
+uint32_t ErrorCheck(uint32_t result, const char* cmd) { |
+ if (result == 0) { |
+ return 0; |
+ } else { |
+ int i; |
+ int n = sizeof(tpm_error_table) / sizeof(tpm_error_table[0]); |
+ fprintf(stderr, "command \"%s\" failed with code 0x%x\n", cmd, result); |
+ for (i = 0; i < n; i++) { |
+ if (tpm_error_table[i].code == result) { |
+ fprintf(stderr, "%s\n%s\n", tpm_error_table[i].name, |
+ tpm_error_table[i].description); |
+ return 1; |
+ } |
+ } |
+ fprintf(stderr, "the TPM error code is unknown to this program\n"); |
+ return 1; |
+ } |
+} |
+ |
+/* Handler functions. These wouldn't exist if C had closures. |
+ */ |
static uint32_t HandlerGetFlags(void) { |
uint8_t disabled; |
uint8_t deactivated; |
@@ -43,6 +97,109 @@ static uint32_t HandlerDeactivate(void) { |
return TlclSetDeactivated(1); |
} |
+static uint32_t HandlerDefineSpace(void) { |
+ uint32_t index, size, perm; |
+ if (nargs != 5) { |
+ fprintf(stderr, "usage: tpmc def <index> <size> <perm>\n"); |
+ exit(1); |
+ } |
+ if (HexStringToUint32(args[2], &index) != 0 || |
+ HexStringToUint32(args[3], &size) != 0 || |
+ HexStringToUint32(args[4], &perm) != 0) { |
+ fprintf(stderr, "<index>, <size>, and <perm> must be " |
+ "32-bit hex (0x[0-9a-f]+)\n"); |
+ exit(1); |
+ } |
+ return TlclDefineSpace(index, perm, size); |
+} |
+ |
+static uint32_t HandlerWrite(void) { |
+ uint32_t index, size; |
+ uint8_t value[TPM_MAX_COMMAND_SIZE]; |
+ char** byteargs; |
+ int i; |
+ if (nargs < 3) { |
+ fprintf(stderr, "usage: tpmc write <index> [<byte0> <byte1> ...]\n"); |
+ exit(1); |
+ } |
+ if (HexStringToUint32(args[2], &index) != 0) { |
+ fprintf(stderr, "<index> must be 32-bit hex (0x[0-9a-f]+)\n"); |
+ exit(1); |
+ } |
+ size = nargs - 3; |
+ if (size > sizeof(value)) { |
+ fprintf(stderr, "byte array too large\n"); |
+ exit(1); |
+ } |
+ |
+ byteargs = args + 3; |
+ for (i = 0; i < size; i++) { |
+ if (HexStringToUint8(byteargs[i], &value[i]) != 0) { |
+ fprintf(stderr, "invalid byte %s, should be [0-9a-f][0-9a-f]?\n", |
+ byteargs[i]); |
+ exit(1); |
+ } |
+ } |
+ |
+ if (size == 0) { |
+ if (index == TPM_NV_INDEX_LOCK) { |
+ fprintf(stderr, "This would set the nvLocked bit. " |
+ "Use \"tpmc setnv\" instead.\n"); |
+ exit(1); |
+ } |
+ printf("warning: zero-length write\n"); |
+ } else { |
+ printf("writing %d byte%s\n", size, size > 1 ? "s" : ""); |
+ } |
+ |
+ return TlclWrite(index, value, size); |
+} |
+ |
+static uint32_t HandlerRead(void) { |
+ uint32_t index, size; |
+ uint8_t value[4096]; |
+ uint32_t result; |
+ int i; |
+ if (nargs != 4) { |
+ fprintf(stderr, "usage: tpmc read <index> <size>\n"); |
+ exit(1); |
+ } |
+ if (HexStringToUint32(args[2], &index) != 0 || |
+ HexStringToUint32(args[3], &size) != 0) { |
+ fprintf(stderr, "<index> and <size> must be 32-bit hex (0x[0-9a-f]+)\n"); |
+ exit(1); |
+ } |
+ if (size > sizeof(value)) { |
+ fprintf(stderr, "size of read (0x%x) is too big\n", size); |
+ exit(1); |
+ } |
+ result = TlclRead(index, value, size); |
+ if (result == 0 && size > 0) { |
+ for (i = 0; i < size - 1; i++) { |
+ printf("%x ", value[i]); |
+ } |
+ printf("%x\n", value[i]); |
+ } |
+ return result; |
+} |
+ |
+static uint32_t HandlerGetPermissions(void) { |
+ uint32_t index, permissions, result; |
+ if (nargs != 3) { |
+ fprintf(stderr, "usage: tpmc getp <index>\n"); |
+ exit(1); |
+ } |
+ if (HexStringToUint32(args[2], &index) != 0) { |
+ fprintf(stderr, "<index> must be 32-bit hex (0x[0-9a-f]+)\n"); |
+ exit(1); |
+ } |
+ result = TlclGetPermissions(index, &permissions); |
+ if (result == 0) { |
+ printf("space 0x%x has permissions 0x%x\n", index, permissions); |
+ } |
+ return result; |
+} |
+ |
/* Table of TPM commands. |
*/ |
command_record command_table[] = { |
@@ -61,18 +218,34 @@ command_record command_table[] = { |
{ "deactivate", "deact", "deactivate the TPM (needs PP, maybe reboot)", |
HandlerDeactivate }, |
{ "clear", "clr", "clear the TPM owner (needs PP)", TlclForceClear }, |
+ { "setnvlocked", "setnv", "set the nvLocked flag permanently (IRREVERSIBLE!)", |
+ TlclSetNvLocked }, |
+ { "lockphysicalpresence", "pplock", "lock PP to current value until reboot", |
+ TlclLockPhysicalPresence }, |
+ { "setbgloballock", "block", "set the bGlobalLock until reboot", |
+ TlclSetGlobalLock }, |
+ { "definespace", "def", "define a space (def <index> <size> <perm>)", |
+ HandlerDefineSpace }, |
+ { "write", "write", "write to a space (write <index> [<byte0> <byte1> ...])", |
+ HandlerWrite }, |
+ { "read", "read", "read from a space (read <index> <size>)", |
+ HandlerRead }, |
+ { "getpermissions", "getp", "print space permissions (getp <index>)", |
+ HandlerGetPermissions }, |
}; |
static int n_commands = sizeof(command_table) / sizeof(command_table[0]); |
int main(int argc, char* argv[]) { |
if (argc < 2) { |
- fprintf(stderr, "usage: %s <TPM command>\n or: %s help\n", |
+ fprintf(stderr, "usage: %s <TPM command> [args]\n or: %s help\n", |
argv[0], argv[0]); |
exit(1); |
} else { |
command_record* c; |
const char* cmd = argv[1]; |
+ nargs = argc; |
+ args = argv; |
if (strcmp(cmd, "help") == 0) { |
printf("%23s %7s %s\n\n", "command", "abbr.", "description"); |
@@ -86,25 +259,7 @@ int main(int argc, char* argv[]) { |
for (c = command_table; c < command_table + n_commands; c++) { |
if (strcmp(cmd, c->name) == 0 || strcmp(cmd, c->abbr) == 0) { |
- uint32_t result; |
- result = c->handler(); |
- if (result == 0) { |
- return 0; |
- } else { |
- int i; |
- int n = sizeof(tpm_error_table) / sizeof(tpm_error_table[0]); |
- fprintf(stderr, "command \"%s\" failed with code 0x%x\n", |
- cmd, result); |
- for (i = 0; i < n; i++) { |
- if (tpm_error_table[i].code == result) { |
- fprintf(stderr, "%s\n%s\n", tpm_error_table[i].name, |
- tpm_error_table[i].description); |
- return 1; |
- } |
- } |
- fprintf(stderr, "the error code is unknown to this program\n"); |
- return 1; |
- } |
+ return ErrorCheck(c->handler(), cmd); |
} |
} |