|
|
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.