1// NetFSServerPrefs.cpp
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6
7#include <Application.h>
8#include <Message.h>
9
10#include "NetFSServerRoster.h"
11#include "Permissions.h"
12
13// simplified permissions
14static const uint32 kMountPermission = MOUNT_SHARE_PERMISSION;
15static const uint32 kQueryPermission = QUERY_SHARE_PERMISSION;
16static const uint32 kReadPermission
17	= READ_PERMISSION | READ_DIR_PERMISSION | RESOLVE_DIR_ENTRY_PERMISSION;
18static const uint32 kWritePermission
19	= WRITE_PERMISSION | WRITE_DIR_PERMISSION;
20
21// usage
22static const char* kUsage =
23"Usage: netfs_server_prefs -h | --help\n"
24"       netfs_server_prefs <command>\n"
25"options:\n"
26"  -h, --help        - print this text\n"
27"\n"
28"commands:\n"
29"  launch\n"
30"      launches the server\n"
31"  terminate\n"
32"      terminates the server\n"
33"  save\n"
34"      saves the server settings\n"
35"  l, list\n"
36"      list all users and all shares\n"
37"  add share <name> <path>\n"
38"      add a new share with the name <name> and path <path>\n"
39"  remove share <name>\n"
40"      remove the share named <name>\n"
41"  add user <name> [ <password> ]\n"
42"      add a new user with the name <name> and, if supplied, \n"
43"      password <password>\n"
44"  remove user <name>\n"
45"      remove the user named <name>\n"
46"  permissions <user> <share> [ m ] [ r ] [ w ] [ q ]\n"
47"      set the permissions of user <user> for share <share> to m(ount),\n"
48"      r(ead), w(rite), and/or q(uery).\n"
49;
50
51// print_usage
52static
53void
54print_usage(bool error)
55{
56	fputs(kUsage, (error ? stderr : stdout));
57}
58
59// print_usage_and_exit
60static
61void
62print_usage_and_exit(bool error)
63{
64	print_usage(error);
65	exit(error ? 1 : 0);
66}
67
68// get_permissions_string
69static
70void
71get_permissions_string(uint32 permissions, char* str)
72{
73	str[0] = (permissions & kMountPermission ? 'm' : '-');
74	str[1] = (permissions & kReadPermission ? 'r' : '-');
75	str[2] = (permissions & kWritePermission ? 'w' : '-');
76	str[3] = (permissions & kQueryPermission ? 'q' : '-');
77	str[4] = '\0';
78}
79
80// get_permissions
81static
82bool
83get_permissions(const char* str, uint32* permissions)
84{
85	*permissions = 0;
86
87	if (!str)
88		return true;
89
90	while (*str) {
91		switch (*str) {
92			case 'm':
93				*permissions |= kMountPermission;
94				break;
95			case 'r':
96				*permissions |= kReadPermission;
97				break;
98			case 'w':
99				*permissions |= kWritePermission;
100				break;
101			case 'q':
102				*permissions |= kQueryPermission;
103				break;
104			default:
105				return false;
106		}
107		str++;
108	}
109
110	return true;
111}
112
113// assert_server_running
114static
115void
116assert_server_running()
117{
118	// check, if the server is running
119	NetFSServerRoster roster;
120	if (!roster.IsServerRunning()) {
121		fprintf(stderr, "Server is not running.\n");
122		exit(1);
123	}
124}
125
126// list
127static
128void
129list()
130{
131	assert_server_running();
132
133	NetFSServerRoster roster;
134
135	// get the users
136	BMessage users;
137	status_t error = roster.GetUsers(&users);
138	if (error == B_OK) {
139		// list the users
140		printf("users\n");
141		printf("-----\n");
142		const char* user;
143		for (int32 i = 0; users.FindString("users", i, &user) == B_OK; i++)
144			printf("%s\n", user);
145		printf("\n");
146	} else
147		fprintf(stderr, "Failed to get users: %s\n", strerror(error));
148
149	// get the shares
150	BMessage shares;
151	error = roster.GetShares(&shares);
152	if (error == B_OK) {
153		// list the shares
154		printf("shares\n");
155		printf("------\n");
156		const char* share;
157		for (int32 i = 0; shares.FindString("shares", i, &share) == B_OK; i++) {
158			// get path
159			const char* path;
160			if (shares.FindString("paths", i, &path) != B_OK)
161				path = "<invalid path>\n";
162
163			// get share users
164			BMessage shareUsers;
165			roster.GetShareUsers(share, &shareUsers);
166
167			// get statistics
168			BMessage statistics;
169			roster.GetShareStatistics(share, &statistics);
170
171			printf("%s:\n", share);
172			printf("  path:         %s\n", path);
173
174			// print permitted users
175			printf("  mountable by: ");
176			const char* user;
177			for (int32 k = 0;
178				 shareUsers.FindString("users", k, &user) == B_OK;
179				 k++) {
180				if (k > 0)
181					printf(", ");
182				printf("%s", user);
183
184				// print permissions
185				uint32 permissions = 0;
186				roster.GetUserPermissions(share, user, &permissions);
187				char permissionsString[8];
188				get_permissions_string(permissions, permissionsString);
189				printf(" (%s)", permissionsString);
190			}
191			printf("\n");
192
193			// print current users
194			printf("  mounted by:   ");
195			for (int32 k = 0;
196				 statistics.FindString("mounted by", k, &user) == B_OK;
197				 k++) {
198				if (k > 0)
199					printf(", ");
200				printf("%s", user);
201			}
202			printf("\n");
203
204			printf("\n");
205		}
206	} else
207		fprintf(stderr, "Failed to get users: %s\n", strerror(error));
208}
209
210// add_share
211static
212void
213add_share(const char* name, const char* path)
214{
215	assert_server_running();
216
217	NetFSServerRoster roster;
218
219	// check whether a share with the given name already exists
220	BMessage statistics;
221	if (roster.GetShareStatistics(name, &statistics) == B_OK) {
222		fprintf(stderr, "A share `%s' does already exist.\n", name);
223		exit(1);
224	}
225
226	// add the share
227	status_t error = roster.AddShare(name, path);
228	if (error != B_OK) {
229		fprintf(stderr, "Failed to add share: %s\n", strerror(error));
230		exit(1);
231	}
232}
233
234// remove_share
235static
236void
237remove_share(const char* name)
238{
239	assert_server_running();
240
241	NetFSServerRoster roster;
242
243	// check whether a share with the given name exists
244	BMessage statistics;
245	if (roster.GetShareStatistics(name, &statistics) != B_OK) {
246		fprintf(stderr, "A share `%s' does not exist.\n", name);
247		exit(1);
248	}
249
250	// remove the share
251	status_t error = roster.RemoveShare(name);
252	if (error != B_OK) {
253		fprintf(stderr, "Failed to remove share: %s\n", strerror(error));
254		exit(1);
255	}
256}
257
258// add_user
259static
260void
261add_user(const char* name, const char* password)
262{
263	assert_server_running();
264
265	NetFSServerRoster roster;
266
267	// check whether a user with the given name already exists
268	BMessage statistics;
269	if (roster.GetUserStatistics(name, &statistics) == B_OK) {
270		fprintf(stderr, "A user `%s' does already exist.\n", name);
271		exit(1);
272	}
273
274	// add the user
275	status_t error = roster.AddUser(name, password);
276	if (error != B_OK) {
277		fprintf(stderr, "Failed to add user: %s\n", strerror(error));
278		exit(1);
279	}
280}
281
282// remove_user
283static
284void
285remove_user(const char* name)
286{
287	assert_server_running();
288
289	NetFSServerRoster roster;
290
291	// check whether a user with the given name exists
292	BMessage statistics;
293	if (roster.GetUserStatistics(name, &statistics) != B_OK) {
294		fprintf(stderr, "A user `%s' does not exist.\n", name);
295		exit(1);
296	}
297
298	// remove the user
299	status_t error = roster.RemoveUser(name);
300	if (error != B_OK) {
301		fprintf(stderr, "Failed to remove user: %s\n", strerror(error));
302		exit(1);
303	}
304}
305
306// set_user_permissions
307static
308void
309set_user_permissions(const char* user, const char* share, uint32 permissions)
310{
311	assert_server_running();
312
313	NetFSServerRoster roster;
314
315	// check whether a user with the given name exists
316	BMessage statistics;
317	if (roster.GetUserStatistics(user, &statistics) != B_OK) {
318		fprintf(stderr, "A user `%s' does not exist.\n", user);
319		exit(1);
320	}
321
322	// check whether a share with the given name exists
323	if (roster.GetShareStatistics(share, &statistics) != B_OK) {
324		fprintf(stderr, "A share `%s' does not exist.\n", share);
325		exit(1);
326	}
327
328	// set the permissions
329	status_t error = roster.SetUserPermissions(share, user, permissions);
330	if (error != B_OK) {
331		fprintf(stderr, "Failed to set permissions: %s\n", strerror(error));
332		exit(1);
333	}
334}
335
336// launch_server
337static
338void
339launch_server()
340{
341	NetFSServerRoster roster;
342
343	if (roster.IsServerRunning()) {
344		fprintf(stderr, "Server is already running.\n");
345		exit(1);
346	}
347
348	status_t error = roster.LaunchServer();
349	if (error != B_OK) {
350		fprintf(stderr, "Failed to launch server: %s\n", strerror(error));
351		exit(1);
352	}
353}
354
355// terminate_server
356static
357void
358terminate_server()
359{
360	assert_server_running();
361
362	NetFSServerRoster roster;
363
364	status_t error = roster.TerminateServer();
365	if (error != B_OK) {
366		fprintf(stderr, "Failed to terminate server: %s\n", strerror(error));
367		exit(1);
368	}
369}
370
371// save_server_setttings
372static
373void
374save_server_setttings()
375{
376	assert_server_running();
377
378	NetFSServerRoster roster;
379
380	status_t error = roster.SaveServerSettings();
381	if (error != B_OK) {
382		fprintf(stderr, "Failed to save settings: %s\n", strerror(error));
383		exit(1);
384	}
385}
386
387// next_arg
388static
389const char*
390next_arg(int argc, char** argv, int& argi, bool dontFail = false)
391{
392	if (argi >= argc) {
393		if (dontFail)
394			return NULL;
395		print_usage_and_exit(true);
396	}
397
398	return argv[argi++];
399}
400
401// no_more_args
402static
403void
404no_more_args(int argc, int argi)
405{
406	if (argi < argc)
407		print_usage_and_exit(true);
408}
409
410// main
411int
412main(int argc, char** argv)
413{
414	BApplication app("application/x-vnd.haiku-netfs_server_prefs");
415
416	// parse first argument
417	int argi = 1;
418	const char* arg = next_arg(argc, argv, argi);
419	if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0)
420		print_usage_and_exit(false);
421
422	if (strcmp(arg, "launch") == 0) {
423		// launch
424		no_more_args(argc, argi);
425		launch_server();
426	} else if (strcmp(arg, "terminate") == 0) {
427		// terminate
428		no_more_args(argc, argi);
429		terminate_server();
430	} else if (strcmp(arg, "save") == 0) {
431		// save
432		no_more_args(argc, argi);
433		save_server_setttings();
434	} else if (strcmp(arg, "l") == 0 || strcmp(arg, "list") == 0) {
435		// list
436		no_more_args(argc, argi);
437		list();
438	} else if (strcmp(arg, "add") == 0) {
439		// add
440		arg = next_arg(argc, argv, argi);
441		if (strcmp(arg, "share") == 0) {
442			// share
443			const char* name = next_arg(argc, argv, argi);
444			const char* path = next_arg(argc, argv, argi);
445			no_more_args(argc, argi);
446			add_share(name, path);
447		} else if (strcmp(arg, "user") == 0) {
448			// user
449			const char* name = next_arg(argc, argv, argi);
450			const char* password = next_arg(argc, argv, argi, true);
451			no_more_args(argc, argi);
452			add_user(name, password);
453		} else
454			print_usage_and_exit(true);
455	} else if (strcmp(arg, "remove") == 0) {
456		// remove
457		arg = next_arg(argc, argv, argi);
458		if (strcmp(arg, "share") == 0) {
459			// share
460			const char* name = next_arg(argc, argv, argi);
461			no_more_args(argc, argi);
462			remove_share(name);
463		} else if (strcmp(arg, "user") == 0) {
464			// user
465			const char* name = next_arg(argc, argv, argi);
466			no_more_args(argc, argi);
467			remove_user(name);
468		} else
469			print_usage_and_exit(true);
470	} else if (strcmp(arg, "permissions") == 0) {
471		// permissions
472		const char* user = next_arg(argc, argv, argi);
473		const char* share = next_arg(argc, argv, argi);
474		uint32 permissions = 0;
475		while (argi < argc) {
476			uint32 perms = 0;
477			arg = next_arg(argc, argv, argi);
478			if (!get_permissions(arg, &perms))
479				print_usage_and_exit(true);
480			permissions |= perms;
481		}
482		set_user_permissions(user, share, permissions);
483	} else {
484		print_usage_and_exit(true);
485	}
486
487	return 0;
488}
489