|
|
1.1 root 1: /*
2: Copyright (c) 2008 TrueCrypt Foundation. All rights reserved.
3:
4: Governed by the TrueCrypt License 2.4 the full text of which is contained
5: in the file License.txt included in TrueCrypt binary and source code
6: distribution packages.
7: */
8:
9: #include "System.h"
10: #ifdef TC_UNIX
11: #include <signal.h>
12: #include <termios.h>
13: #include <unistd.h>
14: #endif
15:
16: #include "Application.h"
17: #include "TextUserInterface.h"
18:
19: namespace TrueCrypt
20: {
21: TextUserInterface::TextUserInterface ()
22: {
23: #ifdef TC_UNIX
24: signal (SIGHUP, OnSignal);
25: signal (SIGINT, OnSignal);
26: signal (SIGQUIT, OnSignal);
27: signal (SIGTERM, OnSignal);
28: #endif
29:
30: FInputStream.reset (new wxFFileInputStream (stdin));
31: TextInputStream.reset (new wxTextInputStream (*FInputStream));
32: }
33:
34: TextUserInterface::~TextUserInterface ()
35: {
36: #ifdef TC_UNIX
37: signal (SIGHUP, SIG_DFL);
38: signal (SIGINT, SIG_DFL);
39: signal (SIGQUIT, SIG_DFL);
40: signal (SIGTERM, SIG_DFL);
41: #endif
42: }
43:
44: shared_ptr <KeyfileList> TextUserInterface::AskKeyfiles (const wxString &message) const
45: {
46: wxString msg = _("Enter keyfile");
47: if (!message.empty())
48: msg = message;
49:
50: make_shared_auto (KeyfileList, keyfiles);
51:
52: wxString s;
53: wxString m = msg + L" [" + _("none") + L"]: ";
54: while (!(s = AskString (m)).empty())
55: {
56: keyfiles->push_back (make_shared <Keyfile> (wstring (s)));
57: m = msg + L" [" + _("finish") + L"]: ";
58: }
59:
60: return keyfiles;
61: }
62:
63: shared_ptr <VolumePassword> TextUserInterface::AskPassword (const wxString &message, bool verify) const
64: {
65: wxString msg = LangString["ENTER_PASSWORD"] + L": ";
66: if (!message.empty())
67: msg = message + L": ";
68:
69: SetTerminalEcho (false);
70: finally_do ({ TextUserInterface::SetTerminalEcho (true); });
71:
72: wchar_t passwordBuf[4096];
73: finally_do_arg (BufferPtr, BufferPtr (reinterpret_cast <byte *> (passwordBuf), sizeof (passwordBuf)), { finally_arg.Erase(); });
74:
75: make_shared_auto (VolumePassword, password);
76:
77: bool verPhase = false;
78: while (true)
79: {
80: ShowString (verPhase ? wxString (_("Re-enter password: ")) : msg);
81:
82: const wxString &passwordStr = TextInputStream->ReadLine();
83: size_t length = passwordStr.size();
84:
85: ShowString (L"\n");
86:
87: if (length < 1)
88: {
89: throw_sys_if (ferror (stdin));
90:
91: password->Set (passwordBuf, 0);
92: return password;
93: }
94:
95: for (size_t i = 0; i < length && i < VolumePassword::MaxSize; ++i)
96: {
97: passwordBuf[i] = (wchar_t) passwordStr[i];
98: const_cast <wchar_t *> (passwordStr.c_str())[i] = L'X';
99: }
100:
101: if (verify && verPhase)
102: {
103: make_shared_auto (VolumePassword, verPassword);
104: verPassword->Set (passwordBuf, length);
105:
106: if (*password != *verPassword)
107: {
108: ShowInfo (_("Passwords do not match."));
109: verPhase = false;
110: continue;
111: }
112: }
113:
114: password->Set (passwordBuf, length);
115:
116: if (!verPhase)
117: {
118: try
119: {
120: password->CheckPortability();
121: }
122: catch (UnportablePassword &e)
123: {
124: if (verify)
125: {
126: ShowError (e);
127: verPhase = false;
128: continue;
129: }
130:
131: ShowWarning ("UNSUPPORTED_CHARS_IN_PWD_RECOM");
132: }
133:
134: if (verify)
135: {
136: if (password->Size() < VolumePassword::WarningSizeThreshold
137: && !AskYesNo (LangString ["PASSWORD_LENGTH_WARNING"], false, true))
138: continue;
139: }
140: }
141:
142: if (!verify || verPhase)
143: return password;
144:
145: if (!verPhase)
146: verPhase = true;
147: }
148:
149: return password;
150: }
151:
152: wstring TextUserInterface::AskString (const wxString &message) const
153: {
154: ShowString (message);
155:
156: return wstring (TextInputStream->ReadLine());
157: }
158:
159: bool TextUserInterface::AskYesNo (const wxString &message, bool defaultYes, bool warning) const
160: {
161: while (true)
162: {
163: wxString s = AskString (StringFormatter (L"{0} (y={1}/n={2}) [{3}]: ",
164: message, LangString["YES"], LangString["NO"], LangString[defaultYes ? "YES" : "NO"]));
165:
166: if (s.IsSameAs (L'n', false) || s.IsSameAs (L"no", false) || !defaultYes && s.empty())
167: return false;
168:
169: if (s.IsSameAs (L'y', false) || s.IsSameAs (L"yes", false) || defaultYes && s.empty())
170: return true;
171: };
172: }
173:
174: shared_ptr <VolumePath> TextUserInterface::AskVolumePath (const wxString &message) const
175: {
176: return make_shared <VolumePath> (AskString (message.empty() ? wxString (_("Enter volume path: ")) : message));
177: }
178:
179: void TextUserInterface::ChangePassword (shared_ptr <VolumePath> volumePath, shared_ptr <VolumePassword> password, shared_ptr <KeyfileList> keyfiles, shared_ptr <VolumePassword> newPassword, shared_ptr <KeyfileList> newKeyfiles) const
180: {
181: shared_ptr <Volume> volume;
182:
183: // Volume path
184: if (!volumePath.get())
185: {
186: if (Preferences.NonInteractive)
187: throw MissingArgument (SRC_POS);
188:
189: volumePath = AskVolumePath ();
190: }
191:
192: bool passwordInteractive = !password.get();
193: bool keyfilesInteractive = !keyfiles.get();
194:
195: while (true)
196: {
197: // Current password
198: if (!passwordInteractive)
199: {
200: try
201: {
202: password->CheckPortability();
203: }
204: catch (UnportablePassword &)
205: {
206: ShowWarning ("UNSUPPORTED_CHARS_IN_PWD_RECOM");
207: }
208: }
209: else if (!Preferences.NonInteractive)
210: {
211: password = AskPassword ();
212: }
213:
214: // Current keyfiles
215: try
216: {
217: if (keyfilesInteractive)
218: {
219: // Ask for keyfiles only if required
220: try
221: {
222: keyfiles.reset (new KeyfileList);
223: volume = Core->OpenVolume (volumePath, Preferences.DefaultMountOptions.PreserveTimestamps, password, keyfiles);
224: }
225: catch (PasswordException&)
226: {
227: if (!Preferences.NonInteractive)
228: keyfiles = AskKeyfiles ();
229: }
230: }
231:
232: if (!volume.get())
233: volume = Core->OpenVolume (volumePath, Preferences.DefaultMountOptions.PreserveTimestamps, password, keyfiles);
234: }
235: catch (PasswordException &e)
236: {
237: if (Preferences.NonInteractive || !passwordInteractive || !keyfilesInteractive)
238: throw;
239:
240: ShowInfo (e);
241: continue;
242: }
243:
244: break;
245: }
246:
247: // New password
248: if (newPassword.get())
249: newPassword->CheckPortability();
250: else if (!Preferences.NonInteractive)
251: newPassword = AskPassword (_("Enter new password"), true);
252:
253: // New keyfiles
254: if (!newKeyfiles.get() && !Preferences.NonInteractive)
255: {
256: if (keyfiles.get() && keyfiles->size() > 0 && AskYesNo (_("Keep current keyfiles?"), true))
257: newKeyfiles = keyfiles;
258: else
259: newKeyfiles = AskKeyfiles (_("Enter new keyfile"));
260: }
261:
262: Core->ChangePassword (volume, newPassword, newKeyfiles);
263:
264: ShowInfo ("PASSWORD_CHANGED");
265: }
266:
267: void TextUserInterface::DoShowError (const wxString &message) const
268: {
269: wcerr << L"Error: " << static_cast<wstring> (message) << endl;
270: }
271:
272: void TextUserInterface::DoShowInfo (const wxString &message) const
273: {
274: wcout << static_cast<wstring> (message) << endl;
275: }
276:
277: void TextUserInterface::DoShowString (const wxString &str) const
278: {
279: wcout << str.c_str();
280: }
281:
282: void TextUserInterface::DoShowWarning (const wxString &message) const
283: {
284: wcerr << L"Warning: " << static_cast<wstring> (message) << endl;
285: }
286:
287: shared_ptr <GetStringFunctor> TextUserInterface::GetAdminPasswordRequestHandler ()
288: {
289: struct AdminPasswordRequestHandler : public GetStringFunctor
290: {
291: AdminPasswordRequestHandler (TextUserInterface *userInterface) : UI (userInterface) { }
292: virtual string operator() ()
293: {
294: UI->ShowString (_("Enter system administrator password: "));
295:
296: TextUserInterface::SetTerminalEcho (false);
297: finally_do ({ TextUserInterface::SetTerminalEcho (true); });
298:
299: string password = StringConverter::ToSingle (wstring (UI->TextInputStream->ReadLine()));
300: UI->ShowString (L"\n");
301: return password;
302: }
303: TextUserInterface *UI;
304: };
305:
306: return shared_ptr <GetStringFunctor> (new AdminPasswordRequestHandler (this));
307: }
308:
309: VolumeInfoList TextUserInterface::MountAllDeviceHostedVolumes (MountOptions &options) const
310: {
311: while (true)
312: {
313: if (!options.Password)
314: options.Password = AskPassword();
315:
316: if (!options.Keyfiles)
317: options.Keyfiles = AskKeyfiles();
318:
319: VolumeInfoList mountedVolumes = UserInterface::MountAllDeviceHostedVolumes (options);
320:
321: if (!mountedVolumes.empty())
322: return mountedVolumes;
323:
324: options.Password.reset();
325: }
326: }
327:
328: shared_ptr <VolumeInfo> TextUserInterface::MountVolume (MountOptions &options) const
329: {
330: shared_ptr <VolumeInfo> volume;
331:
332: // Volume path
333: if (!options.Path)
334: options.Path = AskVolumePath ();
335:
336: if (Core->IsVolumeMounted (*options.Path))
337: {
338: ShowInfo (StringFormatter (LangString["VOLUME_ALREADY_MOUNTED"], wstring (*options.Path)));
339: return volume;
340: }
341:
342: // Mount point
343: if (!options.MountPoint && !options.NoFilesystem)
344: options.MountPoint.reset (new DirectoryPath (AskString (_("Enter mount directory [default]: "))));
345:
346: VolumePassword password;
347: KeyfileList keyfiles;
348:
349: if ((!options.Password || options.Password->IsEmpty())
350: && (!options.Keyfiles || options.Keyfiles->empty())
351: && !Core->IsPasswordCacheEmpty())
352: {
353: // Cached password
354: try
355: {
356: volume = UserInterface::MountVolume (options);
357: }
358: catch (PasswordException&) { }
359: }
360:
361: while (!volume)
362: {
363: // Password
364: if (!options.Password)
365: {
366: options.Password = AskPassword (StringFormatter (_("Enter password for {0}"), wstring (*options.Path)));
367: }
368: else
369: {
370: try
371: {
372: if (options.Password)
373: options.Password->CheckPortability();
374: }
375: catch (UnportablePassword &)
376: {
377: ShowWarning ("UNSUPPORTED_CHARS_IN_PWD_RECOM");
378: }
379: }
380:
381: // Keyfiles
382: if (!options.Keyfiles)
383: options.Keyfiles = AskKeyfiles();
384:
385: // Hidden volume protection
386: if (options.Protection == VolumeProtection::None
387: && AskYesNo (_("Protect hidden volume?")))
388: options.Protection = VolumeProtection::HiddenVolumeReadOnly;
389:
390: if (options.Protection == VolumeProtection::HiddenVolumeReadOnly)
391: {
392: if (!options.ProtectionPassword)
393: options.ProtectionPassword = AskPassword (_("Enter password for hidden volume"));
394: if (!options.ProtectionKeyfiles)
395: options.ProtectionKeyfiles = AskKeyfiles (_("Enter keyfile for hidden volume"));
396: }
397:
398: try
399: {
400: volume = UserInterface::MountVolume (options);
401: }
402: catch (ProtectionPasswordIncorrect &e)
403: {
404: ShowInfo (e);
405: options.ProtectionPassword.reset();
406: }
407: catch (PasswordException &e)
408: {
409: ShowInfo (e);
410: options.Password.reset();
411: }
412: }
413:
414: return volume;
415: }
416:
417: bool TextUserInterface::OnInit ()
418: {
419: try
420: {
421: DefaultMessageOutput = new wxMessageOutputStderr;
422: wxMessageOutput::Set (DefaultMessageOutput);
423:
424: InterfaceType = UserInterfaceType::Text;
425: Init();
426:
427: SetExitOnFrameDelete (false);
428: }
429: catch (exception &e)
430: {
431: ShowError (e);
432: return false;
433: }
434: return true;
435: }
436:
437: int TextUserInterface::OnRun()
438: {
439: try
440: {
441: if (ProcessCommandLine ())
442: {
443: Application::SetExitCode (0);
444: return 0;
445: }
446: }
447: catch (exception &e)
448: {
449: ShowError (e);
450: }
451:
452: Application::SetExitCode (1);
453: return 1;
454: }
455:
456: void TextUserInterface::OnSignal (int signal)
457: {
458: #ifdef TC_UNIX
459: try
460: {
461: SetTerminalEcho (true);
462: }
463: catch (...) { }
464: _exit (1);
465: #endif
466: }
467:
468: void TextUserInterface::SetTerminalEcho (bool enable)
469: {
470: #ifdef TC_UNIX
471: struct termios termAttr;
472: if (tcgetattr (0, &termAttr) == 0)
473: {
474: if (!enable)
475: {
476: termAttr.c_lflag &= ~ECHO;
477: throw_sys_if (tcsetattr (0, TCSANOW, &termAttr) != 0);
478: }
479: else
480: {
481: termAttr.c_lflag |= ECHO;
482: throw_sys_if (tcsetattr (0, TCSANOW, &termAttr) != 0);
483: }
484: }
485: #endif
486: }
487:
488: wxMessageOutput *DefaultMessageOutput;
489: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.