1// SecurityContext.cpp
2
3#include <errno.h>
4#include <string.h>
5#include <sys/stat.h>
6
7#include <AutoDeleter.h>
8#include <AutoLocker.h>
9#include <Entry.h>
10#include <HashMap.h>
11#include <Message.h>
12#include <Path.h>
13
14#include "Compatibility.h"
15#include "Node.h"
16#include "SecurityContext.h"
17#include "UserSecurityContext.h"
18
19typedef AutoLocker<SecurityContext> ContextLocker;
20
21// get_node_ref_for_path
22static
23status_t
24get_node_ref_for_path(const char* path, node_ref* ref)
25{
26	if (!path || !ref)
27		return B_BAD_VALUE;
28	struct stat st;
29	if (lstat(path, &st) < 0)
30		return errno;
31	ref->device = st.st_dev;
32	ref->node = st.st_ino;
33	return B_OK;
34}
35
36// #pragma mark -
37// #pragma mark ----- User -----
38
39// constructor
40User::User()
41	: BReferenceable(),
42	  BArchivable(),
43	  fName(),
44	  fPassword()
45{
46}
47
48// constructor
49User::User(BMessage* archive)
50	: BReferenceable(),
51	  BArchivable(archive),
52	  fName(),
53	  fPassword()
54{
55	Unarchive(archive);
56}
57
58// destructor
59User::~User()
60{
61}
62
63// Archive
64status_t
65User::Archive(BMessage* archive, bool deep) const
66{
67	if (!archive)
68		return B_BAD_VALUE;
69	// name
70	status_t error = B_OK;
71	if (error == B_OK && fName.GetLength() > 0)
72		error = archive->AddString("name", fName.GetString());
73	// password
74	if (error == B_OK && fPassword.GetLength() > 0)
75		error = archive->AddString("password", fPassword.GetString());
76	return error;
77}
78
79// Instantiate
80BArchivable*
81User::Instantiate(BMessage* archive)
82{
83	if (!validate_instantiation(archive, "User"))
84		return NULL;
85	return new(std::nothrow) User(archive);
86}
87
88// Init
89status_t
90User::Init(const char* name, const char* password)
91{
92	if (!name)
93		return B_BAD_VALUE;
94	if (!fName.SetTo(name))
95		return B_NO_MEMORY;
96	if (password && !fPassword.SetTo(password))
97		return B_NO_MEMORY;
98	return B_OK;
99}
100
101// InitCheck
102status_t
103User::InitCheck() const
104{
105	if (fName.GetLength() == 0)
106		return B_NO_INIT;
107	return B_OK;
108}
109
110// Unarchive
111status_t
112User::Unarchive(const BMessage* archive)
113{
114	// name
115	const char* name;
116	if (archive->FindString("name", &name) != B_OK)
117		return B_BAD_DATA;
118	fName.SetTo(name);
119	// password
120	const char* password;
121	if (archive->FindString("password", &password) == B_OK)
122		fPassword.SetTo(password);
123	else
124		fPassword.Unset();
125	return B_OK;
126}
127
128// GetName
129const char*
130User::GetName() const
131{
132	return fName.GetString();
133}
134
135// GetPassword
136const char*
137User::GetPassword() const
138{
139	return fPassword.GetString();
140}
141
142
143// #pragma mark -
144// #pragma mark ----- Share -----
145
146// constructor
147Share::Share()
148	: BReferenceable(),
149	  BArchivable(),
150	  fName(),
151	  fNodeRef(),
152	  fPath()
153{
154}
155
156// constructor
157Share::Share(BMessage* archive)
158	: BReferenceable(),
159	  BArchivable(archive),
160	  fName(),
161	  fNodeRef(),
162	  fPath()
163{
164	Unarchive(archive);
165}
166
167// destructor
168Share::~Share()
169{
170}
171
172// Archive
173status_t
174Share::Archive(BMessage* archive, bool deep) const
175{
176	if (!archive)
177		return B_BAD_VALUE;
178	// name
179	status_t error = B_OK;
180	if (error == B_OK && fName.GetLength() > 0)
181		error = archive->AddString("name", fName.GetString());
182	// path
183	if (error == B_OK && fPath.GetLength() > 0)
184		error = archive->AddString("path", fPath.GetString());
185	return error;
186}
187
188// Instantiate
189BArchivable*
190Share::Instantiate(BMessage* archive)
191{
192	if (!validate_instantiation(archive, "Share"))
193		return NULL;
194	return new(std::nothrow) Share(archive);
195}
196
197// Init
198status_t
199Share::Init(const char* name, const node_ref& ref, const char* path)
200{
201	// check params
202	if (!name)
203		return B_BAD_VALUE;
204	// if a path is not given, retrieve it
205	BPath localPath;
206	if (!path) {
207		entry_ref entryRef(ref.device, ref.node, ".");
208		status_t error = localPath.SetTo(&entryRef);
209		if (error != B_OK)
210			return error;
211		path = localPath.Path();
212	}
213	// set the attributes
214	if (!fName.SetTo(name))
215		return B_NO_MEMORY;
216	if (!fPath.SetTo(path))
217		return B_NO_MEMORY;
218	fNodeRef = ref;
219	return B_OK;
220}
221
222// Init
223status_t
224Share::Init(const char* name, const char* path)
225{
226	if (!name || !path)
227		return B_BAD_VALUE;
228	node_ref nodeRef;
229	if (get_node_ref_for_path(path, &nodeRef) != B_OK) {
230		nodeRef.device = -1;
231		nodeRef.node = -1;
232	}
233	return Init(name, nodeRef, path);
234}
235
236// InitCheck
237status_t
238Share::InitCheck() const
239{
240	if (fName.GetLength() == 0 || fPath.GetLength() == 0)
241		return B_NO_INIT;
242	return B_OK;
243}
244
245// Unarchive
246status_t
247Share::Unarchive(const BMessage* archive)
248{
249	// name
250	const char* name = NULL;
251	if (archive->FindString("name", &name) != B_OK)
252		return B_BAD_DATA;
253	// path
254	const char* path = NULL;
255	if (archive->FindString("path", &path) != B_OK)
256		return B_BAD_DATA;
257	return Init(name, path);
258}
259
260// GetName
261const char*
262Share::GetName() const
263{
264	return fName.GetString();
265}
266
267// DoesExist
268bool
269Share::DoesExist() const
270{
271	return (fNodeRef.device >= 0);
272}
273
274// GetNodeRef
275const node_ref&
276Share::GetNodeRef() const
277{
278	return fNodeRef;
279}
280
281// GetVolumeID
282dev_t
283Share::GetVolumeID() const
284{
285	return fNodeRef.device;
286}
287
288// GetNodeID
289ino_t
290Share::GetNodeID() const
291{
292	return fNodeRef.node;
293}
294
295// GetPath
296const char*
297Share::GetPath() const
298{
299	return fPath.GetString();
300}
301
302
303// #pragma mark -
304// #pragma mark ----- SecurityContext -----
305
306// UserMap
307struct SecurityContext::UserMap : HashMap<HashString, User*> {
308};
309
310// ShareMap
311struct SecurityContext::ShareMap : HashMap<HashString, Share*> {
312};
313
314// UserPath
315struct SecurityContext::UserPath {
316	UserPath() {}
317
318	UserPath(const char* path, User* user)
319		: path(path),
320		  user(user)
321	{
322	}
323
324	UserPath(const UserPath& other)
325		: path(other.path),
326		  user(other.user)
327	{
328	}
329
330	uint32 GetHashCode() const
331	{
332#ifdef B_HAIKU_64_BIT
333		uint64 v = (uint64)user;
334		return (path.GetHashCode() * 31) + ((uint32)(v >> 32) ^ (uint32)v);
335#else
336		return path.GetHashCode() * 31 + (uint32)user;
337#endif
338	}
339
340	UserPath& operator=(const UserPath& other)
341	{
342		path = other.path;
343		user = other.user;
344		return *this;
345	}
346
347	bool operator==(const UserPath& other) const
348	{
349		return (path == other.path && user == other.user);
350	}
351
352	bool operator!=(const UserPath& other) const
353	{
354		return !(*this == other);
355	}
356
357	HashString	path;
358	User*		user;
359};
360
361// PermissionMap
362struct SecurityContext::PermissionMap
363	: HashMap<SecurityContext::UserPath, Permissions> {
364};
365
366// NodePathMap
367struct SecurityContext::NodePathMap : HashMap<NodeRef, HashString> {
368};
369
370// PathNodeMap
371struct SecurityContext::PathNodeMap : HashMap<HashString, NodeRef> {
372};
373
374// constructor
375SecurityContext::SecurityContext()
376	: BArchivable(),
377	  BLocker("security context"),
378	  fUsers(new(std::nothrow) UserMap),
379	  fShares(new(std::nothrow) ShareMap),
380	  fPermissions(new(std::nothrow) PermissionMap),
381	  fNode2Path(new(std::nothrow) NodePathMap),
382	  fPath2Node(new(std::nothrow) PathNodeMap)
383{
384}
385
386// constructor
387SecurityContext::SecurityContext(BMessage* archive)
388	: BArchivable(archive),
389	  fUsers(new(std::nothrow) UserMap),
390	  fShares(new(std::nothrow) ShareMap),
391	  fPermissions(new(std::nothrow) PermissionMap),
392	  fNode2Path(new(std::nothrow) NodePathMap),
393	  fPath2Node(new(std::nothrow) PathNodeMap)
394{
395	if (InitCheck() != B_OK)
396		return;
397	status_t error = B_OK;
398
399	// users
400	BMessage userArchive;
401	for (int32 i = 0;
402		 archive->FindMessage("users", i, &userArchive) == B_OK;
403		 i++) {
404		User tmpUser;
405		error = tmpUser.Unarchive(&userArchive);
406		if (error != B_OK)
407			return;
408		error = AddUser(tmpUser.GetName(), tmpUser.GetPassword());
409		if (error != B_OK)
410			return;
411	}
412
413	// shares
414	BMessage shareArchive;
415	for (int32 i = 0;
416		 archive->FindMessage("shares", i, &shareArchive) == B_OK;
417		 i++) {
418		Share tmpShare;
419		error = tmpShare.Unarchive(&shareArchive);
420		if (error != B_OK)
421			return;
422		error = AddShare(tmpShare.GetName(), tmpShare.GetPath());
423		if (error != B_OK)
424			return;
425	}
426
427	// permissions
428	BMessage permissionsArchive;
429	if (archive->FindMessage("permissions", &permissionsArchive) != B_OK)
430		return;
431	#ifdef HAIKU_TARGET_PLATFORM_DANO
432		const char* userName;
433	#else
434		char* userName;
435	#endif
436	type_code type;
437	for (int32 userIndex = 0;
438		 permissionsArchive.GetInfo(B_MESSAGE_TYPE, userIndex, &userName, &type)
439		 	== B_OK;
440		 userIndex++) {
441		User* user = FindUser(userName);
442		if (!user)
443			return;
444		BReference<User> userReference(user, true);
445		error = permissionsArchive.FindMessage(userName, &userArchive);
446		if (error != B_OK)
447			return;
448
449		// got a user: iterate through its permissions
450		#ifdef HAIKU_TARGET_PLATFORM_DANO
451			const char* path;
452		#else
453			char* path;
454		#endif
455		for (int32 i = 0;
456			 userArchive.GetInfo(B_INT32_TYPE, i, &path, &type) == B_OK;
457			 i++) {
458			uint32 permissions;
459			error = userArchive.FindInt32(path, (int32*)&permissions);
460			if (error == B_OK)
461				error = SetNodePermissions(path, user, permissions);
462		}
463	}
464}
465
466// destructor
467SecurityContext::~SecurityContext()
468{
469	// remove all user references
470	for (UserMap::Iterator it = fUsers->GetIterator(); it.HasNext();) {
471		User* user = it.Next().value;
472		user->ReleaseReference();
473	}
474
475	// remove all share references
476	for (ShareMap::Iterator it = fShares->GetIterator(); it.HasNext();) {
477		Share* share = it.Next().value;
478		share->ReleaseReference();
479	}
480
481	delete fUsers;
482	delete fShares;
483	delete fPermissions;
484	delete fNode2Path;
485	delete fPath2Node;
486}
487
488// Archive
489status_t
490SecurityContext::Archive(BMessage* archive, bool deep) const
491{
492	if (!archive)
493		return B_BAD_VALUE;
494	status_t error = B_OK;
495	ContextLocker _(const_cast<SecurityContext*>(this));
496
497	// users
498	int32 userCount = fUsers->Size();
499	for (UserMap::Iterator it = fUsers->GetIterator(); it.HasNext();) {
500		User* user = it.Next().value;
501		BMessage userArchive;
502		error = user->Archive(&userArchive, deep);
503		if (error != B_OK)
504			return error;
505		error = archive->AddMessage("users", &userArchive);
506		if (error != B_OK)
507			return error;
508	}
509
510	// shares
511	for (ShareMap::Iterator it = fShares->GetIterator(); it.HasNext();) {
512		Share* share = it.Next().value;
513		BMessage shareArchive;
514		error = share->Archive(&shareArchive, deep);
515		if (error != B_OK)
516			return error;
517		error = archive->AddMessage("shares", &shareArchive);
518		if (error != B_OK)
519			return error;
520	}
521
522	// permissions
523	// we slice them per user
524	BMessage* tmpUserArchives = new(std::nothrow) BMessage[userCount];
525	if (!tmpUserArchives)
526		return B_NO_MEMORY;
527	ArrayDeleter<BMessage> deleter(tmpUserArchives);
528	HashMap<HashKeyPointer<User*>, BMessage*> userArchives;
529	int32 i = 0;
530	for (UserMap::Iterator it = fUsers->GetIterator(); it.HasNext();) {
531		User* user = it.Next().value;
532		error = userArchives.Put(user, tmpUserArchives + i);
533		if (error != B_OK)
534			return error;
535		i++;
536	}
537
538	// fill the per user archives
539	for (PermissionMap::Iterator it = fPermissions->GetIterator();
540		 it.HasNext();) {
541		PermissionMap::Entry entry = it.Next();
542		BMessage* userArchive = userArchives.Get(entry.key.user);
543		error = userArchive->AddInt32(entry.key.path.GetString(),
544			entry.value.GetPermissions());
545		if (error != B_OK)
546			return error;
547	}
548
549	// put the user permissions together
550	BMessage permissionsArchive;
551	for (UserMap::Iterator it = fUsers->GetIterator(); it.HasNext();) {
552		User* user = it.Next().value;
553		error = permissionsArchive.AddMessage(user->GetName(),
554			userArchives.Get(user));
555		if (error != B_OK)
556			return error;
557	}
558	error = archive->AddMessage("permissions", &permissionsArchive);
559	if (error != B_OK)
560		return error;
561	return B_OK;
562}
563
564// Instantiate
565BArchivable*
566SecurityContext::Instantiate(BMessage* archive)
567{
568	if (!validate_instantiation(archive, "SecurityContext"))
569		return NULL;
570	return new(std::nothrow) SecurityContext(archive);
571}
572
573
574// InitCheck
575status_t
576SecurityContext::InitCheck() const
577{
578	if (!fUsers || !fShares || !fPermissions || !fNode2Path || !fPath2Node)
579		return B_NO_MEMORY;
580
581	if (fUsers->InitCheck() != B_OK)
582		return fUsers->InitCheck();
583
584	if (fShares->InitCheck() != B_OK)
585		return fShares->InitCheck();
586
587	if (fPermissions->InitCheck() != B_OK)
588		return fPermissions->InitCheck();
589
590	if (fNode2Path->InitCheck() != B_OK)
591		return fNode2Path->InitCheck();
592
593	if (fPath2Node->InitCheck() != B_OK)
594		return fPath2Node->InitCheck();
595
596	return B_OK;
597}
598
599// AddUser
600//
601// The caller gets a reference, if _user is not NULL.
602status_t
603SecurityContext::AddUser(const char* name, const char* password, User** _user)
604{
605	if (!name)
606		return B_BAD_VALUE;
607
608	// check, if the user does already exist
609	ContextLocker _(this);
610	if (fUsers->Get(name))
611		return B_BAD_VALUE;
612
613	// create a the user
614	User* user = new(std::nothrow) User;
615	if (!user)
616		return B_NO_MEMORY;
617	BReference<User> userReference(user, true);
618	status_t error = user->Init(name, password);
619	if (error != B_OK)
620		return error;
621
622	// add the user
623	error = fUsers->Put(name, user);
624	if (error != B_OK)
625		return error;
626
627	userReference.Detach();
628	if (_user) {
629		*_user = user;
630		user->AcquireReference();
631	}
632	return B_OK;
633}
634
635// RemoveUser
636//
637// The caller gets a reference, if _user is not NULL.
638status_t
639SecurityContext::RemoveUser(const char* name, User** _user)
640{
641	if (!name)
642		return B_BAD_VALUE;
643
644	ContextLocker _(this);
645
646	// get the user
647	User* user = FindUser(name);
648	if (!user)
649		return B_ENTRY_NOT_FOUND;
650	BReference<User> userReference(user, true);
651
652	// remove it
653	status_t error = RemoveUser(user);
654	if (error == B_OK && _user) {
655		*_user = user;
656		user->AcquireReference();
657	}
658
659	return error;
660}
661
662// RemoveUser
663status_t
664SecurityContext::RemoveUser(User* user)
665{
666	if (!user)
667		return B_BAD_VALUE;
668
669	ContextLocker _(this);
670
671	// find and remove it
672	if (fUsers->Get(user->GetName()) != user)
673		return B_BAD_VALUE;
674	fUsers->Remove(user->GetName());
675
676	// remove all permission entries for this user
677	for (PermissionMap::Iterator it = fPermissions->GetIterator();
678		 it.HasNext();) {
679		PermissionMap::Entry entry = it.Next();
680		if (entry.key.user == user)
681			fPermissions->Remove(it);
682	}
683
684	// surrender our user reference
685	user->ReleaseReference();
686
687	return B_OK;
688}
689
690// FindUser
691//
692// The caller gets a reference.
693User*
694SecurityContext::FindUser(const char* name)
695{
696	if (!name)
697		return NULL;
698
699	ContextLocker _(this);
700	User* user = fUsers->Get(name);
701	if (user)
702		user->AcquireReference();
703	return user;
704}
705
706// AuthenticateUser
707//
708// The caller gets a reference.
709status_t
710SecurityContext::AuthenticateUser(const char* name, const char* password,
711	User** _user)
712{
713	if (!_user)
714		return B_BAD_VALUE;
715
716	// find user
717	ContextLocker _(this);
718	User* user = FindUser(name);
719	if (!user)
720		return B_PERMISSION_DENIED;
721	BReference<User> userReference(user, true);
722
723	// check password
724	if (user->GetPassword()) {
725		if (!password || strcmp(user->GetPassword(), password) != 0)
726			return B_PERMISSION_DENIED;
727	} else if (password)
728		return B_PERMISSION_DENIED;
729
730	*_user = user;
731	userReference.Detach();
732	return B_OK;
733}
734
735// CountUsers
736int32
737SecurityContext::CountUsers()
738{
739	ContextLocker _(this);
740	return fUsers->Size();
741}
742
743// GetUsers
744status_t
745SecurityContext::GetUsers(BMessage* users)
746{
747	if (!users)
748		return B_BAD_VALUE;
749
750	ContextLocker _(this);
751
752	// iterate through all users and add their names to the message
753	for (UserMap::Iterator it = fUsers->GetIterator(); it.HasNext();) {
754		User* user = it.Next().value;
755		status_t error = users->AddString("users", user->GetName());
756		if (error != B_OK)
757			return error;
758	}
759
760	return B_OK;
761}
762
763// AddShare
764//
765// The caller gets a reference, if _share is not NULL.
766status_t
767SecurityContext::AddShare(const char* name, const node_ref& ref, Share** _share)
768{
769	if (!name)
770		return B_BAD_VALUE;
771
772	// check, if the share does already exist
773	ContextLocker _(this);
774	if (fShares->Get(name))
775		return B_BAD_VALUE;
776
777	// create a the share
778	Share* share = new(std::nothrow) Share;
779	if (!share)
780		return B_NO_MEMORY;
781	BReference<Share> shareReference(share, true);
782	status_t error = share->Init(name, ref);
783	if (error != B_OK)
784		return error;
785
786	// add the share
787	error = fShares->Put(name, share);
788	if (error != B_OK)
789		return error;
790
791	shareReference.Detach();
792	if (_share) {
793		*_share = share;
794		share->AcquireReference();
795	}
796	return B_OK;
797}
798
799// AddShare
800//
801// The caller gets a reference, if _share is not NULL.
802status_t
803SecurityContext::AddShare(const char* name, const char* path, Share** _share)
804{
805	if (!name)
806		return B_BAD_VALUE;
807
808	// check, if the share does already exist
809	ContextLocker _(this);
810	if (fShares->Get(name))
811		return B_BAD_VALUE;
812
813	// create a the share
814	Share* share = new(std::nothrow) Share;
815	if (!share)
816		return B_NO_MEMORY;
817	BReference<Share> shareReference(share, true);
818	status_t error = share->Init(name, path);
819	if (error != B_OK)
820		return error;
821
822	// add the share
823	error = fShares->Put(name, share);
824	if (error != B_OK)
825		return error;
826
827	shareReference.Detach();
828	if (_share) {
829		*_share = share;
830		share->AcquireReference();
831	}
832	return B_OK;
833}
834
835// RemoveShare
836//
837// The caller gets a reference, if _share is not NULL.
838status_t
839SecurityContext::RemoveShare(const char* name, Share** _share)
840{
841	if (!name)
842		return B_BAD_VALUE;
843
844	ContextLocker _(this);
845
846	// get the share
847	Share* share = FindShare(name);
848	if (!share)
849		return B_ENTRY_NOT_FOUND;
850	BReference<Share> shareReference(share, true);
851
852	// remove it
853	status_t error = RemoveShare(share);
854	if (error == B_OK && _share) {
855		*_share = share;
856		share->AcquireReference();
857	}
858
859	return error;
860}
861
862// RemoveShare
863status_t
864SecurityContext::RemoveShare(Share* share)
865{
866	if (!share)
867		return B_BAD_VALUE;
868
869	ContextLocker _(this);
870
871	// find and remove it
872	if (fShares->Get(share->GetName()) != share)
873		return B_BAD_VALUE;
874	fShares->Remove(share->GetName());
875
876	// surrender our share reference
877	share->ReleaseReference();
878
879	return B_OK;
880}
881
882// FindShare
883//
884// The caller gets a reference.
885Share*
886SecurityContext::FindShare(const char* name)
887{
888	if (!name)
889		return NULL;
890
891	ContextLocker _(this);
892	Share* share = fShares->Get(name);
893	if (share)
894		share->AcquireReference();
895	return share;
896}
897
898// CountShares
899int32
900SecurityContext::CountShares()
901{
902	ContextLocker _(this);
903	return fShares->Size();
904}
905
906// GetShares
907status_t
908SecurityContext::GetShares(BMessage* shares)
909{
910	if (!shares)
911		return B_BAD_VALUE;
912
913	ContextLocker _(this);
914
915	// iterate through all shares and add their names to the message
916	for (ShareMap::Iterator it = fShares->GetIterator(); it.HasNext();) {
917		Share* share = it.Next().value;
918		// add name
919		status_t error = shares->AddString("shares", share->GetName());
920		if (error != B_OK)
921			return error;
922
923		// add path
924		error = shares->AddString("paths", share->GetPath());
925		if (error != B_OK)
926			return error;
927	}
928
929	return B_OK;
930}
931
932// SetNodePermissions
933status_t
934SecurityContext::SetNodePermissions(const node_ref& ref, User* user,
935	Permissions permissions)
936{
937	if (!user)
938		return B_BAD_VALUE;
939
940	ContextLocker _(this);
941	// check, whether we know the user
942	if (fUsers->Get(user->GetName()) != user)
943		return B_BAD_VALUE;
944
945	HashString path;
946	status_t error = _AddNodePath(ref, &path);
947	if (error != B_OK)
948		return error;
949	return fPermissions->Put(UserPath(path.GetString(), user), permissions);
950}
951
952// SetNodePermissions
953status_t
954SecurityContext::SetNodePermissions(const char* path, User* user,
955	Permissions permissions)
956{
957	if (!user || !path)
958		return B_BAD_VALUE;
959
960	ContextLocker _(this);
961	// check, whether we know the user
962	if (fUsers->Get(user->GetName()) != user)
963		return B_BAD_VALUE;
964
965	_AddNodePath(path);
966	return fPermissions->Put(UserPath(path, user), permissions);
967}
968
969// ClearNodePermissions
970void
971SecurityContext::ClearNodePermissions(const node_ref& ref, User* user)
972{
973	ContextLocker _(this);
974	HashString path;
975	status_t error = _AddNodePath(ref, &path);
976	if (error != B_OK)
977		return;
978
979	if (user) {
980		fPermissions->Remove(UserPath(path.GetString(), user));
981	} else {
982		for (UserMap::Iterator it = fUsers->GetIterator(); it.HasNext();)
983			fPermissions->Remove(UserPath(path.GetString(), it.Next().value));
984	}
985}
986
987// ClearNodePermissions
988void
989SecurityContext::ClearNodePermissions(const char* path, User* user)
990{
991	if (!path)
992		return;
993
994	ContextLocker _(this);
995	_AddNodePath(path);
996
997	if (user) {
998		fPermissions->Remove(UserPath(path, user));
999	} else {
1000		for (UserMap::Iterator it = fUsers->GetIterator(); it.HasNext();)
1001			fPermissions->Remove(UserPath(path, it.Next().value));
1002	}
1003}
1004
1005// GetNodePermissions
1006Permissions
1007SecurityContext::GetNodePermissions(const node_ref& ref, User* user)
1008{
1009	if (!user)
1010		return Permissions();
1011
1012	ContextLocker _(this);
1013	HashString path;
1014	status_t error = _AddNodePath(ref, &path);
1015	if (error != B_OK)
1016		return Permissions();
1017
1018	return fPermissions->Get(UserPath(path.GetString(), user));
1019}
1020
1021// GetNodePermissions
1022Permissions
1023SecurityContext::GetNodePermissions(const char* path, User* user)
1024{
1025	if (!user || !path)
1026		return Permissions();
1027
1028	ContextLocker _(this);
1029	_AddNodePath(path);
1030
1031	return fPermissions->Get(UserPath(path, user));
1032}
1033
1034// GetUserSecurityContext
1035status_t
1036SecurityContext::GetUserSecurityContext(User* user,
1037	UserSecurityContext* userContext)
1038{
1039	if (!userContext)
1040		return B_BAD_VALUE;
1041
1042	status_t error = userContext->Init(user);
1043	if (error != B_OK)
1044		return error;
1045
1046	// iterate through all permission entries and add the ones whose user
1047	// matches
1048	ContextLocker _(this);
1049	for (PermissionMap::Iterator it = fPermissions->GetIterator();
1050		 it.HasNext();) {
1051		PermissionMap::Entry entry = it.Next();
1052		node_ref ref;
1053		if (entry.key.user == user
1054			&& _GetNodeForPath(entry.key.path.GetString(), &ref)) {
1055			error = userContext->AddNode(ref.device, ref.node, entry.value);
1056			if (error != B_OK)
1057				return error;
1058		}
1059	}
1060	return B_OK;
1061}
1062
1063// _AddNodePath
1064status_t
1065SecurityContext::_AddNodePath(const char* path, node_ref* _ref)
1066{
1067	if (!fPath2Node->ContainsKey(path)) {
1068		node_ref ref;
1069		status_t error = get_node_ref_for_path(path, &ref);
1070		if (error == B_OK)
1071			error = _EnterNodePath(path, ref);
1072		if (error != B_OK)
1073			return error;
1074	}
1075
1076	if (_ref)
1077		*_ref = fPath2Node->Get(path);
1078	return B_OK;
1079}
1080
1081// _AddNodePath
1082status_t
1083SecurityContext::_AddNodePath(const node_ref& ref, HashString* _path)
1084{
1085	if (!fNode2Path->ContainsKey(ref)) {
1086		BPath path;
1087		entry_ref entryRef(ref.device, ref.node, ".");
1088		status_t error = path.SetTo(&entryRef);
1089		if (error == B_OK)
1090			error = _EnterNodePath(path.Path(), ref);
1091		if (error != B_OK)
1092			return error;
1093	}
1094
1095	if (_path)
1096		*_path = fNode2Path->Get(ref);
1097	return B_OK;
1098}
1099
1100// _EnterNodePath
1101status_t
1102SecurityContext::_EnterNodePath(const char* path, const node_ref& ref)
1103{
1104	status_t error = fNode2Path->Put(ref, path);
1105	if (error == B_OK) {
1106		error = fPath2Node->Put(path, ref);
1107		if (error != B_OK)
1108			fNode2Path->Remove(ref);
1109	}
1110	return error;
1111}
1112
1113// _GetNodeForPath
1114bool
1115SecurityContext::_GetNodeForPath(const char* path, node_ref* ref)
1116{
1117	if (path && fPath2Node->ContainsKey(path)) {
1118		if (ref)
1119			*ref = fPath2Node->Get(path);
1120		return true;
1121	}
1122	return false;
1123}
1124
1125