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 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 "data_init.h"
23#include "data_common.h"
24
25#include <tpm_pkcs11.h>
26#include <tpm_utils.h>
27
28#include <stdlib.h>
29#include <unistd.h>
30#define _GNU_SOURCE
31#include <getopt.h>
32
33
34BOOL  g_bYes      = FALSE;		// Yes/No prompt reply
35char *g_pszToken  = NULL;		// Token label to be used
36
37/*
38 * parseCallback
39 *   Process the command specific options.
40 */
41int
42parseCallback( int         a_iOpt,
43               const char *a_pszOptArg ) {
44
45	switch ( a_iOpt ) {
46		// Use the specified token label when finding the token
47		case 'k':
48			if ( !a_pszOptArg )
49				return -1;
50
51			g_pszToken = strdup( a_pszOptArg );
52			break;
53
54		case 'y':
55			g_bYes = TRUE;
56			break;
57	}
58
59	return 0;
60}
61
62/*
63 * usageCallback
64 *   Display command usage information.
65 */
66void
67usageCallback( const char *a_pszCmd ) {
68
69	logCmdHelp( a_pszCmd );
70	logCmdOption( "-k, --token STRING",
71			_("Use STRING to identify the label of the PKCS#11 token to be used") );
72	logCmdOption( "-y, --yes",
73			_("Reply 'yes' to the clear TPM token prompt") );
74}
75
76/*
77 * parseCmd
78 *   Parse the command line options.
79 */
80int
81parseCmd( int    a_iArgc,
82          char **a_pszArgv ) {
83
84	char *pszShortOpts = "k:y";
85	struct option  stLongOpts[] = {
86					{ "token", required_argument, NULL, 'k' },
87					{ "yes", no_argument, NULL, 'y' },
88				};
89	int  iNumLongOpts = sizeof( stLongOpts ) / sizeof( struct option );
90
91	return genericOptHandler( a_iArgc, a_pszArgv,
92					pszShortOpts, stLongOpts, iNumLongOpts,
93					parseCallback, usageCallback );
94}
95
96int
97main( int    a_iArgc,
98      char **a_pszArgv ) {
99
100	int  rc = 1;
101
102	// Create buffers for PIN prompts for formatting using sprintf
103	char  szSoNewPinPrompt[ strlen( TOKEN_SO_NEW_PIN_PROMPT ) + 16 ];
104	char  szUserNewPinPrompt[ strlen( TOKEN_USER_NEW_PIN_PROMPT ) + 16 ];
105
106	char *pszReply      = NULL;
107	char *pszSoPin      = NULL;
108	char *pszNewSoPin   = NULL;
109	char *pszNewUserPin = NULL;
110
111	CK_RV              rv       = CKR_OK;
112	CK_SESSION_HANDLE  hSession = 0;
113
114	// Set up i18n
115	initIntlSys( );
116
117	// Parse the command
118	if ( parseCmd( a_iArgc, a_pszArgv ) == -1 )
119		goto out;
120
121	// Open the PKCS#11 TPM Token
122	rv = openToken( g_pszToken );
123	if ( rv != CKR_OK )
124		goto out;
125
126	// Check if the token is already initialized
127	if ( isTokenInitialized( ) ) {
128		// Warn and ask the user before clearing
129		if ( !g_bYes ) {
130			pszReply = getReply( TOKEN_CLEAR_PROMPT, 1 );
131			if ( !pszReply ||
132				( strlen( pszReply ) == 0 ) ||
133				( strcasecmp( pszReply, TOKEN_CLEAR_NO ) == 0 ) ) {
134				goto out;
135			}
136		}
137
138		// Prompt for the current SO password
139		pszSoPin = getPlainPasswd( TOKEN_SO_PIN_PROMPT, FALSE );
140		if ( !pszSoPin )
141			goto out;
142	}
143	else
144		pszSoPin = strdup( TOKEN_SO_INIT_PIN );
145
146	// Clear the TPM token
147	rv = initToken( pszSoPin );
148	if ( rv != CKR_OK )
149		goto out;
150
151	// Open a session
152	rv = openTokenSession( CKF_RW_SESSION, &hSession );
153	if ( rv != CKR_OK )
154		goto out;
155
156	// Login to the token
157	rv = loginToken( hSession, CKU_SO, TOKEN_SO_INIT_PIN );
158	if ( rv != CKR_OK )
159		goto out;
160
161	sprintf( szSoNewPinPrompt, TOKEN_SO_NEW_PIN_PROMPT, getMinPinLen( ), getMaxPinLen( ) );
162	while ( TRUE ) {
163		// Prompt for a new SO password
164		pszNewSoPin = getPlainPasswd( szSoNewPinPrompt, TRUE );
165		if ( !pszNewSoPin )
166			goto out;
167
168		// Set the new password
169		rv = setPin( hSession, TOKEN_SO_INIT_PIN, pszNewSoPin );
170		if ( rv == CKR_OK )
171			break;
172
173		if ( ( rv == CKR_PIN_INVALID ) || ( rv == CKR_PIN_LEN_RANGE ) )
174			logError( TOKEN_INVALID_PIN );
175		else
176			goto out;
177
178		shredPasswd( pszNewSoPin );
179	}
180
181	// Open a new session
182	closeTokenSession( hSession );
183	hSession = 0;
184	rv = openTokenSession( CKF_RW_SESSION, &hSession );
185	if ( rv != CKR_OK )
186		goto out;
187
188	// Login to the token
189	rv = loginToken( hSession, CKU_USER, TOKEN_USER_INIT_PIN );
190	if ( rv != CKR_OK )
191		goto out;
192
193	sprintf( szUserNewPinPrompt, TOKEN_USER_NEW_PIN_PROMPT, getMinPinLen( ), getMaxPinLen( ) );
194	while ( TRUE ) {
195		// Prompt for a new User password
196		pszNewUserPin = getPlainPasswd( szUserNewPinPrompt, TRUE );
197		if ( !pszNewUserPin )
198			goto out;
199
200		// Set the new password
201		rv = setPin( hSession, TOKEN_USER_INIT_PIN, pszNewUserPin );
202		if ( rv == CKR_OK )
203			break;
204
205		if ( ( rv == CKR_PIN_INVALID ) || ( rv == CKR_PIN_LEN_RANGE ) )
206			logError( TOKEN_INVALID_PIN );
207		else
208			goto out;
209
210		shredPasswd( pszNewUserPin );
211	}
212
213	rc = 0;
214
215out:
216	free( pszReply );
217	shredPasswd( pszSoPin );
218	shredPasswd( pszNewSoPin );
219	shredPasswd( pszNewUserPin );
220
221	if ( hSession )
222		closeTokenSession( hSession );
223
224	closeToken( );
225
226	if ( rc == 0 )
227		logInfo( TOKEN_CMD_SUCCESS, a_pszArgv[ 0 ] );
228	else
229		logInfo( TOKEN_CMD_FAILED, a_pszArgv[ 0 ] );
230
231	return rc;
232}
233