1/*
2 * The Initial Developer of the Original Code is International
3 * Business Machines Corporation. Portions created by IBM
4 * Corporation are Copyright (C) 2005, 2006 International Business
5 * Machines Corporation. All Rights Reserved.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the Common Public License as published by
9 * IBM Corporation; either version 1 of the License, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * Common Public License for more details.
16 *
17 * You should have received a copy of the Common Public License
18 * along with this program; if not, a copy can be viewed at
19 * http://www.opensource.org/licenses/cpl1.0.php.
20 */
21
22#include "tpm_utils.h"
23#include "tpm_tspi.h"
24
25/*
26 * Never set change to false.
27 * Value doesn't matter for the locks.
28 */
29struct physFlag {
30	char *name;
31	TSS_FLAG property;
32	BOOL change;
33	BOOL value;
34};
35
36/*
37 * Order is important.
38 * First must set cmd and hw enable correctly followed by the lock.
39 * Then setting presence can be attempted followed by the lock
40 */
41enum {
42	cmdEnable = 0,
43	hwdEnable,
44	lifeLock,
45	present,
46	lock,
47	num_flags
48};
49
50static struct physFlag flags[] = {
51	{N_("Command Enable"), TSS_TPMSTATUS_PHYSPRES_CMDENABLE},
52	{N_("Hardware Enable"), TSS_TPMSTATUS_PHYSPRES_HWENABLE},
53	{N_("Lifetime Lock"), TSS_TPMSTATUS_PHYSPRES_LIFETIMELOCK},
54	{N_("Physical Presence"), TSS_TPMSTATUS_PHYSPRESENCE},
55	{N_("Lock"), TSS_TPMSTATUS_PHYSPRES_LOCK},
56	{0, 0, 0, 0}
57};
58static BOOL bCheck = FALSE;
59static BOOL bChangeRequested = FALSE;
60static BOOL bYes = FALSE;
61static TSS_BOOL bValue;
62static BOOL isWellKnown = FALSE;
63static BYTE well_known[] = TSS_WELL_KNOWN_SECRET;
64TSS_HCONTEXT hContext = 0;
65
66
67static void help(const char *aCmd)
68{
69	logCmdHelp(aCmd);
70	logUnicodeCmdOption();
71	logCmdOption("-s, --status",
72		     _("Report current physical presence states."));
73	logCmdOption("-a, --assert", _("Assert that admin is present."));
74	logCmdOption("-c, --clear", _("Clear assertion of admin presence."));
75	logCmdOption("--lock",
76		     _("Lock TPM presence assertion into specified state."));
77	logCmdOption("--enable-cmd",
78		     _("Allow TPM to accept Physical Presence Command."));
79	logCmdOption("--disable-cmd",
80		     _("Disallow TPM to accept Physical Presence Command."));
81	logCmdOption("--enable-hw",
82		     _("Allow TPM to accept Hardware Physical Presence."));
83	logCmdOption("--disable-hw",
84		     _("Disallow TPM to accept Hardware Physical Presence."));
85	logCmdOption("--set-lifetime-lock",
86		     _("Prevent further modification of TPM Physical Presence\n\t\tCommand and Hardware Enablement states.\n\t\tTHIS ACTION IS PERMANENT AND CAN NEVER BE UNDONE."));
87	logCmdOption("-y, --yes",
88		     _("Automatically respond yes to all prompts.  Only use\n\t\tthis if you are sure of the current state and don't want\n\t\tany textra checking done before setting the lifetime lock"));
89	logCmdOption("-z, --well-known",
90		     _("Use 20 bytes of zeros (TSS_WELL_KNOWN_SECRET) as the TPM secret authorization data."));
91}
92
93static int parse(const int aOpt, const char *aArg)
94{
95	switch (aOpt) {
96	case 's':
97		logDebug(_("Changing mode to check status.\n"));
98		bCheck = TRUE;
99		break;
100	case 'a':
101		logDebug(_("Changing mode to assert presence.\n"));
102		flags[present].change = TRUE;
103		flags[present].value = TRUE;
104		bChangeRequested = TRUE;
105		break;
106	case 'c':
107		logDebug(_("Changing mode to clear presence.\n"));
108		flags[present].change = TRUE;
109		flags[present].value = FALSE;
110		bChangeRequested = TRUE;
111		break;
112	case 'k':
113		logDebug(_("Changing mode to lock presence.\n"));
114		flags[lock].change = TRUE;
115		flags[lock].value = TRUE;
116		bChangeRequested = TRUE;
117		break;
118	case 'm':
119		logDebug(_("Changing mode to enable command presence.\n"));
120		flags[cmdEnable].change = TRUE;
121		flags[cmdEnable].value = TRUE;
122		bChangeRequested = TRUE;
123		break;
124	case 'd':
125		logDebug(_("Changing mode to disable command presence.\n"));
126		flags[cmdEnable].change = TRUE;
127		flags[cmdEnable].value = FALSE;
128		bChangeRequested = TRUE;
129		break;
130	case 'e':
131		logDebug(_("Changing mode to enable hardware presence.\n"));
132		flags[hwdEnable].change = TRUE;
133		flags[hwdEnable].value = TRUE;
134		bChangeRequested = TRUE;
135		break;
136	case 'h':
137		logDebug(_("Changing mode to disable hardware presence.\n"));
138		flags[hwdEnable].change = TRUE;
139		flags[hwdEnable].value = FALSE;
140		bChangeRequested = TRUE;
141		break;
142	case 't':
143		logDebug(_("Changing mode to set lifetime presence lock.\n"));
144		flags[lifeLock].change = TRUE;
145		flags[lifeLock].value = TRUE;
146		bChangeRequested = TRUE;
147		break;
148	case 'y':
149		logDebug(_("Changing mode to automatically answer yes.\n"));
150		bYes = TRUE;
151		break;
152	case 'z':
153		logDebug(_("Using TSS_WELL_KNOWN_SECRET to authorize the TPM command\n"));
154		isWellKnown = TRUE;
155		break;
156	default:
157		return -1;
158	}
159	return 0;
160
161}
162
163static BOOL confirmLifeLock(TSS_HCONTEXT hContext, TSS_HTPM hTpm)
164{
165
166	TSS_BOOL bCmd, bHwd;
167	BOOL bRc;
168	TSS_HPOLICY hTpmPolicy;
169	char *pwd = NULL;
170	int pswd_len;
171	char rsp[5];
172	int scanCount;
173
174	//get status w/o owner auth (FAILS 1.1, should PASS 1.2)
175	if (tpmGetStatus(hTpm, flags[cmdEnable].property, &bCmd) !=
176	    TSS_SUCCESS
177	    || tpmGetStatus(hTpm, flags[hwdEnable].property,
178			    &bHwd) != TSS_SUCCESS) {
179		logDebug
180		    (_("Unable to determine current state without authorization\n"));
181		if (isTpmOwned(hContext)) {
182			logDebug(_("TPM is owned\n"));
183			if (isWellKnown) {
184				pwd = (char *)well_known;
185				pswd_len = sizeof(well_known);
186			} else {
187				// Prompt for owner password
188				pwd = GETPASSWD(_("Enter owner password: "), &pswd_len, FALSE);
189				if (!pwd) {
190					logMsg(_("Failed to get password\n"));
191					goto warn;
192				}
193			}
194
195			if (policyGet(hTpm, &hTpmPolicy) != TSS_SUCCESS)
196				goto warn;
197
198			if (policySetSecret(hTpmPolicy, pswd_len, (BYTE *)pwd)
199			    != TSS_SUCCESS)
200				goto warn;
201			//get status w/ owner auth
202			if (tpmGetStatus
203			    (hTpm, flags[cmdEnable].property,
204			     &bCmd) != TSS_SUCCESS
205			    || tpmGetStatus(hTpm,
206					    flags[hwdEnable].property,
207					    &bHwd) != TSS_SUCCESS) {
208				logDebug
209				    (_("Unable to determine current state with the entered password.\n"));
210				goto warn;
211			}
212			goto give_vals;
213		} else {	//can't determine values
214		      warn:
215			logMsg
216			    (_("Unable to programatically determine the current setting of TPM Physcial Presence Command Enable and Hardware Enable states.  Make sure you are aware of and comfortable with the current states.\n"));
217		}
218	} else {
219	      give_vals:
220		logMsg(_("Current State:\n"));
221		logMsg("\t%s: %s\n", _(flags[cmdEnable].name), logBool(mapTssBool(bCmd)));
222		logMsg("\t%s: %s\n", _(flags[hwdEnable].name), logBool(mapTssBool(bHwd)));
223		logMsg
224		    (_("These will be the permanent values if you choose to proceed.\n"));
225	}
226	logMsg
227	    (_("This command cannot be undone.  Are you sure you want to continue?[y/N]\n"));
228	scanCount = scanf("%5s", rsp);
229
230	 /* TRANSLATORS: this should be the affirmative letter that was  prompted for in the message corresponding to: "Are you sure you want to continue?[y/N]" */
231	if (strcmp(rsp, _("y")) == 0) {
232		logMsg
233		    (_("Setting the lifetime lock was confirmed.\nContinuing.\n"));
234		bRc = TRUE;
235
236	} else {
237		logMsg
238		    (_("Continuing to set the lifetime lock was declined.\nAction canceled.\n"));
239		bRc = FALSE;
240	}
241
242	if (hTpmPolicy)
243		policyFlushSecret(hTpmPolicy);
244
245	if (pwd && !isWellKnown)
246		shredPasswd(pwd);
247
248	return bRc;
249}
250
251
252
253/*
254 * Affect: Toggle TPM presence states
255 * Default: Display current states
256 * Requires: Display requires owner auth.
257 * 	Lifetime lock will attempt owner auth to warn about current states before confirming
258 */
259int main(int argc, char **argv)
260{
261
262	char *szTpmPasswd = NULL;
263	int pswd_len;
264	TSS_HTPM hTpm;
265	TSS_HPOLICY hTpmPolicy;
266	int iRc = -1;
267	int i = 0;
268	struct option opts[] = { {"status", no_argument, NULL, 's'},
269	{"assert", no_argument, NULL, 'a'},
270	{"clear", no_argument, NULL, 'c'},
271	{"lock", no_argument, NULL, 'k'},
272	{"enable-cmd", no_argument, NULL, 'm'},
273	{"disable-cmd", no_argument, NULL, 'd'},
274	{"enable-hw", no_argument, NULL, 'e'},
275	{"disable-hw", no_argument, NULL, 'w'},
276	{"set-lifetime-lock", no_argument, NULL, 't'},
277	{"yes", no_argument, NULL, 'y'},
278	{"well-known", no_argument, NULL, 'z'},
279	};
280
281	initIntlSys();
282
283	if (genericOptHandler
284	    (argc, argv, "acsyz", opts,
285	     sizeof(opts) / sizeof(struct option), parse, help) != 0)
286		goto out;
287
288	//Connect to TSS and TPM
289	if (contextCreate(&hContext) != TSS_SUCCESS)
290		goto out;
291
292	if (contextConnect(hContext) != TSS_SUCCESS)
293		goto out_close;
294
295	if (contextGetTpm(hContext, &hTpm) != TSS_SUCCESS)
296		goto out_close;
297
298	if (bCheck || !bChangeRequested) {
299		logInfo(_("Checking current status: \n"));
300		if (isWellKnown) {
301			szTpmPasswd = (char *)well_known;
302			pswd_len = sizeof(well_known);
303		} else {
304			// Prompt for owner password
305			szTpmPasswd = GETPASSWD(_("Enter owner password: "), &pswd_len, FALSE);
306			if (!szTpmPasswd) {
307				logMsg(_("Failed to get password\n"));
308				goto out_close;
309			}
310		}
311
312		if (policyGet(hTpm, &hTpmPolicy) != TSS_SUCCESS)
313			goto out_close;
314
315		if (policySetSecret(hTpmPolicy, pswd_len,
316				    (BYTE *)szTpmPasswd) != TSS_SUCCESS)
317			goto out_close;
318
319		logMsg(_("Physical Presence Status:\n"));
320
321		do {
322			if (tpmGetStatus(hTpm, flags[i].property,
323					 &bValue) != TSS_SUCCESS)
324				goto out_close;
325			logMsg("\t%s: %s\n", _(flags[i].name),
326			       logBool(mapTssBool(bValue)));
327		} while (flags[++i].name);
328
329		goto out_success;
330	}
331
332	do {
333		if (flags[i].change) {
334			logInfo(_("Requested to Change %s to %s\n"),
335				_(flags[i].name), logBool(flags[i].value));
336
337			if (i == lifeLock && !
338			    (bYes || confirmLifeLock(hContext, hTpm)))
339				continue;
340
341			if (tpmSetStatus(hTpm, flags[i].property,
342					 flags[i].value) != TSS_SUCCESS) {
343				logError(_("Change to %s Failed\n"),
344					 _(flags[i].name));
345				goto out;
346			}
347			logInfo(_("Change to %s Successful\n"),
348				_(flags[i].name));
349		}
350	} while (flags[++i].name);
351
352      out_success:
353	logSuccess(argv[0]);
354	iRc = 0;
355      out_close:
356	contextClose(hContext);
357      out:
358    if (szTpmPasswd && !isWellKnown)
359	shredPasswd( szTpmPasswd );
360	return iRc;
361}
362