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 #include "llong.h"
36 
37 #ifdef USE_FLOPPYD
38 
39 #define USE_FLOPPYD_BUFFERED_IO  1
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 
104 
105 #define MAX_XAUTHORITY_LENGTH    3000
106 #define MAX_DATA_REQUEST         3000000
107 #define BUFFERED_IO_SIZE         16348
108 
109 unsigned int mtools_lock_timeout=30;
110 
111 void serve_client(int sock, char **device_name, unsigned int n_dev,
112 		  int close_stderr);
113 
114 
115 #ifdef USE_FLOPPYD_BUFFERED_IO
116 typedef struct io_buffer {
117 	Byte out_buffer[BUFFERED_IO_SIZE];
118 	Byte in_buffer[BUFFERED_IO_SIZE];
119 
120 	size_t in_valid;
121 	size_t in_start;
122 	size_t out_valid;
123 
124 	int handle;
125 } *io_buffer;
126 
new_io_buffer(int _handle)127 static io_buffer new_io_buffer (int _handle) {
128 	io_buffer buffer;
129 
130 	buffer = New(struct io_buffer);
131 
132 	buffer->handle = _handle;
133 	buffer->in_valid = buffer->in_start = 0;
134 	buffer->out_valid = 0;
135 	return buffer;
136 }
137 
138 
flush(io_buffer buffer)139 static void flush(io_buffer buffer) {
140 	if (buffer->out_valid) {
141 		if(write(buffer->handle, buffer->out_buffer, buffer->out_valid) < 0) {
142 			perror("floppyd flush");
143 		}
144 		buffer->out_valid = 0;
145 	}
146 }
147 
free_io_buffer(io_buffer buffer)148 static void free_io_buffer(io_buffer buffer) {
149 	flush(buffer);
150 	free(buffer);
151 }
152 
153 
buf_read(io_buffer buf,Byte * buffer,size_t nbytes)154 static size_t buf_read (io_buffer buf, Byte* buffer, size_t nbytes) {
155 	size_t ret;
156 
157 	if (nbytes <= buf->in_valid) {
158 		memcpy(buffer, buf->in_buffer+buf->in_start, nbytes);
159 		buf->in_valid -= nbytes;
160 		buf->in_start += nbytes;
161 		ret = nbytes;
162 	} else {
163 		if (buf->in_valid)
164 			memcpy(buffer, buf->in_buffer+buf->in_start,
165 				   buf->in_valid);
166 		nbytes -= buf->in_valid;
167 		buffer += buf->in_valid;
168 		if (nbytes > BUFFERED_IO_SIZE) {
169 			ssize_t rval = read(buf->handle, buffer, nbytes);
170 			if (rval >= 0) {
171 				ret = (size_t) rval + buf->in_valid;
172 			} else {
173 				perror("read error");
174 				exit(1);
175 			}
176 			buf->in_valid = buf->in_start = 0;
177 		} else {
178 			ssize_t rval = read(buf->handle, buf->in_buffer,
179 					    BUFFERED_IO_SIZE);
180 			if (rval >= 0) {
181 				if (rval < (ssize_t) nbytes) {
182 					memcpy(buffer, buf->in_buffer,
183 					       (size_t) rval);
184 					ret = (size_t) rval + buf->in_valid;
185 					buf->in_valid = buf->in_start = 0;
186 				} else {
187 					size_t a;
188 					memcpy(buffer, buf->in_buffer, nbytes);
189 					buf->in_start = nbytes;
190 					a = buf->in_valid;
191 					buf->in_valid = (size_t) rval-nbytes;
192 					ret = a + nbytes;
193 				}
194 			} else {
195 				perror("read error");
196 				exit(1);
197 			}
198 		}
199 	}
200 	return ret;
201 }
202 
buf_write(io_buffer buf,void * buffer,size_t nbytes)203 static ssize_t buf_write(io_buffer buf, void* buffer, size_t nbytes) {
204 	if (buf->out_valid + nbytes > BUFFERED_IO_SIZE) {
205 		flush(buf);
206 		return write(buf->handle, buffer, nbytes);
207 	}
208 	memcpy(buf->out_buffer+buf->out_valid, buffer, nbytes);
209 	buf->out_valid += nbytes;
210 	return (ssize_t) nbytes;
211 }
212 
213 
214 
215 #else
216 
217 typedef int io_buffer;
218 
new_io_buffer(int handle)219 io_buffer new_io_buffer (int handle) {
220 	return handle;
221 }
222 
223 
buf_read(io_buffer handle,Byte * buffer,size_t nbytes)224 size_t buf_read (io_buffer handle, Byte* buffer, size_t nbytes) {
225 	return (read(handle, buffer, nbytes));
226 }
227 
buf_write(io_buffer handle,void * buffer,size_t nbytes)228 ssize_t buf_write(io_buffer handle, void* buffer, size_t nbytes) {
229 	return (write(handle, buffer, nbytes));
230 }
231 
232 
free_io_buffer(io_buffer buffer)233 void free_io_buffer(io_buffer buffer) { }
234 
235 
flush(io_buffer buffer)236 void flush(io_buffer buffer) { }
237 
238 #endif
239 
240 typedef struct Packet {
241 	Byte* data;
242 	Dword len;
243 	Dword alloc_size;
244 } *Packet;
245 
246 #include "byte_dword.h"
247 
read_dword(io_buffer fp)248 static Dword read_dword(io_buffer fp)
249 {
250 	Byte val[4];
251 	if (buf_read(fp, val, 4) < 4) {
252 		return 0xffffffff;
253 	}
254 
255 	return byte2dword(val);
256 }
257 
write_dword(io_buffer fp,Dword parm)258 static void write_dword(io_buffer fp, Dword parm)
259 {
260 	Byte val[4];
261 
262 	dword2byte(parm, val);
263 
264 	buf_write(fp, val,4);
265 }
266 
267 
newPacket(void)268 static Packet newPacket(void)
269 {
270 	Packet packet;
271 
272 	packet = New(struct Packet);
273 	packet->data = NULL;
274 	packet->len = packet->alloc_size = 0;
275 	return packet;
276 }
277 
278 
destroyPacket(Packet packet)279 static void destroyPacket(Packet packet)
280 {
281 	if(packet->data)
282 		free(packet->data);
283 	free(packet);
284 }
285 
kill_packet(Packet packet)286 static void kill_packet(Packet packet)
287 {
288 	if(packet->data)
289 		free(packet->data);
290 	packet->data = NULL;
291 	packet->len = 0;
292 	packet->alloc_size = 0;
293 }
294 
make_new(Packet packet,Dword l)295 static void make_new(Packet packet, Dword l)
296 {
297 	if (l < packet->alloc_size) {
298 		packet->len = l;
299 		return;
300 	}
301 	kill_packet(packet);
302 	packet->len = packet->alloc_size = l;
303 	packet->data = malloc(l);
304 	memset(packet->data, 0, l);
305 }
306 
send_packet(Packet packet,io_buffer fp)307 static char send_packet(Packet packet, io_buffer fp)
308 {
309 	if (packet->data) {
310 		write_dword(fp, packet->len);
311 		buf_write(fp, packet->data, packet->len);
312 		flush(fp);
313 #if DEBUG
314 		fprintf(stderr, "send_packet(): Size: %li\n", packet->len);
315 #endif
316 
317 #if DEBUG
318 		fprintf(stderr, "send_packet(): ");
319 		for (int i = 0; i < packet->len; i++) {
320 			fprintf(stderr, "%d ", packet->data[i]);
321 		}
322 		fprintf(stderr, "\n");
323 #endif
324 
325 	}
326 	return (packet->data != NULL);
327 }
328 
recv_packet(Packet packet,io_buffer fp,Dword maxlength)329 static char recv_packet(Packet packet, io_buffer fp, Dword maxlength)
330 {
331 	Dword start;
332 	size_t l;
333 	Dword length = read_dword(fp);
334 #if DEBUG
335 	fprintf(stderr, "recv_packet(): Size: %li\n", length);
336 #endif
337 	if (length > maxlength || length == 0xffffffff ) {
338 		return 0;
339 	}
340 	make_new(packet, length);
341 	l = 0;
342 	for (start = 0; start < length; start += l) {
343 		l = buf_read(fp, packet->data+start, length-start);
344 		if (l == 0) {
345 			return 0;
346 		}
347 	}
348 	if (packet->len == 0) {
349 		return 0;
350 	}
351 #if DEBUG
352 	fprintf(stderr, "*** read: %li\n", packet->len);
353 #endif
354 
355 #if DEBUG
356 	fprintf(stderr, "recv_packet(): ");
357 	for (i = 0; i < packet->len; i++) {
358 		fprintf(stderr, "%d ", packet->data[i]);
359 	}
360 	fprintf(stderr, "\n");
361 #endif
362 	return 1;
363 }
364 
read_packet(Packet packet,int fd,Dword length)365 static ssize_t read_packet(Packet packet, int fd, Dword length) {
366 	ssize_t ret;
367 	make_new(packet, length);
368 	ret = read(fd, packet->data, packet->len);
369 	if(ret < 0)
370 		return ret;
371 	packet->len = (Dword) ret;
372 	return 0;
373 }
374 
write_packet(Packet packet,int fd)375 static int write_packet(Packet packet, int fd) {
376 	return (int)write(fd, packet->data, packet->len);
377 }
378 
put_dword(Packet packet,int my_index,Dword val)379 static void put_dword(Packet packet, int my_index, Dword val) {
380 	dword2byte(val, packet->data+my_index);
381 }
382 
put_qword(Packet packet,int my_index,Qword val)383 static void put_qword(Packet packet, int my_index, Qword val) {
384 	qword2byte(val, packet->data+my_index);
385 }
386 
get_dword(Packet packet,int my_index)387 static Dword get_dword(Packet packet, int my_index) {
388 	return byte2dword(packet->data+my_index);
389 }
390 
get_qword(Packet packet,int my_index)391 static Qword get_qword(Packet packet, int my_index) {
392 	return byte2qword(packet->data+my_index);
393 }
394 
get_length(Packet packet)395 static Dword get_length(Packet packet) {
396 	return packet->len;
397 }
398 
eat(unsigned char ** ptr,size_t * len,unsigned char c)399 static int eat(unsigned char **ptr, size_t *len, unsigned char c) {
400     /* remove length + size code + terminating 0 */
401     if (*len < c + 3)
402 	return -1;
403     (*ptr) += c + 2;
404     (*len) -= c + 2;
405     return 0;
406 }
407 
408 static const char *dispName;
409 
410 static char XAUTHORITY[]="XAUTHORITY";
411 
do_auth(io_buffer sock,unsigned int * version)412 static char do_auth(io_buffer sock, unsigned int *version)
413 {
414 	int fd;
415 	Display* displ;
416 	Packet proto_version = newPacket();
417 	Packet mit_cookie;
418 	unsigned char *ptr;
419 	size_t len;
420 
421 	char authFile[41]="/tmp/floppyd.XXXXXX";
422 	unsigned char template[4096];
423 
424 	Packet reply = newPacket();
425 
426 	make_new(reply, 4);
427 
428 	if (!recv_packet(proto_version, sock, 4)) {
429 		put_dword(reply, 0, AUTH_PACKETOVERSIZE);
430 		send_packet(reply, sock);
431 		destroyPacket(reply);
432 		destroyPacket(proto_version);
433 		return 0;
434 	}
435 
436 	*version = get_dword(proto_version, 0);
437 	if (*version > FLOPPYD_PROTOCOL_VERSION ||
438 	    *version < FLOPPYD_PROTOCOL_VERSION_OLD) {
439 		/* fail if client requests a newer version than us */
440 		put_dword(reply, 0, AUTH_WRONGVERSION);
441 		send_packet(reply, sock);
442 		destroyPacket(reply);
443 		destroyPacket(proto_version);
444 		return 0;
445 	}
446 
447 	if(*version == FLOPPYD_PROTOCOL_VERSION_OLD) {
448 		put_dword(reply, 0, AUTH_SUCCESS);
449 	} else {
450 		Dword cap = FLOPPYD_CAP_EXPLICIT_OPEN;
451 		if(sizeof(mt_off_t) >= 8) {
452 			cap |= FLOPPYD_CAP_LARGE_SEEK;
453 		}
454 		make_new(reply, 12);
455 		put_dword(reply, 0, AUTH_SUCCESS);
456 		put_dword(reply, 4, FLOPPYD_PROTOCOL_VERSION);
457 		put_dword(reply, 8, cap);
458 	}
459 	send_packet(reply, sock);
460 	destroyPacket(proto_version);
461 
462 	make_new(reply, 4);
463 	mit_cookie = newPacket();
464 	if (!recv_packet(mit_cookie, sock, MAX_XAUTHORITY_LENGTH)) {
465 		put_dword(reply, 0, AUTH_PACKETOVERSIZE);
466 		send_packet(reply, sock);
467 		destroyPacket(reply);
468 		destroyPacket(mit_cookie);
469 		return 0;
470 	}
471 
472 	umask(077);
473 	fd = mkstemp(authFile);
474 	if(fd == -1) {
475 		/* Different error than file exists */
476 		put_dword(reply, 0, AUTH_DEVLOCKED);
477 		send_packet(reply, sock);
478 		close(fd);
479 		destroyPacket(reply);
480 		destroyPacket(mit_cookie);
481 		return 0;
482 	}
483 #ifdef HAVE_SETENV
484 	setenv(XAUTHORITY, authFile, 1);
485 #else
486 	{
487 	  char *buffer=malloc(strlen(XAUTHORITY)+strlen(authFile)+2);
488 	  strcpy(buffer, XAUTHORITY);
489 	  strcat(buffer, "=");
490 	  strcat(buffer, authFile);
491 	  putenv(buffer);
492 	}
493 #endif
494 
495 	ptr = template;
496 	ptr[4095] = 0;
497 	*ptr++ = 1;
498 	*ptr++ = 0;
499 	*ptr++ = 0;
500 	gethostname((char*)ptr+1, 4088);
501 	len = strlen((char*)ptr+1);
502 	*ptr++ = (unsigned char) len;
503 	ptr += len;
504 	*ptr++ = 0;
505 	*ptr++ = 1;
506 	*ptr++ = '0'; /* Display number */
507 	*ptr++ = '\0';
508 
509 	if(write(fd, template, len+8) < (ssize_t) (len + 8)) {
510 		close(fd);
511 		return 0;
512 	}
513 	ptr = mit_cookie->data;
514 	len = mit_cookie->len;
515 
516 	if (eat(&ptr,&len,1) ||    /* the "type"    */
517 	    eat(&ptr,&len,*ptr) || /* the hostname  */
518 	    eat(&ptr,&len,*ptr)) { /* the display number */
519 	    destroyPacket(mit_cookie);
520 	    unlink(XauFileName());
521 	    put_dword(reply, 0, AUTH_BADPACKET);
522 	    send_packet(reply, sock);
523 	    destroyPacket(reply);
524 	    return 0;
525 	}
526 
527 	if(write(fd, ptr, len) < (ssize_t) len) {
528 		close(fd);
529 		return 0;
530 	}
531 	close(fd);
532 
533 	destroyPacket(mit_cookie);
534 
535 	displ = XOpenDisplay(dispName);
536 	if (!displ) {
537 		unlink(XauFileName());
538 		put_dword(reply, 0, AUTH_AUTHFAILED);
539 		send_packet(reply, sock);
540 		destroyPacket(reply);
541 		return 0;
542 	}
543 	XCloseDisplay(displ);
544 
545 	put_dword(reply, 0, AUTH_SUCCESS);
546 	send_packet(reply, sock);
547 	destroyPacket(reply);
548 	unlink(XauFileName());
549 	return 1;
550 }
551 
552 /*
553  * Return the port number, in network order, of the specified service.
554  */
getportnum(char * portnum)555 static uint16_t getportnum(char *portnum)
556 {
557 	char		*digits = portnum;
558 	struct servent	*serv;
559 	uint16_t	port;
560 
561 	for (port = 0; isdigit(*digits); ++digits)
562 		{
563 			port = (port * 10) + (*digits - '0');
564 		}
565 
566 	if ((*digits != '\0') || (port <= 0))
567 		{
568 			if ((serv = getservbyname(portnum, "tcp")) != NULL)
569 				{
570 					port = ntohs(serv->s_port);
571 				}
572 			else
573 				{
574 					port = 0;
575 				}
576 			endservent();
577 		}
578 
579 #if DEBUG
580 	fprintf(stderr, "Port lookup %s -> %hd\n", portnum, port);
581 #endif
582 
583 	return (port);
584 }
585 
586 /*
587  * Return the IP address of the specified host.
588  */
getipaddress(char * ipaddr)589 static in_addr_t getipaddress(char *ipaddr)
590 {
591 	struct hostent	*host;
592 	in_addr_t ip;
593 
594 	if (((ip = inet_addr(ipaddr)) == INADDR_NONE)
595 	    &&
596 		(strcmp(ipaddr, "255.255.255.255") != 0))
597 		{
598 			if ((host = gethostbyname(ipaddr)) != NULL)
599 				{
600 					memcpy(&ip, host->h_addr, sizeof(ip));
601 				}
602 			endhostent();
603 		}
604 
605 #if DEBUG
606 	fprintf(stderr, "IP lookup %s -> 0x%08lx\n", ipaddr, ip);
607 #endif
608 
609 	return (ip);
610 }
611 
612 /*
613  * Find the userid of the specified user.
614  */
getuserid(char * user)615 static uid_t getuserid(char *user)
616 {
617 	struct passwd	*pw;
618 	uid_t			uid;
619 
620 	if ((pw = getpwnam(user)) != NULL)
621 		{
622 			uid = pw->pw_uid;
623 		}
624 	else if (*user == '#')
625 		{
626 			uid = (uid_t)atoi(&user[1]);
627 		}
628 	else
629 		{
630 #ifdef HAVE_GETUSERID
631 			id = getuserid("nobody");
632 #else
633 			uid = 65535;
634 #endif
635 		}
636 
637 #if DEBUG
638 	fprintf(stderr, "User lookup %s -> %d\n", user, uid);
639 #endif
640 
641 	endpwent();
642 
643 	return (uid);
644 }
645 
646 /*
647  * Find the groupid of the specified user.
648  */
getgroupid(uid_t uid)649 static uid_t getgroupid(uid_t uid)
650 {
651 	struct passwd	*pw;
652 	gid_t			gid;
653 
654 	if ((pw = getpwuid(uid)) != NULL)
655 		{
656 			gid = pw->pw_gid;
657 		}
658 	else
659 		{
660 #ifdef HAVE_GETGROUPID
661 			id = getgroupid(uid);
662 #else
663 			gid = 65535;
664 #endif
665 		}
666 
667 #if DEBUG
668 	fprintf(stderr, "Group lookup %d -> %d\n", uid, gid);
669 #endif
670 
671 	endpwent();
672 
673 	return (gid);
674 }
675 
676 /*
677  * Bind to the specified ip and port.
678  */
bind_to_port(in_addr_t bind_ip,uint16_t bind_port)679 static int bind_to_port(in_addr_t bind_ip, uint16_t bind_port)
680 {
681 	struct sockaddr_in	addr;
682 	int					sock;
683 
684 	/*
685 	 * Allocate a socket.
686 	 */
687 	if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
688 		{
689 			perror("socket()");
690 			exit(1);
691 		}
692 
693 	/*
694 	 * Set the SO_REUSEADDR option for debugging.
695 	 */
696 	{
697 	 	int	on = 1;
698 		if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
699 			      (char *)&on, sizeof(on)) < 0) {
700 			perror("setsockopt");
701 			exit(1);
702 		}
703 	}
704 
705 	/*
706 	 * Set the address to listen to.
707 	 */
708 	addr.sin_family = AF_INET;
709 	addr.sin_port = htons(bind_port);
710 	addr.sin_addr.s_addr = bind_ip;
711 
712 	/*
713 	 * Bind our socket to the above address.
714 	 */
715 	if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
716 		{
717 			perror("bind()");
718 			exit(1);
719 		}
720 
721 	/*
722 	 * Establish a large listen backlog.
723 	 */
724 	if (listen(sock, SOMAXCONN) < 0)
725 		{
726 			perror("listen()");
727 			exit(1);
728 		}
729 
730 	return (sock);
731 }
732 
733 static int sockethandle_now = -1;
734 
735 /*
736  * Catch alarm signals and exit.
737  */
738 static void alarm_signal(int a UNUSEDP) NORETURN;
alarm_signal(int a UNUSEDP)739 static void alarm_signal(int a UNUSEDP)
740 {
741 	if (sockethandle_now != -1) {
742 		close(sockethandle_now);
743 		sockethandle_now = -1;
744 		unlink(XauFileName());
745 	}
746 	exit(1);
747 }
748 
749 
750 /*
751  * This is the main loop when running as a server.
752  */
753 static void server_main_loop(int sock, char **device_name,
754 			     unsigned  int n_dev) NORETURN;
server_main_loop(int sock,char ** device_name,unsigned int n_dev)755 static void server_main_loop(int sock, char **device_name,
756 			     unsigned int n_dev)
757 {
758 	struct sockaddr_in	addr;
759 	unsigned int		len;
760 
761 	/*
762 	 * Ignore dead servers so no zombies should be left hanging.
763 	 */
764 	signal(SIGCLD, SIG_IGN);
765 
766 	for (;;) {
767 		int					new_sock;
768 		/*
769 		 * Accept an incoming connection.
770 		 */
771 		len = sizeof(addr);
772 		while ((new_sock = accept(sock, (struct sockaddr *)&addr, &len)) < 0){}
773 
774 		/*
775 		 * Create a new process to handle the connection.
776 		 */
777 #if DEBUG == 0
778 		switch (fork()) {
779 			case -1:
780 				/*
781 				 * Under load conditions just ignore new connections.
782 				 */
783 				break;
784 
785 			case 0:
786 				/*
787 				 * Start the proxy work in the new socket.
788 				 */
789 #endif
790 				serve_client(new_sock,device_name, n_dev, 0);
791 				exit(0);
792 #if DEBUG == 0
793 		}
794 #endif
795 		/*
796 		 * Close the socket as the child does the handling.
797 		 */
798 		close(new_sock);
799 		new_sock = -1;
800 	}
801 }
802 
803 /*
804  * Print some basic help information.
805  */
806 static void usage(char *prog, const char *opt, int ret) NORETURN;
usage(char * prog,const char * opt,int ret)807 static void usage(char *prog, const char *opt, int ret)
808 {
809 	if (opt)
810 		{
811 			fprintf(stderr, "%s: %s\n", prog, opt);
812 		}
813 	fprintf(stderr, "usage: %s [-s port [-r user] [-b ipaddr]] devicename [Names of local host]\n",
814 			prog);
815 	fprintf(stderr, "    -d          Run as a server (default port 5703 + DISPLAY)\n");
816 	fprintf(stderr, "    -s port     Run as a server bound to the specified port.\n");
817 	fprintf(stderr, "    -r user     Run as the specified user in server mode.\n");
818 	fprintf(stderr, "    -b ipaddr   Bind to the specified ipaddr in server mode.\n");
819 	fprintf(stderr, "    -l          Do not attempt to connect to localhost:0 to validate connection\n");
820 	exit(ret);
821 }
822 
823 
makeDisplayName(int dispNr)824 static char *makeDisplayName(int dispNr)
825 {
826 	char result[80];
827 	sprintf(result, ":%d.0", dispNr);
828 	return strdup(result);
829 }
830 
main(int argc,char ** argv)831 int main (int argc, char** argv)
832 {
833 	int sockfd = 0;
834 	int			arg;
835 	int			run_as_server = 0;
836 	in_addr_t		bind_ip = INADDR_ANY;
837 	uint16_t		bind_port = 0;
838 	uid_t			run_uid = 65535;
839 	gid_t			run_gid = 65535;
840 	char*			username = strdup("nobody");
841 	int			sock;
842 
843 	char **device_name = NULL;
844 	const char *floppy0 = "/dev/fd0";
845 	unsigned int n_dev;
846 
847 
848 	/*
849 	 * Parse the command line arguments.
850 	 */
851 	if(argc > 1 && !strcmp(argv[0], "--help"))
852 		usage(argv[0], NULL, 0);
853 	while ((arg = getopt(argc, argv, "ds:r:b:x:h")) != EOF)
854 		{
855 			switch (arg)
856 				{
857 					case 'd':
858 						run_as_server = 1;
859 						break;
860 					case 's':
861 						run_as_server = 1;
862 						bind_port = getportnum(optarg);
863 						break;
864 
865 					case 'r':
866 						free(username); username = strdup(optarg);
867 						run_uid = getuserid(optarg);
868 						run_gid = getgroupid(run_uid);
869 						break;
870 
871 					case 'b':
872 						run_as_server = 1;
873 						bind_ip = getipaddress(optarg);
874 						break;
875 					case 'x':
876 						dispName = strdup(optarg);
877 						break;
878 
879 					case 'h':
880 						usage(argv[0], NULL, 0);
881 					case '?':
882 						usage(argv[0], NULL, 1);
883 				}
884 		}
885 
886 	if(optind < argc) {
887 		device_name = argv + optind;
888 		n_dev = argc - optind;
889 	} else {
890 		device_name = (char **)&floppy0;
891 		n_dev = 1;
892 	}
893 
894 	if(dispName == NULL)
895 		dispName = getenv("DISPLAY");
896 	if(dispName==NULL && bind_port != 0)
897 		dispName=makeDisplayName((unsigned short)(bind_port - 5703));
898 	if(dispName==NULL)
899 		dispName=":0";
900 
901 	if(bind_port == 0) {
902 		char *p = strchr(dispName,':');
903 		bind_port = FLOPPYD_DEFAULT_PORT;
904 		if(p != NULL)
905 			bind_port += atoi(p+1);
906 	}
907 
908 	if(!run_as_server) {
909 		struct sockaddr_in	addr;
910 		unsigned int len = sizeof(addr);
911 
912 		/* try to find out port that we are connected to */
913 		if(getsockname(0, (struct sockaddr*) &addr, &len) >= 0 &&
914 		   len == sizeof(addr)) {
915 			bind_port = ntohs(addr.sin_port);
916 		}
917 	}
918 
919 	umask(0077);
920 
921 	/*
922 	 * Test to make sure required args were provided and are valid.
923 	 */
924 	if (run_as_server && (bind_ip == INADDR_NONE)) {
925 		usage(argv[0], "The server ipaddr is invalid.", 1);
926 	}
927 	if (run_as_server && (bind_port == 0))	{
928 		usage(argv[0], "No server port was specified (or it was invalid).", 1);
929 	}
930 
931 
932 	/*
933 	 * See if we should run as a server.
934 	 */
935 	if (run_as_server) {
936 		/*
937 		 * Start by binding to the port, the child inherits this socket.
938 		 */
939 		sock = bind_to_port(bind_ip, bind_port);
940 
941 		/*
942 		 * Start a server process. When DEBUG is defined, just run
943 		 * in the foreground.
944 		 */
945 #if DEBUG
946 		switch (0)
947 #else
948 			switch (fork())
949 #endif
950 				{
951 				case -1:
952 					perror("fork()");
953 					exit(1);
954 
955 				case 0:
956 					/*
957 					 * Ignore some signals.
958 					 */
959 					signal(SIGHUP, SIG_IGN);
960 #if DEBUG
961 					signal(SIGINT, SIG_IGN);
962 #endif
963 					signal(SIGQUIT, SIG_IGN);
964 					signal(SIGTSTP, SIG_IGN);
965 					signal(SIGCONT, SIG_IGN);
966 					signal(SIGPIPE, alarm_signal);
967 					/*signal(SIGALRM, alarm_signal);*/
968 
969 					/*
970 					 * Drop back to an untrusted user.
971 					 */
972 					setgid(run_gid);
973 					initgroups(username, run_gid);
974 					setuid(run_uid);
975 
976 					/*
977 					 * Start a new session and group.
978 					 */
979 					setsid();
980 #ifdef HAVE_SETPGRP
981 #ifdef SETPGRP_VOID
982 					setpgrp();
983 #else
984 					setpgrp(0,0);
985 #endif
986 #endif
987 #if DEBUG
988 					close(2);
989 					open("/dev/null", O_WRONLY);
990 #endif
991 					/*
992 					 * Handle the server main loop.
993 					 */
994 					server_main_loop(sock, device_name,
995 							 n_dev);
996 				}
997 
998 		/*
999 		 * Parent exits at this stage.
1000 		 */
1001 		exit(0);
1002 	}
1003 
1004 	signal(SIGHUP, alarm_signal);
1005 #if DEBUG == 0
1006 	signal(SIGINT, alarm_signal);
1007 #endif
1008 	signal(SIGQUIT, alarm_signal);
1009 	signal(SIGTERM, alarm_signal);
1010 	signal(SIGTSTP, SIG_IGN);
1011 	signal(SIGCONT, SIG_IGN);
1012 	signal(SIGPIPE, alarm_signal);
1013 	/*signal(SIGALRM, alarm_signal);*/
1014 
1015 	/* Starting from inetd */
1016 
1017 	serve_client(sockfd, device_name, n_dev, 1);
1018 	return 0;
1019 }
1020 
send_reply(int rval,io_buffer sock,Dword len)1021 static void send_reply(int rval, io_buffer sock, Dword len) {
1022 	Packet reply = newPacket();
1023 
1024 	make_new(reply, 8);
1025 	put_dword(reply, 0, len);
1026 	if (rval == -1) {
1027 		put_dword(reply, 4, 0);
1028 	} else {
1029 		put_dword(reply, 4, (Dword) errno);
1030 	}
1031 	send_packet(reply, sock);
1032 	destroyPacket(reply);
1033 }
1034 
send_reply64(int rval,io_buffer sock,mt_off_t len)1035 static void send_reply64(int rval, io_buffer sock, mt_off_t len) {
1036 	Packet reply = newPacket();
1037 
1038 	make_new(reply, 12);
1039 	put_qword(reply, 0, len);
1040 	if (rval == -1) {
1041 		put_dword(reply, 8, 0);
1042 	} else {
1043 		put_dword(reply, 8, (Dword) errno);
1044 	}
1045 	send_packet(reply, sock);
1046 	destroyPacket(reply);
1047 }
1048 
1049 static void cleanup(int x UNUSEDP) NORETURN;
cleanup(int x UNUSEDP)1050 static void cleanup(int x UNUSEDP) {
1051 	unlink(XauFileName());
1052 	exit(-1);
1053 }
1054 
1055 #include "lockdev.h"
1056 
serve_client(int sockhandle,char ** device_name,unsigned int n_dev,int close_stderr)1057 void serve_client(int sockhandle, char **device_name, unsigned int n_dev,
1058 		  int close_stderr) {
1059 	Packet opcode;
1060 	Packet parm;
1061 
1062 	int readOnly;
1063 	int devFd;
1064 	io_buffer sock;
1065 	int stopLoop;
1066 	unsigned int version;
1067 	int needSendReply=0;
1068 	int rval=0;
1069 
1070 	/*
1071 	 * Set the keepalive socket option to on.
1072 	 */
1073 	{
1074 		int		on = 1;
1075 		if(setsockopt(sockhandle, SOL_SOCKET,
1076 			      SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0) {
1077 			perror("setsockopt");
1078 			exit(1);
1079 		}
1080 
1081 	}
1082 
1083 
1084 #if DEBUG == 0
1085 	if(close_stderr) {
1086 		close(2);
1087 		open("/dev/null", O_WRONLY);
1088 	}
1089 #endif
1090 
1091 	sock = new_io_buffer(sockhandle);
1092 
1093 	/*
1094 	 * Allow 60 seconds for any activity.
1095 	 */
1096 	alarm(60);
1097 
1098 	version = 0;
1099 	if (!do_auth(sock, &version)) {
1100 		free_io_buffer(sock);
1101 		return;
1102 	}
1103 	alarm(0);
1104 
1105 
1106 	signal(SIGTERM, cleanup);
1107 	signal(SIGALRM, cleanup);
1108 
1109 
1110 
1111 	sockethandle_now = sockhandle;
1112 
1113 
1114 	opcode = newPacket();
1115 	parm = newPacket();
1116 
1117 	devFd = -1;
1118 	readOnly = 1;
1119 
1120 	stopLoop = 0;
1121 	if(version == FLOPPYD_PROTOCOL_VERSION_OLD) {
1122 				/* old protocol */
1123 		readOnly = 0;
1124 		devFd = open(device_name[0], O_RDWR|O_LARGEFILE);
1125 
1126 		if (devFd < 0) {
1127 			readOnly = 1;
1128 			devFd = open(device_name[0],
1129 				     O_RDONLY|O_LARGEFILE);
1130 		}
1131 		if(devFd < 0) {
1132 			send_reply(0, sock, devFd >= 0 ? 0 : DWORD_ERR);
1133 			stopLoop = 1;
1134 		}
1135 		lock_dev(devFd, !readOnly, NULL);
1136 	}
1137 
1138 
1139 	while(!stopLoop) {
1140 		uint32_t dev_nr = 0;
1141 		/*
1142 		 * Allow 60 seconds for any activity.
1143 		 */
1144 		/*alarm(60);*/
1145 
1146 		if (!recv_packet(opcode, sock, 1)) {
1147 			break;
1148 		}
1149 /*		if(opcode->data[0] != OP_CLOSE)*/
1150 		    recv_packet(parm, sock, MAX_DATA_REQUEST);
1151 
1152 		/* on its own, floppyd does several small writes,
1153 		 * running into the performance issue described in
1154 		 * https://eklitzke.org/the-caveats-of-tcp-nodelay
1155 		 * Cork fixes this by stalling the small writes until
1156 		 * floppyd has assembled its entire message, thus
1157 		 * preventing the bad interaction between Nagle's
1158 		 * algorithm and Linux' delayed ACKs. Another fix
1159 		 * would be to not send the small batches immediately,
1160 		 * but instead keep them around and submit them to the
1161 		 * kernel in one go using writev. However, writev is
1162 		 * not available everywhere
1163 		 */
1164 		cork(sock->handle, 1);
1165 
1166 		switch(opcode->data[0]) {
1167 			case OP_OPRO:
1168 				if(get_length(parm) >= 4)
1169 					dev_nr = get_dword(parm,0);
1170 				else
1171 					dev_nr = 0;
1172 				if(dev_nr >= n_dev) {
1173 					send_reply(0, sock, DWORD_ERR);
1174 					break;
1175 				}
1176 
1177 				devFd = open(device_name[dev_nr],
1178 					     O_RDONLY | O_LARGEFILE);
1179 #if DEBUG
1180 				fprintf(stderr, "Device opened\n");
1181 #endif
1182 				if(devFd >= 0 && lock_dev(devFd, 0, NULL)) {
1183 					send_reply(0, sock, DWORD_ERR);
1184 					break;
1185 				}
1186 				send_reply(0, sock,
1187 					   devFd >= 0 ? 0 : DWORD_ERR);
1188 				readOnly = 1;
1189 				break;
1190 			case OP_OPRW:
1191 				if(get_length(parm) >= 4)
1192 					dev_nr = get_dword(parm,0);
1193 				else
1194 					dev_nr = 0;
1195 				if(dev_nr >= n_dev) {
1196 					send_reply(0, sock, DWORD_ERR);
1197 					break;
1198 				}
1199 				devFd = open(device_name[dev_nr], O_RDWR);
1200 				if(devFd >= 0 && lock_dev(devFd, 1, NULL)) {
1201 					send_reply(0, sock, DWORD_ERR);
1202 					break;
1203 				}
1204 				send_reply(0, sock,
1205 					   devFd >= 0 ? 0 : DWORD_ERR);
1206 				readOnly = 0;
1207 				break;
1208 			case OP_READ:
1209 #if DEBUG
1210 				fprintf(stderr, "READ:\n");
1211 #endif
1212 				if(read_packet(parm, devFd,
1213 					       get_dword(parm, 0)) < 0)
1214 					send_reply(devFd, sock, DWORD_ERR);
1215 				else {
1216 					send_reply(devFd, sock,
1217 						   get_length(parm));
1218 					send_packet(parm, sock);
1219 				}
1220 				break;
1221 			case OP_WRITE:
1222 #if DEBUG
1223 				fprintf(stderr, "WRITE:\n");
1224 #endif
1225 				if(readOnly) {
1226 					errno = -EROFS;
1227 					rval = -1;
1228 				} else {
1229 					rval = write_packet(parm, devFd);
1230 				}
1231 				send_reply(devFd, sock, rval);
1232 				break;
1233 			case OP_SEEK:
1234 #if DEBUG
1235 				fprintf(stderr, "SEEK:\n");
1236 #endif
1237 
1238 				lseek(devFd,
1239 				      get_dword(parm, 0), get_dword(parm, 4));
1240 				send_reply(devFd,
1241 					   sock,
1242 					   (Dword) lseek(devFd, 0, SEEK_CUR));
1243 				break;
1244 			case OP_SEEK64:
1245 				if(sizeof(mt_off_t) < 8) {
1246 #if DEBUG
1247 					fprintf(stderr, "64 bit requested where not available!\n");
1248 #endif
1249 					errno = EINVAL;
1250 					send_reply(devFd, sock, DWORD_ERR);
1251 					break;
1252 				}
1253 #if DEBUG
1254 				fprintf(stderr, "SEEK64:\n");
1255 #endif
1256 				mt_lseek(devFd,
1257 					 get_qword(parm,0), get_dword(parm,8));
1258 				send_reply64(devFd,
1259 					     sock,
1260 					     mt_lseek(devFd, 0, SEEK_CUR));
1261 				break;
1262 			case OP_FLUSH:
1263 #if DEBUG
1264 				fprintf(stderr, "FLUSH:\n");
1265 #endif
1266 				fsync(devFd);
1267 				send_reply(devFd, sock, 0);
1268 				break;
1269 			case OP_CLOSE:
1270 #if DEBUG
1271 				fprintf(stderr, "CLOSE:\n");
1272 #endif
1273 
1274 				close(devFd);
1275 				needSendReply = 1;
1276 				rval = devFd;
1277 				devFd = -1;
1278 				stopLoop = 1;
1279 				break;
1280 			case OP_IOCTL:
1281 				/* Unimplemented for now... */
1282 				break;
1283 			default:
1284 #if DEBUG
1285 				fprintf(stderr, "Invalid Opcode!\n");
1286 #endif
1287 				errno = EINVAL;
1288 				send_reply(devFd, sock, DWORD_ERR);
1289 				break;
1290 		}
1291 		cork(sock->handle, 0);
1292 		kill_packet(parm);
1293 		alarm(0);
1294 	}
1295 
1296 
1297 
1298 #if DEBUG
1299 	fprintf(stderr, "Closing down...\n");
1300 #endif
1301 
1302 	if (devFd >= 0) {
1303 		close(devFd);
1304 		devFd = -1;
1305 	}
1306 
1307 	free_io_buffer(sock);
1308 
1309 	/* remove "Lock"-File  */
1310 	unlink(XauFileName());
1311 
1312 	if(needSendReply)
1313 	    send_reply(rval, sock, 0);
1314 	destroyPacket(opcode);
1315 	destroyPacket(parm);
1316 }
1317 
1318 #else
1319 #include <stdio.h>
1320 
main(int argc,char ** argv)1321 int main(int argc, char **argv)
1322 {
1323 	puts("Floppyd support not included!");
1324 	return -1;
1325 }
1326 
1327 #endif
1328