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.
This commit is contained in:
Michael Lotz 2012-01-06 11:13:58 +01:00 committed by Ryan Leavengood
parent 5d4a0da455
commit ac9b28f058
7 changed files with 346 additions and 2 deletions

View File

@ -3,6 +3,7 @@ SubDir HAIKU_TOP src servers keystore ;
UsePrivateHeaders app ;
Server keystore_server :
KeyRequestWindow.cpp
Keyring.cpp
KeyStoreServer.cpp

View File

@ -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 <Button.h>
#include <CheckBox.h>
#include <GridLayout.h>
#include <GridView.h>
#include <GroupLayout.h>
#include <GroupView.h>
#include <MenuField.h>
#include <MenuItem.h>
#include <NetworkDevice.h>
#include <PopUpMenu.h>
#include <SpaceLayoutItem.h>
#include <TextControl.h>
#include <View.h>
#include <new>
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;
}

View File

@ -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 <Message.h>
#include <Window.h>
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

View File

@ -5,6 +5,8 @@
#include "KeyStoreServer.h"
#include "KeyRequestWindow.h"
#include "Keyring.h"
#include <KeyStoreDefs.h>
@ -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[])
{

View File

@ -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;

View File

@ -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)

View File

@ -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;
};