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