VirtualBox

Ignore:
Timestamp:
Mar 12, 2015 3:05:55 PM (10 years ago)
Author:
vboxsync
Message:

FE/Qt: 7676: Runtime UI: Disk Encryption (DE) support: Dialog to ask user for the DE passwords at VM startup.

Location:
trunk/src/VBox/Frontends/VirtualBox
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VirtualBox/Makefile.kmk

    r54590 r54731  
    494494        src/runtime/UIIndicatorsPool.cpp \
    495495        src/runtime/UIStatusBarEditorWindow.cpp \
     496    src/runtime/UISession.cpp \
    496497        src/selector/UIActionPoolSelector.cpp \
    497498        src/selector/UIVMDesktop.cpp \
  • trunk/src/VBox/Frontends/VirtualBox/src/globals/UIMessageCenter.cpp

    r54597 r54731  
    20522052             "virtual machine settings window.</p>")
    20532053             .arg(strMachineName));
     2054}
     2055
     2056void UIMessageCenter::cannotAddDiskEncryptionPassword(const CConsole &console)
     2057{
     2058    error(0, MessageType_Error,
     2059          tr("Unable to enter password!"),
     2060          formatErrorInfo(console));
    20542061}
    20552062
  • trunk/src/VBox/Frontends/VirtualBox/src/globals/UIMessageCenter.h

    r54505 r54731  
    303303    void remindAboutGuestAdditionsAreNotActive() const;
    304304    void cannotMountGuestAdditions(const QString &strMachineName) const;
     305    void cannotAddDiskEncryptionPassword(const CConsole &console);
    305306
    306307#ifdef VBOX_GUI_WITH_NETWORK_MANAGER
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UISession.cpp

    r54590 r54731  
    8282
    8383
     84/* Qt includes: */
     85#include <QDialog>
     86#include <QVBoxLayout>
     87#include <QLineEdit>
     88#include <QTableView>
     89#include <QHeaderView>
     90#include <QItemEditorFactory>
     91#include <QAbstractTableModel>
     92#include <QStandardItemEditorCreator>
     93/* GUI includes: */
     94#include "QILabel.h"
     95#include "QIDialogButtonBox.h"
     96#include "QIWithRetranslateUI.h"
     97#include "QIStyledItemDelegate.h"
     98
     99/* Type definitions: */
     100typedef QMap<QString, QString> EncryptionPasswordsMap;
     101typedef QMultiMap<QString, QString> EncryptedMediumsMap;
     102
     103/** Encryption-data table field indexes.
     104  * @todo To be moved into separate file.. */
     105enum UIEncryptionTableSection
     106{
     107    UIEncryptionTableSection_Id,
     108    UIEncryptionTableSection_Password,
     109    UIEncryptionTableSection_Max
     110};
     111
     112/** QLineEdit implementation allowing to enter
     113  * disk encryption password for particular password id.
     114  * @todo To be moved into separate file.. */
     115class UILineEdit : public QLineEdit
     116{
     117    Q_OBJECT;
     118    Q_PROPERTY(QString password READ password WRITE setPassword USER true);
     119
     120signals:
     121
     122    /** Notifies listener about data should be committed. */
     123    void sigCommitData(QWidget *pThis);
     124
     125public:
     126
     127    /** Constructor.
     128      * @param pParent being passed to the base-class. */
     129    UILineEdit(QWidget *pParent)
     130        : QLineEdit(pParent)
     131    {
     132        /* Prepare: */
     133        prepare();
     134    }
     135
     136public slots:
     137
     138    /** Handles @s strText changes. */
     139    void sltTextChanged(const QString &strText)
     140    {
     141        Q_UNUSED(strText);
     142        /* Commit data to the listener: */
     143        emit sigCommitData(this);
     144    }
     145
     146private:
     147
     148    /** Prepare routine. */
     149    void prepare()
     150    {
     151        /* Set alignment: */
     152        setAlignment(Qt::AlignCenter);
     153        /* Set echo mode: */
     154        setEchoMode(QLineEdit::Password);
     155        /* Listen for the text changes: */
     156        connect(this, SIGNAL(textChanged(const QString&)),
     157                this, SLOT(sltTextChanged(const QString&)));
     158    }
     159
     160    /** Returns the password from the editor. */
     161    QString password() const { return QLineEdit::text(); }
     162    /** Defines the @a strPassword to the editor. */
     163    void setPassword(const QString &strPassword) { QLineEdit::setText(strPassword); }
     164};
     165
     166/** QAbstractTableModel implementation reflecting
     167  * disk encryption passwords for particular password ids.
     168  * @todo To be moved into separate file.. */
     169class UIEncryptionDataModel : public QAbstractTableModel
     170{
     171    Q_OBJECT;
     172
     173public:
     174
     175    /** Constructor.
     176      * @param pParent          being passed to the base-class,
     177      * @param encryptedMediums contains the lists of medium ids (values) encrypted with passwords with ids (keys). */
     178    UIEncryptionDataModel(QObject *pParent, const EncryptedMediumsMap &encryptedMediums)
     179        : QAbstractTableModel(pParent)
     180        , m_encryptedMediums(encryptedMediums)
     181    {
     182        /* Prepare: */
     183        prepare();
     184    }
     185
     186    /** Returns encryption passwords. */
     187    EncryptionPasswordsMap encryptionPasswords() const { return m_encryptionPasswords; }
     188
     189    /** Returns the @a index flags. */
     190    virtual Qt::ItemFlags flags(const QModelIndex &index) const
     191    {
     192        /* Check index validness: */
     193        if (!index.isValid())
     194            return Qt::NoItemFlags;
     195        /* Depending on column index: */
     196        switch (index.column())
     197        {
     198            case UIEncryptionTableSection_Id:       return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
     199            case UIEncryptionTableSection_Password: return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
     200            default: break;
     201        }
     202        /* No flags by default: */
     203        return Qt::NoItemFlags;
     204    }
     205
     206    /** Returns the row count. Provide optional @a parent instead of root if necessary. */
     207    virtual int rowCount(const QModelIndex &parent = QModelIndex()) const
     208    {
     209        Q_UNUSED(parent);
     210        return m_encryptionPasswords.size();
     211    }
     212
     213    /** Returns the column count. Provide optional @a parent instead of root if necessary. */
     214    virtual int columnCount(const QModelIndex &parent = QModelIndex()) const
     215    {
     216        Q_UNUSED(parent);
     217        return UIEncryptionTableSection_Max;
     218    }
     219
     220    /** Returns header data for @a iSection, @a orientation and @a iRole. */
     221    virtual QVariant headerData(int iSection, Qt::Orientation orientation, int iRole) const
     222    {
     223        /* Check argument validness: */
     224        if (iRole != Qt::DisplayRole || orientation != Qt::Horizontal)
     225            return QVariant();
     226        /* Depending on column index: */
     227        switch (iSection)
     228        {
     229            case UIEncryptionTableSection_Id:       return tr("Password ID");
     230            case UIEncryptionTableSection_Password: return tr("Password");
     231            default: break;
     232        }
     233        /* Null value by default: */
     234        return QVariant();
     235    }
     236
     237    /** Returns @a index data for @a iRole. */
     238    virtual QVariant data(const QModelIndex &index, int iRole /* = Qt::DisplayRole */) const
     239    {
     240        /* Check index validness: */
     241        if (!index.isValid())
     242            return QVariant();
     243        /* Depending on role: */
     244        switch (iRole)
     245        {
     246            case Qt::DisplayRole:
     247            {
     248                /* Depending on column index: */
     249                switch (index.column())
     250                {
     251                    case UIEncryptionTableSection_Id:
     252                        return m_encryptionPasswords.keys().at(index.row());
     253                    case UIEncryptionTableSection_Password:
     254                        return QString().fill('*', m_encryptionPasswords.value(m_encryptionPasswords.keys().at(index.row())).size());
     255                    default:
     256                        return QVariant();
     257                }
     258                break;
     259            }
     260            case Qt::EditRole:
     261            {
     262                /* Depending on column index: */
     263                switch (index.column())
     264                {
     265                    case UIEncryptionTableSection_Password:
     266                        return m_encryptionPasswords.value(m_encryptionPasswords.keys().at(index.row()));
     267                    default:
     268                        return QVariant();
     269                }
     270                break;
     271            }
     272            case Qt::TextAlignmentRole:
     273            {
     274                /* Depending on column index: */
     275                switch (index.column())
     276                {
     277                    case UIEncryptionTableSection_Password:
     278                        return Qt::AlignCenter;
     279                    default: return QVariant();
     280                }
     281                break;
     282            }
     283            default:
     284                break;
     285        }
     286        /* Null value by default: */
     287        return QVariant();
     288    }
     289
     290    /** Defines @a index data for @a iRole as @a value. */
     291    virtual bool setData(const QModelIndex &index, const QVariant &value, int iRole /* = Qt::EditRole */)
     292    {
     293        /* Check index validness: */
     294        if (!index.isValid())
     295            return false;
     296        /* Check argument validness: */
     297        if (iRole != Qt::EditRole)
     298            return false;
     299        /* Depending on column index: */
     300        switch (index.column())
     301        {
     302            case UIEncryptionTableSection_Password: m_encryptionPasswords[m_encryptionPasswords.keys().at(index.row())] = value.toString(); break;
     303            default: break;
     304        }
     305        /* Nothing to set by default: */
     306        return false;
     307    }
     308
     309private:
     310
     311    /** Prepare routine. */
     312    void prepare()
     313    {
     314        /* Populate the map of passwords. */
     315        foreach (const QString &strPasswordId, m_encryptedMediums.keys())
     316            m_encryptionPasswords.insert(strPasswordId, QString());
     317    }
     318
     319    /** Holds the encrypted medium map reference. */
     320    const EncryptedMediumsMap &m_encryptedMediums;
     321
     322    /** Holds the encrypted password id map. */
     323    EncryptionPasswordsMap m_encryptionPasswords;
     324};
     325
     326/** QTableView implementation allowing to enter
     327  * disk encryption passwords for particular password ids.
     328  * @todo To be moved into separate file.. */
     329class UIEncryptionDataTable : public QTableView
     330{
     331    Q_OBJECT;
     332
     333public:
     334
     335    /** Constructor.
     336      * @param pParent being passed to the base-class. */
     337    UIEncryptionDataTable(const EncryptedMediumsMap &encryptedMediums)
     338        : m_encryptedMediums(encryptedMediums)
     339        , m_pModelEncryptionData(0)
     340    {
     341        /* Prepare: */
     342        prepare();
     343    }
     344
     345    /** Returns encryption passwords. */
     346    EncryptionPasswordsMap encryptionPasswords() const
     347    {
     348        AssertPtrReturn(m_pModelEncryptionData, EncryptionPasswordsMap());
     349        return m_pModelEncryptionData->encryptionPasswords();
     350    }
     351
     352private:
     353
     354    /** Prepare routine. */
     355    void prepare()
     356    {
     357        /* Create encryption-data model: */
     358        m_pModelEncryptionData = new UIEncryptionDataModel(this, m_encryptedMediums);
     359        AssertPtrReturnVoid(m_pModelEncryptionData);
     360        {
     361            /* Assign configured model to table: */
     362            setModel(m_pModelEncryptionData);
     363        }
     364
     365        /* Create item delegate: */
     366        QIStyledItemDelegate *pStyledItemDelegate = new QIStyledItemDelegate(this);
     367        AssertPtrReturnVoid(pStyledItemDelegate);
     368        {
     369            /* Create item editor factory: */
     370            QItemEditorFactory *pNewItemEditorFactory = new QItemEditorFactory;
     371            AssertPtrReturnVoid(pNewItemEditorFactory);
     372            {
     373                /* Create item editor creator: */
     374                QStandardItemEditorCreator<UILineEdit> *pQStringItemEditorCreator = new QStandardItemEditorCreator<UILineEdit>();
     375                AssertPtrReturnVoid(pQStringItemEditorCreator);
     376                {
     377                    /* Register UILineEdit as the QString editor: */
     378                    pNewItemEditorFactory->registerEditor(QVariant::String, pQStringItemEditorCreator);
     379                }
     380                /* Assign configured item editor factory to table delegate: */
     381                pStyledItemDelegate->setItemEditorFactory(pNewItemEditorFactory);
     382            }
     383            /* Assign configured item delegate to table: */
     384            delete itemDelegate();
     385            setItemDelegate(pStyledItemDelegate);
     386        }
     387
     388        /* Configure table: */
     389        setTabKeyNavigation(false);
     390        setContextMenuPolicy(Qt::CustomContextMenu);
     391        setSelectionBehavior(QAbstractItemView::SelectRows);
     392        setSelectionMode(QAbstractItemView::SingleSelection);
     393        setEditTriggers(QAbstractItemView::CurrentChanged | QAbstractItemView::SelectedClicked);
     394
     395        /* Configure headers: */
     396        verticalHeader()->hide();
     397        verticalHeader()->setDefaultSectionSize((int)(verticalHeader()->minimumSectionSize() * 1.33));
     398        horizontalHeader()->setStretchLastSection(false);
     399        horizontalHeader()->setResizeMode(UIEncryptionTableSection_Id, QHeaderView::Interactive);
     400        horizontalHeader()->setResizeMode(UIEncryptionTableSection_Password, QHeaderView::Stretch);
     401    }
     402
     403    /** Holds the encrypted medium map reference. */
     404    const EncryptedMediumsMap &m_encryptedMediums;
     405
     406    /** Holds the encryption-data model. */
     407    UIEncryptionDataModel *m_pModelEncryptionData;
     408};
     409
     410/** QDialog implementation allowing to enter
     411  * disk encryption passwords for particular password ids.
     412  * @todo To be moved into separate files.. */
     413class UIAddDiskEncryptionPasswordDialog : public QIWithRetranslateUI<QDialog>
     414{
     415    Q_OBJECT;
     416
     417public:
     418
     419    /** Constructor.
     420      * @param pParent          being passed to the base-class,
     421      * @param encryptedMediums contains the lists of medium ids (values) encrypted with passwords with ids (keys). */
     422    UIAddDiskEncryptionPasswordDialog(QWidget *pParent, const EncryptedMediumsMap &encryptedMediums)
     423        : QIWithRetranslateUI<QDialog>(pParent)
     424        , m_encryptedMediums(encryptedMediums)
     425        , m_pLabelDescription(0)
     426        , m_pTableEncryptionData(0)
     427    {
     428        /* Prepare: */
     429        prepare();
     430        /* Retranslate: */
     431        retranslateUi();
     432    }
     433
     434    /** Returns encryption passwords. */
     435    EncryptionPasswordsMap encryptionPasswords() const
     436    {
     437        AssertPtrReturn(m_pTableEncryptionData, EncryptionPasswordsMap());
     438        return m_pTableEncryptionData->encryptionPasswords();
     439    }
     440
     441private:
     442
     443    /** Prepare routine. */
     444    void prepare()
     445    {
     446        /* Create main-layout: */
     447        QVBoxLayout *pMainLayout = new QVBoxLayout(this);
     448        AssertPtrReturnVoid(pMainLayout);
     449        {
     450            /* Create input-layout: */
     451            QVBoxLayout *pInputLayout = new QVBoxLayout;
     452            AssertPtrReturnVoid(pInputLayout);
     453            {
     454                /* Create description label: */
     455                m_pLabelDescription = new QILabel;
     456                m_pLabelDescription->useSizeHintForWidth(450);
     457                m_pLabelDescription->updateGeometry();
     458                AssertPtrReturnVoid(m_pLabelDescription);
     459                {
     460                    /* Configure description label: */
     461                    m_pLabelDescription->setWordWrap(true);
     462                    /* Add label into layout: */
     463                    pInputLayout->addWidget(m_pLabelDescription);
     464                }
     465                /* Create encryption-data table: */
     466                m_pTableEncryptionData = new UIEncryptionDataTable(m_encryptedMediums);
     467                AssertPtrReturnVoid(m_pTableEncryptionData);
     468                {
     469                    /* Add label into layout: */
     470                    pInputLayout->addWidget(m_pTableEncryptionData);
     471                }
     472                /* Add layout into parent: */
     473                pMainLayout->addLayout(pInputLayout);
     474            }
     475            /* Create button-box: */
     476            QIDialogButtonBox *pButtonBox = new QIDialogButtonBox;
     477            AssertPtrReturnVoid(pButtonBox);
     478            {
     479                /* Configure button-box: */
     480                pButtonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
     481                connect(pButtonBox, SIGNAL(accepted()), this, SLOT(accept()));
     482                connect(pButtonBox, SIGNAL(rejected()), this, SLOT(reject()));
     483                /* Add button-box into layout: */
     484                pMainLayout->addWidget(pButtonBox);
     485            }
     486        }
     487    }
     488
     489    /** Translation routine. */
     490    void retranslateUi()
     491    {
     492        AssertPtrReturnVoid(m_pLabelDescription);
     493        m_pLabelDescription->setText(tr("This virtual machine is password protected. "
     494                                        "Please enter the %n encryption password(s) below.",
     495                                        "This text is never used with n == 0. "
     496                                        "Feel free to drop the %n where possible, "
     497                                        "we only included it because of problems with Qt Linguist "
     498                                        "(but the user can see how many passwords are in the list "
     499                                        "and doesn't need to be told).",
     500                                        m_encryptedMediums.size()));
     501    }
     502
     503    /** Holds the encrypted medium map reference. */
     504    const EncryptedMediumsMap &m_encryptedMediums;
     505
     506    /** Holds the description label. */
     507    QILabel *m_pLabelDescription;
     508    /** Holds the encryption-data table. */
     509    UIEncryptionDataTable *m_pTableEncryptionData;
     510};
     511
     512
    84513#ifdef VBOX_GUI_WITH_KEYS_RESET_HANDLER
    85514static void signalHandlerSIGUSR1(int sig, siginfo_t *, void *);
     
    252681bool UISession::powerUp()
    253682{
     683    /* Prepare map of the encrypted ids: */
     684    EncryptedMediumsMap encryptedPasswordIds;
     685    foreach (const CMediumAttachment &attachment, machine().GetMediumAttachments())
     686    {
     687        /* Acquire hard-drives only: */
     688        if (attachment.GetType() == KDeviceType_HardDisk)
     689        {
     690            /* Get attachment medium: */
     691            const CMedium medium = attachment.GetMedium();
     692            /* Append our map if this medium has encryption: */
     693            const QString strKeyId = medium.GetProperty("CRYPT/KeyId");
     694            if (!strKeyId.isNull())
     695                encryptedPasswordIds.insert(strKeyId, medium.GetId());
     696        }
     697    }
     698    /* Ask for disk encryption passwords: */
     699    EncryptionPasswordsMap encryptionPasswords;
     700    QPointer<UIAddDiskEncryptionPasswordDialog> pDlg =
     701         new UIAddDiskEncryptionPasswordDialog(machineLogic()->activeMachineWindow(),
     702                                               encryptedPasswordIds);
     703    if (pDlg->exec() == QDialog::Accepted)
     704        encryptionPasswords = pDlg->encryptionPasswords();
     705    if (pDlg)
     706        delete pDlg;
     707
    254708    /* Power UP machine: */
    255709#ifdef VBOX_WITH_DEBUGGER_GUI
     
    288742            msgCenter().cannotStartMachine(progress, machineName());
    289743        return false;
     744    }
     745
     746    /* Add the disk encryption passwords: */
     747    if (!encryptionPasswords.isEmpty())
     748    {
     749        foreach (const QString &strKey, encryptionPasswords.keys())
     750        {
     751            console().AddDiskEncryptionPassword(strKey, encryptionPasswords.value(strKey), true);
     752            if (!console().isOk())
     753                msgCenter().cannotAddDiskEncryptionPassword(console());
     754        }
    290755    }
    291756
     
    19442409#endif /* VBOX_GUI_WITH_KEYS_RESET_HANDLER */
    19452410
     2411#include "UISession.moc"
     2412
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette