From ac9b28f058fe4671b5034f6a3ed3f85091f53c5f Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Fri, 6 Jan 2012 11:13:58 +0100 Subject: [PATCH] Implement basic keyring access logic and key request dialog. * The keyring needs to be made accessible before allowing any operation. * Before executing commands the keyring is made accessible if possible (the command is aborted as needed). * Accessing a keyring opens up a preliminary key request dialog. * If the default keyring is accessible and a keyring key for the requested keyring is found, that key will be used to automatically make the requested keyring accessible. --- src/servers/keystore/Jamfile | 1 + src/servers/keystore/KeyRequestWindow.cpp | 212 ++++++++++++++++++++++ src/servers/keystore/KeyRequestWindow.h | 34 ++++ src/servers/keystore/KeyStoreServer.cpp | 62 +++++++ src/servers/keystore/KeyStoreServer.h | 4 + src/servers/keystore/Keyring.cpp | 32 +++- src/servers/keystore/Keyring.h | 3 + 7 files changed, 346 insertions(+), 2 deletions(-) create mode 100644 src/servers/keystore/KeyRequestWindow.cpp create mode 100644 src/servers/keystore/KeyRequestWindow.h diff --git a/src/servers/keystore/Jamfile b/src/servers/keystore/Jamfile index ed51642e49..e0ccaffba9 100644 --- a/src/servers/keystore/Jamfile +++ b/src/servers/keystore/Jamfile @@ -3,6 +3,7 @@ SubDir HAIKU_TOP src servers keystore ; UsePrivateHeaders app ; Server keystore_server : + KeyRequestWindow.cpp Keyring.cpp KeyStoreServer.cpp diff --git a/src/servers/keystore/KeyRequestWindow.cpp b/src/servers/keystore/KeyRequestWindow.cpp new file mode 100644 index 0000000000..22355609d9 --- /dev/null +++ b/src/servers/keystore/KeyRequestWindow.cpp @@ -0,0 +1,212 @@ +/* + * Copyright 2012, Michael Lotz, mmlr@mlotz.ch. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "KeyRequestWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +static const uint32 kMessageCancel = 'btcl'; +static const uint32 kMessageOk = 'btok'; + + +class KeyRequestView : public BView { +public: + KeyRequestView() + : + BView("KeyRequestView", B_WILL_DRAW), + fPassword(NULL) + { + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + + BGroupLayout* rootLayout = new(std::nothrow) BGroupLayout(B_VERTICAL); + if (rootLayout == NULL) + return; + + SetLayout(rootLayout); + + BGridView* controls = new(std::nothrow) BGridView(); + if (controls == NULL) + return; + + BGridLayout* layout = controls->GridLayout(); + + float inset = ceilf(be_plain_font->Size() * 0.7); + rootLayout->SetInsets(inset, inset, inset, inset); + rootLayout->SetSpacing(inset); + layout->SetSpacing(inset, inset); + + fKeyringName = new(std::nothrow) BTextControl("Keyring:", "", NULL); + if (fKeyringName == NULL) + return; + + int32 row = 0; + layout->AddItem(fKeyringName->CreateLabelLayoutItem(), 0, row); + layout->AddItem(fKeyringName->CreateTextViewLayoutItem(), 1, row++); + + fPassword = new(std::nothrow) BTextControl("Password:", "", NULL); + if (fPassword == NULL) + return; + + BLayoutItem* layoutItem = fPassword->CreateTextViewLayoutItem(); + layoutItem->SetExplicitMinSize(BSize(fPassword->StringWidth( + "0123456789012345678901234567890123456789") + inset, + B_SIZE_UNSET)); + + layout->AddItem(fPassword->CreateLabelLayoutItem(), 0, row); + layout->AddItem(layoutItem, 1, row++); + + fPersist = new(std::nothrow) BCheckBox("Not yet"); + layout->AddItem(BSpaceLayoutItem::CreateGlue(), 0, row); + layout->AddView(fPersist, 1, row++); + + BGroupView* buttons = new(std::nothrow) BGroupView(B_HORIZONTAL); + if (buttons == NULL) + return; + + fCancelButton = new(std::nothrow) BButton("Cancel", + new BMessage(kMessageCancel)); + buttons->GroupLayout()->AddView(fCancelButton); + + buttons->GroupLayout()->AddItem(BSpaceLayoutItem::CreateGlue()); + + fOkButton = new(std::nothrow) BButton("OK", new BMessage(kMessageOk)); + buttons->GroupLayout()->AddView(fOkButton); + + rootLayout->AddView(controls); + rootLayout->AddView(buttons); + } + + virtual void + AttachedToWindow() + { + fCancelButton->SetTarget(Window()); + fOkButton->SetTarget(Window()); + fOkButton->MakeDefault(true); + } + + void + SetUp(const BMessage& keyMessage) + { + BString keyringName; + if (keyMessage.FindString("keyring", &keyringName) == B_OK) + fKeyringName->SetText(keyringName); + } + + void + Complete(BMessage& keyMessage) + { + keyMessage.RemoveName("password"); + keyMessage.AddString("password", fPassword->Text()); + + keyMessage.RemoveName("persistent"); + keyMessage.AddBool("persistent", fPersist->Value() != 0); + } + +private: + BTextControl* fKeyringName; + BTextControl* fPassword; + BCheckBox* fPersist; + BButton* fCancelButton; + BButton* fOkButton; +}; + + +KeyRequestWindow::KeyRequestWindow() + : + BWindow(BRect(50, 50, 269, 302), "Access Keyring", + B_TITLED_WINDOW, B_NOT_RESIZABLE | B_ASYNCHRONOUS_CONTROLS + | B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS), + fRequestView(NULL), + fDoneSem(-1), + fResult(B_ERROR) +{ + fDoneSem = create_sem(0, "keyring access dialog"); + if (fDoneSem < 0) + return; + + BLayout* layout = new(std::nothrow) BGroupLayout(B_HORIZONTAL); + if (layout == NULL) + return; + + SetLayout(layout); + + fRequestView = new(std::nothrow) KeyRequestView(); + if (fRequestView == NULL) + return; + + layout->AddView(fRequestView); +} + + +KeyRequestWindow::~KeyRequestWindow() +{ + if (fDoneSem >= 0) + delete_sem(fDoneSem); +} + + +void +KeyRequestWindow::DispatchMessage(BMessage* message, BHandler* handler) +{ + int8 key; + if (message->what == B_KEY_DOWN + && message->FindInt8("byte", 0, &key) == B_OK + && key == B_ESCAPE) { + PostMessage(kMessageCancel); + } + + BWindow::DispatchMessage(message, handler); +} + + +void +KeyRequestWindow::MessageReceived(BMessage* message) +{ + switch (message->what) { + case kMessageCancel: + case kMessageOk: + fResult = message->what == kMessageOk ? B_OK : B_CANCELED; + release_sem(fDoneSem); + return; + } + + BWindow::MessageReceived(message); +} + + +status_t +KeyRequestWindow::RequestKey(BMessage& keyMessage) +{ + fRequestView->SetUp(keyMessage); + + CenterOnScreen(); + Show(); + + while (acquire_sem(fDoneSem) == B_INTERRUPTED) + ; + + status_t result = fResult; + fRequestView->Complete(keyMessage); + + LockLooper(); + Quit(); + return result; +} diff --git a/src/servers/keystore/KeyRequestWindow.h b/src/servers/keystore/KeyRequestWindow.h new file mode 100644 index 0000000000..c5f89c79c1 --- /dev/null +++ b/src/servers/keystore/KeyRequestWindow.h @@ -0,0 +1,34 @@ +/* + * Copyright 2012, Michael Lotz, mmlr@mlotz.ch. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _KEY_REQUEST_WINDOW_H +#define _KEY_REQUEST_WINDOW_H + + +#include +#include + + +class KeyRequestView; + + +class KeyRequestWindow : public BWindow { +public: + KeyRequestWindow(); +virtual ~KeyRequestWindow(); + +virtual void DispatchMessage(BMessage* message, + BHandler* handler); +virtual void MessageReceived(BMessage* message); + + status_t RequestKey(BMessage& keyMessage); + +private: + KeyRequestView* fRequestView; + sem_id fDoneSem; + status_t fResult; +}; + + +#endif // _KEY_REQUEST_WINDOW_H diff --git a/src/servers/keystore/KeyStoreServer.cpp b/src/servers/keystore/KeyStoreServer.cpp index caca6a7255..f007cc0e4f 100644 --- a/src/servers/keystore/KeyStoreServer.cpp +++ b/src/servers/keystore/KeyStoreServer.cpp @@ -5,6 +5,8 @@ #include "KeyStoreServer.h" + +#include "KeyRequestWindow.h" #include "Keyring.h" #include @@ -89,6 +91,24 @@ KeyStoreServer::MessageReceived(BMessage* message) break; } + switch (message->what) { + case KEY_STORE_GET_KEY: + case KEY_STORE_GET_NEXT_KEY: + case KEY_STORE_ADD_KEY: + case KEY_STORE_REMOVE_KEY: + { + // These need keyring access to do anything. + while (!keyring->IsAccessible()) { + status_t accessResult = _AccessKeyring(*keyring); + if (accessResult != B_OK) { + result = accessResult; + message->what = 0; + break; + } + } + } + } + break; } } @@ -247,6 +267,12 @@ KeyStoreServer::MessageReceived(BMessage* message) result = B_OK; } + case KEY_STORE_REVOKE_ACCESS: + { + keyring->RevokeAccess(); + result = B_OK; + } + case 0: { // Just the error case from above. @@ -380,6 +406,42 @@ KeyStoreServer::_RemoveKeyring(const BString& name) } +status_t +KeyStoreServer::_AccessKeyring(Keyring& keyring) +{ + // If we are accessing a keyring that has been added to master access we + // get the key from the default keyring and unlock with that. + BMessage keyMessage; + if (&keyring != fDefaultKeyring && fDefaultKeyring->IsAccessible()) { + if (fDefaultKeyring->FindKey("Keyrings", keyring.Name(), false, + &keyMessage) == B_OK) { + // We found a key for this keyring, try to access with it. + if (keyring.Access(keyMessage) == B_OK) + return B_OK; + } + } + + // No key, we need to request one from the user. + keyMessage.AddString("keyring", keyring.Name()); + status_t result = _RequestKey(keyMessage); + if (result != B_OK) + return result; + + return keyring.Access(keyMessage); +} + + +status_t +KeyStoreServer::_RequestKey(BMessage& keyMessage) +{ + KeyRequestWindow* requestWindow = new(std::nothrow) KeyRequestWindow(); + if (requestWindow == NULL) + return B_NO_MEMORY; + + return requestWindow->RequestKey(keyMessage); +} + + int main(int argc, char* argv[]) { diff --git a/src/servers/keystore/KeyStoreServer.h b/src/servers/keystore/KeyStoreServer.h index 2272bc85b4..b0bff8a8dd 100644 --- a/src/servers/keystore/KeyStoreServer.h +++ b/src/servers/keystore/KeyStoreServer.h @@ -34,6 +34,10 @@ private: const BMessage& keyMessage); status_t _RemoveKeyring(const BString& name); + status_t _AccessKeyring(Keyring& keyring); + + status_t _RequestKey(BMessage& keyMessage); + Keyring* fDefaultKeyring; KeyringList fKeyrings; BFile fKeyStoreFile; diff --git a/src/servers/keystore/Keyring.cpp b/src/servers/keystore/Keyring.cpp index 6e0249514d..e337f41b48 100644 --- a/src/servers/keystore/Keyring.cpp +++ b/src/servers/keystore/Keyring.cpp @@ -10,7 +10,8 @@ Keyring::Keyring(const char* name, const BMessage& data) : fName(name), - fData(data) + fData(data), + fAccessible(false) { } @@ -20,10 +21,25 @@ Keyring::~Keyring() } +status_t +Keyring::Access(const BMessage& keyMessage) +{ + fAccessible = true; + return B_OK; +} + + +void +Keyring::RevokeAccess() +{ + fAccessible = false; +} + + bool Keyring::IsAccessible() { - return true; + return fAccessible; } @@ -31,6 +47,9 @@ status_t Keyring::FindKey(const BString& identifier, const BString& secondaryIdentifier, bool secondaryIdentifierOptional, BMessage* _foundKeyMessage) { + if (!fAccessible) + return B_NOT_ALLOWED; + int32 count; type_code type; if (fData.GetInfo(identifier, &type, &count) != B_OK) @@ -74,6 +93,9 @@ status_t Keyring::FindKey(BKeyType type, BKeyPurpose purpose, uint32 index, BMessage& _foundKeyMessage) { + if (!fAccessible) + return B_NOT_ALLOWED; + for (int32 keyIndex = 0;; keyIndex++) { int32 count = 0; char* identifier = NULL; @@ -136,6 +158,9 @@ status_t Keyring::AddKey(const BString& identifier, const BString& secondaryIdentifier, const BMessage& keyMessage) { + if (!fAccessible) + return B_NOT_ALLOWED; + // Check for collisions. if (FindKey(identifier, secondaryIdentifier, false, NULL) == B_OK) return B_NAME_IN_USE; @@ -149,6 +174,9 @@ status_t Keyring::RemoveKey(const BString& identifier, const BMessage& keyMessage) { + if (!fAccessible) + return B_NOT_ALLOWED; + int32 count; type_code type; if (fData.GetInfo(identifier, &type, &count) != B_OK) diff --git a/src/servers/keystore/Keyring.h b/src/servers/keystore/Keyring.h index f7634943d7..eb3ad609a9 100644 --- a/src/servers/keystore/Keyring.h +++ b/src/servers/keystore/Keyring.h @@ -19,6 +19,8 @@ public: const char* Name() const { return fName; } const BMessage& Data() const { return fData; } + status_t Access(const BMessage& keyMessage); + void RevokeAccess(); bool IsAccessible(); status_t FindKey(const BString& identifier, @@ -43,6 +45,7 @@ static int Compare(const BString* name, private: BString fName; BMessage fData; + bool fAccessible; };