1// btAdd.cpp : Defines the entry point for the console application.
2//
3
4#include "FindDirectory.h"
5
6#include "betalk.h"
7#include "sysdepdefs.h"
8#include "besure_auth.h"
9#include "BlowFish.h"
10
11#include "netdb.h"
12#include "utime.h"
13#include "ctype.h"
14#include "time.h"
15#include "signal.h"
16#include "stdlib.h"
17#include "syslog.h"
18
19#define BT_MAX_THREADS		128
20#define BT_MAX_RETRIES		3
21#define BT_THREAD_NAME		"BeSure Handler"
22
23typedef struct
24{
25	unsigned int type;
26	unsigned int length;
27	char *data;
28} bt_arg_t;
29
30typedef struct session
31{
32	int socket;
33	unsigned int client_s_addr;
34	thread_id handlerID;
35	struct session *next;
36} bt_session_t;
37
38typedef void (*bt_net_func)(bt_session_t *, unsigned int, int, bt_arg_t *);
39
40typedef struct dirCommand
41{
42	unsigned char command;
43	bt_net_func handler;
44	bool supported;
45	uint8 args;
46	uint32 argTypes[MAX_COMMAND_ARGS];
47} bt_command_t;
48
49
50int main(int argc, char *argv[]);
51void daemonInit();
52void startService();
53void endService();
54void restartService();
55int32 requestThread(void *data);
56int receiveRequest(bt_session_t *session);
57void handleRequest(bt_session_t *session, unsigned int xid, unsigned char command, int argc, bt_arg_t argv[]);
58void launchThread(int client, struct sockaddr_in *addr);
59void sendErrorToClient(int client, unsigned int xid, int error);
60void getArguments(bt_session_t *session, bt_inPacket *packet, unsigned char command);
61
62int btRecv(int sock, void *data, int dataLen, int flags);
63int btSend(int sock, void *data, int dataLen, int flags);
64
65void btLock(sem_id semaphore, int32 *atomic);
66void btUnlock(sem_id semaphore, int32 *atomic);
67
68int generateTicket(const char *client, const char *server, unsigned char *key, char *ticket);
69void recordLogin(char *server, char *share, char *client, bool authenticated);
70//void strlwr(char *str);
71
72int cmdAuthenticate(unsigned int addr, char *client, char *token, char *response);
73int cmdReadUsers(DIR **dir, char *user, char *fullName);
74int cmdReadGroups(DIR **dir, char *group);
75int cmdWhichGroups(DIR **dir, char *user, char *group);
76
77void netcmdAuthenticate(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
78void netcmdReadUsers(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
79void netcmdReadGroups(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
80void netcmdWhichGroups(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
81void netcmdQuit(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]);
82
83bt_session_t *rootSession = NULL;
84bool running = true;
85int server;
86sem_id sessionSem;
87int32 sessionVar;
88
89bt_command_t dirCommands[] =
90{
91	{ BT_CMD_AUTH,				netcmdAuthenticate,		true,	2,	{ B_STRING_TYPE, B_STRING_TYPE } },
92	{ BT_CMD_READUSERS,			netcmdReadUsers,		true,	1,	{ B_INT32_TYPE } },
93	{ BT_CMD_READGROUPS,		netcmdReadGroups,		true,	1,	{ B_INT32_TYPE } },
94	{ BT_CMD_WHICHGROUPS,		netcmdWhichGroups,		true,	1,	{ B_STRING_TYPE } },
95	{ BT_CMD_QUIT,				netcmdQuit,				true,	0,	{ 0 } },
96	{ 0,						NULL,					false,	0,	{ 0 } }
97};
98
99
100int main(int argc, char *argv[])
101{
102	daemonInit();
103
104	signal(SIGINT, endService);
105	signal(SIGTERM, endService);
106	signal(SIGHUP, restartService);
107	signal(SIGPIPE, SIG_IGN);
108
109	if ((sessionSem = create_sem(0, "Session Semaphore")) > 0)
110	{
111		// Run the daemon.  We will not return until the service is being stopped.
112		startService();
113		delete_sem(sessionSem);
114	}
115
116	return 0;
117}
118
119void daemonInit()
120{
121	int i;
122
123	// Cause the parent task to terminate, freeing the terminal.
124	if (fork() != 0)
125		exit(0);
126
127	// In the child process, become the session leader.
128	setsid();
129
130	// Now fork again, causing the first child to exit, since the session
131	// leader can be assigned a controlling terminal under SVR4.
132	signal(SIGHUP, SIG_IGN);
133	if (fork() != 0)
134		exit(0);
135
136	// Change to the root directory, since if we hold on to a working
137	// folder that was in a mounted file system, that file system cannot
138	// be unmounted.
139	chdir("/");
140
141	// Reset the file creation mask to zero to eliminate the inherited value.
142	umask(0);
143
144	// Close open file descriptors.  Since we can't know how many of a
145	// potentially unlimited value can be open, just close the first 64
146	// and assume that will be enough.
147	for (i = 0; i < 64; i++)
148		close(i);
149
150	// Open the syslog.
151	openlog("besure_server", LOG_PID, LOG_DAEMON);
152}
153
154void restartService()
155{
156}
157
158void startService()
159{
160	struct sockaddr_in serverAddr, clientAddr;
161	int client, addrLen;
162	int flags;
163
164	// Store the length of the socket addressing structure for accept().
165	addrLen = sizeof(struct sockaddr_in);
166
167	// Initialize the server address structure.
168	memset(&serverAddr, 0, sizeof(serverAddr));
169	serverAddr.sin_port = htons(BT_BESURE_PORT);
170	serverAddr.sin_family = AF_INET;
171	serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
172
173	// Create a new socket to receive incoming requests.
174	server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
175	if (server == INVALID_SOCKET)
176		return;
177
178	// Set the socket option to reuse the current address in case it was
179	// in use by a prior version of the service that has not yet relinquished
180	// the socket.
181	flags = 1;
182	setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof(flags));
183
184	// Bind that socket to the address constructed above.
185	if (bind(server, (struct sockaddr *) &serverAddr, sizeof(serverAddr)))
186		return;
187
188	// Listen for incoming connections.
189	if (listen(server, 5))
190		return;
191
192	// Continually accept incoming connections.  When one is found,
193	// fire off a handler thread to accept commands.
194	while (running)
195	{
196		client = accept(server, (struct sockaddr *) &clientAddr, &addrLen);
197		if (client != INVALID_SOCKET)
198			launchThread(client, &clientAddr);
199	}
200
201	// Close the socket.  Technically, I believe we should call shutdown()
202	// first, but the BeOS header file socket.h indicates that this
203	// function is not currently working.  It is present but may not have
204	// any effect.
205	shutdown(server, 2);
206	closesocket(server);
207	server = INVALID_SOCKET;
208}
209
210void endService()
211{
212	signal(SIGINT, SIG_DFL);
213	signal(SIGTERM, SIG_DFL);
214	signal(SIGHUP, SIG_DFL);
215	signal(SIGPIPE, SIG_DFL);
216	exit(0);
217}
218
219// launchThread()
220//
221void launchThread(int client, struct sockaddr_in *addr)
222{
223	bt_session_t *s, *cur, *last = NULL;
224	int count = 0;
225
226	// First verify that the server's not too busy by scanning the list of active
227	// sessions.  This is also useful because we need to eliminate unused sessions
228	// from the list, i.e., sessions that have closed.
229	btLock(sessionSem, &sessionVar);
230
231	s = rootSession;
232	while (s)
233	{
234		if (s->socket == INVALID_SOCKET)
235		{
236			if (last)
237				last->next = s->next;
238			else
239				rootSession = s->next;
240
241			cur = s->next;
242			free(s);
243			s = cur;
244			continue;
245		}
246
247		last = s;
248		s = s->next;
249		count++;
250	}
251
252	// If the total number of valid sessions was less than our allowed maximum, then
253	// we can create a new session.
254	if (count < BT_MAX_THREADS)
255	{
256		// We need to create an available session for this connection.
257		bt_session_t *session = (bt_session_t *) malloc(sizeof(bt_session_t));
258		if (session)
259		{
260			session->socket = client;
261			session->client_s_addr = addr->sin_addr.s_addr;
262
263			session->handlerID =
264				spawn_thread(requestThread, BT_THREAD_NAME, B_NORMAL_PRIORITY, session);
265			resume_thread(session->handlerID);
266
267			// Add this to the session list.
268			session->next = rootSession;
269			rootSession = session;
270			btUnlock(sessionSem, &sessionVar);
271			return;
272		}
273	}
274
275	btUnlock(sessionSem, &sessionVar);
276
277	// We must have too many threads active, so let the client know we're busy.
278	sendErrorToClient(client, 0, EBUSY);
279	shutdown(client, 2);
280	closesocket(client);
281}
282
283int32 requestThread(void *data)
284{
285	bt_session_t *session = (bt_session_t *) data;
286//	int flags;
287
288	if (!session)
289		return 0;
290
291//	flags = 1;
292//	setsockopt(server, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof(flags));
293
294	while (receiveRequest(session));
295
296	shutdown(session->socket, 2);
297	closesocket(session->socket);
298	session->socket = INVALID_SOCKET;
299	return 0;
300}
301
302int receiveRequest(bt_session_t *session)
303{
304	bt_inPacket packet;
305	char signature[20], *buffer;
306	unsigned char command;
307	int client, sigLen;
308	int32 length;
309
310	client = session->socket;
311
312	// Read the BeTalk RPC header.
313	sigLen = strlen(BT_RPC_SIGNATURE);
314	if (btRecvMsg(client, signature, sigLen, 0) == -1)
315		return 0;
316
317//	recv(client, &verHi, sizeof(verHi), 0);
318//	recv(client, &verLo, sizeof(verLo), 0);
319
320	signature[sigLen] = 0;
321	if (strcmp(signature, BT_RPC_SIGNATURE))
322		return 0;
323
324	// Read in the rest of the packet.
325	if (btRecvMsg(client, &length, sizeof(int32), 0) == -1)
326		return 0;
327
328	length = B_LENDIAN_TO_HOST_INT32(length);
329	if (length == 0 || length > BT_RPC_MAX_PACKET_SIZE)
330		return 0;
331
332	buffer = (char *) malloc(length + 1);
333	if (!buffer)
334		return 0;
335
336	if (btRecvMsg(client, buffer, length, 0) == -1)
337	{
338		free(buffer);
339		return 0;
340	}
341
342	buffer[length] = 0;
343	packet.buffer = buffer;
344	packet.length = length;
345	packet.offset = 0;
346
347	// Read the transmission ID and command.
348	command = btRPCGetChar(&packet);
349	getArguments(session, &packet, command);
350	free(buffer);
351	return (command != BT_CMD_AUTH && command != BT_CMD_QUIT);
352}
353
354void getArguments(bt_session_t *session, bt_inPacket *packet, unsigned char command)
355{
356	bt_arg_t args[MAX_COMMAND_ARGS];
357	int i, client;
358	bool error;
359	unsigned char argc, terminator;
360	int32 xid;
361
362	error = false;
363	client = session->socket;
364	argc = btRPCGetChar(packet);
365	if (argc > MAX_COMMAND_ARGS)
366		return;
367
368	for (i = 0; i < argc && !error; i++)
369	{
370		args[i].type = btRPCGetInt32(packet);
371		args[i].data = btRPCGetNewString(packet);
372		if (args[i].data == NULL)
373			error = true;
374	}
375
376	if (!error)
377	{
378		xid = btRPCGetInt32(packet);
379		terminator = btRPCGetChar(packet);
380		if (terminator == BT_CMD_TERMINATOR)
381			handleRequest(session, xid, command, argc, args);
382	}
383	else
384		sendErrorToClient(session->socket, 0, EINVAL);
385
386	while (--i >= 0)
387		free(args[i].data);
388}
389
390void handleRequest(bt_session_t *session, unsigned int xid, unsigned char command, int argc, bt_arg_t argv[])
391{
392	bool validated = true;
393	int i, j;
394
395	for (i = 0; dirCommands[i].handler; i++)
396		if (command == dirCommands[i].command)
397		{
398			// We may have received a valid command, but one that is not supported by this
399			// server.  In this case, we'll want to return an operation not supported error,
400			// as opposed to an invalid command error.
401			if (!dirCommands[i].supported)
402			{
403				sendErrorToClient(session->socket, xid, EOPNOTSUPP);
404				return;
405			}
406
407			// Now verify that the argument count is correct, and if so, the type of all
408			// arguments is correct.  If not, an invalid command error is returned.
409			// Otherise, the command is executed, and the handler returns any necessary
410			// acknowledgement.
411			if (argc == dirCommands[i].args)
412			{
413				for (j = 0; j < argc; j++)
414					if (dirCommands[i].argTypes[j] != argv[j].type)
415					{
416						validated = false;
417						break;
418					}
419
420				if (validated)
421				{
422					(*dirCommands[i].handler)(session, xid, argc, argv);
423					return;
424				}
425			}
426		}
427
428	sendErrorToClient(session->socket, xid, EINVAL);
429}
430
431void sendErrorToClient(int client, unsigned int xid, int error)
432{
433	bt_outPacket packet;
434	btRPCCreateAck(&packet, xid, error);
435	btRPCSendAck(client, &packet);
436}
437
438int btRecvMsg(int sock, void *data, int dataLen, int flags)
439{
440	int bytesRead = 0;
441	do
442	{
443		int bytes = btRecv(sock, (char *) data + bytesRead, dataLen - bytesRead, flags);
444		if (bytes == -1)
445			return -1;
446
447		bytesRead += bytes;
448	} while (bytesRead < dataLen);
449
450	return bytesRead;
451}
452
453// btRecv()
454//
455int btRecv(int sock, void *data, int dataLen, int flags)
456{
457	int bytes;
458
459	for (;;)
460	{
461		bytes = recv(sock, data, dataLen, flags);
462		if (bytes == 0)
463			return -1;
464		else if (bytes == -1)
465			if (errno == EINTR)
466				continue;
467			else
468				return -1;
469		else
470			break;
471	}
472
473	return bytes;
474}
475
476int btSendMsg(int sock, void *data, int dataLen, int flags)
477{
478	int bytesSent = 0;
479	do
480	{
481		int bytes = btSend(sock, (char *) data + bytesSent, dataLen - bytesSent, flags);
482		if (bytes == -1)
483			return -1;
484
485		bytesSent += bytes;
486	} while (bytesSent < dataLen);
487
488	return bytesSent;
489}
490
491// btSend()
492//
493int btSend(int sock, void *data, int dataLen, int flags)
494{
495	int bytes;
496
497	for (;;)
498	{
499		bytes = send(sock, data, dataLen, flags);
500		if (bytes == -1)
501			if (errno == EINTR)
502				continue;
503			else
504				return -1;
505		else
506			break;
507	}
508
509	return bytes;
510}
511
512void btRPCCreateAck(bt_outPacket *packet, unsigned int xid, int error)
513{
514	packet->size = BT_RPC_MIN_PACKET_SIZE;
515	packet->buffer = (char *) malloc(packet->size);
516	packet->length = 0;
517
518	if (!packet->buffer)
519		return;
520
521	strcpy(packet->buffer, BT_RPC_SIGNATURE);
522	packet->length += strlen(BT_RPC_SIGNATURE);
523	btRPCPutInt32(packet, xid);
524	btRPCPutInt32(packet, 0);
525	btRPCPutInt32(packet, error);
526}
527
528void btRPCSendAck(int client, bt_outPacket *packet)
529{
530	if (packet)
531		if (packet->buffer)
532		{
533			*(int32 *)(&packet->buffer[9]) = B_HOST_TO_LENDIAN_INT32(packet->length - 13);
534			btSendMsg(client, packet->buffer, packet->length, 0);
535			free(packet->buffer);
536		}
537}
538
539unsigned char btRPCGetChar(bt_inPacket *packet)
540{
541	unsigned char value;
542
543	if (packet->offset < packet->length)
544		value = (unsigned char) packet->buffer[packet->offset];
545	else
546		value = 0;
547
548	packet->offset += sizeof(value);
549	return value;
550}
551
552unsigned int btRPCGetInt32(bt_inPacket *packet)
553{
554	int32 value;
555
556	if (packet->offset < packet->length)
557		value = B_LENDIAN_TO_HOST_INT32(*((int32 *) &packet->buffer[packet->offset]));
558	else
559		value = 0;
560
561	packet->offset += sizeof(value);
562	return value;
563}
564
565int64 btRPCGetInt64(bt_inPacket *packet)
566{
567	int64 value;
568
569	if (packet->offset < packet->length)
570		value = B_LENDIAN_TO_HOST_INT64(*((int64 *) &packet->buffer[packet->offset]));
571	else
572		value = 0;
573
574	packet->offset += sizeof(value);
575	return value;
576}
577
578char *btRPCGetNewString(bt_inPacket *packet)
579{
580	char *str;
581	unsigned int bytes;
582
583	if (packet->offset >= packet->length)
584		return NULL;
585
586	bytes = B_LENDIAN_TO_HOST_INT32(*((int32 *) &packet->buffer[packet->offset]));
587	packet->offset += sizeof(bytes);
588	if (bytes < 0 || bytes > BT_MAX_IO_BUFFER)
589		return NULL;
590
591	str = (char *) malloc(bytes + 1);
592	if (!str)
593		return NULL;
594
595	if (bytes > 0)
596		memcpy(str, &packet->buffer[packet->offset], bytes);
597
598	str[bytes] = 0;
599	packet->offset += bytes;
600
601	return str;
602}
603
604int btRPCGetString(bt_inPacket *packet, char *buffer, int length)
605{
606	unsigned int bytes;
607
608	if (packet->offset >= packet->length)
609		return ERANGE;
610
611	bytes = B_LENDIAN_TO_HOST_INT32(*((int32 *) &packet->buffer[packet->offset]));
612	packet->offset += sizeof(bytes);
613	if (bytes < 0 || bytes > BT_MAX_IO_BUFFER)
614		return ERANGE;
615
616	if (length < bytes)
617		return ERANGE;
618
619	if (bytes > 0)
620		memcpy(buffer, &packet->buffer[packet->offset], bytes);
621
622	packet->offset += bytes;
623	return bytes;
624}
625
626void btRPCGrowPacket(bt_outPacket *packet, int bytes)
627{
628	if (packet->length + bytes > packet->size)
629	{
630		int growth = ((bytes / BT_RPC_MIN_PACKET_SIZE) + 1) * BT_RPC_MIN_PACKET_SIZE;
631		packet->buffer = (char *) realloc(packet->buffer, packet->size + growth);
632		packet->size += growth;
633	}
634}
635
636void btRPCPutChar(bt_outPacket *packet, char value)
637{
638	btRPCGrowPacket(packet, sizeof(value));
639	packet->buffer[packet->length] = value;
640	packet->length += sizeof(value);
641}
642
643void btRPCPutInt32(bt_outPacket *packet, int32 value)
644{
645	btRPCGrowPacket(packet, sizeof(value));
646	*(int32 *)(&packet->buffer[packet->length]) = B_HOST_TO_LENDIAN_INT32(value);
647	packet->length += sizeof(value);
648}
649
650void btRPCPutInt64(bt_outPacket *packet, int64 value)
651{
652	btRPCGrowPacket(packet, sizeof(value));
653	*(int64 *)(&packet->buffer[packet->length]) = B_HOST_TO_LENDIAN_INT64(value);
654	packet->length += sizeof(value);
655}
656
657void btRPCPutString(bt_outPacket *packet, char *buffer, int length)
658{
659	if (packet && buffer)
660	{
661		btRPCGrowPacket(packet, sizeof(length) + length);
662		btRPCPutInt32(packet, length);
663		memcpy(&packet->buffer[packet->length], buffer, length);
664		packet->length += length;
665	}
666}
667
668void btRPCPutBinary(bt_outPacket *packet, void *buffer, int length)
669{
670	if (packet && buffer)
671	{
672		btRPCGrowPacket(packet, length);
673		memcpy(&packet->buffer[packet->length], buffer, length);
674		packet->length += length;
675	}
676}
677
678/////////////////////////////////////////////////////////////////////
679
680void btLock(sem_id semaphore, int32 *atomic)
681{
682	int32 previous = atomic_add(atomic, 1);
683	if (previous >= 1)
684		while (acquire_sem(semaphore) == B_INTERRUPTED);
685}
686
687void btUnlock(sem_id semaphore, int32 *atomic)
688{
689	int32 previous = atomic_add(atomic, -1);
690	if (previous > 1)
691		release_sem(semaphore);
692}
693
694////////////////////////////////////////////////////////////////////
695
696int generateTicket(const char *client, const char *server, unsigned char *key, char *ticket)
697{
698	blf_ctx ctx;
699	char buffer[128], session[128];
700	int length;
701
702	// Generate a session key.
703	sprintf(session, "%s.%s.%lx", client, server, time(NULL));
704
705	// Generate the connection ticket.  Because the ticket will be encrypted via the
706	// BlowFish algorithm, it's length must be divisible by four.  We can pad the
707	// buffer with NULL characters so it won't affect the string.
708	sprintf(buffer, "%s,%s", client, session);
709	length = strlen(buffer);
710	while (length % 4)
711		buffer[length++] = ' ';
712
713	buffer[length] = 0;
714	blf_key(&ctx, key, strlen(key));
715	blf_enc(&ctx, (unsigned long *) buffer, length / 4);
716
717	// Now we have the ticket.  It gets wrapped into a response buffer here.
718	sprintf(ticket, "%s,%s,%s,%s", client, server, session, buffer);
719	return strlen(ticket);
720}
721
722// strlwr()
723/*
724void strlwr(char *str)
725{
726	char *p;
727	for (p = str; *p; p++)
728		*p = tolower(*p);
729}*/
730
731////////////////////////////////////////////////////////////////////
732
733int cmdAuthenticate(unsigned int addr, char *client, char *token, char *response)
734{
735	blf_ctx ctx;
736	char server[B_FILE_NAME_LENGTH + 1], share[B_FILE_NAME_LENGTH + 1], user[MAX_USERNAME_LENGTH + 1];
737	char buffer[BT_AUTH_TOKEN_LENGTH * 2 + 1];
738	unsigned char clientKey[MAX_KEY_LENGTH + 1];
739	int i;
740
741	// Obtain the host name of our peer from the socket information.
742	struct hostent *ent = gethostbyaddr((const char *) &addr, sizeof(addr), AF_INET);
743	if (ent)
744		strcpy(server, ent->h_name);
745	else
746	{
747		uint8 *p = (uint8 *) &addr;
748		sprintf(server, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
749	}
750
751//	printf("\tClient = %s\n", client);
752//	printf("\tToken = %s\n", token);
753
754	// Obtain the specified client's key.
755	if (!getUserPassword(client, clientKey, sizeof(clientKey)))
756		return EACCES;
757
758//	printf("\tClient key = %s\n", clientKey);
759
760	// Get the encrypted authentication information.
761	memcpy(buffer, token, BT_AUTH_TOKEN_LENGTH);
762	buffer[BT_AUTH_TOKEN_LENGTH] = 0;
763
764	// Now decrypt the request using the client's key.
765	blf_key(&ctx, clientKey, strlen(clientKey));
766	blf_dec(&ctx, (unsigned long *) buffer, BT_AUTH_TOKEN_LENGTH / 4);
767
768//	printf("\tDecrypted buffer = [%s]\n", buffer);
769
770	//  The encrypted buffer may have been padded with spaces to make its length
771	// evenly divisible by four.
772	i = strlen(buffer);
773	while (buffer[--i] == ' ' && i >= 0)
774		buffer[i] = 0;
775
776	// Once decrypted, we can extract the server being contacted.
777	memcpy(share, buffer, B_FILE_NAME_LENGTH);
778	for (i = B_FILE_NAME_LENGTH - 1; i && share[i] == ' '; i--);
779	share[i + 1] = 0;
780//	printf("\tShare = %s\n", share);
781
782	// The remainder of the buffer is the MD5-encoded client name.
783	memcpy(user, &buffer[B_FILE_NAME_LENGTH], MAX_USERNAME_LENGTH);
784	for (i = MAX_USERNAME_LENGTH - 1; i && user[i] == ' '; i--);
785	user[i + 1] = 0;
786
787//	printf("\tComparing: Client [%s] and tok [%s]\n", client, user);
788	if (strcmp(client, user) != 0)
789	{
790		recordLogin(server, share, client, false);
791		return EACCES;
792	}
793
794	recordLogin(server, share, client, true);
795	generateTicket(client, share, clientKey, response);
796
797	return B_OK;
798}
799
800void recordLogin(char *server, char *share, char *client, bool authenticated)
801{
802	FILE *fp;
803	struct tm *localTime;
804	time_t curTime;
805	char path[B_PATH_NAME_LENGTH], timeStamp[50];
806
807	if (!isServerRecordingLogins(server))
808		return;
809
810	// Obtain the filename for the log file.
811	find_directory(B_COMMON_LOG_DIRECTORY, 0, false, path, sizeof(path));
812	strcat(path, "/BeServed-Logins.log");
813
814	// Build the time stamp.
815	curTime = time(NULL);
816	localTime = localtime(&curTime);
817	strftime(timeStamp, sizeof(timeStamp), "%m/%d/%Y %H:%M:%S", localTime);
818
819	fp = fopen(path, "a");
820	if (fp)
821	{
822		fprintf(fp, "%s: %s [%s] %s %s\n", timeStamp, server,
823			authenticated ? share : "--",
824			client,
825			authenticated ? "authenticated" : "rejected");
826		fclose(fp);
827	}
828}
829
830int cmdReadUsers(DIR **dir, char *user, char *fullName)
831{
832	struct dirent *dirInfo;
833
834	if (!user || !fullName)
835		return EINVAL;
836
837	if (!*dir)
838		*dir = OpenUsers();
839
840	if (*dir)
841		if ((dirInfo = ReadUser(*dir)) != NULL)
842		{
843			strcpy(user, dirInfo->d_name);
844			getUserFullName(user, fullName, MAX_DESC_LENGTH);
845			return B_OK;
846		}
847		else
848		{
849			CloseUsers(*dir);
850			return ENOENT;
851		}
852
853	return EINVAL;
854}
855
856int cmdReadGroups(DIR **dir, char *group)
857{
858	struct dirent *dirInfo;
859
860	if (!group)
861		return EINVAL;
862
863	if (!*dir)
864		*dir = OpenGroups();
865
866	if (*dir)
867		if ((dirInfo = ReadGroup(*dir)) != NULL)
868		{
869			strcpy(group, dirInfo->d_name);
870			return B_OK;
871		}
872		else
873		{
874			CloseGroups(*dir);
875			return ENOENT;
876		}
877
878	return EINVAL;
879}
880
881int cmdWhichGroups(DIR **dir, char *user, char *group)
882{
883	int error = cmdReadGroups(dir, group);
884	while (error == B_OK)
885	{
886		if (isUserInGroup(user, group))
887			return B_OK;
888
889		error = cmdReadGroups(dir, group);
890	}
891
892	return error;
893}
894
895////////////////////////////////////////////////////////////////////
896
897void netcmdAuthenticate(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
898{
899	bt_outPacket packet;
900	int client, error;
901	char response[256];
902
903	client = session->socket;
904
905	error = cmdAuthenticate(session->client_s_addr, argv[0].data, argv[1].data, response);
906	btRPCCreateAck(&packet, xid, error);
907	if (error == B_OK)
908		btRPCPutString(&packet, response, strlen(response));
909
910	btRPCSendAck(client, &packet);
911}
912
913void netcmdReadUsers(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
914{
915	bt_outPacket packet;
916	int client, error;
917	DIR *dir = (DIR *)(*((int32 *) argv[0].data));
918	char user[MAX_USERNAME_LENGTH + 1], fullName[MAX_DESC_LENGTH + 1];
919	int entries = 0;
920
921	client = session->socket;
922
923	error = cmdReadUsers(&dir, user, fullName);
924	if (error != B_OK)
925	{
926		btRPCCreateAck(&packet, xid, error);
927		btRPCSendAck(client, &packet);
928		return;
929	}
930
931	btRPCCreateAck(&packet, xid, B_OK);
932	while (error == B_OK)
933	{
934		btRPCPutString(&packet, user, strlen(user));
935		btRPCPutString(&packet, fullName, strlen(fullName));
936
937		if (++entries >= 80)
938			break;
939
940		error = cmdReadUsers(&dir, user, fullName);
941		btRPCPutInt32(&packet, error);
942	}
943
944	// If we exhausted the list of directory entries without filling
945	// the buffer, add an error message that will prevent the client
946	// from requesting further entries.
947	if (entries < 80)
948		btRPCPutInt32(&packet, ENOENT);
949
950	btRPCSendAck(client, &packet);
951}
952
953void netcmdReadGroups(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
954{
955	bt_outPacket packet;
956	int client, error;
957	DIR *dir = (DIR *)(*((int32 *) argv[0].data));
958	char group[MAX_USERNAME_LENGTH + 1];
959	int entries = 0;
960
961	client = session->socket;
962
963	error = cmdReadGroups(&dir, group);
964	if (error != B_OK)
965	{
966		btRPCCreateAck(&packet, xid, error);
967		btRPCSendAck(client, &packet);
968		return;
969	}
970
971	btRPCCreateAck(&packet, xid, B_OK);
972	while (error == B_OK)
973	{
974		btRPCPutString(&packet, group, strlen(group));
975
976		if (++entries >= 80)
977			break;
978
979		error = cmdReadGroups(&dir, group);
980		btRPCPutInt32(&packet, error);
981	}
982
983	// If we exhausted the list of directory entries without filling
984	// the buffer, add an error message that will prevent the client
985	// from requesting further entries.
986	if (entries < 80)
987		btRPCPutInt32(&packet, ENOENT);
988
989	btRPCSendAck(client, &packet);
990}
991
992void netcmdWhichGroups(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
993{
994	bt_outPacket packet;
995	int client, error;
996	DIR *dir = 0;
997	char group[MAX_USERNAME_LENGTH + 1];
998	int entries = 0;
999
1000	client = session->socket;
1001
1002	error = cmdWhichGroups(&dir, argv[0].data, group);
1003	if (error != B_OK)
1004	{
1005		btRPCCreateAck(&packet, xid, error);
1006		btRPCSendAck(client, &packet);
1007		return;
1008	}
1009
1010	btRPCCreateAck(&packet, xid, B_OK);
1011	while (error == B_OK)
1012	{
1013		btRPCPutString(&packet, group, strlen(group));
1014
1015		if (++entries >= 80)
1016			break;
1017
1018		error = cmdWhichGroups(&dir, argv[0].data, group);
1019		btRPCPutInt32(&packet, error);
1020	}
1021
1022	// If we exhausted the list of directory entries without filling
1023	// the buffer, add an error message that will prevent the client
1024	// from requesting further entries.
1025	if (entries < 80)
1026		btRPCPutInt32(&packet, ENOENT);
1027
1028	btRPCSendAck(client, &packet);
1029}
1030
1031// netcmdQuit()
1032//
1033void netcmdQuit(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[])
1034{
1035	bt_outPacket packet;
1036	int client;
1037
1038	client = session->socket;
1039	btRPCCreateAck(&packet, xid, B_OK);
1040	btRPCSendAck(client, &packet);
1041}
1042