1/*
2 * Copyright 2012, Michael Lotz, mmlr@mlotz.ch. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "KeyStoreServer.h"
8
9#include "AppAccessRequestWindow.h"
10#include "KeyRequestWindow.h"
11#include "Keyring.h"
12
13#include <KeyStoreDefs.h>
14
15#include <Directory.h>
16#include <Entry.h>
17#include <FindDirectory.h>
18#include <Path.h>
19#include <Roster.h>
20#include <String.h>
21
22#include <new>
23
24#include <stdio.h>
25
26
27using namespace BPrivate;
28
29
30static const char* kMasterKeyringName = "Master";
31static const char* kKeyringKeysIdentifier = "Keyrings";
32
33static const uint32 kKeyStoreFormatVersion = 1;
34
35static const uint32 kFlagGetKey						= 0x0001;
36static const uint32 kFlagEnumerateKeys				= 0x0002;
37static const uint32 kFlagAddKey						= 0x0004;
38static const uint32 kFlagRemoveKey					= 0x0008;
39static const uint32 kFlagAddKeyring					= 0x0010;
40static const uint32 kFlagRemoveKeyring				= 0x0020;
41static const uint32 kFlagEnumerateKeyrings			= 0x0040;
42static const uint32 kFlagSetUnlockKey				= 0x0080;
43static const uint32 kFlagRemoveUnlockKey			= 0x0100;
44static const uint32 kFlagAddKeyringsToMaster		= 0x0200;
45static const uint32 kFlagRemoveKeyringsFromMaster	= 0x0400;
46static const uint32 kFlagEnumerateMasterKeyrings	= 0x0800;
47static const uint32 kFlagQueryLockState				= 0x1000;
48static const uint32 kFlagLockKeyring				= 0x2000;
49static const uint32 kFlagEnumerateApplications		= 0x4000;
50static const uint32 kFlagRemoveApplications			= 0x8000;
51
52static const uint32 kDefaultAppFlags = kFlagGetKey | kFlagEnumerateKeys
53	| kFlagAddKey | kFlagRemoveKey | kFlagAddKeyring | kFlagRemoveKeyring
54	| kFlagEnumerateKeyrings | kFlagSetUnlockKey | kFlagRemoveUnlockKey
55	| kFlagAddKeyringsToMaster | kFlagRemoveKeyringsFromMaster
56	| kFlagEnumerateMasterKeyrings | kFlagQueryLockState | kFlagLockKeyring
57	| kFlagEnumerateApplications | kFlagRemoveApplications;
58
59
60KeyStoreServer::KeyStoreServer()
61	:
62	BApplication(kKeyStoreServerSignature),
63	fMasterKeyring(NULL),
64	fKeyrings(20, true)
65{
66	BPath path;
67	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
68		return;
69
70	BDirectory settingsDir(path.Path());
71	path.Append("system");
72	if (!settingsDir.Contains(path.Path()))
73		settingsDir.CreateDirectory(path.Path(), NULL);
74
75	settingsDir.SetTo(path.Path());
76	path.Append("keystore");
77	if (!settingsDir.Contains(path.Path()))
78		settingsDir.CreateDirectory(path.Path(), NULL);
79
80	settingsDir.SetTo(path.Path());
81	path.Append("keystore_database");
82
83	fKeyStoreFile.SetTo(path.Path(), B_READ_WRITE
84		| (settingsDir.Contains(path.Path()) ? 0 : B_CREATE_FILE));
85
86	_ReadKeyStoreDatabase();
87
88	if (fMasterKeyring == NULL) {
89		fMasterKeyring = new(std::nothrow) Keyring(kMasterKeyringName);
90		fKeyrings.BinaryInsert(fMasterKeyring, &Keyring::Compare);
91	}
92}
93
94
95KeyStoreServer::~KeyStoreServer()
96{
97}
98
99
100void
101KeyStoreServer::MessageReceived(BMessage* message)
102{
103	BMessage reply;
104	status_t result = B_UNSUPPORTED;
105	app_info callingAppInfo;
106
107	uint32 accessFlags = _AccessFlagsFor(message->what);
108	if (accessFlags == 0)
109		message->what = 0;
110
111	if (message->what != 0) {
112		result = _ResolveCallingApp(*message, callingAppInfo);
113		if (result != B_OK)
114			message->what = 0;
115	}
116
117	// Resolve the keyring for the relevant messages.
118	Keyring* keyring = NULL;
119	switch (message->what) {
120		case KEY_STORE_GET_KEY:
121		case KEY_STORE_GET_NEXT_KEY:
122		case KEY_STORE_ADD_KEY:
123		case KEY_STORE_REMOVE_KEY:
124		case KEY_STORE_IS_KEYRING_UNLOCKED:
125		case KEY_STORE_LOCK_KEYRING:
126		case KEY_STORE_SET_UNLOCK_KEY:
127		case KEY_STORE_REMOVE_UNLOCK_KEY:
128		case KEY_STORE_ADD_KEYRING_TO_MASTER:
129		case KEY_STORE_REMOVE_KEYRING_FROM_MASTER:
130		case KEY_STORE_GET_NEXT_APPLICATION:
131		case KEY_STORE_REMOVE_APPLICATION:
132		{
133			BString keyringName;
134			if (message->FindString("keyring", &keyringName) != B_OK)
135				keyringName = "";
136
137			keyring = _FindKeyring(keyringName);
138			if (keyring == NULL) {
139				result = B_BAD_VALUE;
140				message->what = 0;
141					// So that we don't do anything in the second switch.
142				break;
143			}
144
145			switch (message->what) {
146				case KEY_STORE_GET_KEY:
147				case KEY_STORE_GET_NEXT_KEY:
148				case KEY_STORE_ADD_KEY:
149				case KEY_STORE_REMOVE_KEY:
150				case KEY_STORE_SET_UNLOCK_KEY:
151				case KEY_STORE_REMOVE_UNLOCK_KEY:
152				case KEY_STORE_ADD_KEYRING_TO_MASTER:
153				case KEY_STORE_GET_NEXT_APPLICATION:
154				case KEY_STORE_REMOVE_APPLICATION:
155				{
156					// These need keyring access to do anything.
157					while (!keyring->IsUnlocked()) {
158						status_t unlockResult = _UnlockKeyring(*keyring);
159						if (unlockResult != B_OK) {
160							result = unlockResult;
161							message->what = 0;
162							break;
163						}
164					}
165
166					status_t validateResult = _ValidateAppAccess(*keyring,
167						callingAppInfo, accessFlags);
168					if (validateResult != B_OK) {
169						result = validateResult;
170						message->what = 0;
171						break;
172					}
173
174					break;
175				}
176			}
177
178			break;
179		}
180	}
181
182	switch (message->what) {
183		case KEY_STORE_GET_KEY:
184		{
185			BString identifier;
186			if (message->FindString("identifier", &identifier) != B_OK) {
187				result = B_BAD_VALUE;
188				break;
189			}
190
191			bool secondaryIdentifierOptional;
192			if (message->FindBool("secondaryIdentifierOptional",
193					&secondaryIdentifierOptional) != B_OK) {
194				secondaryIdentifierOptional = false;
195			}
196
197			BString secondaryIdentifier;
198			if (message->FindString("secondaryIdentifier",
199					&secondaryIdentifier) != B_OK) {
200				secondaryIdentifier = "";
201				secondaryIdentifierOptional = true;
202			}
203
204			BMessage keyMessage;
205			result = keyring->FindKey(identifier, secondaryIdentifier,
206				secondaryIdentifierOptional, &keyMessage);
207			if (result == B_OK)
208				reply.AddMessage("key", &keyMessage);
209
210			break;
211		}
212
213		case KEY_STORE_GET_NEXT_KEY:
214		{
215			BKeyType type;
216			BKeyPurpose purpose;
217			uint32 cookie;
218			if (message->FindUInt32("type", (uint32*)&type) != B_OK
219				|| message->FindUInt32("purpose", (uint32*)&purpose) != B_OK
220				|| message->FindUInt32("cookie", &cookie) != B_OK) {
221				result = B_BAD_VALUE;
222				break;
223			}
224
225			BMessage keyMessage;
226			result = keyring->FindKey(type, purpose, cookie, keyMessage);
227			if (result == B_OK) {
228				cookie++;
229				reply.AddUInt32("cookie", cookie);
230				reply.AddMessage("key", &keyMessage);
231			}
232
233			break;
234		}
235
236		case KEY_STORE_ADD_KEY:
237		{
238			BMessage keyMessage;
239			BString identifier;
240			if (message->FindMessage("key", &keyMessage) != B_OK
241				|| keyMessage.FindString("identifier", &identifier) != B_OK) {
242				result = B_BAD_VALUE;
243				break;
244			}
245
246			BString secondaryIdentifier;
247			if (keyMessage.FindString("secondaryIdentifier",
248					&secondaryIdentifier) != B_OK) {
249				secondaryIdentifier = "";
250			}
251
252			result = keyring->AddKey(identifier, secondaryIdentifier, keyMessage);
253			if (result == B_OK)
254				_WriteKeyStoreDatabase();
255
256			break;
257		}
258
259		case KEY_STORE_REMOVE_KEY:
260		{
261			BMessage keyMessage;
262			BString identifier;
263			if (message->FindMessage("key", &keyMessage) != B_OK
264				|| keyMessage.FindString("identifier", &identifier) != B_OK) {
265				result = B_BAD_VALUE;
266				break;
267			}
268
269			result = keyring->RemoveKey(identifier, keyMessage);
270			if (result == B_OK)
271				_WriteKeyStoreDatabase();
272
273			break;
274		}
275
276		case KEY_STORE_ADD_KEYRING:
277		{
278			BMessage keyMessage;
279			BString keyring;
280			if (message->FindString("keyring", &keyring) != B_OK) {
281				result = B_BAD_VALUE;
282				break;
283			}
284
285			result = _AddKeyring(keyring);
286			if (result == B_OK)
287				_WriteKeyStoreDatabase();
288
289			break;
290		}
291
292		case KEY_STORE_REMOVE_KEYRING:
293		{
294			BString keyringName;
295			if (message->FindString("keyring", &keyringName) != B_OK)
296				keyringName = "";
297
298			result = _RemoveKeyring(keyringName);
299			if (result == B_OK)
300				_WriteKeyStoreDatabase();
301
302			break;
303		}
304
305		case KEY_STORE_GET_NEXT_KEYRING:
306		{
307			uint32 cookie;
308			if (message->FindUInt32("cookie", &cookie) != B_OK) {
309				result = B_BAD_VALUE;
310				break;
311			}
312
313			keyring = fKeyrings.ItemAt(cookie);
314			if (keyring == NULL) {
315				result = B_ENTRY_NOT_FOUND;
316				break;
317			}
318
319			cookie++;
320			reply.AddUInt32("cookie", cookie);
321			reply.AddString("keyring", keyring->Name());
322			result = B_OK;
323			break;
324		}
325
326		case KEY_STORE_IS_KEYRING_UNLOCKED:
327		{
328			reply.AddBool("unlocked", keyring->IsUnlocked());
329			result = B_OK;
330			break;
331		}
332
333		case KEY_STORE_LOCK_KEYRING:
334		{
335			keyring->Lock();
336			result = B_OK;
337			break;
338		}
339
340		case KEY_STORE_SET_UNLOCK_KEY:
341		{
342			BMessage keyMessage;
343			if (message->FindMessage("key", &keyMessage) != B_OK) {
344				result = B_BAD_VALUE;
345				break;
346			}
347
348			result = keyring->SetUnlockKey(keyMessage);
349			if (result == B_OK)
350				_WriteKeyStoreDatabase();
351
352			// TODO: Update the key in the master if this keyring was added.
353			break;
354		}
355
356		case KEY_STORE_REMOVE_UNLOCK_KEY:
357		{
358			result = keyring->RemoveUnlockKey();
359			if (result == B_OK)
360				_WriteKeyStoreDatabase();
361
362			break;
363		}
364
365		case KEY_STORE_ADD_KEYRING_TO_MASTER:
366		case KEY_STORE_REMOVE_KEYRING_FROM_MASTER:
367		{
368			// We also need access to the master keyring.
369			while (!fMasterKeyring->IsUnlocked()) {
370				status_t unlockResult = _UnlockKeyring(*fMasterKeyring);
371				if (unlockResult != B_OK) {
372					result = unlockResult;
373					message->what = 0;
374					break;
375				}
376			}
377
378			if (message->what == 0)
379				break;
380
381			BString secondaryIdentifier = keyring->Name();
382			BMessage keyMessage = keyring->UnlockKey();
383			keyMessage.RemoveName("identifier");
384			keyMessage.AddString("identifier", kKeyringKeysIdentifier);
385			keyMessage.RemoveName("secondaryIdentifier");
386			keyMessage.AddString("secondaryIdentifier", secondaryIdentifier);
387
388			switch (message->what) {
389				case KEY_STORE_ADD_KEYRING_TO_MASTER:
390					result = fMasterKeyring->AddKey(kKeyringKeysIdentifier,
391						secondaryIdentifier, keyMessage);
392					break;
393
394				case KEY_STORE_REMOVE_KEYRING_FROM_MASTER:
395					result = fMasterKeyring->RemoveKey(kKeyringKeysIdentifier,
396						keyMessage);
397					break;
398			}
399
400			if (result == B_OK)
401				_WriteKeyStoreDatabase();
402
403			break;
404		}
405
406		case KEY_STORE_GET_NEXT_APPLICATION:
407		{
408			uint32 cookie;
409			if (message->FindUInt32("cookie", &cookie) != B_OK) {
410				result = B_BAD_VALUE;
411				break;
412			}
413
414			BString signature;
415			BString path;
416			result = keyring->GetNextApplication(cookie, signature, path);
417			if (result != B_OK)
418				break;
419
420			reply.AddUInt32("cookie", cookie);
421			reply.AddString("signature", signature);
422			reply.AddString("path", path);
423			result = B_OK;
424			break;
425		}
426
427		case KEY_STORE_REMOVE_APPLICATION:
428		{
429			const char* signature = NULL;
430			const char* path = NULL;
431
432			if (message->FindString("signature", &signature) != B_OK) {
433				result = B_BAD_VALUE;
434				break;
435			}
436
437			if (message->FindString("path", &path) != B_OK)
438				path = NULL;
439
440			result = keyring->RemoveApplication(signature, path);
441			if (result == B_OK)
442				_WriteKeyStoreDatabase();
443
444			break;
445		}
446
447		case 0:
448		{
449			// Just the error case from above.
450			break;
451		}
452
453		default:
454		{
455			printf("unknown message received: %" B_PRIu32 " \"%.4s\"\n",
456				message->what, (const char*)&message->what);
457			break;
458		}
459	}
460
461	if (message->IsSourceWaiting()) {
462		if (result == B_OK)
463			reply.what = KEY_STORE_SUCCESS;
464		else {
465			reply.what = KEY_STORE_RESULT;
466			reply.AddInt32("result", result);
467		}
468
469		message->SendReply(&reply);
470	}
471}
472
473
474status_t
475KeyStoreServer::_ReadKeyStoreDatabase()
476{
477	BMessage keystore;
478	status_t result = keystore.Unflatten(&fKeyStoreFile);
479	if (result != B_OK) {
480		printf("failed to read keystore database\n");
481		_WriteKeyStoreDatabase();
482			// Reinitializes the database.
483		return result;
484	}
485
486	int32 index = 0;
487	BMessage keyringData;
488	while (keystore.FindMessage("keyrings", index++, &keyringData) == B_OK) {
489		Keyring* keyring = new(std::nothrow) Keyring();
490		if (keyring == NULL) {
491			printf("no memory for allocating keyring\n");
492			break;
493		}
494
495		status_t result = keyring->ReadFromMessage(keyringData);
496		if (result != B_OK) {
497			printf("failed to read keyring from data\n");
498			delete keyring;
499			continue;
500		}
501
502		if (strcmp(keyring->Name(), kMasterKeyringName) == 0)
503			fMasterKeyring = keyring;
504
505		fKeyrings.BinaryInsert(keyring, &Keyring::Compare);
506	}
507
508	return B_OK;
509}
510
511
512status_t
513KeyStoreServer::_WriteKeyStoreDatabase()
514{
515	BMessage keystore;
516	keystore.AddUInt32("format", kKeyStoreFormatVersion);
517
518	for (int32 i = 0; i < fKeyrings.CountItems(); i++) {
519		Keyring* keyring = fKeyrings.ItemAt(i);
520		if (keyring == NULL)
521			continue;
522
523		BMessage keyringData;
524		status_t result = keyring->WriteToMessage(keyringData);
525		if (result != B_OK)
526			return result;
527
528		keystore.AddMessage("keyrings", &keyringData);
529	}
530
531	fKeyStoreFile.SetSize(0);
532	fKeyStoreFile.Seek(0, SEEK_SET);
533	return keystore.Flatten(&fKeyStoreFile);
534}
535
536
537uint32
538KeyStoreServer::_AccessFlagsFor(uint32 command) const
539{
540	switch (command) {
541		case KEY_STORE_GET_KEY:
542			return kFlagGetKey;
543		case KEY_STORE_GET_NEXT_KEY:
544			return kFlagEnumerateKeys;
545		case KEY_STORE_ADD_KEY:
546			return kFlagAddKey;
547		case KEY_STORE_REMOVE_KEY:
548			return kFlagRemoveKey;
549		case KEY_STORE_ADD_KEYRING:
550			return kFlagAddKeyring;
551		case KEY_STORE_REMOVE_KEYRING:
552			return kFlagRemoveKeyring;
553		case KEY_STORE_GET_NEXT_KEYRING:
554			return kFlagEnumerateKeyrings;
555		case KEY_STORE_SET_UNLOCK_KEY:
556			return kFlagSetUnlockKey;
557		case KEY_STORE_REMOVE_UNLOCK_KEY:
558			return kFlagRemoveUnlockKey;
559		case KEY_STORE_ADD_KEYRING_TO_MASTER:
560			return kFlagAddKeyringsToMaster;
561		case KEY_STORE_REMOVE_KEYRING_FROM_MASTER:
562			return kFlagRemoveKeyringsFromMaster;
563		case KEY_STORE_GET_NEXT_MASTER_KEYRING:
564			return kFlagEnumerateMasterKeyrings;
565		case KEY_STORE_IS_KEYRING_UNLOCKED:
566			return kFlagQueryLockState;
567		case KEY_STORE_LOCK_KEYRING:
568			return kFlagLockKeyring;
569		case KEY_STORE_GET_NEXT_APPLICATION:
570			return kFlagEnumerateApplications;
571		case KEY_STORE_REMOVE_APPLICATION:
572			return kFlagRemoveApplications;
573	}
574
575	return 0;
576}
577
578
579const char*
580KeyStoreServer::_AccessStringFor(uint32 accessFlag) const
581{
582	switch (accessFlag) {
583		case kFlagGetKey:
584			return "Get keys from the keyring.";
585		case kFlagEnumerateKeys:
586			return "Enumerate and get keys from the keyring.";
587		case kFlagAddKey:
588			return "Add keys to the keyring.";
589		case kFlagRemoveKey:
590			return "Remove keys from the keyring.";
591		case kFlagAddKeyring:
592			return "Add new keyrings.";
593		case kFlagRemoveKeyring:
594			return "Remove keyrings.";
595		case kFlagEnumerateKeyrings:
596			return "Enumerate the available keyrings.";
597		case kFlagSetUnlockKey:
598			return "Set the unlock key of the keyring.";
599		case kFlagRemoveUnlockKey:
600			return "Remove the unlock key of the keyring.";
601		case kFlagAddKeyringsToMaster:
602			return "Add the keyring key to the master keyring.";
603		case kFlagRemoveKeyringsFromMaster:
604			return "Remove the keyring key from the master keyring.";
605		case kFlagEnumerateMasterKeyrings:
606			return "Enumerate keyrings added to the master keyring.";
607		case kFlagQueryLockState:
608			return "Query the lock state of the keyring.";
609		case kFlagLockKeyring:
610			return "Lock the keyring.";
611		case kFlagEnumerateApplications:
612			return "Enumerate the applications of the keyring.";
613		case kFlagRemoveApplications:
614			return "Remove applications from the keyring.";
615	}
616
617	return NULL;
618}
619
620
621status_t
622KeyStoreServer::_ResolveCallingApp(const BMessage& message,
623	app_info& callingAppInfo) const
624{
625	team_id callingTeam = message.ReturnAddress().Team();
626	status_t result = be_roster->GetRunningAppInfo(callingTeam,
627		&callingAppInfo);
628	if (result != B_OK)
629		return result;
630
631	// Do some sanity checks.
632	if (callingAppInfo.team != callingTeam)
633		return B_ERROR;
634
635	return B_OK;
636}
637
638
639status_t
640KeyStoreServer::_ValidateAppAccess(Keyring& keyring, const app_info& appInfo,
641	uint32 accessFlags)
642{
643	BMessage appMessage;
644	BPath path(&appInfo.ref);
645	status_t result = keyring.FindApplication(appInfo.signature,
646		path.Path(), appMessage);
647	if (result != B_OK && result != B_ENTRY_NOT_FOUND)
648		return result;
649
650	// TODO: Implement running image checksum mechanism.
651	BString checksum = path.Path();
652
653	bool appIsNew = false;
654	bool appWasUpdated = false;
655	uint32 appFlags = 0;
656	BString appSum = "";
657	if (result == B_OK) {
658		if (appMessage.FindUInt32("flags", &appFlags) != B_OK
659			|| appMessage.FindString("checksum", &appSum) != B_OK) {
660			appIsNew = true;
661			appFlags = 0;
662		} else if (appSum != checksum) {
663			appWasUpdated = true;
664			appFlags = 0;
665		}
666	} else
667		appIsNew = true;
668
669	if ((accessFlags & appFlags) == accessFlags)
670		return B_OK;
671
672	const char* accessString = _AccessStringFor(accessFlags);
673	bool allowAlways = false;
674	result = _RequestAppAccess(keyring.Name(), appInfo.signature, path.Path(),
675		accessString, appIsNew, appWasUpdated, accessFlags, allowAlways);
676	if (result != B_OK || !allowAlways)
677		return result;
678
679	appMessage.MakeEmpty();
680	appMessage.AddString("path", path.Path());
681	appMessage.AddUInt32("flags", appFlags | accessFlags);
682	appMessage.AddString("checksum", checksum);
683
684	keyring.RemoveApplication(appInfo.signature, path.Path());
685	if (keyring.AddApplication(appInfo.signature, appMessage) == B_OK)
686		_WriteKeyStoreDatabase();
687
688	return B_OK;
689}
690
691
692status_t
693KeyStoreServer::_RequestAppAccess(const BString& keyringName,
694	const char* signature, const char* path, const char* accessString,
695	bool appIsNew, bool appWasUpdated, uint32 accessFlags, bool& allowAlways)
696{
697	AppAccessRequestWindow* requestWindow
698		= new(std::nothrow) AppAccessRequestWindow(keyringName, signature, path,
699			accessString, appIsNew, appWasUpdated);
700	if (requestWindow == NULL)
701		return B_NO_MEMORY;
702
703	return requestWindow->RequestAppAccess(allowAlways);
704}
705
706
707Keyring*
708KeyStoreServer::_FindKeyring(const BString& name)
709{
710	if (name.IsEmpty() || name == kMasterKeyringName)
711		return fMasterKeyring;
712
713	return fKeyrings.BinarySearchByKey(name, &Keyring::Compare);
714}
715
716
717status_t
718KeyStoreServer::_AddKeyring(const BString& name)
719{
720	if (_FindKeyring(name) != NULL)
721		return B_NAME_IN_USE;
722
723	Keyring* keyring = new(std::nothrow) Keyring(name);
724	if (keyring == NULL)
725		return B_NO_MEMORY;
726
727	if (!fKeyrings.BinaryInsert(keyring, &Keyring::Compare)) {
728		delete keyring;
729		return B_ERROR;
730	}
731
732	return B_OK;
733}
734
735
736status_t
737KeyStoreServer::_RemoveKeyring(const BString& name)
738{
739	Keyring* keyring = _FindKeyring(name);
740	if (keyring == NULL)
741		return B_ENTRY_NOT_FOUND;
742
743	if (keyring == fMasterKeyring) {
744		// The master keyring can't be removed.
745		return B_NOT_ALLOWED;
746	}
747
748	return fKeyrings.RemoveItem(keyring) ? B_OK : B_ERROR;
749}
750
751
752status_t
753KeyStoreServer::_UnlockKeyring(Keyring& keyring)
754{
755	if (!keyring.HasUnlockKey())
756		return keyring.Unlock(NULL);
757
758	// If we are accessing a keyring that has been added to master access we
759	// get the key from the master keyring and unlock with that.
760	BMessage keyMessage;
761	if (&keyring != fMasterKeyring && fMasterKeyring->IsUnlocked()) {
762		if (fMasterKeyring->FindKey(kKeyringKeysIdentifier, keyring.Name(),
763				false, &keyMessage) == B_OK) {
764			// We found a key for this keyring, try to unlock with it.
765			if (keyring.Unlock(&keyMessage) == B_OK)
766				return B_OK;
767		}
768	}
769
770	// No key, we need to request one from the user.
771	status_t result = _RequestKey(keyring.Name(), keyMessage);
772	if (result != B_OK)
773		return result;
774
775	return keyring.Unlock(&keyMessage);
776}
777
778
779status_t
780KeyStoreServer::_RequestKey(const BString& keyringName, BMessage& keyMessage)
781{
782	KeyRequestWindow* requestWindow = new(std::nothrow) KeyRequestWindow();
783	if (requestWindow == NULL)
784		return B_NO_MEMORY;
785
786	return requestWindow->RequestKey(keyringName, keyMessage);
787}
788
789
790int
791main(int argc, char* argv[])
792{
793	KeyStoreServer* app = new(std::nothrow) KeyStoreServer();
794	if (app == NULL)
795		return 1;
796
797	app->Run();
798	delete app;
799	return 0;
800}
801