1/*  Copyright 1999 Peter Schlaile.
2 *  Copyright 1999-2005,2007-2009 Alain Knaff.
3 *  This file is part of mtools.
4 *
5 *  Mtools is free software: you can redistribute it and/or modify
6 *  it under the terms of the GNU General Public License as published by
7 *  the Free Software Foundation, either version 3 of the License, or
8 *  (at your option) any later version.
9 *
10 *  Mtools is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 *  GNU General Public License for more details.
14 *
15 *  You should have received a copy of the GNU General Public License
16 *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
17 *
18 * the floppyd daemon running on the local X-Server
19 *
20 * written by:
21 *
22 * Peter Schlaile
23 *
24 * udbz@rz.uni-karlsruhe.de
25 *
26 * Large parts of the network code shamelessly stolen from
27 * transproxy by John Saunders <john@nlc.net.au>
28 *
29 * Rewritten in C by Alain Knaff.  Apparently C++ is still not as
30 * portable as C.  */
31
32#define DEBUG 0
33
34#include "sysincludes.h"
35
36#ifdef USE_FLOPPYD
37
38#define USE_FLOPPYD_BUFFERED_IO  1
39#define FLOPPYD_DEFAULT_PORT     5703
40
41#include "sysincludes.h"
42#include "grp.h"
43#include <X11/Xlib.h>
44#include <X11/Xauth.h>
45
46#include "floppyd_io.h"
47
48#ifndef SIGCLD
49#define SIGCLD SIGCHLD
50#endif
51
52/* For Linux 1.2.13 */
53#ifndef SOMAXCONN
54#define SOMAXCONN 5
55#endif
56
57/*
58   To compile:
59
60   gcc -Wall floppyd.cpp -o floppyd -lX11
61
62   floppyd
63
64   Communication to the clients works the following way:
65
66   Client sends his protocol-version. If the version between server and client
67   differ: bail out.
68
69   After that,we send our .Xauthority-file (a maximum of MAX_XAUTHORITY_LENGTH
70   Bytes long) to the server.
71
72   The server then checks, if it already has a .Xauthority file. If so
73   it is interpreted as LOCK-File for the floppy-device and the communication
74   gets terminated.
75
76   (What if we have 2 floppy devices? Well. Two floppy users with different
77   home-directories should work nicely...)
78
79   Now, the data is written to the .Xauthority file. Then we try to open
80   a connection to the local X-Server. If this fails -> bail out.
81
82   ***
83
84   The data packets are built as follows:
85
86   Base-packets: 1 Dword length, then data.
87                 length is in Network-Byte order. (4 Bytes)
88
89   Commands are: 1. Packet Opcode (length 1), 1. Data packet as parameter.
90
91   Return: 1.Packet: 1. Dword: Bytes processed, 2. Dword: Error-Code
92
93   ***
94
95   TODO:
96	  * Implement some IOCTL calls to format floppy disks or so...
97	  * Read is somewhat dirty implemented. Tries multiple times to
98	    read the expected bytes from the socket stream. Don't know
99	    why this is necessary. Maybe the socket stream is nonblocking
100	    or something IT SHOULD NOT BE!
101
102*/
103
104typedef unsigned char Byte;
105typedef unsigned long Dword;
106
107
108#define MAX_XAUTHORITY_LENGTH    3000
109#define MAX_DATA_REQUEST         3000000
110#define BUFFERED_IO_SIZE         16348
111
112
113void serve_client(int sock, char **device_name, int n_dev);
114
115
116#ifdef USE_FLOPPYD_BUFFERED_IO
117typedef struct io_buffer {
118	Byte out_buffer[BUFFERED_IO_SIZE];
119	Byte in_buffer[BUFFERED_IO_SIZE];
120
121	long in_valid;
122	long in_start;
123	long out_valid;
124
125	int handle;
126} *io_buffer;
127
128static io_buffer new_io_buffer (int _handle) {
129	io_buffer buffer;
130
131	buffer = New(struct io_buffer);
132
133	buffer->handle = _handle;
134	buffer->in_valid = buffer->in_start = 0;
135	buffer->out_valid = 0;
136	return buffer;
137}
138
139
140static void flush(io_buffer buffer) {
141	if (buffer->out_valid) {
142		write(buffer->handle, buffer->out_buffer, buffer->out_valid);
143		buffer->out_valid = 0;
144	}
145}
146
147static void free_io_buffer(io_buffer buffer) {
148	flush(buffer);
149	free(buffer);
150}
151
152
153static size_t buf_read (io_buffer buf, Byte* buffer, size_t nbytes) {
154	size_t rval;
155
156	if (nbytes <= buf->in_valid) {
157		memcpy(buffer, buf->in_buffer+buf->in_start, nbytes);
158		buf->in_valid -= nbytes;
159		buf->in_start += nbytes;
160		rval = nbytes;
161	} else {
162		if (buf->in_valid)
163			memcpy(buffer, buf->in_buffer+buf->in_start,
164				   buf->in_valid);
165		nbytes -= buf->in_valid;
166		buffer += buf->in_valid;
167		if (nbytes > BUFFERED_IO_SIZE) {
168			rval = read(buf->handle, buffer, nbytes);
169			if (rval >= 0) {
170				rval += buf->in_valid;
171			}
172			buf->in_valid = buf->in_start = 0;
173		} else {
174			rval = read(buf->handle, buf->in_buffer,
175						BUFFERED_IO_SIZE);
176			if (rval >= 0) {
177				if (rval < nbytes) {
178					memcpy(buffer, buf->in_buffer, rval);
179					rval += buf->in_valid;
180					buf->in_valid = buf->in_start = 0;
181				} else {
182					size_t a;
183					memcpy(buffer, buf->in_buffer, nbytes);
184					buf->in_start = nbytes;
185					a = buf->in_valid;
186					buf->in_valid = rval-nbytes;
187					rval = a + nbytes;
188				}
189			}
190		}
191	}
192	return rval;
193}
194
195static size_t buf_write(io_buffer buf, void* buffer, size_t nbytes) {
196	if (buf->out_valid + nbytes > BUFFERED_IO_SIZE) {
197		flush(buf);
198		return write(buf->handle, buffer, nbytes);
199	}
200	memcpy(buf->out_buffer+buf->out_valid, buffer, nbytes);
201	buf->out_valid += nbytes;
202	return nbytes;
203}
204
205
206
207#else
208
209typedef int io_buffer;
210
211io_buffer new_io_buffer (int handle) {
212	return handle;
213}
214
215
216size_t buf_read (io_buffer handle, Byte* buffer, size_t nbytes) {
217	return (read(handle, buffer, nbytes));
218}
219
220size_t buf_write(io_buffer handle, void* buffer, size_t nbytes) {
221	return (write(handle, buffer, nbytes));
222}
223
224
225void free_io_buffer(io_buffer buffer) { }
226
227
228void flush(io_buffer buffer) { }
229
230#endif
231
232typedef struct Packet {
233	Byte* data;
234	Dword len;
235	Dword alloc_size;
236} *Packet;
237
238#include "byte_dword.h"
239
240static Dword read_dword(io_buffer fp)
241{
242	Byte val[4];
243	if (buf_read(fp, val, 4) < 4) {
244		return 0xffffffff;
245	}
246
247	return byte2dword(val);
248}
249
250static void write_dword(io_buffer fp, Dword parm)
251{
252	Byte val[4];
253
254	dword2byte(parm, val);
255
256	buf_write(fp, val,4);
257}
258
259
260static Packet newPacket(void)
261{
262	Packet packet;
263
264	packet = New(struct Packet);
265	packet->data = NULL;
266	packet->len = packet->alloc_size = 0;
267	return packet;
268}
269
270
271static void destroyPacket(Packet packet)
272{
273	if(packet->data)
274		free(packet->data);
275	free(packet);
276}
277
278static void kill_packet(Packet packet)
279{
280	if(packet->data)
281		free(packet->data);
282	packet->data = NULL;
283	packet->len = 0;
284	packet->alloc_size = 0;
285}
286
287static void make_new(Packet packet, unsigned long l)
288{
289	if (l < packet->alloc_size) {
290		packet->len = l;
291		return;
292	}
293	kill_packet(packet);
294	packet->len = packet->alloc_size = l;
295	packet->data = malloc(l);
296	memset(packet->data, 0, l);
297}
298
299static char send_packet(Packet packet, io_buffer fp)
300{
301	if (packet->data) {
302		write_dword(fp, packet->len);
303		buf_write(fp, packet->data, packet->len);
304		flush(fp);
305#if DEBUG
306		fprintf(stderr, "send_packet(): Size: %li\n", packet->len);
307#endif
308
309#if DEBUG
310		fprintf(stderr, "send_packet(): ");
311		for (int i = 0; i < packet->len; i++) {
312			fprintf(stderr, "%d ", packet->data[i]);
313		}
314		fprintf(stderr, "\n");
315#endif
316
317	}
318	return (packet->data != NULL);
319}
320
321static char recv_packet(Packet packet, io_buffer fp, Dword maxlength)
322{
323	int start;
324	int l;
325	Dword length = read_dword(fp);
326#if DEBUG
327	fprintf(stderr, "recv_packet(): Size: %li\n", length);
328#endif
329	if (length > maxlength || length == 0xffffffff ) {
330		return 0;
331	}
332	make_new(packet, length);
333	l = 0;
334	for (start = 0; start < length; start += l) {
335		l = buf_read(fp, packet->data+start, length-start);
336		if (l == 0) {
337			return 0;
338		}
339	}
340	if (packet->len == 0) {
341		return 0;
342	}
343#if DEBUG
344	fprintf(stderr, "*** read: %li\n", packet->len);
345#endif
346
347#if DEBUG
348	fprintf(stderr, "recv_packet(): ");
349	for (i = 0; i < packet->len; i++) {
350		fprintf(stderr, "%d ", packet->data[i]);
351	}
352	fprintf(stderr, "\n");
353#endif
354	return 1;
355}
356
357static void read_packet(Packet packet, int fd, int length) {
358	make_new(packet, length);
359	packet->len = read(fd, packet->data, packet->len);
360}
361
362static int write_packet(Packet packet, int fd) {
363	return (write(fd, packet->data, packet->len));
364}
365
366static void put_dword(Packet packet, int my_index, Dword val) {
367	dword2byte(val, packet->data+my_index);
368}
369
370static Dword get_dword(Packet packet, int my_index) {
371	return byte2dword(packet->data+my_index);
372}
373
374static Dword get_length(Packet packet) {
375	return packet->len;
376}
377
378static int eat(char **ptr, int *len, unsigned char c) {
379    /* remove length + size code + terminating 0 */
380    if (*len < c + 3)
381	return -1;
382    (*ptr) += c + 2;
383    (*len) -= c + 2;
384    return 0;
385}
386
387static const char *dispName;
388
389static char XAUTHORITY[]="XAUTHORITY";
390
391static char do_auth(io_buffer sock, int *version)
392{
393	int fd;
394	Display* displ;
395	Packet proto_version = newPacket();
396	Packet mit_cookie;
397	char *ptr;
398	int len;
399
400	char authFile[41]="/tmp/floppyd.XXXXXX";
401	char template[4096];
402
403	Packet reply = newPacket();
404
405	make_new(reply, 4);
406
407	if (!recv_packet(proto_version, sock, 4)) {
408		put_dword(reply, 0, AUTH_PACKETOVERSIZE);
409		send_packet(reply, sock);
410		destroyPacket(reply);
411		destroyPacket(proto_version);
412		return 0;
413	}
414
415	*version = get_dword(proto_version, 0);
416	if (*version > FLOPPYD_PROTOCOL_VERSION ||
417	    *version < FLOPPYD_PROTOCOL_VERSION_OLD) {
418		/* fail if client requests a newer version than us */
419		put_dword(reply, 0, AUTH_WRONGVERSION);
420		send_packet(reply, sock);
421		destroyPacket(reply);
422		destroyPacket(proto_version);
423		return 0;
424	}
425
426	if(*version == FLOPPYD_PROTOCOL_VERSION_OLD) {
427		put_dword(reply, 0, AUTH_SUCCESS);
428	} else {
429		make_new(reply, 12);
430		put_dword(reply, 0, AUTH_SUCCESS);
431		put_dword(reply, 4, FLOPPYD_PROTOCOL_VERSION);
432		put_dword(reply, 8, FLOPPYD_CAP_EXPLICIT_OPEN);
433	}
434	send_packet(reply, sock);
435	destroyPacket(proto_version);
436
437	make_new(reply, 4);
438	mit_cookie = newPacket();
439	if (!recv_packet(mit_cookie, sock, MAX_XAUTHORITY_LENGTH)) {
440		put_dword(reply, 0, AUTH_PACKETOVERSIZE);
441		send_packet(reply, sock);
442		destroyPacket(reply);
443		destroyPacket(mit_cookie);
444		return 0;
445	}
446
447	umask(077);
448	fd = mkstemp(authFile);
449	if(fd == -1) {
450		/* Different error than file exists */
451		put_dword(reply, 0, AUTH_DEVLOCKED);
452		send_packet(reply, sock);
453		close(fd);
454		destroyPacket(reply);
455		destroyPacket(mit_cookie);
456		return 0;
457	}
458#ifdef HAVE_SETENV
459	setenv(XAUTHORITY, authFile, 1);
460#else
461	{
462	  char *buffer=malloc(strlen(XAUTHORITY)+strlen(authFile)+2);
463	  strcpy(buffer, XAUTHORITY);
464	  strcat(buffer, "=");
465	  strcat(buffer, authFile);
466	  putenv(buffer);
467	}
468#endif
469
470	ptr = template;
471	ptr[4095] = 0;
472	*ptr++ = 1;
473	*ptr++ = 0;
474	*ptr++ = 0;
475	gethostname(ptr+1, 4088);
476	len = strlen(ptr+1);
477	*ptr++ = len;
478	ptr += len;
479	*ptr++ = 0;
480	*ptr++ = 1;
481	*ptr++ = '0'; /* Display number */
482	*ptr++ = '\0';
483
484	write(fd, template, len+8);
485	ptr = (char *)mit_cookie->data;
486	len = mit_cookie->len;
487
488	if (eat(&ptr,&len,1) ||    /* the "type"    */
489	    eat(&ptr,&len,*ptr) || /* the hostname  */
490	    eat(&ptr,&len,*ptr)) { /* the display number */
491	    destroyPacket(mit_cookie);
492	    unlink(XauFileName());
493	    put_dword(reply, 0, AUTH_BADPACKET);
494	    send_packet(reply, sock);
495	    destroyPacket(reply);
496	    return 0;
497	}
498
499	write(fd, ptr, len);
500	close(fd);
501
502	destroyPacket(mit_cookie);
503
504	displ = XOpenDisplay(dispName);
505	if (!displ) {
506		unlink(XauFileName());
507		put_dword(reply, 0, AUTH_AUTHFAILED);
508		send_packet(reply, sock);
509		destroyPacket(reply);
510		return 0;
511	}
512	XCloseDisplay(displ);
513
514	put_dword(reply, 0, AUTH_SUCCESS);
515	send_packet(reply, sock);
516	destroyPacket(reply);
517	unlink(XauFileName());
518	return 1;
519}
520
521/*
522 * Return the port number, in network order, of the specified service.
523 */
524static short getportnum(char *portnum)
525{
526	char			*digits = portnum;
527	struct servent	*serv;
528	short			port;
529
530	for (port = 0; isdigit(*digits); ++digits)
531		{
532			port = (port * 10) + (*digits - '0');
533		}
534
535	if ((*digits != '\0') || (port <= 0))
536		{
537			if ((serv = getservbyname(portnum, "tcp")) != NULL)
538				{
539					port = ntohs(serv->s_port);
540				}
541			else
542				{
543					port = -1;
544				}
545			endservent();
546		}
547
548#if DEBUG
549	fprintf(stderr, "Port lookup %s -> %hd\n", portnum, port);
550#endif
551
552	return (port);
553}
554
555/*
556 * Return the IP address of the specified host.
557 */
558static IPaddr_t getipaddress(char *ipaddr)
559{
560	struct hostent	*host;
561	IPaddr_t ip;
562
563	if (((ip = inet_addr(ipaddr)) == INADDR_NONE)
564	    &&
565		(strcmp(ipaddr, "255.255.255.255") != 0))
566		{
567			if ((host = gethostbyname(ipaddr)) != NULL)
568				{
569					memcpy(&ip, host->h_addr, sizeof(ip));
570				}
571			endhostent();
572		}
573
574#if DEBUG
575	fprintf(stderr, "IP lookup %s -> 0x%08lx\n", ipaddr, ip);
576#endif
577
578	return (ip);
579}
580
581/*
582 * Find the userid of the specified user.
583 */
584static uid_t getuserid(char *user)
585{
586	struct passwd	*pw;
587	uid_t			uid;
588
589	if ((pw = getpwnam(user)) != NULL)
590		{
591			uid = pw->pw_uid;
592		}
593	else if (*user == '#')
594		{
595			uid = (uid_t)atoi(&user[1]);
596		}
597	else
598		{
599#ifdef HAVE_GETUSERID
600			id = getuserid("nobody");
601#else
602			uid = 65535;
603#endif
604		}
605
606#if DEBUG
607	fprintf(stderr, "User lookup %s -> %d\n", user, uid);
608#endif
609
610	endpwent();
611
612	return (uid);
613}
614
615/*
616 * Find the groupid of the specified user.
617 */
618static uid_t getgroupid(uid_t uid)
619{
620	struct passwd	*pw;
621	gid_t			gid;
622
623	if ((pw = getpwuid(uid)) != NULL)
624		{
625			gid = pw->pw_gid;
626		}
627	else
628		{
629#ifdef HAVE_GETGROUPID
630			id = getgroupid(uid);
631#else
632			gid = 65535;
633#endif
634		}
635
636#if DEBUG
637	fprintf(stderr, "Group lookup %d -> %d\n", uid, gid);
638#endif
639
640	endpwent();
641
642	return (gid);
643}
644
645/*
646 * Bind to the specified ip and port.
647 */
648static int bind_to_port(IPaddr_t bind_ip, short bind_port)
649{
650	struct sockaddr_in	addr;
651	int					sock;
652
653	/*
654	 * Allocate a socket.
655	 */
656	if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
657		{
658			perror("socket()");
659			exit(1);
660		}
661
662	/*
663	 * Set the SO_REUSEADDR option for debugging.
664	 */
665	{
666	 	int	on = 1;
667		setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
668				   (char *)&on, sizeof(on));
669	}
670
671	/*
672	 * Set the address to listen to.
673	 */
674	addr.sin_family = AF_INET;
675	addr.sin_port = htons(bind_port);
676	addr.sin_addr.s_addr = bind_ip;
677
678	/*
679	 * Bind our socket to the above address.
680	 */
681	if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
682		{
683			perror("bind()");
684			exit(1);
685		}
686
687	/*
688	 * Establish a large listen backlog.
689	 */
690	if (listen(sock, SOMAXCONN) < 0)
691		{
692			perror("listen()");
693			exit(1);
694		}
695
696	return (sock);
697}
698
699static int sockethandle_now = -1;
700
701/*
702 * Catch alarm signals and exit.
703 */
704static void alarm_signal(int a)
705{
706	if (sockethandle_now != -1) {
707		close(sockethandle_now);
708		sockethandle_now = -1;
709		unlink(XauFileName());
710	}
711	exit(1);
712}
713
714
715/*
716 * This is the main loop when running as a server.
717 */
718static void server_main_loop(int sock, char **device_name, int n_dev)
719{
720	struct sockaddr_in	addr;
721	unsigned int		len;
722
723	/*
724	 * Ignore dead servers so no zombies should be left hanging.
725	 */
726	signal(SIGCLD, SIG_IGN);
727
728	for (;;) {
729		int					new_sock;
730		/*
731		 * Accept an incoming connection.
732		 */
733		len = sizeof(addr);
734		while ((new_sock = accept(sock, (struct sockaddr *)&addr, &len)) < 0){}
735
736		/*
737		 * Create a new process to handle the connection.
738		 */
739#if DEBUG == 0
740		switch (fork()) {
741			case -1:
742				/*
743				 * Under load conditions just ignore new connections.
744				 */
745				break;
746
747			case 0:
748				/*
749				 * Start the proxy work in the new socket.
750				 */
751#endif
752				serve_client(new_sock,device_name, n_dev);
753				exit(0);
754#if DEBUG == 0
755		}
756#endif
757		/*
758		 * Close the socket as the child does the handling.
759		 */
760		close(new_sock);
761		new_sock = -1;
762	}
763}
764
765/*
766 * Print some basic help information.
767 */
768static void usage(char *prog, const char *opt, int ret)
769{
770	if (opt)
771		{
772			fprintf(stderr, "%s: %s\n", prog, opt);
773		}
774	fprintf(stderr, "usage: %s [-s port [-r user] [-b ipaddr]] devicename [Names of local host]\n",
775			prog);
776	fprintf(stderr, "    -d          Run as a server (default port 5703 + DISPLAY)\n");
777	fprintf(stderr, "    -s port     Run as a server bound to the specified port.\n");
778	fprintf(stderr, "    -r user     Run as the specified user in server mode.\n");
779	fprintf(stderr, "    -b ipaddr   Bind to the specified ipaddr in server mode.\n");
780	fprintf(stderr, "    -l          Do not attempt to connect to localhost:0 to validate connection\n");
781	exit(ret);
782}
783
784
785static char *makeDisplayName(int dispNr)
786{
787	char result[80];
788	sprintf(result, ":%d.0", dispNr);
789	return strdup(result);
790}
791
792int main (int argc, char** argv)
793{
794	int sockfd = 0;
795	int			arg;
796	int			run_as_server = 0;
797	IPaddr_t		bind_ip = INADDR_ANY;
798	unsigned short		bind_port = 0;
799	uid_t			run_uid = 65535;
800	gid_t			run_gid = 65535;
801	char*			username = strdup("nobody");
802	int			sock;
803	int			port_is_supplied = 0;
804
805	char *server_hostname=NULL;
806	char **device_name = NULL;
807	const char *floppy0 = "/dev/fd0";
808	int n_dev;
809
810
811	/*
812	 * Parse the command line arguments.
813	 */
814	if(argc > 1 && !strcmp(argv[0], "--help"))
815		usage(argv[0], NULL, 0);
816	while ((arg = getopt(argc, argv, "ds:r:b:x:h")) != EOF)
817		{
818			switch (arg)
819				{
820					case 'd':
821						run_as_server = 1;
822						break;
823					case 's':
824						run_as_server = 1;
825						port_is_supplied = 1;
826						bind_port = getportnum(optarg);
827						break;
828
829					case 'r':
830						free(username); username = strdup(optarg);
831						run_uid = getuserid(optarg);
832						run_gid = getgroupid(run_uid);
833						break;
834
835					case 'b':
836						run_as_server = 1;
837						bind_ip = getipaddress(optarg);
838						server_hostname=optarg;
839						break;
840					case 'x':
841						dispName = strdup(optarg);
842						break;
843
844					case 'h':
845						usage(argv[0], NULL, 0);
846						break;
847					case '?':
848						usage(argv[0], NULL, 1);
849						break;
850				}
851		}
852
853	if(optind < argc) {
854		device_name = argv + optind;
855		n_dev = argc - optind;
856	} else {
857		device_name = (char **)&floppy0;
858		n_dev = 1;
859	}
860
861	if(dispName == NULL)
862		dispName = getenv("DISPLAY");
863	if(dispName==NULL && bind_port != 0)
864		dispName=makeDisplayName((unsigned short)(bind_port - 5703));
865	if(dispName==NULL)
866		dispName=":0";
867
868	if(bind_port == 0) {
869		char *p = strchr(dispName,':');
870		bind_port = FLOPPYD_DEFAULT_PORT;
871		if(p != NULL)
872			bind_port += atoi(p+1);
873	}
874
875	if(!run_as_server) {
876		struct sockaddr_in	addr;
877		unsigned int len = sizeof(addr);
878
879		/* try to find out port that we are connected to */
880		if(getsockname(0, (struct sockaddr*) &addr, &len) >= 0 &&
881		   len == sizeof(addr)) {
882			port_is_supplied = 1;
883			bind_port = ntohs(addr.sin_port);
884			server_hostname = strdup(inet_ntoa(addr.sin_addr));
885		}
886	}
887
888	umask(0077);
889
890	/*
891	 * Test to make sure required args were provided and are valid.
892	 */
893	if (run_as_server && (bind_ip == INADDR_NONE)) {
894		usage(argv[0], "The server ipaddr is invalid.", 1);
895	}
896	if (run_as_server && (bind_port == 0))	{
897		usage(argv[0], "No server port was specified (or it was invalid).", 1);
898	}
899
900
901	/*
902	 * See if we should run as a server.
903	 */
904	if (run_as_server) {
905		/*
906		 * Start by binding to the port, the child inherits this socket.
907		 */
908		sock = bind_to_port(bind_ip, bind_port);
909
910		/*
911		 * Start a server process. When DEBUG is defined, just run
912		 * in the foreground.
913		 */
914#if DEBUG
915		switch (0)
916#else
917			switch (fork())
918#endif
919				{
920				case -1:
921					perror("fork()");
922					exit(1);
923
924				case 0:
925					/*
926					 * Ignore some signals.
927					 */
928					signal(SIGHUP, SIG_IGN);
929#if DEBUG
930					signal(SIGINT, SIG_IGN);
931#endif
932					signal(SIGQUIT, SIG_IGN);
933					signal(SIGTSTP, SIG_IGN);
934					signal(SIGCONT, SIG_IGN);
935					signal(SIGPIPE, alarm_signal);
936					/*signal(SIGALRM, alarm_signal);*/
937
938					/*
939					 * Drop back to an untrusted user.
940					 */
941					setgid(run_gid);
942					initgroups(username, -1);
943					setuid(run_uid);
944
945					/*
946					 * Start a new session and group.
947					 */
948					setsid();
949#ifdef HAVE_SETPGRP
950#ifdef SETPGRP_VOID
951					setpgrp();
952#else
953					setpgrp(0,0);
954#endif
955#endif
956#if DEBUG
957					close(2);
958					open("/dev/null", O_WRONLY);
959#endif
960					/*
961					 * Handle the server main loop.
962					 */
963					server_main_loop(sock, device_name, n_dev);
964
965					/*
966					 * Should never exit.
967					 */
968					exit(1);
969				}
970
971		/*
972		 * Parent exits at this stage.
973		 */
974		exit(0);
975	}
976
977	signal(SIGHUP, alarm_signal);
978#if DEBUG == 0
979	signal(SIGINT, alarm_signal);
980#endif
981	signal(SIGQUIT, alarm_signal);
982	signal(SIGTERM, alarm_signal);
983	signal(SIGTSTP, SIG_IGN);
984	signal(SIGCONT, SIG_IGN);
985	signal(SIGPIPE, alarm_signal);
986	/*signal(SIGALRM, alarm_signal);*/
987
988#if DEBUG == 0
989	close(2);
990	open("/dev/null", O_WRONLY);
991#endif
992	/* Starting from inetd */
993
994	serve_client(sockfd, device_name, n_dev);
995	return 0;
996}
997
998static void send_reply(int rval, io_buffer sock, int len) {
999	Packet reply = newPacket();
1000
1001	make_new(reply, 8);
1002	put_dword(reply, 0, len);
1003	if (rval == -1) {
1004		put_dword(reply, 4, 0);
1005	} else {
1006		put_dword(reply, 4, errno);
1007	}
1008	send_packet(reply, sock);
1009	destroyPacket(reply);
1010}
1011
1012static void cleanup(int x) {
1013	unlink(XauFileName());
1014	exit(-1);
1015}
1016
1017#include "lockdev.h"
1018
1019void serve_client(int sockhandle, char **device_name, int n_dev) {
1020	Packet opcode;
1021	Packet parm;
1022
1023	int readOnly;
1024	int devFd;
1025	io_buffer sock;
1026	int stopLoop;
1027	int version;
1028	int needSendReply=0;
1029	int rval=0;
1030
1031	/*
1032	 * Set the keepalive socket option to on.
1033	 */
1034	{
1035		int		on = 1;
1036		setsockopt(sockhandle, SOL_SOCKET,
1037				   SO_KEEPALIVE, (char *)&on, sizeof(on));
1038	}
1039
1040	sock = new_io_buffer(sockhandle);
1041
1042	/*
1043	 * Allow 60 seconds for any activity.
1044	 */
1045	alarm(60);
1046
1047	version = 0;
1048	if (!do_auth(sock, &version)) {
1049		free_io_buffer(sock);
1050		return;
1051	}
1052	alarm(0);
1053
1054
1055	signal(SIGTERM, cleanup);
1056	signal(SIGALRM, cleanup);
1057
1058
1059
1060	sockethandle_now = sockhandle;
1061
1062
1063	opcode = newPacket();
1064	parm = newPacket();
1065
1066	devFd = -1;
1067	readOnly = 1;
1068
1069	stopLoop = 0;
1070	if(version == FLOPPYD_PROTOCOL_VERSION_OLD) {
1071				/* old protocol */
1072		readOnly = 0;
1073		devFd = open(device_name[0], O_RDWR);
1074
1075		if (devFd < 0) {
1076			readOnly = 1;
1077			devFd = open(device_name[0],
1078				     O_RDONLY);
1079		}
1080		if(devFd < 0) {
1081			send_reply(0, sock, devFd);
1082			stopLoop = 1;
1083		}
1084		lock_dev(devFd, !readOnly, NULL);
1085	}
1086
1087
1088	while(!stopLoop) {
1089		int dev_nr = 0;
1090		/*
1091		 * Allow 60 seconds for any activity.
1092		 */
1093		/*alarm(60);*/
1094
1095		if (!recv_packet(opcode, sock, 1)) {
1096			break;
1097		}
1098/*		if(opcode->data[0] != OP_CLOSE)*/
1099		    recv_packet(parm, sock, MAX_DATA_REQUEST);
1100
1101
1102		switch(opcode->data[0]) {
1103			case OP_OPRO:
1104				if(get_length(parm) >= 4)
1105					dev_nr = get_dword(parm,0);
1106				else
1107					dev_nr = 0;
1108				if(dev_nr >= n_dev) {
1109					send_reply(0, sock, -1);
1110					break;
1111				}
1112
1113				devFd = open(device_name[dev_nr], O_RDONLY);
1114#if DEBUG
1115				fprintf(stderr, "Device opened\n");
1116#endif
1117				if(devFd >= 0 && lock_dev(devFd, 0, NULL)) {
1118					send_reply(0, sock, -1);
1119					break;
1120				}
1121				send_reply(0, sock, devFd);
1122				readOnly = 1;
1123				break;
1124			case OP_OPRW:
1125				if(get_length(parm) >= 4)
1126					dev_nr = get_dword(parm,0);
1127				else
1128					dev_nr = 0;
1129				if(dev_nr >= n_dev) {
1130					send_reply(0, sock, -1);
1131					break;
1132				}
1133				devFd = open(device_name[dev_nr], O_RDWR);
1134				if(devFd >= 0 && lock_dev(devFd, 1, NULL)) {
1135					send_reply(0, sock, -1);
1136					break;
1137				}
1138				send_reply(0, sock, devFd);
1139				readOnly = 0;
1140				break;
1141			case OP_READ:
1142#if DEBUG
1143				fprintf(stderr, "READ:\n");
1144#endif
1145				read_packet(parm, devFd, get_dword(parm, 0));
1146				send_reply(devFd, sock, get_length(parm));
1147				if(get_length(parm) >= 0)
1148					send_packet(parm, sock);
1149				break;
1150			case OP_WRITE:
1151#if DEBUG
1152				fprintf(stderr, "WRITE:\n");
1153#endif
1154				if(readOnly) {
1155					errno = -EROFS;
1156					rval = -1;
1157				} else {
1158					rval = write_packet(parm, devFd);
1159				}
1160				send_reply(devFd, sock, rval);
1161				break;
1162			case OP_SEEK:
1163#if DEBUG
1164				fprintf(stderr, "SEEK:\n");
1165#endif
1166
1167				lseek(devFd,
1168				      get_dword(parm, 0), get_dword(parm, 4));
1169				send_reply(devFd,
1170					   sock,
1171					   lseek(devFd, 0, SEEK_CUR));
1172				break;
1173			case OP_FLUSH:
1174#if DEBUG
1175				fprintf(stderr, "FLUSH:\n");
1176#endif
1177				fsync(devFd);
1178				send_reply(devFd, sock, 0);
1179				break;
1180			case OP_CLOSE:
1181#if DEBUG
1182				fprintf(stderr, "CLOSE:\n");
1183#endif
1184
1185				close(devFd);
1186				needSendReply = 1;
1187				rval = devFd;
1188				devFd = -1;
1189				stopLoop = 1;
1190				break;
1191			case OP_IOCTL:
1192				/* Unimplemented for now... */
1193				break;
1194			default:
1195#if DEBUG
1196				fprintf(stderr, "Invalid Opcode!\n");
1197#endif
1198				errno = EINVAL;
1199				send_reply(devFd, sock, -1);
1200				break;
1201		}
1202		kill_packet(parm);
1203		alarm(0);
1204	}
1205
1206
1207
1208#if DEBUG
1209	fprintf(stderr, "Closing down...\n");
1210#endif
1211
1212	if (devFd >= 0) {
1213		close(devFd);
1214		devFd = -1;
1215	}
1216
1217	free_io_buffer(sock);
1218
1219	/* remove "Lock"-File  */
1220	unlink(XauFileName());
1221
1222	if(needSendReply)
1223	    send_reply(rval, sock, 0);
1224	destroyPacket(opcode);
1225	destroyPacket(parm);
1226}
1227
1228#else
1229#include <stdio.h>
1230
1231int main(int argc, char **argv)
1232{
1233	puts("Floppyd support not included!");
1234	return -1;
1235}
1236
1237#endif
1238