801 lines
19 KiB
C++
801 lines
19 KiB
C++
/*
|
|
* Copyright 2012, Michael Lotz, [email protected]. All Rights Reserved.
|
|
* Distributed under the terms of the MIT License.
|
|
*/
|
|
|
|
|
|
#include "KeyStoreServer.h"
|
|
|
|
#include "AppAccessRequestWindow.h"
|
|
#include "KeyRequestWindow.h"
|
|
#include "Keyring.h"
|
|
|
|
#include <KeyStoreDefs.h>
|
|
|
|
#include <Directory.h>
|
|
#include <Entry.h>
|
|
#include <FindDirectory.h>
|
|
#include <Path.h>
|
|
#include <Roster.h>
|
|
#include <String.h>
|
|
|
|
#include <new>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
using namespace BPrivate;
|
|
|
|
|
|
static const char* kMasterKeyringName = "Master";
|
|
static const char* kKeyringKeysIdentifier = "Keyrings";
|
|
|
|
static const uint32 kKeyStoreFormatVersion = 1;
|
|
|
|
static const uint32 kFlagGetKey = 0x0001;
|
|
static const uint32 kFlagEnumerateKeys = 0x0002;
|
|
static const uint32 kFlagAddKey = 0x0004;
|
|
static const uint32 kFlagRemoveKey = 0x0008;
|
|
static const uint32 kFlagAddKeyring = 0x0010;
|
|
static const uint32 kFlagRemoveKeyring = 0x0020;
|
|
static const uint32 kFlagEnumerateKeyrings = 0x0040;
|
|
static const uint32 kFlagSetUnlockKey = 0x0080;
|
|
static const uint32 kFlagRemoveUnlockKey = 0x0100;
|
|
static const uint32 kFlagAddKeyringsToMaster = 0x0200;
|
|
static const uint32 kFlagRemoveKeyringsFromMaster = 0x0400;
|
|
static const uint32 kFlagEnumerateMasterKeyrings = 0x0800;
|
|
static const uint32 kFlagQueryLockState = 0x1000;
|
|
static const uint32 kFlagLockKeyring = 0x2000;
|
|
static const uint32 kFlagEnumerateApplications = 0x4000;
|
|
static const uint32 kFlagRemoveApplications = 0x8000;
|
|
|
|
static const uint32 kDefaultAppFlags = kFlagGetKey | kFlagEnumerateKeys
|
|
| kFlagAddKey | kFlagRemoveKey | kFlagAddKeyring | kFlagRemoveKeyring
|
|
| kFlagEnumerateKeyrings | kFlagSetUnlockKey | kFlagRemoveUnlockKey
|
|
| kFlagAddKeyringsToMaster | kFlagRemoveKeyringsFromMaster
|
|
| kFlagEnumerateMasterKeyrings | kFlagQueryLockState | kFlagLockKeyring
|
|
| kFlagEnumerateApplications | kFlagRemoveApplications;
|
|
|
|
|
|
KeyStoreServer::KeyStoreServer()
|
|
:
|
|
BApplication(kKeyStoreServerSignature),
|
|
fMasterKeyring(NULL),
|
|
fKeyrings(20, true)
|
|
{
|
|
BPath path;
|
|
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
|
|
return;
|
|
|
|
BDirectory settingsDir(path.Path());
|
|
path.Append("system");
|
|
if (!settingsDir.Contains(path.Path()))
|
|
settingsDir.CreateDirectory(path.Path(), NULL);
|
|
|
|
settingsDir.SetTo(path.Path());
|
|
path.Append("keystore");
|
|
if (!settingsDir.Contains(path.Path()))
|
|
settingsDir.CreateDirectory(path.Path(), NULL);
|
|
|
|
settingsDir.SetTo(path.Path());
|
|
path.Append("keystore_database");
|
|
|
|
fKeyStoreFile.SetTo(path.Path(), B_READ_WRITE
|
|
| (settingsDir.Contains(path.Path()) ? 0 : B_CREATE_FILE));
|
|
|
|
_ReadKeyStoreDatabase();
|
|
|
|
if (fMasterKeyring == NULL) {
|
|
fMasterKeyring = new(std::nothrow) Keyring(kMasterKeyringName);
|
|
fKeyrings.BinaryInsert(fMasterKeyring, &Keyring::Compare);
|
|
}
|
|
}
|
|
|
|
|
|
KeyStoreServer::~KeyStoreServer()
|
|
{
|
|
}
|
|
|
|
|
|
void
|
|
KeyStoreServer::MessageReceived(BMessage* message)
|
|
{
|
|
BMessage reply;
|
|
status_t result = B_UNSUPPORTED;
|
|
app_info callingAppInfo;
|
|
|
|
uint32 accessFlags = _AccessFlagsFor(message->what);
|
|
if (accessFlags == 0)
|
|
message->what = 0;
|
|
|
|
if (message->what != 0) {
|
|
result = _ResolveCallingApp(*message, callingAppInfo);
|
|
if (result != B_OK)
|
|
message->what = 0;
|
|
}
|
|
|
|
// Resolve the keyring for the relevant messages.
|
|
Keyring* keyring = NULL;
|
|
switch (message->what) {
|
|
case KEY_STORE_GET_KEY:
|
|
case KEY_STORE_GET_NEXT_KEY:
|
|
case KEY_STORE_ADD_KEY:
|
|
case KEY_STORE_REMOVE_KEY:
|
|
case KEY_STORE_IS_KEYRING_UNLOCKED:
|
|
case KEY_STORE_LOCK_KEYRING:
|
|
case KEY_STORE_SET_UNLOCK_KEY:
|
|
case KEY_STORE_REMOVE_UNLOCK_KEY:
|
|
case KEY_STORE_ADD_KEYRING_TO_MASTER:
|
|
case KEY_STORE_REMOVE_KEYRING_FROM_MASTER:
|
|
case KEY_STORE_GET_NEXT_APPLICATION:
|
|
case KEY_STORE_REMOVE_APPLICATION:
|
|
{
|
|
BString keyringName;
|
|
if (message->FindString("keyring", &keyringName) != B_OK)
|
|
keyringName = "";
|
|
|
|
keyring = _FindKeyring(keyringName);
|
|
if (keyring == NULL) {
|
|
result = B_BAD_VALUE;
|
|
message->what = 0;
|
|
// So that we don't do anything in the second switch.
|
|
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:
|
|
case KEY_STORE_SET_UNLOCK_KEY:
|
|
case KEY_STORE_REMOVE_UNLOCK_KEY:
|
|
case KEY_STORE_ADD_KEYRING_TO_MASTER:
|
|
case KEY_STORE_GET_NEXT_APPLICATION:
|
|
case KEY_STORE_REMOVE_APPLICATION:
|
|
{
|
|
// These need keyring access to do anything.
|
|
while (!keyring->IsUnlocked()) {
|
|
status_t unlockResult = _UnlockKeyring(*keyring);
|
|
if (unlockResult != B_OK) {
|
|
result = unlockResult;
|
|
message->what = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
status_t validateResult = _ValidateAppAccess(*keyring,
|
|
callingAppInfo, accessFlags);
|
|
if (validateResult != B_OK) {
|
|
result = validateResult;
|
|
message->what = 0;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch (message->what) {
|
|
case KEY_STORE_GET_KEY:
|
|
{
|
|
BString identifier;
|
|
if (message->FindString("identifier", &identifier) != B_OK) {
|
|
result = B_BAD_VALUE;
|
|
break;
|
|
}
|
|
|
|
bool secondaryIdentifierOptional;
|
|
if (message->FindBool("secondaryIdentifierOptional",
|
|
&secondaryIdentifierOptional) != B_OK) {
|
|
secondaryIdentifierOptional = false;
|
|
}
|
|
|
|
BString secondaryIdentifier;
|
|
if (message->FindString("secondaryIdentifier",
|
|
&secondaryIdentifier) != B_OK) {
|
|
secondaryIdentifier = "";
|
|
secondaryIdentifierOptional = true;
|
|
}
|
|
|
|
BMessage keyMessage;
|
|
result = keyring->FindKey(identifier, secondaryIdentifier,
|
|
secondaryIdentifierOptional, &keyMessage);
|
|
if (result == B_OK)
|
|
reply.AddMessage("key", &keyMessage);
|
|
|
|
break;
|
|
}
|
|
|
|
case KEY_STORE_GET_NEXT_KEY:
|
|
{
|
|
BKeyType type;
|
|
BKeyPurpose purpose;
|
|
uint32 cookie;
|
|
if (message->FindUInt32("type", (uint32*)&type) != B_OK
|
|
|| message->FindUInt32("purpose", (uint32*)&purpose) != B_OK
|
|
|| message->FindUInt32("cookie", &cookie) != B_OK) {
|
|
result = B_BAD_VALUE;
|
|
break;
|
|
}
|
|
|
|
BMessage keyMessage;
|
|
result = keyring->FindKey(type, purpose, cookie, keyMessage);
|
|
if (result == B_OK) {
|
|
cookie++;
|
|
reply.AddUInt32("cookie", cookie);
|
|
reply.AddMessage("key", &keyMessage);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case KEY_STORE_ADD_KEY:
|
|
{
|
|
BMessage keyMessage;
|
|
BString identifier;
|
|
if (message->FindMessage("key", &keyMessage) != B_OK
|
|
|| keyMessage.FindString("identifier", &identifier) != B_OK) {
|
|
result = B_BAD_VALUE;
|
|
break;
|
|
}
|
|
|
|
BString secondaryIdentifier;
|
|
if (keyMessage.FindString("secondaryIdentifier",
|
|
&secondaryIdentifier) != B_OK) {
|
|
secondaryIdentifier = "";
|
|
}
|
|
|
|
result = keyring->AddKey(identifier, secondaryIdentifier, keyMessage);
|
|
if (result == B_OK)
|
|
_WriteKeyStoreDatabase();
|
|
|
|
break;
|
|
}
|
|
|
|
case KEY_STORE_REMOVE_KEY:
|
|
{
|
|
BMessage keyMessage;
|
|
BString identifier;
|
|
if (message->FindMessage("key", &keyMessage) != B_OK
|
|
|| keyMessage.FindString("identifier", &identifier) != B_OK) {
|
|
result = B_BAD_VALUE;
|
|
break;
|
|
}
|
|
|
|
result = keyring->RemoveKey(identifier, keyMessage);
|
|
if (result == B_OK)
|
|
_WriteKeyStoreDatabase();
|
|
|
|
break;
|
|
}
|
|
|
|
case KEY_STORE_ADD_KEYRING:
|
|
{
|
|
BMessage keyMessage;
|
|
BString keyring;
|
|
if (message->FindString("keyring", &keyring) != B_OK) {
|
|
result = B_BAD_VALUE;
|
|
break;
|
|
}
|
|
|
|
result = _AddKeyring(keyring);
|
|
if (result == B_OK)
|
|
_WriteKeyStoreDatabase();
|
|
|
|
break;
|
|
}
|
|
|
|
case KEY_STORE_REMOVE_KEYRING:
|
|
{
|
|
BString keyringName;
|
|
if (message->FindString("keyring", &keyringName) != B_OK)
|
|
keyringName = "";
|
|
|
|
result = _RemoveKeyring(keyringName);
|
|
if (result == B_OK)
|
|
_WriteKeyStoreDatabase();
|
|
|
|
break;
|
|
}
|
|
|
|
case KEY_STORE_GET_NEXT_KEYRING:
|
|
{
|
|
uint32 cookie;
|
|
if (message->FindUInt32("cookie", &cookie) != B_OK) {
|
|
result = B_BAD_VALUE;
|
|
break;
|
|
}
|
|
|
|
keyring = fKeyrings.ItemAt(cookie);
|
|
if (keyring == NULL) {
|
|
result = B_ENTRY_NOT_FOUND;
|
|
break;
|
|
}
|
|
|
|
cookie++;
|
|
reply.AddUInt32("cookie", cookie);
|
|
reply.AddString("keyring", keyring->Name());
|
|
result = B_OK;
|
|
break;
|
|
}
|
|
|
|
case KEY_STORE_IS_KEYRING_UNLOCKED:
|
|
{
|
|
reply.AddBool("unlocked", keyring->IsUnlocked());
|
|
result = B_OK;
|
|
break;
|
|
}
|
|
|
|
case KEY_STORE_LOCK_KEYRING:
|
|
{
|
|
keyring->Lock();
|
|
result = B_OK;
|
|
break;
|
|
}
|
|
|
|
case KEY_STORE_SET_UNLOCK_KEY:
|
|
{
|
|
BMessage keyMessage;
|
|
if (message->FindMessage("key", &keyMessage) != B_OK) {
|
|
result = B_BAD_VALUE;
|
|
break;
|
|
}
|
|
|
|
result = keyring->SetUnlockKey(keyMessage);
|
|
if (result == B_OK)
|
|
_WriteKeyStoreDatabase();
|
|
|
|
// TODO: Update the key in the master if this keyring was added.
|
|
break;
|
|
}
|
|
|
|
case KEY_STORE_REMOVE_UNLOCK_KEY:
|
|
{
|
|
result = keyring->RemoveUnlockKey();
|
|
if (result == B_OK)
|
|
_WriteKeyStoreDatabase();
|
|
|
|
break;
|
|
}
|
|
|
|
case KEY_STORE_ADD_KEYRING_TO_MASTER:
|
|
case KEY_STORE_REMOVE_KEYRING_FROM_MASTER:
|
|
{
|
|
// We also need access to the master keyring.
|
|
while (!fMasterKeyring->IsUnlocked()) {
|
|
status_t unlockResult = _UnlockKeyring(*fMasterKeyring);
|
|
if (unlockResult != B_OK) {
|
|
result = unlockResult;
|
|
message->what = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (message->what == 0)
|
|
break;
|
|
|
|
BString secondaryIdentifier = keyring->Name();
|
|
BMessage keyMessage = keyring->UnlockKey();
|
|
keyMessage.RemoveName("identifier");
|
|
keyMessage.AddString("identifier", kKeyringKeysIdentifier);
|
|
keyMessage.RemoveName("secondaryIdentifier");
|
|
keyMessage.AddString("secondaryIdentifier", secondaryIdentifier);
|
|
|
|
switch (message->what) {
|
|
case KEY_STORE_ADD_KEYRING_TO_MASTER:
|
|
result = fMasterKeyring->AddKey(kKeyringKeysIdentifier,
|
|
secondaryIdentifier, keyMessage);
|
|
break;
|
|
|
|
case KEY_STORE_REMOVE_KEYRING_FROM_MASTER:
|
|
result = fMasterKeyring->RemoveKey(kKeyringKeysIdentifier,
|
|
keyMessage);
|
|
break;
|
|
}
|
|
|
|
if (result == B_OK)
|
|
_WriteKeyStoreDatabase();
|
|
|
|
break;
|
|
}
|
|
|
|
case KEY_STORE_GET_NEXT_APPLICATION:
|
|
{
|
|
uint32 cookie;
|
|
if (message->FindUInt32("cookie", &cookie) != B_OK) {
|
|
result = B_BAD_VALUE;
|
|
break;
|
|
}
|
|
|
|
BString signature;
|
|
BString path;
|
|
result = keyring->GetNextApplication(cookie, signature, path);
|
|
if (result != B_OK)
|
|
break;
|
|
|
|
reply.AddUInt32("cookie", cookie);
|
|
reply.AddString("signature", signature);
|
|
reply.AddString("path", path);
|
|
result = B_OK;
|
|
break;
|
|
}
|
|
|
|
case KEY_STORE_REMOVE_APPLICATION:
|
|
{
|
|
const char* signature = NULL;
|
|
const char* path = NULL;
|
|
|
|
if (message->FindString("signature", &signature) != B_OK) {
|
|
result = B_BAD_VALUE;
|
|
break;
|
|
}
|
|
|
|
if (message->FindString("path", &path) != B_OK)
|
|
path = NULL;
|
|
|
|
result = keyring->RemoveApplication(signature, path);
|
|
if (result == B_OK)
|
|
_WriteKeyStoreDatabase();
|
|
|
|
break;
|
|
}
|
|
|
|
case 0:
|
|
{
|
|
// Just the error case from above.
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
printf("unknown message received: %" B_PRIu32 " \"%.4s\"\n",
|
|
message->what, (const char*)&message->what);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (message->IsSourceWaiting()) {
|
|
if (result == B_OK)
|
|
reply.what = KEY_STORE_SUCCESS;
|
|
else {
|
|
reply.what = KEY_STORE_RESULT;
|
|
reply.AddInt32("result", result);
|
|
}
|
|
|
|
message->SendReply(&reply);
|
|
}
|
|
}
|
|
|
|
|
|
status_t
|
|
KeyStoreServer::_ReadKeyStoreDatabase()
|
|
{
|
|
BMessage keystore;
|
|
status_t result = keystore.Unflatten(&fKeyStoreFile);
|
|
if (result != B_OK) {
|
|
printf("failed to read keystore database\n");
|
|
_WriteKeyStoreDatabase();
|
|
// Reinitializes the database.
|
|
return result;
|
|
}
|
|
|
|
int32 index = 0;
|
|
BMessage keyringData;
|
|
while (keystore.FindMessage("keyrings", index++, &keyringData) == B_OK) {
|
|
Keyring* keyring = new(std::nothrow) Keyring();
|
|
if (keyring == NULL) {
|
|
printf("no memory for allocating keyring\n");
|
|
break;
|
|
}
|
|
|
|
status_t result = keyring->ReadFromMessage(keyringData);
|
|
if (result != B_OK) {
|
|
printf("failed to read keyring from data\n");
|
|
delete keyring;
|
|
continue;
|
|
}
|
|
|
|
if (strcmp(keyring->Name(), kMasterKeyringName) == 0)
|
|
fMasterKeyring = keyring;
|
|
|
|
fKeyrings.BinaryInsert(keyring, &Keyring::Compare);
|
|
}
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
KeyStoreServer::_WriteKeyStoreDatabase()
|
|
{
|
|
BMessage keystore;
|
|
keystore.AddUInt32("format", kKeyStoreFormatVersion);
|
|
|
|
for (int32 i = 0; i < fKeyrings.CountItems(); i++) {
|
|
Keyring* keyring = fKeyrings.ItemAt(i);
|
|
if (keyring == NULL)
|
|
continue;
|
|
|
|
BMessage keyringData;
|
|
status_t result = keyring->WriteToMessage(keyringData);
|
|
if (result != B_OK)
|
|
return result;
|
|
|
|
keystore.AddMessage("keyrings", &keyringData);
|
|
}
|
|
|
|
fKeyStoreFile.SetSize(0);
|
|
fKeyStoreFile.Seek(0, SEEK_SET);
|
|
return keystore.Flatten(&fKeyStoreFile);
|
|
}
|
|
|
|
|
|
uint32
|
|
KeyStoreServer::_AccessFlagsFor(uint32 command) const
|
|
{
|
|
switch (command) {
|
|
case KEY_STORE_GET_KEY:
|
|
return kFlagGetKey;
|
|
case KEY_STORE_GET_NEXT_KEY:
|
|
return kFlagEnumerateKeys;
|
|
case KEY_STORE_ADD_KEY:
|
|
return kFlagAddKey;
|
|
case KEY_STORE_REMOVE_KEY:
|
|
return kFlagRemoveKey;
|
|
case KEY_STORE_ADD_KEYRING:
|
|
return kFlagAddKeyring;
|
|
case KEY_STORE_REMOVE_KEYRING:
|
|
return kFlagRemoveKeyring;
|
|
case KEY_STORE_GET_NEXT_KEYRING:
|
|
return kFlagEnumerateKeyrings;
|
|
case KEY_STORE_SET_UNLOCK_KEY:
|
|
return kFlagSetUnlockKey;
|
|
case KEY_STORE_REMOVE_UNLOCK_KEY:
|
|
return kFlagRemoveUnlockKey;
|
|
case KEY_STORE_ADD_KEYRING_TO_MASTER:
|
|
return kFlagAddKeyringsToMaster;
|
|
case KEY_STORE_REMOVE_KEYRING_FROM_MASTER:
|
|
return kFlagRemoveKeyringsFromMaster;
|
|
case KEY_STORE_GET_NEXT_MASTER_KEYRING:
|
|
return kFlagEnumerateMasterKeyrings;
|
|
case KEY_STORE_IS_KEYRING_UNLOCKED:
|
|
return kFlagQueryLockState;
|
|
case KEY_STORE_LOCK_KEYRING:
|
|
return kFlagLockKeyring;
|
|
case KEY_STORE_GET_NEXT_APPLICATION:
|
|
return kFlagEnumerateApplications;
|
|
case KEY_STORE_REMOVE_APPLICATION:
|
|
return kFlagRemoveApplications;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
const char*
|
|
KeyStoreServer::_AccessStringFor(uint32 accessFlag) const
|
|
{
|
|
switch (accessFlag) {
|
|
case kFlagGetKey:
|
|
return "Get keys from the keyring.";
|
|
case kFlagEnumerateKeys:
|
|
return "Enumerate and get keys from the keyring.";
|
|
case kFlagAddKey:
|
|
return "Add keys to the keyring.";
|
|
case kFlagRemoveKey:
|
|
return "Remove keys from the keyring.";
|
|
case kFlagAddKeyring:
|
|
return "Add new keyrings.";
|
|
case kFlagRemoveKeyring:
|
|
return "Remove keyrings.";
|
|
case kFlagEnumerateKeyrings:
|
|
return "Enumerate the available keyrings.";
|
|
case kFlagSetUnlockKey:
|
|
return "Set the unlock key of the keyring.";
|
|
case kFlagRemoveUnlockKey:
|
|
return "Remove the unlock key of the keyring.";
|
|
case kFlagAddKeyringsToMaster:
|
|
return "Add the keyring key to the master keyring.";
|
|
case kFlagRemoveKeyringsFromMaster:
|
|
return "Remove the keyring key from the master keyring.";
|
|
case kFlagEnumerateMasterKeyrings:
|
|
return "Enumerate keyrings added to the master keyring.";
|
|
case kFlagQueryLockState:
|
|
return "Query the lock state of the keyring.";
|
|
case kFlagLockKeyring:
|
|
return "Lock the keyring.";
|
|
case kFlagEnumerateApplications:
|
|
return "Enumerate the applications of the keyring.";
|
|
case kFlagRemoveApplications:
|
|
return "Remove applications from the keyring.";
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
status_t
|
|
KeyStoreServer::_ResolveCallingApp(const BMessage& message,
|
|
app_info& callingAppInfo) const
|
|
{
|
|
team_id callingTeam = message.ReturnAddress().Team();
|
|
status_t result = be_roster->GetRunningAppInfo(callingTeam,
|
|
&callingAppInfo);
|
|
if (result != B_OK)
|
|
return result;
|
|
|
|
// Do some sanity checks.
|
|
if (callingAppInfo.team != callingTeam)
|
|
return B_ERROR;
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
KeyStoreServer::_ValidateAppAccess(Keyring& keyring, const app_info& appInfo,
|
|
uint32 accessFlags)
|
|
{
|
|
BMessage appMessage;
|
|
BPath path(&appInfo.ref);
|
|
status_t result = keyring.FindApplication(appInfo.signature,
|
|
path.Path(), appMessage);
|
|
if (result != B_OK && result != B_ENTRY_NOT_FOUND)
|
|
return result;
|
|
|
|
// TODO: Implement running image checksum mechanism.
|
|
BString checksum = path.Path();
|
|
|
|
bool appIsNew = false;
|
|
bool appWasUpdated = false;
|
|
uint32 appFlags = 0;
|
|
BString appSum = "";
|
|
if (result == B_OK) {
|
|
if (appMessage.FindUInt32("flags", &appFlags) != B_OK
|
|
|| appMessage.FindString("checksum", &appSum) != B_OK) {
|
|
appIsNew = true;
|
|
appFlags = 0;
|
|
} else if (appSum != checksum) {
|
|
appWasUpdated = true;
|
|
appFlags = 0;
|
|
}
|
|
} else
|
|
appIsNew = true;
|
|
|
|
if ((accessFlags & appFlags) == accessFlags)
|
|
return B_OK;
|
|
|
|
const char* accessString = _AccessStringFor(accessFlags);
|
|
bool allowAlways = false;
|
|
result = _RequestAppAccess(keyring.Name(), appInfo.signature, path.Path(),
|
|
accessString, appIsNew, appWasUpdated, accessFlags, allowAlways);
|
|
if (result != B_OK || !allowAlways)
|
|
return result;
|
|
|
|
appMessage.MakeEmpty();
|
|
appMessage.AddString("path", path.Path());
|
|
appMessage.AddUInt32("flags", appFlags | accessFlags);
|
|
appMessage.AddString("checksum", checksum);
|
|
|
|
keyring.RemoveApplication(appInfo.signature, path.Path());
|
|
if (keyring.AddApplication(appInfo.signature, appMessage) == B_OK)
|
|
_WriteKeyStoreDatabase();
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
KeyStoreServer::_RequestAppAccess(const BString& keyringName,
|
|
const char* signature, const char* path, const char* accessString,
|
|
bool appIsNew, bool appWasUpdated, uint32 accessFlags, bool& allowAlways)
|
|
{
|
|
AppAccessRequestWindow* requestWindow
|
|
= new(std::nothrow) AppAccessRequestWindow(keyringName, signature, path,
|
|
accessString, appIsNew, appWasUpdated);
|
|
if (requestWindow == NULL)
|
|
return B_NO_MEMORY;
|
|
|
|
return requestWindow->RequestAppAccess(allowAlways);
|
|
}
|
|
|
|
|
|
Keyring*
|
|
KeyStoreServer::_FindKeyring(const BString& name)
|
|
{
|
|
if (name.IsEmpty() || name == kMasterKeyringName)
|
|
return fMasterKeyring;
|
|
|
|
return fKeyrings.BinarySearchByKey(name, &Keyring::Compare);
|
|
}
|
|
|
|
|
|
status_t
|
|
KeyStoreServer::_AddKeyring(const BString& name)
|
|
{
|
|
if (_FindKeyring(name) != NULL)
|
|
return B_NAME_IN_USE;
|
|
|
|
Keyring* keyring = new(std::nothrow) Keyring(name);
|
|
if (keyring == NULL)
|
|
return B_NO_MEMORY;
|
|
|
|
if (!fKeyrings.BinaryInsert(keyring, &Keyring::Compare)) {
|
|
delete keyring;
|
|
return B_ERROR;
|
|
}
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
KeyStoreServer::_RemoveKeyring(const BString& name)
|
|
{
|
|
Keyring* keyring = _FindKeyring(name);
|
|
if (keyring == NULL)
|
|
return B_ENTRY_NOT_FOUND;
|
|
|
|
if (keyring == fMasterKeyring) {
|
|
// The master keyring can't be removed.
|
|
return B_NOT_ALLOWED;
|
|
}
|
|
|
|
return fKeyrings.RemoveItem(keyring) ? B_OK : B_ERROR;
|
|
}
|
|
|
|
|
|
status_t
|
|
KeyStoreServer::_UnlockKeyring(Keyring& keyring)
|
|
{
|
|
if (!keyring.HasUnlockKey())
|
|
return keyring.Unlock(NULL);
|
|
|
|
// If we are accessing a keyring that has been added to master access we
|
|
// get the key from the master keyring and unlock with that.
|
|
BMessage keyMessage;
|
|
if (&keyring != fMasterKeyring && fMasterKeyring->IsUnlocked()) {
|
|
if (fMasterKeyring->FindKey(kKeyringKeysIdentifier, keyring.Name(),
|
|
false, &keyMessage) == B_OK) {
|
|
// We found a key for this keyring, try to unlock with it.
|
|
if (keyring.Unlock(&keyMessage) == B_OK)
|
|
return B_OK;
|
|
}
|
|
}
|
|
|
|
// No key, we need to request one from the user.
|
|
status_t result = _RequestKey(keyring.Name(), keyMessage);
|
|
if (result != B_OK)
|
|
return result;
|
|
|
|
return keyring.Unlock(&keyMessage);
|
|
}
|
|
|
|
|
|
status_t
|
|
KeyStoreServer::_RequestKey(const BString& keyringName, BMessage& keyMessage)
|
|
{
|
|
KeyRequestWindow* requestWindow = new(std::nothrow) KeyRequestWindow();
|
|
if (requestWindow == NULL)
|
|
return B_NO_MEMORY;
|
|
|
|
return requestWindow->RequestKey(keyringName, keyMessage);
|
|
}
|
|
|
|
|
|
int
|
|
main(int argc, char* argv[])
|
|
{
|
|
KeyStoreServer* app = new(std::nothrow) KeyStoreServer();
|
|
if (app == NULL)
|
|
return 1;
|
|
|
|
app->Run();
|
|
delete app;
|
|
return 0;
|
|
}
|