Annotation of truecrypt/main/textuserinterface.cpp, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.