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_passwd.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#include <errno.h>
33#include <string.h>
34#include <pwd.h>
35
36
37/*
38 * Global variables
39 */
40BOOL  g_bSystem   = FALSE;		// Set SO pin specifier
41char *g_pszToken  = NULL;		// Token label to be used
42
43/*
44 * parseCallback
45 *   Process the command specific options.
46 */
47int
48parseCallback( int         a_iOpt,
49               const char *a_pszOptArg ) {
50
51	switch ( a_iOpt ) {
52		// Use the specified token label when finding the token
53		case 'k':
54			if ( !a_pszOptArg )
55				return -1;
56
57			g_pszToken = strdup( a_pszOptArg );
58			break;
59
60		case 's':
61			g_bSystem = TRUE;
62			break;
63	}
64
65	return 0;
66}
67
68/*
69 * usageCallback
70 *   Display command usage information.
71 */
72void
73usageCallback( const char *a_pszCmd ) {
74
75	logCmdHelp( a_pszCmd );
76	logCmdOption( "-k, --token STRING",
77			_("Use STRING to identify the label of the PKCS#11 token to be used") );
78	logCmdOption( "-s, --security-officer",
79			_("Change the security officer password") );
80}
81
82/*
83 * parseCmd
84 *   Parse the command line options.
85 */
86int
87parseCmd( int    a_iArgc,
88          char **a_pszArgv ) {
89
90	char *pszShortOpts = "k:s";
91	struct option  stLongOpts[] = {
92					{ "token", required_argument, NULL, 'k' },
93					{ "security-officer", no_argument, NULL, 's' },
94				};
95	int  iNumLongOpts = sizeof( stLongOpts ) / sizeof( struct option );
96
97	return genericOptHandler( a_iArgc, a_pszArgv,
98					pszShortOpts, stLongOpts, iNumLongOpts,
99					parseCallback, usageCallback );
100}
101
102int
103main( int    a_iArgc,
104      char **a_pszArgv ) {
105
106	int  rc = 1;
107
108	// Create buffers for PIN prompts for formatting using sprintf
109	char  szSoNewPinPrompt[ strlen( TOKEN_SO_NEW_PIN_PROMPT ) + 16 ];
110	char  szUserNewPinPrompt[ strlen( TOKEN_USER_NEW_PIN_PROMPT ) + 16 ];
111
112	char *pszPrompt = NULL;
113	char *pszPin    = NULL;
114	char *pszNewPin = NULL;
115
116	CK_RV              rv        = CKR_OK;
117	CK_USER_TYPE       tUser     = CKU_USER;
118	CK_SESSION_HANDLE  hSession  = 0;
119
120	// Set up i18n
121	initIntlSys( );
122
123	// Parse the command
124	if ( parseCmd( a_iArgc, a_pszArgv ) == -1 )
125		goto out;
126
127	// Open the PKCS#11 TPM Token
128	rv = openToken( g_pszToken );
129	if ( rv != CKR_OK )
130		goto out;
131
132	// Make sure the token is initialized
133	if ( !isTokenInitialized( ) ) {
134		logMsg( TOKEN_NOT_INIT_ERROR );
135		goto out;
136	}
137
138	// Open a session
139	rv = openTokenSession( CKF_RW_SESSION, &hSession );
140	if ( rv != CKR_OK )
141		goto out;
142
143	// Get the current password
144	if ( g_bSystem ) {
145		pszPrompt = TOKEN_SO_PIN_PROMPT;
146		tUser = CKU_SO;
147	}
148	else {
149		pszPrompt = TOKEN_USER_PIN_PROMPT;
150		tUser = CKU_USER;
151	}
152	pszPin = getPlainPasswd( pszPrompt, FALSE );
153	if ( !pszPin )
154		goto out;
155
156	// Login to the token
157	rv = loginToken( hSession, tUser, pszPin );
158	if ( rv != CKR_OK )
159		goto out;
160
161	// Get the new password
162	if ( g_bSystem ) {
163		sprintf( szSoNewPinPrompt, TOKEN_SO_NEW_PIN_PROMPT, getMinPinLen( ), getMaxPinLen( ) );
164		pszPrompt = szSoNewPinPrompt;
165	}
166	else {
167		sprintf( szUserNewPinPrompt, TOKEN_USER_NEW_PIN_PROMPT, getMinPinLen( ), getMaxPinLen( ) );
168		pszPrompt = szUserNewPinPrompt;
169	}
170
171	while ( TRUE ) {
172		// Prompt for a new SO password
173		pszNewPin = getPlainPasswd( pszPrompt, TRUE );
174		if ( !pszNewPin )
175			goto out;
176
177		// Set the new password
178		rv = setPin( hSession, pszPin, pszNewPin );
179		if ( rv == CKR_OK )
180			break;
181
182		if ( ( rv == CKR_PIN_INVALID ) || ( rv == CKR_PIN_LEN_RANGE ) )
183			logError( TOKEN_INVALID_PIN );
184		else
185			goto out;
186
187		shredPasswd( pszNewPin );
188	}
189
190	rc = 0;
191
192out:
193	shredPasswd( pszPin );
194	shredPasswd( pszNewPin );
195
196	if ( hSession )
197		closeTokenSession( hSession );
198
199	closeToken( );
200
201	if ( rc == 0 )
202		logInfo( TOKEN_CMD_SUCCESS, a_pszArgv[ 0 ] );
203	else
204		logInfo( TOKEN_CMD_FAILED, a_pszArgv[ 0 ] );
205
206	return rc;
207}
208