1// NetFSServer.cpp
2
3#include <errno.h>
4#include <netdb.h>
5#include <new>
6#include <stdio.h>
7#include <string.h>
8
9#ifdef HAIKU_TARGET_PLATFORM_BEOS
10#	include <socket.h>
11#else
12#	include <unistd.h>
13#	include <netinet/in.h>
14#	include <sys/socket.h>
15#endif
16
17#include <AutoDeleter.h>
18#include <AutoLocker.h>
19#include <Directory.h>
20#include <File.h>
21#include <FindDirectory.h>
22#include <Node.h>
23#include <Path.h>
24#include <util/DoublyLinkedList.h>
25
26#include "Connection.h"
27#include "ConnectionListener.h"
28#include "DebugSupport.h"
29#include "DriverSettings.h"
30#include "FDManager.h"
31#include "InsecureChannel.h"
32#include "NetFSDefs.h"
33#include "NetFSServer.h"
34#include "NetFSServerRosterDefs.h"
35#include "RequestChannel.h"
36#include "Requests.h"
37#include "SecurityContext.h"
38#include "StatisticsManager.h"
39#include "TaskManager.h"
40#include "Utils.h"
41#include "VolumeManager.h"
42
43static const char* kSettingsDirName				= "netfs";
44static const char* kSettingsFileName			= "netfs_server";
45static const char* kFallbackSettingsFileName	= "netfs_server_fallback";
46
47// usage
48static const char* kUsage =
49"Usage: netfs_server <options>\n"
50"options:\n"
51"  --dont-broadcast  - don't use broadcasting to announce the server's\n"
52"                      availability to clients\n"
53"  -h, --help        - print this text\n"
54;
55
56// ConnectionInitializer
57class NetFSServer::ConnectionInitializer {
58public:
59	ConnectionInitializer(NetFSServer* server,
60		ConnectionListener* connectionListener, Connection* connection)
61		: fServer(server),
62		  fConnectionListener(connectionListener),
63		  fConnection(connection),
64		  fThread(-1)
65	{
66	}
67
68	~ConnectionInitializer()
69	{
70		delete fConnection;
71	}
72
73	status_t Run()
74	{
75		fThread = spawn_thread(&_ThreadEntry, "connection initializer",
76			B_NORMAL_PRIORITY, this);
77		if (fThread < 0)
78			return fThread;
79		resume_thread(fThread);
80		return B_OK;
81	}
82
83private:
84	static int32 _ThreadEntry(void* data)
85	{
86		return ((ConnectionInitializer*)data)->_Thread();
87	}
88
89	int32 _Thread()
90	{
91		// finish connection initialization
92		User* user = NULL;
93		status_t error = fConnectionListener->FinishInitialization(
94			fConnection, fServer->GetSecurityContext(), &user);
95		// create a client connection
96		ClientConnection* clientConnection = NULL;
97		if (error == B_OK) {
98			clientConnection = new(std::nothrow) ClientConnection(fConnection,
99				fServer->GetSecurityContext(), user, fServer);
100			if (!clientConnection)
101				error = B_NO_MEMORY;
102		}
103		if (error == B_OK) {
104			fConnection = NULL;	// connection belongs to client connection now
105			error = clientConnection->Init();
106		}
107		// add the client connection to the server
108		if (error == B_OK)
109			error = fServer->_AddClientConnection(clientConnection);
110		// cleanup on error
111		if (error != B_OK)
112			delete clientConnection;
113		delete this;
114		return 0;
115	}
116
117private:
118	NetFSServer*		fServer;
119	ConnectionListener*	fConnectionListener;
120	Connection*			fConnection;
121	thread_id			fThread;
122};
123
124
125// ServerInfoSender
126class NetFSServer::ServerInfoSender : public Task {
127public:
128	ServerInfoSender(int socket, const ServerInfo& serverInfo)
129		: Task("server info sender"),
130		  fChannel(new(std::nothrow) InsecureChannel(socket)),
131		  fServerInfo(serverInfo)
132	{
133		if (!fChannel)
134			closesocket(socket);
135	}
136
137	~ServerInfoSender()
138	{
139		delete fChannel;
140	}
141
142	status_t Init()
143	{
144		if (!fChannel)
145			return B_NO_MEMORY;
146
147		return B_OK;
148	}
149
150	virtual void Stop()
151	{
152		if (fChannel)
153			fChannel->Close();
154	}
155
156	virtual status_t Execute()
157	{
158		if (!fChannel) {
159			SetDone(true);
160			return B_NO_INIT;
161		}
162
163		RequestChannel requestChannel(fChannel);
164
165		// create the server info request
166		ServerInfoRequest request;
167		request.serverInfo = fServerInfo;
168
169		// send the request
170		status_t error = requestChannel.SendRequest(&request);
171		if (error != B_OK) {
172			ERROR("ServerInfoSender: ERROR: Failed to send request: %s\n",
173				strerror(error));
174		}
175
176		SetDone(true);
177		return B_OK;
178	}
179
180private:
181	Channel*		fChannel;
182	ServerInfo		fServerInfo;
183};
184
185
186// NetFSServer
187
188// constructor
189NetFSServer::NetFSServer(bool useBroadcasting)
190	:
191	BApplication(kNetFSServerSignature),
192	fSecurityContext(NULL),
193	fConnectionListenerFactory(),
194	fConnectionListener(NULL),
195	fLock("netfs server"),
196	fClientConnections(),
197	fVolumeManager(NULL),
198	fClosedConnections(),
199	fClosedConnectionsSemaphore(-1),
200	fConnectionListenerThread(-1),
201	fConnectionDeleter(-1),
202	fBroadcaster(-1),
203	fBroadcastingSocket(-1),
204	fBroadcasterSemaphore(-1),
205	fServerInfoConnectionListener(-1),
206	fServerInfoConnectionListenerSocket(-1),
207	fServerInfoUpdated(0),
208	fUseBroadcasting(useBroadcasting),
209	fTerminating(false)
210{
211}
212
213// destructor
214NetFSServer::~NetFSServer()
215{
216	fTerminating = true;
217	// stop the connection listener
218	if (fConnectionListener)
219		fConnectionListener->StopListening();
220	if (fConnectionListenerThread >= 0) {
221		int32 result;
222		wait_for_thread(fConnectionListenerThread, &result);
223	}
224	delete fConnectionListener;
225
226	// delete the broadcaster semaphore
227	if (fBroadcasterSemaphore >= 0)
228		delete_sem(fBroadcasterSemaphore);
229
230	// terminate the broadcaster
231	if (fBroadcaster >= 0) {
232		safe_closesocket(fBroadcastingSocket);
233
234		// interrupt the thread in case it is currently snoozing
235		suspend_thread(fBroadcaster);
236		int32 result;
237		wait_for_thread(fBroadcaster, &result);
238	}
239
240	// terminate the server info connection listener
241	_ExitServerInfoConnectionListener();
242
243	// terminate the connection deleter
244	if (fClosedConnectionsSemaphore >= 0)
245		delete_sem(fClosedConnectionsSemaphore);
246	if (fConnectionDeleter >= 0) {
247		int32 result;
248		wait_for_thread(fConnectionDeleter, &result);
249	}
250
251	// blow away all remaining connections
252	AutoLocker<Locker> _(fLock);
253	// open connections
254	for (int32 i = 0;
255		 ClientConnection* connection
256		 	= (ClientConnection*)fClientConnections.ItemAt(i);
257		 i++) {
258		connection->Close();
259		delete connection;
260	}
261
262	// closed connections
263	for (int32 i = 0;
264		 ClientConnection* connection
265		 	= (ClientConnection*)fClosedConnections.ItemAt(i);
266		 i++) {
267		delete connection;
268	}
269	VolumeManager::DeleteDefault();
270	FDManager::DeleteDefault();
271	delete fSecurityContext;
272}
273
274// Init
275status_t
276NetFSServer::Init()
277{
278	// init the settings
279	status_t error = _InitSettings();
280	if (error != B_OK)
281		return error;
282
283	// create the FD manager
284	error = FDManager::CreateDefault();
285	if (error != B_OK)
286		return error;
287
288	// create the volume manager
289	error = VolumeManager::CreateDefault();
290	if (error != B_OK)
291		return error;
292	fVolumeManager = VolumeManager::GetDefault();
293
294	// create a connection listener
295//	error = fConnectionListenerFactory.CreateConnectionListener(
296//		"port", NULL, &fConnectionListener);
297	error = fConnectionListenerFactory.CreateConnectionListener(
298		"insecure", NULL, &fConnectionListener);
299	if (error != B_OK)
300		return error;
301
302	// spawn the connection listener thread
303	fConnectionListenerThread = spawn_thread(&_ConnectionListenerEntry,
304		"connection listener", B_NORMAL_PRIORITY, this);
305	if (fConnectionListenerThread < 0)
306		return fConnectionListenerThread;
307
308	// create the closed connections semaphore
309	fClosedConnectionsSemaphore = create_sem(0, "closed connections");
310	if (fClosedConnectionsSemaphore < 0)
311		return fClosedConnectionsSemaphore;
312
313	// spawn the connection deleter
314	fConnectionDeleter = spawn_thread(&_ConnectionDeleterEntry,
315		"connection deleter", B_NORMAL_PRIORITY, this);
316	if (fConnectionDeleter < 0)
317		return fConnectionDeleter;
318
319	// init the server info connection listener
320	error = _InitServerInfoConnectionListener();
321	if (error != B_OK)
322		return error;
323
324	// create the broadcaster semaphore
325	fBroadcasterSemaphore = create_sem(0, "broadcaster snooze");
326
327	// spawn the broadcaster
328	if (fUseBroadcasting) {
329		fBroadcaster = spawn_thread(&_BroadcasterEntry, "broadcaster",
330			B_NORMAL_PRIORITY, this);
331		if (fBroadcaster < 0) {
332			WARN("NetFSServer::Init(): Failed to spawn broadcaster thread "
333				"(%s). Continuing anyway.\n", strerror(fBroadcaster));
334		}
335	}
336	return B_OK;
337}
338
339// Run
340thread_id
341NetFSServer::Run()
342{
343	// start the connection listener
344	resume_thread(fConnectionListenerThread);
345
346	// start the connection deleter
347	resume_thread(fConnectionDeleter);
348
349	// start the server info connection listener
350	resume_thread(fServerInfoConnectionListener);
351
352	// start the broadcaster
353	resume_thread(fBroadcaster);
354
355	return BApplication::Run();
356}
357
358// MessageReceived
359void
360NetFSServer::MessageReceived(BMessage* message)
361{
362	switch (message->what) {
363		case NETFS_REQUEST_GET_MESSENGER:
364		{
365			// for the time being we process all requests here
366			BMessage reply;
367			reply.AddMessenger("messenger", be_app_messenger);
368			_SendReply(message, &reply);
369			break;
370		}
371
372		case NETFS_REQUEST_ADD_USER:
373		{
374			// get user name and password
375			const char* user;
376			const char* password;
377			if (message->FindString("user", &user) != B_OK) {
378				_SendReply(message, B_BAD_VALUE);
379				break;
380			}
381			if (message->FindString("password", &password) != B_OK)
382				password = NULL;
383
384			// add the user
385			status_t error = fSecurityContext->AddUser(user, password);
386			_SendReply(message, error);
387			break;
388		}
389
390		case NETFS_REQUEST_REMOVE_USER:
391		{
392			// get user name
393			const char* userName;
394			if (message->FindString("user", &userName) != B_OK) {
395				_SendReply(message, B_BAD_VALUE);
396				break;
397			}
398
399			// remove the user
400			User* user;
401			status_t error = fSecurityContext->RemoveUser(userName, &user);
402			if (error == B_OK) {
403				// propagate the information to the client connections
404				AutoLocker<Locker> _(fLock);
405				for (int32 i = 0;
406					 ClientConnection* connection
407					 	= (ClientConnection*)fClientConnections.ItemAt(i);
408					 i++) {
409					connection->UserRemoved(user);
410				}
411
412				user->ReleaseReference();
413			}
414
415			_SendReply(message, error);
416			break;
417		}
418
419		case NETFS_REQUEST_GET_USERS:
420		{
421			// get the users
422			BMessage reply;
423			BMessage users;
424			status_t error = fSecurityContext->GetUsers(&users);
425			if (error == B_OK)
426				error = reply.AddMessage("users", &users);
427
428			if (error == B_OK)
429				_SendReply(message, &reply);
430			else
431				_SendReply(message, error);
432			break;
433		}
434
435		case NETFS_REQUEST_GET_USER_STATISTICS:
436		{
437			// get user name
438			const char* userName;
439			if (message->FindString("user", &userName) != B_OK) {
440				_SendReply(message, B_BAD_VALUE);
441				break;
442			}
443
444			// get the user
445			User* user = fSecurityContext->FindUser(userName);
446			if (!user) {
447				_SendReply(message, B_ENTRY_NOT_FOUND);
448				break;
449			}
450			BReference<User> userReference(user, true);
451
452			// get the statistics
453			BMessage statistics;
454			status_t error = StatisticsManager::GetDefault()
455				->GetUserStatistics(user, &statistics);
456
457			// prepare the reply
458			BMessage reply;
459			if (error == B_OK)
460				error = reply.AddMessage("statistics", &statistics);
461
462			// send the reply
463			if (error == B_OK)
464				_SendReply(message, &reply);
465			else
466				_SendReply(message, error);
467			break;
468		}
469
470		case NETFS_REQUEST_ADD_SHARE:
471		{
472			// get share name and path
473			const char* share;
474			const char* path;
475			if (message->FindString("share", &share) != B_OK
476				|| message->FindString("path", &path) != B_OK) {
477				_SendReply(message, B_BAD_VALUE);
478				break;
479			}
480
481			// add the share
482			status_t error = fSecurityContext->AddShare(share, path);
483
484			if (error == B_OK)
485				_ServerInfoUpdated();
486
487			_SendReply(message, error);
488			break;
489		}
490
491		case NETFS_REQUEST_REMOVE_SHARE:
492		{
493			// get share name
494			const char* shareName;
495			if (message->FindString("share", &shareName) != B_OK) {
496				_SendReply(message, B_BAD_VALUE);
497				break;
498			}
499
500			// remove the share
501			Share* share;
502			status_t error = fSecurityContext->RemoveShare(shareName, &share);
503			if (error == B_OK) {
504				// propagate the information to the client connections
505				AutoLocker<Locker> _(fLock);
506				for (int32 i = 0;
507					 ClientConnection* connection
508					 	= (ClientConnection*)fClientConnections.ItemAt(i);
509					 i++) {
510					connection->ShareRemoved(share);
511				}
512
513				share->ReleaseReference();
514			}
515
516			if (error == B_OK)
517				_ServerInfoUpdated();
518
519			_SendReply(message, error);
520			break;
521		}
522
523		case NETFS_REQUEST_GET_SHARES:
524		{
525			// get the shares
526			BMessage reply;
527			BMessage shares;
528			status_t error = fSecurityContext->GetShares(&shares);
529			if (error == B_OK)
530				error = reply.AddMessage("shares", &shares);
531
532			if (error == B_OK)
533				_SendReply(message, &reply);
534			else
535				_SendReply(message, error);
536			break;
537		}
538
539		case NETFS_REQUEST_GET_SHARE_USERS:
540		{
541			// get share name
542			const char* shareName;
543			if (message->FindString("share", &shareName) != B_OK) {
544				_SendReply(message, B_BAD_VALUE);
545				break;
546			}
547
548			AutoLocker<Locker> securityContextLocker(fSecurityContext);
549
550			// get the share
551			Share* share = fSecurityContext->FindShare(shareName);
552			if (!share) {
553				_SendReply(message, B_ENTRY_NOT_FOUND);
554				break;
555			}
556			BReference<Share> shareReference(share, true);
557
558			// get all users
559			BMessage allUsers;
560			status_t error = fSecurityContext->GetUsers(&allUsers);
561			if (error != B_OK) {
562				_SendReply(message, error);
563				break;
564			}
565
566			// filter the users with mount permission
567			BMessage users;
568			const char* userName;
569			for (int32 i = 0;
570				 allUsers.FindString("users", i, &userName) == B_OK;
571				 i++) {
572				if (User* user = fSecurityContext->FindUser(userName)) {
573					// get the user's permissions
574					Permissions permissions = fSecurityContext
575						->GetNodePermissions(share->GetPath(), user);
576					user->ReleaseReference();
577
578					// add the user, if they have the permission to mount the
579					// share
580					if (permissions.ImpliesMountSharePermission()) {
581						error = users.AddString("users", userName);
582						if (error != B_OK) {
583							_SendReply(message, error);
584							break;
585						}
586					}
587				}
588			}
589
590			securityContextLocker.Unlock();
591
592			// prepare the reply
593			BMessage reply;
594			if (error == B_OK)
595				error = reply.AddMessage("users", &users);
596
597			// send the reply
598			if (error == B_OK)
599				_SendReply(message, &reply);
600			else
601				_SendReply(message, error);
602			break;
603		}
604
605		case NETFS_REQUEST_GET_SHARE_STATISTICS:
606		{
607			// get share name
608			const char* shareName;
609			if (message->FindString("share", &shareName) != B_OK) {
610				_SendReply(message, B_BAD_VALUE);
611				break;
612			}
613
614			// get the share
615			Share* share = fSecurityContext->FindShare(shareName);
616			if (!share) {
617				_SendReply(message, B_ENTRY_NOT_FOUND);
618				break;
619			}
620			BReference<Share> shareReference(share, true);
621
622			// get the statistics
623			BMessage statistics;
624			status_t error = StatisticsManager::GetDefault()
625				->GetShareStatistics(share, &statistics);
626
627			// prepare the reply
628			BMessage reply;
629			if (error == B_OK)
630				error = reply.AddMessage("statistics", &statistics);
631
632			// send the reply
633			if (error == B_OK)
634				_SendReply(message, &reply);
635			else
636				_SendReply(message, error);
637			break;
638		}
639
640		case NETFS_REQUEST_SET_USER_PERMISSIONS:
641		{
642			// get share and user name, and the permissions
643			const char* shareName;
644			const char* userName;
645			uint32 permissions;
646			if (message->FindString("share", &shareName) != B_OK
647				|| message->FindString("user", &userName) != B_OK
648				|| message->FindInt32("permissions", (int32*)&permissions)
649					!= B_OK) {
650				_SendReply(message, B_BAD_VALUE);
651				break;
652			}
653
654			// get the share and the user
655			Share* share = fSecurityContext->FindShare(shareName);
656			User* user = fSecurityContext->FindUser(userName);
657			BReference<Share> shareReference(share);
658			BReference<User> userReference(user);
659			if (!share || !user) {
660				_SendReply(message, B_ENTRY_NOT_FOUND);
661				break;
662			}
663
664			// set the permissions
665			status_t error = B_OK;
666			if (permissions == 0) {
667				fSecurityContext->ClearNodePermissions(share->GetPath(), user);
668			} else {
669				error = fSecurityContext->SetNodePermissions(share->GetPath(),
670					user, permissions);
671			}
672
673			if (error == B_OK) {
674				// propagate the information to the client connections
675				AutoLocker<Locker> _(fLock);
676				for (int32 i = 0;
677					 ClientConnection* connection
678					 	= (ClientConnection*)fClientConnections.ItemAt(i);
679					 i++) {
680					connection->UserPermissionsChanged(share, user,
681						permissions);
682				}
683			}
684
685			_SendReply(message, error);
686			break;
687		}
688
689		case NETFS_REQUEST_GET_USER_PERMISSIONS:
690		{
691			// get share and user name
692			const char* shareName;
693			const char* userName;
694			if (message->FindString("share", &shareName) != B_OK
695				|| message->FindString("user", &userName) != B_OK) {
696				_SendReply(message, B_BAD_VALUE);
697				break;
698			}
699
700			// get the share and the user
701			Share* share = fSecurityContext->FindShare(shareName);
702			User* user = fSecurityContext->FindUser(userName);
703			BReference<Share> shareReference(share);
704			BReference<User> userReference(user);
705			if (!share || !user) {
706				_SendReply(message, B_ENTRY_NOT_FOUND);
707				break;
708			}
709
710			// get the permissions
711			Permissions permissions = fSecurityContext->GetNodePermissions(
712				share->GetPath(), user);
713
714			// prepare the reply
715			BMessage reply;
716			status_t error = reply.AddInt32("permissions",
717				(int32)permissions.GetPermissions());
718
719			// send it
720			if (error == B_OK)
721				_SendReply(message, &reply);
722			else
723				_SendReply(message, error);
724			break;
725		}
726
727		case NETFS_REQUEST_SAVE_SETTINGS:
728		{
729			status_t error = _SaveSettings();
730
731			// send a reply
732			_SendReply(message, error);
733			break;
734		}
735	}
736}
737
738// GetVolumeManager
739VolumeManager*
740NetFSServer::GetVolumeManager() const
741{
742	return fVolumeManager;
743}
744
745// GetSecurityContext
746SecurityContext*
747NetFSServer::GetSecurityContext() const
748{
749	return fSecurityContext;
750}
751
752// _AddClientConnection
753status_t
754NetFSServer::_AddClientConnection(ClientConnection* clientConnection)
755{
756	if (!clientConnection)
757		return B_BAD_VALUE;
758	AutoLocker<Locker> locker(fLock);
759	if (!fClientConnections.AddItem(clientConnection))
760		return B_NO_MEMORY;
761	return B_OK;
762}
763
764// ClientConnectionClosed
765void
766NetFSServer::ClientConnectionClosed(ClientConnection* connection, bool broken)
767{
768	PRINT("NetFSServer::ClientConnectionClosed(%d)\n", broken);
769	if (!connection)
770		return;
771	AutoLocker<Locker> locker(fLock);
772	if (!fClientConnections.RemoveItem(connection))
773		return;
774	if (!fClosedConnections.AddItem(connection)) {
775		// out of memory: Try to delete the connection right now.,
776		// There's a certain chance that we'll access free()d memory in the
777		// process, but things are apparently bad enough, anyway.
778		locker.Unlock();
779		delete connection;
780		return;
781	}
782	release_sem(fClosedConnectionsSemaphore);
783}
784
785// _LoadSecurityContext
786status_t
787NetFSServer::_LoadSecurityContext(SecurityContext** _securityContext)
788{
789	// create a security context
790	SecurityContext* securityContext = new(std::nothrow) SecurityContext;
791	if (!securityContext)
792		return B_NO_MEMORY;
793	status_t error = securityContext->InitCheck();
794	if (error != B_OK) {
795		delete securityContext;
796		return error;
797	}
798	ObjectDeleter<SecurityContext> securityContextDeleter(securityContext);
799
800	// load the fallback settings, if present
801	BPath path;
802	DriverSettings settings;
803
804	if (_GetSettingsDirPath(&path, false) == B_OK
805			&& path.Append(kFallbackSettingsFileName) == B_OK
806			&& settings.Load(path.Path()) == B_OK) {
807		// load users
808		DriverParameter parameter;
809		for (DriverParameterIterator it = settings.GetParameterIterator("user");
810			 it.GetNext(&parameter);) {
811			const char* userName = parameter.ValueAt(0);
812			const char* password = parameter.GetParameterValue("password");
813			if (!userName) {
814				WARN("Skipping nameless user settings entry.\n");
815				continue;
816			}
817//			PRINT(("user: %s, password: %s\n", parameter.ValueAt(0),
818//				parameter.GetParameterValue("password")));
819			error = securityContext->AddUser(userName, password);
820			if (error != B_OK)
821				ERROR("ERROR: Failed to add user `%s'\n", userName);
822		}
823
824		// load shares
825		for (DriverParameterIterator it = settings.GetParameterIterator("share");
826			 it.GetNext(&parameter);) {
827			const char* shareName = parameter.ValueAt(0);
828			const char* path = parameter.GetParameterValue("path");
829			if (!shareName || !path) {
830				WARN("settings: Skipping invalid share settings entry (no name"
831					" or no path).\n");
832				continue;
833			}
834//			PRINT(("share: %s, path: %s\n", parameter.ValueAt(0),
835//				parameter.GetParameterValue("path")));
836			Share* share;
837			error = securityContext->AddShare(shareName, path, &share);
838			if (error != B_OK) {
839				ERROR("ERROR: Failed to add share `%s'\n", shareName);
840				continue;
841			}
842			BReference<Share> shareReference(share, true);
843			DriverParameter userParameter;
844			// iterate through the share users
845			for (DriverParameterIterator userIt
846					= parameter.GetParameterIterator("user");
847				 userIt.GetNext(&userParameter);) {
848				const char* userName = userParameter.ValueAt(0);
849//				PRINT(("  user: %s\n", userName));
850				User* user = securityContext->FindUser(userName);
851				if (!user) {
852					ERROR("ERROR: Undefined user `%s'.\n", userName);
853					continue;
854				}
855				BReference<User> userReference(user, true);
856				DriverParameter permissionsParameter;
857				if (!userParameter.FindParameter("permissions",
858						&permissionsParameter)) {
859					continue;
860				}
861				Permissions permissions;
862				for (int32 i = 0; i < permissionsParameter.CountValues(); i++) {
863					const char* permission = permissionsParameter.ValueAt(i);
864//					PRINT(("    permission: %s\n", permission));
865					if (strcmp(permission, "mount") == 0) {
866						permissions.AddPermissions(MOUNT_SHARE_PERMISSION);
867					} else if (strcmp(permission, "query") == 0) {
868						permissions.AddPermissions(QUERY_SHARE_PERMISSION);
869					} else if (strcmp(permission, "read") == 0) {
870						permissions.AddPermissions(READ_PERMISSION
871							| READ_DIR_PERMISSION | RESOLVE_DIR_ENTRY_PERMISSION);
872					} else if (strcmp(permission, "write") == 0) {
873						permissions.AddPermissions(WRITE_PERMISSION
874							| WRITE_DIR_PERMISSION);
875					} else if (strcmp(permission, "all") == 0) {
876						permissions.AddPermissions(ALL_PERMISSIONS);
877					}
878				}
879				error = securityContext->SetNodePermissions(share->GetPath(), user,
880					permissions);
881				if (error != B_OK) {
882					ERROR("ERROR: Failed to set permissions for share `%s'\n",
883						share->GetName());
884				}
885			}
886		}
887	}
888
889	securityContextDeleter.Detach();
890	*_securityContext = securityContext;
891	return B_OK;
892}
893
894// _InitSettings
895status_t
896NetFSServer::_InitSettings()
897{
898	status_t error = _LoadSettings();
899	if (error != B_OK) {
900		WARN("NetFSServer::_InitSettings(): WARNING: Failed to load settings "
901			"file: %s - falling back to driver settings.\n", strerror(error));
902
903		// fall back to the driver settings file
904		error = _LoadSecurityContext(&fSecurityContext);
905		if (error != B_OK) {
906			WARN("NetFSServer::_InitSettings(): WARNING: Failed to load "
907				"settings from driver settings: %s\n", strerror(error));
908
909			// use defaults
910			// create a security context
911			fSecurityContext = new(std::nothrow) SecurityContext;
912			if (!fSecurityContext)
913				return B_NO_MEMORY;
914			error = fSecurityContext->InitCheck();
915			if (error != B_OK)
916				return error;
917		}
918	}
919
920	return B_OK;
921}
922
923// _LoadSettings
924status_t
925NetFSServer::_LoadSettings()
926{
927	// get the settings file path
928	BPath filePath;
929	status_t error = _GetSettingsFilePath(&filePath, false);
930	if (error != B_OK)
931		RETURN_ERROR(error);
932
933	// if existing load the settings
934	BEntry bEntry;
935	if (FDManager::SetEntry(&bEntry, filePath.Path()) != B_OK
936		|| !bEntry.Exists()) {
937		return B_ENTRY_NOT_FOUND;
938	}
939
940	// open the settings file
941	BFile file;
942	error = FDManager::SetFile(&file, filePath.Path(), B_READ_ONLY);
943	if (error != B_OK)
944		RETURN_ERROR(error);
945
946	// read the settings
947	BMessage settings;
948	error = settings.Unflatten(&file);
949	if (error != B_OK)
950		RETURN_ERROR(error);
951
952	// get the security context archive
953	BMessage securityContextArchive;
954	error = settings.FindMessage("security context",
955		&securityContextArchive);
956	if (error != B_OK)
957		RETURN_ERROR(error);
958
959	// create a security context
960	SecurityContext* securityContext
961		= new(std::nothrow) SecurityContext(&securityContextArchive);
962	if (!securityContext)
963		RETURN_ERROR(B_NO_MEMORY);
964	ObjectDeleter<SecurityContext> securityContextDeleter(securityContext);
965	error = securityContext->InitCheck();
966	if (error != B_OK)
967		RETURN_ERROR(error);
968
969	// set it
970	delete fSecurityContext;
971	fSecurityContext = securityContext;
972	securityContextDeleter.Detach();
973
974	return B_OK;
975}
976
977// _SaveSettings
978status_t
979NetFSServer::_SaveSettings()
980{
981	AutoLocker<Locker> locker(fSecurityContext);
982
983	// create the settings archive
984	BMessage settings;
985
986	// archive the security context
987	BMessage securityContextArchive;
988	status_t error = fSecurityContext->Archive(&securityContextArchive, true);
989	if (error != B_OK)
990		RETURN_ERROR(error);
991
992	// add it to the settings archive
993	error = settings.AddMessage("security context", &securityContextArchive);
994	if (error != B_OK)
995		RETURN_ERROR(error);
996
997	// open the settings file
998	BPath filePath;
999	error = _GetSettingsFilePath(&filePath, true);
1000	if (error != B_OK)
1001		RETURN_ERROR(error);
1002	BFile file;
1003	error = FDManager::SetFile(&file, filePath.Path(),
1004		B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE);
1005	if (error != B_OK)
1006		RETURN_ERROR(error);
1007
1008	// write to the settings file
1009	error = settings.Flatten(&file);
1010	if (error != B_OK)
1011		RETURN_ERROR(error);
1012
1013	return B_OK;
1014}
1015
1016// _GetSettingsDirPath
1017status_t
1018NetFSServer::_GetSettingsDirPath(BPath* path, bool create)
1019{
1020	// get the user settings directory
1021	BPath settingsDir;
1022	status_t error = find_directory(B_USER_SETTINGS_DIRECTORY, &settingsDir,
1023		create);
1024	if (error != B_OK)
1025		RETURN_ERROR(error);
1026
1027	// create our subdir, if not existing and desired
1028	error = path->SetTo(settingsDir.Path(), kSettingsDirName);
1029	if (error != B_OK)
1030		RETURN_ERROR(error);
1031	BEntry bEntry;
1032	if (create
1033		&& (FDManager::SetEntry(&bEntry, settingsDir.Path()) != B_OK
1034			|| !bEntry.Exists())) {
1035		error = create_directory(path->Path(), S_IRWXU | S_IRWXG | S_IRWXO);
1036		if (error != B_OK)
1037			RETURN_ERROR(error);
1038	}
1039
1040	return B_OK;
1041}
1042
1043// _GetSettingsFilePath
1044status_t
1045NetFSServer::_GetSettingsFilePath(BPath* path, bool createDir)
1046{
1047	// get settings dir
1048	BPath dirPath;
1049	status_t error = _GetSettingsDirPath(&dirPath, createDir);
1050	if (error != B_OK)
1051		return error;
1052
1053	// construct the file path
1054	return path->SetTo(dirPath.Path(), kSettingsFileName);
1055}
1056
1057// _InitServerInfoConnectionListener
1058status_t
1059NetFSServer::_InitServerInfoConnectionListener()
1060{
1061	// spawn the listener thread
1062	fServerInfoConnectionListener = spawn_thread(
1063		&_ServerInfoConnectionListenerEntry,
1064		"server info connection listener", B_NORMAL_PRIORITY, this);
1065	if (fServerInfoConnectionListener < 0)
1066		return fServerInfoConnectionListener;
1067	// create a listener socket
1068	fServerInfoConnectionListenerSocket = socket(AF_INET, SOCK_STREAM, 0);
1069	if (fServerInfoConnectionListenerSocket < 0)
1070		return errno;
1071	// bind it to the port
1072	sockaddr_in addr;
1073	addr.sin_family = AF_INET;
1074	addr.sin_port = htons(kDefaultServerInfoPort);
1075	addr.sin_addr.s_addr = INADDR_ANY;
1076	if (bind(fServerInfoConnectionListenerSocket, (sockaddr*)&addr,
1077		sizeof(addr)) < 0) {
1078		return errno;
1079	}
1080	// start listening
1081	if (listen(fServerInfoConnectionListenerSocket, 5) < 0)
1082		return errno;
1083	return B_OK;
1084}
1085
1086// _ExitServerInfoConnectionListener
1087void
1088NetFSServer::_ExitServerInfoConnectionListener()
1089{
1090	// close the socket
1091	safe_closesocket(fServerInfoConnectionListenerSocket);
1092	// wait for the listener
1093	if (fServerInfoConnectionListener >= 0) {
1094		int32 result;
1095		wait_for_thread(fServerInfoConnectionListener, &result);
1096	}
1097}
1098
1099// _ConnectionListenerEntry
1100int32
1101NetFSServer::_ConnectionListenerEntry(void* data)
1102{
1103	return ((NetFSServer*)data)->_ConnectionListener();
1104}
1105
1106// _ConnectionListener
1107int32
1108NetFSServer::_ConnectionListener()
1109{
1110	// start listening for connections
1111	Connection* connection = NULL;
1112	status_t error = B_OK;
1113	do {
1114		error = fConnectionListener->Listen(&connection);
1115		if (error == B_OK) {
1116			ConnectionInitializer* initializer
1117				= new(std::nothrow) ConnectionInitializer(this, fConnectionListener,
1118					connection);
1119			if (initializer) {
1120				if (initializer->Run() != B_OK) {
1121					ERROR("Failed to run connection initializer.\n")
1122					delete initializer;
1123				}
1124			} else {
1125				ERROR("Failed to create connection initializer.\n")
1126				delete connection;
1127			}
1128
1129		}
1130	} while (error == B_OK && !fTerminating);
1131
1132	return 0;
1133}
1134
1135// _ConnectionDeleterEntry
1136int32
1137NetFSServer::_ConnectionDeleterEntry(void* data)
1138{
1139	return ((NetFSServer*)data)->_ConnectionDeleter();
1140}
1141
1142// _ConnectionDeleter
1143int32
1144NetFSServer::_ConnectionDeleter()
1145{
1146	while (!fTerminating) {
1147		status_t error = acquire_sem(fClosedConnectionsSemaphore);
1148		ClientConnection* connection = NULL;
1149		if (error == B_OK) {
1150			AutoLocker<Locker> _(fLock);
1151			connection = (ClientConnection*)fClosedConnections.RemoveItem((int32)0);
1152		}
1153		if (connection)
1154			delete connection;
1155	}
1156	return 0;
1157}
1158
1159// _BroadcasterEntry
1160int32
1161NetFSServer::_BroadcasterEntry(void* data)
1162{
1163	return ((NetFSServer*)data)->_Broadcaster();
1164}
1165
1166// _Broadcaster
1167int32
1168NetFSServer::_Broadcaster()
1169{
1170	// create the socket
1171	fBroadcastingSocket = socket(AF_INET, SOCK_DGRAM, 0);
1172	if (fBroadcastingSocket < 0) {
1173		WARN("NetFSServer::_Broadcaster(): WARN: Failed to init broadcasting: "
1174			"%s.\n", strerror(errno));
1175		return errno;
1176	}
1177
1178	// set the socket broadcast option
1179	#ifndef HAIKU_TARGET_PLATFORM_BEOS
1180		int soBroadcastValue = 1;
1181		if (setsockopt(fBroadcastingSocket, SOL_SOCKET, SO_BROADCAST,
1182			&soBroadcastValue, sizeof(soBroadcastValue)) < 0) {
1183			WARN("NetFSServer::_Broadcaster(): WARN: Failed to set "
1184				"SO_BROADCAST on socket: %s.\n", strerror(errno));
1185		}
1186	#endif
1187
1188	// prepare the broadcast message
1189	BroadcastMessage message;
1190	message.magic = B_HOST_TO_BENDIAN_INT32(BROADCAST_MESSAGE_MAGIC);
1191	message.protocolVersion = B_HOST_TO_BENDIAN_INT32(NETFS_PROTOCOL_VERSION);
1192
1193	bool update = false;
1194	while (!fTerminating) {
1195		// set tick/update
1196		uint32 messageCode = (update ? BROADCAST_MESSAGE_SERVER_UPDATE
1197			: BROADCAST_MESSAGE_SERVER_TICK);
1198		message.message = B_HOST_TO_BENDIAN_INT32(messageCode);
1199
1200		// send broadcasting message
1201		sockaddr_in addr;
1202		addr.sin_family = AF_INET;
1203		addr.sin_port = htons(kDefaultBroadcastPort);
1204		addr.sin_addr.s_addr = INADDR_BROADCAST;
1205		int addrSize = sizeof(addr);
1206		ssize_t bytesSent = sendto(fBroadcastingSocket, &message,
1207			sizeof(message), 0, (sockaddr*)&addr, addrSize);
1208		if (bytesSent < 0) {
1209			WARN("NetFSServer::_Broadcaster(): WARN: sending failed: %s.\n",
1210				strerror(errno));
1211			return errno;
1212		}
1213
1214		// snooze a bit
1215		// we snooze a minimal interval to avoid shooting updates like a
1216		// machine gun
1217		snooze(kMinBroadcastingInterval);
1218		bigtime_t remainingTime = kBroadcastingInterval
1219			- kMinBroadcastingInterval;
1220
1221		// snooze the rest blocking on our semaphore (if it exists)
1222		if (fBroadcasterSemaphore >= 0) {
1223			status_t snoozeError = acquire_sem_etc(fBroadcasterSemaphore, 1,
1224				B_RELATIVE_TIMEOUT, remainingTime);
1225
1226			// set the semaphore count back to zero
1227			while (snoozeError == B_OK) {
1228				snoozeError = acquire_sem_etc(fBroadcasterSemaphore, 1,
1229					B_RELATIVE_TIMEOUT, 0);
1230			}
1231		} else
1232			snooze(remainingTime);
1233
1234		update = atomic_and(&fServerInfoUpdated, 0);
1235	}
1236
1237	// close the socket
1238	safe_closesocket(fBroadcastingSocket);
1239	return B_OK;
1240}
1241
1242// _ServerInfoConnectionListenerEntry
1243int32
1244NetFSServer::_ServerInfoConnectionListenerEntry(void* data)
1245{
1246	return ((NetFSServer*)data)->_ServerInfoConnectionListener();
1247}
1248
1249// _ServerInfoConnectionListener
1250int32
1251NetFSServer::_ServerInfoConnectionListener()
1252{
1253	if (fServerInfoConnectionListenerSocket < 0)
1254		return B_BAD_VALUE;
1255
1256	TaskManager taskManager;
1257
1258	// accept a incoming connection
1259	while (!fTerminating) {
1260		int fd = -1;
1261		do {
1262			taskManager.RemoveDoneTasks();
1263
1264			fd = accept(fServerInfoConnectionListenerSocket, NULL, 0);
1265			if (fd < 0) {
1266				status_t error = errno;
1267				if (error != B_INTERRUPTED)
1268					return error;
1269				if (fTerminating)
1270					return B_OK;
1271			}
1272		} while (fd < 0);
1273
1274		// get a fresh server info
1275		ServerInfo info;
1276		status_t error = _GetServerInfo(info);
1277		if (error != B_OK) {
1278			closesocket(fd);
1279			return error;
1280		}
1281
1282		// create a server info sender thread
1283		ServerInfoSender* sender = new(std::nothrow) ServerInfoSender(fd, info);
1284		if (sender == NULL) {
1285			closesocket(fd);
1286			delete sender;
1287			return B_NO_MEMORY;
1288		}
1289		if ((error = sender->Init()) != B_OK) {
1290			closesocket(fd);
1291			delete sender;
1292			return error;
1293		}
1294		taskManager.RunTask(sender);
1295	}
1296
1297	return B_OK;
1298}
1299
1300// _GetServerInfo
1301status_t
1302NetFSServer::_GetServerInfo(ServerInfo& serverInfo)
1303{
1304	// set the server name and the connection method
1305	char hostName[1024];
1306	if (gethostname(hostName, sizeof(hostName)) < 0) {
1307		ERROR("NetFSServer::_GetServerInfo(): ERROR: Failed to get host "
1308			"name.");
1309		return B_ERROR;
1310	}
1311	status_t error = serverInfo.SetServerName(hostName);
1312// TODO: Set the actually used connection method!
1313	if (error == B_OK)
1314		error = serverInfo.SetConnectionMethod("insecure");
1315	if (error != B_OK)
1316		return error;
1317
1318	// get the shares from the security context
1319	BMessage shares;
1320	error = fSecurityContext->GetShares(&shares);
1321	if (error != B_OK)
1322		return error;
1323
1324	// add the shares
1325	const char* shareName;
1326	for (int32 i = 0; shares.FindString("shares", i, &shareName) == B_OK; i++) {
1327		error = serverInfo.AddShare(shareName);
1328		if (error != B_OK)
1329			return error;
1330	}
1331	return B_OK;
1332}
1333
1334// _ServerInfoUpdated
1335void
1336NetFSServer::_ServerInfoUpdated()
1337{
1338	atomic_or(&fServerInfoUpdated, 1);
1339	release_sem(fBroadcasterSemaphore);
1340}
1341
1342// _SendReply
1343void
1344NetFSServer::_SendReply(BMessage* message, BMessage* reply, status_t error)
1345{
1346	// no reply is specified, if no data have to be sent
1347	BMessage stackReply;
1348	if (!reply)
1349		reply = &stackReply;
1350
1351	reply->AddInt32("error", error);
1352	message->SendReply(reply, (BHandler*)NULL, 0LL);
1353}
1354
1355// _SendReply
1356void
1357NetFSServer::_SendReply(BMessage* message, status_t error)
1358{
1359	_SendReply(message, NULL, error);
1360}
1361
1362
1363// #pragma mark -
1364
1365// print_usage
1366static
1367void
1368print_usage(bool error)
1369{
1370	fputs(kUsage, (error ? stderr : stdout));
1371}
1372
1373// main
1374int
1375main(int argc, char** argv)
1376{
1377	#ifdef DEBUG_OBJECT_TRACKING
1378		ObjectTracker::InitDefault();
1379	#endif
1380
1381	// parse the arguments
1382	bool broadcast = true;
1383	for (int argi = 1; argi < argc; argi++) {
1384		const char* arg = argv[argi];
1385		if (strcmp(arg, "--dont-broadcast") == 0) {
1386			broadcast = false;
1387		} else if (strcmp(arg, "--help") == 0 || strcmp(arg, "-h") == 0) {
1388			print_usage(false);
1389			return 0;
1390		} else {
1391			print_usage(true);
1392			return 1;
1393		}
1394	}
1395
1396	// create the statistics manager
1397	status_t error = StatisticsManager::CreateDefault();
1398	if (error != B_OK) {
1399		fprintf(stderr, "Failed to create statistics manager: %s\n",
1400			strerror(error));
1401		return 1;
1402	}
1403
1404	// init and run the server
1405	{
1406		NetFSServer server(broadcast);
1407		error = server.Init();
1408		if (error != B_OK) {
1409			fprintf(stderr, "Failed to initialize server: %s\n",
1410				strerror(error));
1411			return 1;
1412		}
1413		server.Run();
1414	}
1415
1416	// delete the statistics manager
1417	StatisticsManager::DeleteDefault();
1418
1419	#ifdef DEBUG_OBJECT_TRACKING
1420		ObjectTracker::ExitDefault();
1421	#endif
1422
1423	return 0;
1424}
1425
1426