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