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 "config.h"
23 #include <unistd.h>
24 #include <stdlib.h>
25 #include <trousers/tss.h>
26 #include <trousers/trousers.h>
27 
28 #include "tpm_tspi.h"
29 #include "tpm_utils.h"
30 
31 BOOL useUnicode = FALSE;
32 
33 static const struct option sGenLongOpts[] = {
34 	{ "help", no_argument, NULL, 'h' },
35 	{ "version", no_argument, NULL, 'v' },
36 	{ "log", required_argument, NULL, 'l' },
37 	{ "unicode", no_argument, NULL, 'u' },
38 };
39 
40 static const char *pszGenShortOpts = "hvl:u";
41 
initIntlSys()42 void initIntlSys( ) {
43 
44 	setlocale( LC_ALL, "" );
45 	bindtextdomain( PACKAGE, LOCALEDIR );
46 	textdomain( PACKAGE );
47 }
48 
49 int
genericOptHandler(int a_iNumArgs,char ** a_pszArgs,const char * a_pszShortOpts,struct option * a_sLongOpts,int a_iNumOpts,CmdOptParser a_tCmdOptParser,CmdHelpFunction a_tCmdHelpFunction)50 genericOptHandler( int a_iNumArgs, char **a_pszArgs,
51 		   const char *a_pszShortOpts,
52 		   struct option *a_sLongOpts, int a_iNumOpts,
53 		   CmdOptParser a_tCmdOptParser, CmdHelpFunction a_tCmdHelpFunction ) {
54 
55 	CmdHelpFunction  tCmdHelp = ( a_tCmdHelpFunction ) ? a_tCmdHelpFunction
56 							   : logCmdHelp;
57 
58 #ifdef __GCC
59 	char  szShortOpts[strlen( pszGenShortOpts )
60 			  + ( ( a_pszShortOpts == NULL ) ? 0 : strlen( a_pszShortOpts ) )
61 			  + 1];
62 
63 	int            iNumGenLongOpts = sizeof( sGenLongOpts ) / sizeof( struct option );
64 	struct option  sLongOpts[iNumGenLongOpts + a_iNumOpts + 1];
65 
66 	int  iOpt;
67 	int  rc;
68 #else
69 	int  iOpt;
70 	int  rc;
71 
72 	char *szShortOpts;
73 	int  iNumShortOpts, iNumGenLongOpts;
74 	struct option *sLongOpts;
75 
76 	iNumShortOpts = strlen( pszGenShortOpts ) +
77 	    ( ( a_pszShortOpts == NULL ) ? 0 : strlen( a_pszShortOpts ) );
78 	iNumGenLongOpts = sizeof( sGenLongOpts ) / sizeof( struct option );
79 
80 	szShortOpts = malloc(iNumShortOpts + 1);
81 	sLongOpts = malloc((iNumGenLongOpts + a_iNumOpts + 1)
82 	    * sizeof(struct option));
83 	if( (szShortOpts == NULL) || (sLongOpts == NULL) ) {
84 		perror("malloc");
85 		return -1;
86 	}
87 #endif
88 	strcpy( szShortOpts, pszGenShortOpts);
89 	if ( a_pszShortOpts )
90 		strcat( szShortOpts, a_pszShortOpts );
91 
92 #ifdef __GCC
93 	__memset( sLongOpts, 0, sizeof( sLongOpts ) );
94 #else
95 	__memset( sLongOpts, 0, (iNumGenLongOpts + a_iNumOpts + 1) * sizeof(struct option));
96 #endif
97 	memcpy( sLongOpts, sGenLongOpts, sizeof( sGenLongOpts ) );
98 	if ( a_sLongOpts ) {
99 		memcpy( sLongOpts + iNumGenLongOpts,
100 			a_sLongOpts,
101 			a_iNumOpts * sizeof( struct option ) );
102 	}
103 
104 	while ( ( iOpt = getopt_long( a_iNumArgs, a_pszArgs,
105 					szShortOpts, sLongOpts, NULL ) ) != -1 ) {
106 
107 		switch ( iOpt ) {
108 			case 'h':
109 				tCmdHelp( a_pszArgs[0] );
110 				return -1;
111 
112 			case 'v':
113 				logMsg( _("%s version: %s\n"), a_pszArgs[0], CMD_VERSION );
114 				return -1;
115 
116 			case 'l':
117 				if ( !optarg ) {
118 					tCmdHelp( a_pszArgs[0] );
119 					return -1;
120 				}
121 
122 				if ( strcmp( optarg, LOG_NONE ) == 0 )
123 					iLogLevel = LOG_LEVEL_NONE;
124 				else if ( strcmp( optarg, LOG_ERROR ) == 0 )
125 					iLogLevel = LOG_LEVEL_ERROR;
126 				else if ( strcmp( optarg, LOG_INFO ) == 0 )
127 					iLogLevel = LOG_LEVEL_INFO;
128 				else if ( strcmp( optarg, LOG_DEBUG ) == 0 )
129 					iLogLevel = LOG_LEVEL_DEBUG;
130 				else {
131 					logMsg( _("Valid log levels are: %s, %s, %s, %s\n"),
132 						LOG_NONE,
133 						LOG_ERROR,
134 						LOG_INFO,
135 						LOG_DEBUG );
136 					tCmdHelp( a_pszArgs[0] );
137 					return -1;
138 				}
139 				break;
140 			case 'u':
141 				useUnicode = TRUE;
142 				break;
143 			case '?':
144 				tCmdHelp( a_pszArgs[0] );
145 				return -1;
146 
147 			default:
148 				if ( !a_tCmdOptParser )
149 					return -1;
150 
151 				rc = a_tCmdOptParser( iOpt, optarg );
152 				if ( rc != 0 )
153 					return rc;
154 				break;
155 		}
156 	}
157 
158 	return 0;
159 }
160 
161 void * __no_optimize
__memset(void * s,int c,size_t n)162 __memset(void *s, int c, size_t n)
163 {
164 	return memset(s, c, n);
165 }
166 
167 /*
168  * This function should be called when you are done with a password
169  * the above getPasswd function to properly clean up.
170  */
shredPasswd(char * a_pszPasswd)171 void shredPasswd( char *a_pszPasswd ) {
172 
173 	if ( a_pszPasswd ) {
174 		__memset( a_pszPasswd, 0, strlen( a_pszPasswd ) );
175 		free( a_pszPasswd );
176 	}
177 }
178 
179 /*
180  * You must free the memory passed back to you when you are finished.
181  * Loop will always terminate by the second pass.
182  * Safest use of getpass is to zero the memory as soon as possible.
183  */
getPlainPasswd(const char * a_pszPrompt,BOOL a_bConfirm)184 char *getPlainPasswd(const char *a_pszPrompt, BOOL a_bConfirm) {
185 	int len;
186 	return _getPasswd(a_pszPrompt, &len, a_bConfirm, FALSE);
187 }
188 
189 #ifndef TSS_LIB_IS_12
getPasswd(const char * a_pszPrompt,int * a_iLen,BOOL a_bConfirm)190 char *getPasswd(const char *a_pszPrompt, int* a_iLen,
191 		BOOL a_bConfirm) {
192 	return _getPasswd( a_pszPrompt, a_iLen, a_bConfirm, useUnicode);
193 }
194 #endif
_getPasswd(const char * a_pszPrompt,int * a_iLen,BOOL a_bConfirm,BOOL a_bUseUnicode)195 char *_getPasswd(const char *a_pszPrompt, int* a_iLen,
196 		BOOL a_bConfirm, BOOL a_bUseUnicode) {
197 
198 	char *pszPrompt = (char *)a_pszPrompt;
199 	char *pszPasswd = NULL;
200 	char *pszRetPasswd = NULL;
201 
202 	do {
203 		// Get password value from user - this is a static buffer
204 		// and should never be freed
205 		pszPasswd = getpass( pszPrompt );
206 		if (!pszPasswd && pszRetPasswd) {
207 			shredPasswd( pszRetPasswd );
208 			return NULL;
209 		}
210 
211 		// If this is confirmation pass check for match
212 		if ( pszRetPasswd ) {
213 			// Matched work complete
214 			if ( strcmp( pszPasswd, pszRetPasswd ) == 0)
215 				goto out;
216 
217 			// No match clean-up
218 			logMsg( _("Passwords didn't match\n") );
219 
220 			// pszPasswd will be cleaned up at out label
221 			shredPasswd( pszRetPasswd );
222 			pszRetPasswd = NULL;
223 			goto out;
224 		}
225 
226 		// Save this passwd for next pass and/or return val
227 		pszRetPasswd = strdup( pszPasswd );
228 		if ( !pszRetPasswd )
229 			goto out;
230 
231 		pszPrompt = _("Confirm password: ");
232 	} while (a_bConfirm);
233 
234 out:
235 	if (pszRetPasswd) {
236 		*a_iLen = strlen(pszRetPasswd);
237 
238 		if (a_bUseUnicode) {
239 			shredPasswd(pszRetPasswd);
240 			pszRetPasswd = (char *)Trspi_Native_To_UNICODE((BYTE *)pszPasswd, (unsigned int *)a_iLen);
241 		}
242 	}
243 
244 	// pszPasswd is a static buffer, just clear it
245 	if ( pszPasswd )
246 		__memset( pszPasswd, 0, strlen( pszPasswd ) );
247 
248 	return pszRetPasswd;
249 }
250 
251 /*
252  * You must free the memory passed back to you when you are finished.
253  */
getReply(const char * a_pszPrompt,int a_iMaxLen)254 char *getReply( const char *a_pszPrompt, int a_iMaxLen ) {
255 
256 	char *pszReply  = NULL;
257 	int   iReplyLen = a_iMaxLen + 2; // Room for newline and trailing zero
258 
259 	if ( iReplyLen <= 0 )
260 		goto out;
261 
262 	pszReply = (char *)calloc( iReplyLen, 1 );
263 	if ( !pszReply )
264 		goto out;
265 
266 	logMsg( "%s", a_pszPrompt );
267 	pszReply = fgets( pszReply, iReplyLen, stdin );
268 	if ( !pszReply )
269 		goto out;
270 
271 	// Be certain that a complete line was read
272 	if ( ( pszReply[ a_iMaxLen ] != '\n' ) && ( pszReply[ a_iMaxLen ] != '\0' ) ) {
273 		free( pszReply );
274 		pszReply = NULL;
275 		goto out;
276 	}
277 
278 	for ( iReplyLen -= 1; iReplyLen >= 0; iReplyLen-- ) {
279 		if ( pszReply[ iReplyLen ] == '\0' )
280 			continue;
281 
282 		if ( pszReply[ iReplyLen ] == '\n' )
283 			pszReply[ iReplyLen ] = '\0';
284 		break;
285 	}
286 
287 out:
288 	return pszReply;
289 }
290