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  */
40 BOOL  g_bSystem   = FALSE;		// Set SO pin specifier
41 char *g_pszToken  = NULL;		// Token label to be used
42 
43 /*
44  * parseCallback
45  *   Process the command specific options.
46  */
47 int
parseCallback(int a_iOpt,const char * a_pszOptArg)48 parseCallback( 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  */
72 void
usageCallback(const char * a_pszCmd)73 usageCallback( 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  */
86 int
parseCmd(int a_iArgc,char ** a_pszArgv)87 parseCmd( 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 
102 int
main(int a_iArgc,char ** a_pszArgv)103 main( 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 
192 out:
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