vfs: check userland buffers before reading them.
[haiku.git] / src / servers / keystore / KeyStoreServer.cpp
blob41b173294572e8db9cf170e0d69ec40cb601f439
1 /*
2 * Copyright 2012, Michael Lotz, mmlr@mlotz.ch. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "KeyStoreServer.h"
9 #include "AppAccessRequestWindow.h"
10 #include "KeyRequestWindow.h"
11 #include "Keyring.h"
13 #include <KeyStoreDefs.h>
15 #include <Directory.h>
16 #include <Entry.h>
17 #include <FindDirectory.h>
18 #include <Path.h>
19 #include <Roster.h>
20 #include <String.h>
22 #include <new>
24 #include <stdio.h>
27 using namespace BPrivate;
30 static const char* kMasterKeyringName = "Master";
31 static const char* kKeyringKeysIdentifier = "Keyrings";
33 static const uint32 kKeyStoreFormatVersion = 1;
35 static const uint32 kFlagGetKey = 0x0001;
36 static const uint32 kFlagEnumerateKeys = 0x0002;
37 static const uint32 kFlagAddKey = 0x0004;
38 static const uint32 kFlagRemoveKey = 0x0008;
39 static const uint32 kFlagAddKeyring = 0x0010;
40 static const uint32 kFlagRemoveKeyring = 0x0020;
41 static const uint32 kFlagEnumerateKeyrings = 0x0040;
42 static const uint32 kFlagSetUnlockKey = 0x0080;
43 static const uint32 kFlagRemoveUnlockKey = 0x0100;
44 static const uint32 kFlagAddKeyringsToMaster = 0x0200;
45 static const uint32 kFlagRemoveKeyringsFromMaster = 0x0400;
46 static const uint32 kFlagEnumerateMasterKeyrings = 0x0800;
47 static const uint32 kFlagQueryLockState = 0x1000;
48 static const uint32 kFlagLockKeyring = 0x2000;
49 static const uint32 kFlagEnumerateApplications = 0x4000;
50 static const uint32 kFlagRemoveApplications = 0x8000;
52 static const uint32 kDefaultAppFlags = kFlagGetKey | kFlagEnumerateKeys
53 | kFlagAddKey | kFlagRemoveKey | kFlagAddKeyring | kFlagRemoveKeyring
54 | kFlagEnumerateKeyrings | kFlagSetUnlockKey | kFlagRemoveUnlockKey
55 | kFlagAddKeyringsToMaster | kFlagRemoveKeyringsFromMaster
56 | kFlagEnumerateMasterKeyrings | kFlagQueryLockState | kFlagLockKeyring
57 | kFlagEnumerateApplications | kFlagRemoveApplications;
60 KeyStoreServer::KeyStoreServer()
62 BApplication(kKeyStoreServerSignature),
63 fMasterKeyring(NULL),
64 fKeyrings(20, true)
66 BPath path;
67 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
68 return;
70 BDirectory settingsDir(path.Path());
71 path.Append("system");
72 if (!settingsDir.Contains(path.Path()))
73 settingsDir.CreateDirectory(path.Path(), NULL);
75 settingsDir.SetTo(path.Path());
76 path.Append("keystore");
77 if (!settingsDir.Contains(path.Path()))
78 settingsDir.CreateDirectory(path.Path(), NULL);
80 settingsDir.SetTo(path.Path());
81 path.Append("keystore_database");
83 fKeyStoreFile.SetTo(path.Path(), B_READ_WRITE
84 | (settingsDir.Contains(path.Path()) ? 0 : B_CREATE_FILE));
86 _ReadKeyStoreDatabase();
88 if (fMasterKeyring == NULL) {
89 fMasterKeyring = new(std::nothrow) Keyring(kMasterKeyringName);
90 fKeyrings.BinaryInsert(fMasterKeyring, &Keyring::Compare);
95 KeyStoreServer::~KeyStoreServer()
100 void
101 KeyStoreServer::MessageReceived(BMessage* message)
103 BMessage reply;
104 status_t result = B_UNSUPPORTED;
105 app_info callingAppInfo;
107 uint32 accessFlags = _AccessFlagsFor(message->what);
108 if (accessFlags == 0)
109 message->what = 0;
111 if (message->what != 0) {
112 result = _ResolveCallingApp(*message, callingAppInfo);
113 if (result != B_OK)
114 message->what = 0;
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:
133 BString keyringName;
134 if (message->FindString("keyring", &keyringName) != B_OK)
135 keyringName = "";
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;
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:
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;
166 status_t validateResult = _ValidateAppAccess(*keyring,
167 callingAppInfo, accessFlags);
168 if (validateResult != B_OK) {
169 result = validateResult;
170 message->what = 0;
171 break;
174 break;
178 break;
182 switch (message->what) {
183 case KEY_STORE_GET_KEY:
185 BString identifier;
186 if (message->FindString("identifier", &identifier) != B_OK) {
187 result = B_BAD_VALUE;
188 break;
191 bool secondaryIdentifierOptional;
192 if (message->FindBool("secondaryIdentifierOptional",
193 &secondaryIdentifierOptional) != B_OK) {
194 secondaryIdentifierOptional = false;
197 BString secondaryIdentifier;
198 if (message->FindString("secondaryIdentifier",
199 &secondaryIdentifier) != B_OK) {
200 secondaryIdentifier = "";
201 secondaryIdentifierOptional = true;
204 BMessage keyMessage;
205 result = keyring->FindKey(identifier, secondaryIdentifier,
206 secondaryIdentifierOptional, &keyMessage);
207 if (result == B_OK)
208 reply.AddMessage("key", &keyMessage);
210 break;
213 case KEY_STORE_GET_NEXT_KEY:
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;
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);
233 break;
236 case KEY_STORE_ADD_KEY:
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;
246 BString secondaryIdentifier;
247 if (keyMessage.FindString("secondaryIdentifier",
248 &secondaryIdentifier) != B_OK) {
249 secondaryIdentifier = "";
252 result = keyring->AddKey(identifier, secondaryIdentifier, keyMessage);
253 if (result == B_OK)
254 _WriteKeyStoreDatabase();
256 break;
259 case KEY_STORE_REMOVE_KEY:
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;
269 result = keyring->RemoveKey(identifier, keyMessage);
270 if (result == B_OK)
271 _WriteKeyStoreDatabase();
273 break;
276 case KEY_STORE_ADD_KEYRING:
278 BMessage keyMessage;
279 BString keyring;
280 if (message->FindString("keyring", &keyring) != B_OK) {
281 result = B_BAD_VALUE;
282 break;
285 result = _AddKeyring(keyring);
286 if (result == B_OK)
287 _WriteKeyStoreDatabase();
289 break;
292 case KEY_STORE_REMOVE_KEYRING:
294 BString keyringName;
295 if (message->FindString("keyring", &keyringName) != B_OK)
296 keyringName = "";
298 result = _RemoveKeyring(keyringName);
299 if (result == B_OK)
300 _WriteKeyStoreDatabase();
302 break;
305 case KEY_STORE_GET_NEXT_KEYRING:
307 uint32 cookie;
308 if (message->FindUInt32("cookie", &cookie) != B_OK) {
309 result = B_BAD_VALUE;
310 break;
313 keyring = fKeyrings.ItemAt(cookie);
314 if (keyring == NULL) {
315 result = B_ENTRY_NOT_FOUND;
316 break;
319 cookie++;
320 reply.AddUInt32("cookie", cookie);
321 reply.AddString("keyring", keyring->Name());
322 result = B_OK;
323 break;
326 case KEY_STORE_IS_KEYRING_UNLOCKED:
328 reply.AddBool("unlocked", keyring->IsUnlocked());
329 result = B_OK;
330 break;
333 case KEY_STORE_LOCK_KEYRING:
335 keyring->Lock();
336 result = B_OK;
337 break;
340 case KEY_STORE_SET_UNLOCK_KEY:
342 BMessage keyMessage;
343 if (message->FindMessage("key", &keyMessage) != B_OK) {
344 result = B_BAD_VALUE;
345 break;
348 result = keyring->SetUnlockKey(keyMessage);
349 if (result == B_OK)
350 _WriteKeyStoreDatabase();
352 // TODO: Update the key in the master if this keyring was added.
353 break;
356 case KEY_STORE_REMOVE_UNLOCK_KEY:
358 result = keyring->RemoveUnlockKey();
359 if (result == B_OK)
360 _WriteKeyStoreDatabase();
362 break;
365 case KEY_STORE_ADD_KEYRING_TO_MASTER:
366 case KEY_STORE_REMOVE_KEYRING_FROM_MASTER:
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;
378 if (message->what == 0)
379 break;
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);
388 switch (message->what) {
389 case KEY_STORE_ADD_KEYRING_TO_MASTER:
390 result = fMasterKeyring->AddKey(kKeyringKeysIdentifier,
391 secondaryIdentifier, keyMessage);
392 break;
394 case KEY_STORE_REMOVE_KEYRING_FROM_MASTER:
395 result = fMasterKeyring->RemoveKey(kKeyringKeysIdentifier,
396 keyMessage);
397 break;
400 if (result == B_OK)
401 _WriteKeyStoreDatabase();
403 break;
406 case KEY_STORE_GET_NEXT_APPLICATION:
408 uint32 cookie;
409 if (message->FindUInt32("cookie", &cookie) != B_OK) {
410 result = B_BAD_VALUE;
411 break;
414 BString signature;
415 BString path;
416 result = keyring->GetNextApplication(cookie, signature, path);
417 if (result != B_OK)
418 break;
420 reply.AddUInt32("cookie", cookie);
421 reply.AddString("signature", signature);
422 reply.AddString("path", path);
423 result = B_OK;
424 break;
427 case KEY_STORE_REMOVE_APPLICATION:
429 const char* signature = NULL;
430 const char* path = NULL;
432 if (message->FindString("signature", &signature) != B_OK) {
433 result = B_BAD_VALUE;
434 break;
437 if (message->FindString("path", &path) != B_OK)
438 path = NULL;
440 result = keyring->RemoveApplication(signature, path);
441 if (result == B_OK)
442 _WriteKeyStoreDatabase();
444 break;
447 case 0:
449 // Just the error case from above.
450 break;
453 default:
455 printf("unknown message received: %" B_PRIu32 " \"%.4s\"\n",
456 message->what, (const char*)&message->what);
457 break;
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);
469 message->SendReply(&reply);
474 status_t
475 KeyStoreServer::_ReadKeyStoreDatabase()
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;
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;
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;
502 if (strcmp(keyring->Name(), kMasterKeyringName) == 0)
503 fMasterKeyring = keyring;
505 fKeyrings.BinaryInsert(keyring, &Keyring::Compare);
508 return B_OK;
512 status_t
513 KeyStoreServer::_WriteKeyStoreDatabase()
515 BMessage keystore;
516 keystore.AddUInt32("format", kKeyStoreFormatVersion);
518 for (int32 i = 0; i < fKeyrings.CountItems(); i++) {
519 Keyring* keyring = fKeyrings.ItemAt(i);
520 if (keyring == NULL)
521 continue;
523 BMessage keyringData;
524 status_t result = keyring->WriteToMessage(keyringData);
525 if (result != B_OK)
526 return result;
528 keystore.AddMessage("keyrings", &keyringData);
531 fKeyStoreFile.SetSize(0);
532 fKeyStoreFile.Seek(0, SEEK_SET);
533 return keystore.Flatten(&fKeyStoreFile);
537 uint32
538 KeyStoreServer::_AccessFlagsFor(uint32 command) const
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;
575 return 0;
579 const char*
580 KeyStoreServer::_AccessStringFor(uint32 accessFlag) const
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.";
617 return NULL;
621 status_t
622 KeyStoreServer::_ResolveCallingApp(const BMessage& message,
623 app_info& callingAppInfo) const
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;
631 // Do some sanity checks.
632 if (callingAppInfo.team != callingTeam)
633 return B_ERROR;
635 return B_OK;
639 status_t
640 KeyStoreServer::_ValidateAppAccess(Keyring& keyring, const app_info& appInfo,
641 uint32 accessFlags)
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;
650 // TODO: Implement running image checksum mechanism.
651 BString checksum = path.Path();
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;
666 } else
667 appIsNew = true;
669 if ((accessFlags & appFlags) == accessFlags)
670 return B_OK;
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;
679 appMessage.MakeEmpty();
680 appMessage.AddString("path", path.Path());
681 appMessage.AddUInt32("flags", appFlags | accessFlags);
682 appMessage.AddString("checksum", checksum);
684 keyring.RemoveApplication(appInfo.signature, path.Path());
685 if (keyring.AddApplication(appInfo.signature, appMessage) == B_OK)
686 _WriteKeyStoreDatabase();
688 return B_OK;
692 status_t
693 KeyStoreServer::_RequestAppAccess(const BString& keyringName,
694 const char* signature, const char* path, const char* accessString,
695 bool appIsNew, bool appWasUpdated, uint32 accessFlags, bool& allowAlways)
697 AppAccessRequestWindow* requestWindow
698 = new(std::nothrow) AppAccessRequestWindow(keyringName, signature, path,
699 accessString, appIsNew, appWasUpdated);
700 if (requestWindow == NULL)
701 return B_NO_MEMORY;
703 return requestWindow->RequestAppAccess(allowAlways);
707 Keyring*
708 KeyStoreServer::_FindKeyring(const BString& name)
710 if (name.IsEmpty() || name == kMasterKeyringName)
711 return fMasterKeyring;
713 return fKeyrings.BinarySearchByKey(name, &Keyring::Compare);
717 status_t
718 KeyStoreServer::_AddKeyring(const BString& name)
720 if (_FindKeyring(name) != NULL)
721 return B_NAME_IN_USE;
723 Keyring* keyring = new(std::nothrow) Keyring(name);
724 if (keyring == NULL)
725 return B_NO_MEMORY;
727 if (!fKeyrings.BinaryInsert(keyring, &Keyring::Compare)) {
728 delete keyring;
729 return B_ERROR;
732 return B_OK;
736 status_t
737 KeyStoreServer::_RemoveKeyring(const BString& name)
739 Keyring* keyring = _FindKeyring(name);
740 if (keyring == NULL)
741 return B_ENTRY_NOT_FOUND;
743 if (keyring == fMasterKeyring) {
744 // The master keyring can't be removed.
745 return B_NOT_ALLOWED;
748 return fKeyrings.RemoveItem(keyring) ? B_OK : B_ERROR;
752 status_t
753 KeyStoreServer::_UnlockKeyring(Keyring& keyring)
755 if (!keyring.HasUnlockKey())
756 return keyring.Unlock(NULL);
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;
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;
775 return keyring.Unlock(&keyMessage);
779 status_t
780 KeyStoreServer::_RequestKey(const BString& keyringName, BMessage& keyMessage)
782 KeyRequestWindow* requestWindow = new(std::nothrow) KeyRequestWindow();
783 if (requestWindow == NULL)
784 return B_NO_MEMORY;
786 return requestWindow->RequestKey(keyringName, keyMessage);
791 main(int argc, char* argv[])
793 KeyStoreServer* app = new(std::nothrow) KeyStoreServer();
794 if (app == NULL)
795 return 1;
797 app->Run();
798 delete app;
799 return 0;