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