blob: 1601271c50040ba61466908b7c930ef8477c8bb3 [file] [log] [blame]
Alistair Delvabeaee832021-02-24 11:27:23 -08001/* 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 *
Yi Kong39bbd962022-01-09 19:41:38 +080026 * Large parts of the network code shamelessly stolen from
Alistair Delvabeaee832021-02-24 11:27:23 -080027 * 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
Yi Kong39bbd962022-01-09 19:41:38 +080069 After that,we send our .Xauthority-file (a maximum of MAX_XAUTHORITY_LENGTH
Alistair Delvabeaee832021-02-24 11:27:23 -080070 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!
Yi Kong39bbd962022-01-09 19:41:38 +0800101
Alistair Delvabeaee832021-02-24 11:27:23 -0800102*/
103
104
105#define MAX_XAUTHORITY_LENGTH 3000
106#define MAX_DATA_REQUEST 3000000
107#define BUFFERED_IO_SIZE 16348
108
109unsigned int mtools_lock_timeout=30;
110
Yi Kong39bbd962022-01-09 19:41:38 +0800111void serve_client(int sock, const char *const*device_name, unsigned int n_dev,
Alistair Delvabeaee832021-02-24 11:27:23 -0800112 int close_stderr);
113
114
115#ifdef USE_FLOPPYD_BUFFERED_IO
116typedef struct io_buffer {
117 Byte out_buffer[BUFFERED_IO_SIZE];
118 Byte in_buffer[BUFFERED_IO_SIZE];
Yi Kong39bbd962022-01-09 19:41:38 +0800119
Alistair Delvabeaee832021-02-24 11:27:23 -0800120 size_t in_valid;
121 size_t in_start;
122 size_t out_valid;
Yi Kong39bbd962022-01-09 19:41:38 +0800123
Alistair Delvabeaee832021-02-24 11:27:23 -0800124 int handle;
125} *io_buffer;
126
127static 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
139static 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
148static void free_io_buffer(io_buffer buffer) {
149 flush(buffer);
150 free(buffer);
151}
152
153
154static size_t buf_read (io_buffer buf, Byte* buffer, size_t nbytes) {
155 size_t ret;
Yi Kong39bbd962022-01-09 19:41:38 +0800156
Alistair Delvabeaee832021-02-24 11:27:23 -0800157 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 {
Yi Kong39bbd962022-01-09 19:41:38 +0800163 if (buf->in_valid)
164 memcpy(buffer, buf->in_buffer+buf->in_start,
Alistair Delvabeaee832021-02-24 11:27:23 -0800165 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 {
Yi Kong39bbd962022-01-09 19:41:38 +0800178 ssize_t rval = read(buf->handle, buf->in_buffer,
Alistair Delvabeaee832021-02-24 11:27:23 -0800179 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
203static 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
217typedef int io_buffer;
218
219io_buffer new_io_buffer (int handle) {
220 return handle;
221}
222
223
224size_t buf_read (io_buffer handle, Byte* buffer, size_t nbytes) {
225 return (read(handle, buffer, nbytes));
226}
227
228ssize_t buf_write(io_buffer handle, void* buffer, size_t nbytes) {
229 return (write(handle, buffer, nbytes));
230}
231
232
233void free_io_buffer(io_buffer buffer) { }
234
235
236void flush(io_buffer buffer) { }
237
238#endif
239
240typedef struct Packet {
241 Byte* data;
242 Dword len;
243 Dword alloc_size;
244} *Packet;
245
246#include "byte_dword.h"
247
248static Dword read_dword(io_buffer fp)
249{
250 Byte val[4];
251 if (buf_read(fp, val, 4) < 4) {
252 return 0xffffffff;
253 }
Yi Kong39bbd962022-01-09 19:41:38 +0800254
Alistair Delvabeaee832021-02-24 11:27:23 -0800255 return byte2dword(val);
256}
257
258static void write_dword(io_buffer fp, Dword parm)
259{
260 Byte val[4];
Yi Kong39bbd962022-01-09 19:41:38 +0800261
Alistair Delvabeaee832021-02-24 11:27:23 -0800262 dword2byte(parm, val);
Yi Kong39bbd962022-01-09 19:41:38 +0800263
Alistair Delvabeaee832021-02-24 11:27:23 -0800264 buf_write(fp, val,4);
265}
266
267
268static 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
279static void destroyPacket(Packet packet)
280{
281 if(packet->data)
282 free(packet->data);
283 free(packet);
284}
285
286static 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
295static 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
307static 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");
Yi Kong39bbd962022-01-09 19:41:38 +0800323#endif
Alistair Delvabeaee832021-02-24 11:27:23 -0800324
325 }
326 return (packet->data != NULL);
327}
328
329static 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
Yi Kong39bbd962022-01-09 19:41:38 +0800354
Alistair Delvabeaee832021-02-24 11:27:23 -0800355#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");
Yi Kong39bbd962022-01-09 19:41:38 +0800361#endif
Alistair Delvabeaee832021-02-24 11:27:23 -0800362 return 1;
363}
364
365static 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
375static int write_packet(Packet packet, int fd) {
376 return (int)write(fd, packet->data, packet->len);
377}
378
379static void put_dword(Packet packet, int my_index, Dword val) {
380 dword2byte(val, packet->data+my_index);
381}
382
383static void put_qword(Packet packet, int my_index, Qword val) {
384 qword2byte(val, packet->data+my_index);
385}
386
387static Dword get_dword(Packet packet, int my_index) {
388 return byte2dword(packet->data+my_index);
Yi Kong39bbd962022-01-09 19:41:38 +0800389}
Alistair Delvabeaee832021-02-24 11:27:23 -0800390
391static Qword get_qword(Packet packet, int my_index) {
392 return byte2qword(packet->data+my_index);
Yi Kong39bbd962022-01-09 19:41:38 +0800393}
Alistair Delvabeaee832021-02-24 11:27:23 -0800394
395static Dword get_length(Packet packet) {
396 return packet->len;
397}
398
399static int eat(unsigned char **ptr, size_t *len, unsigned char c) {
400 /* remove length + size code + terminating 0 */
Yi Kong39bbd962022-01-09 19:41:38 +0800401 if (*len < c + 3u)
Alistair Delvabeaee832021-02-24 11:27:23 -0800402 return -1;
403 (*ptr) += c + 2;
404 (*len) -= c + 2;
405 return 0;
406}
407
408static const char *dispName;
409
410static char XAUTHORITY[]="XAUTHORITY";
411
Yi Kong39bbd962022-01-09 19:41:38 +0800412static char do_auth(io_buffer sock, unsigned int *version)
Alistair Delvabeaee832021-02-24 11:27:23 -0800413{
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);
Yi Kong39bbd962022-01-09 19:41:38 +0800437 if (*version > FLOPPYD_PROTOCOL_VERSION ||
Alistair Delvabeaee832021-02-24 11:27:23 -0800438 *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 */
555static 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 {
Yi Kong39bbd962022-01-09 19:41:38 +0800563 port = (port * 10) + (uint8_t)(*digits - '0');
Alistair Delvabeaee832021-02-24 11:27:23 -0800564 }
565
566 if ((*digits != '\0') || (port <= 0))
567 {
568 if ((serv = getservbyname(portnum, "tcp")) != NULL)
569 {
Yi Kong39bbd962022-01-09 19:41:38 +0800570 port = ntohs((uint16_t)serv->s_port);
Alistair Delvabeaee832021-02-24 11:27:23 -0800571 }
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 */
589static 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 */
615static 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 */
649static 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 */
679static 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;
Yi Kong39bbd962022-01-09 19:41:38 +0800698 if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
Alistair Delvabeaee832021-02-24 11:27:23 -0800699 (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
733static int sockethandle_now = -1;
Yi Kong39bbd962022-01-09 19:41:38 +0800734
Alistair Delvabeaee832021-02-24 11:27:23 -0800735/*
736 * Catch alarm signals and exit.
737 */
738static void alarm_signal(int a UNUSEDP) NORETURN;
739static 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 */
Yi Kong39bbd962022-01-09 19:41:38 +0800753static void server_main_loop(int sock, const char *const*device_name,
754 unsigned int n_dev) NORETURN;
755static void server_main_loop(int sock, const char *const*device_name,
Alistair Delvabeaee832021-02-24 11:27:23 -0800756 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){}
Yi Kong39bbd962022-01-09 19:41:38 +0800773
Alistair Delvabeaee832021-02-24 11:27:23 -0800774 /*
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;
Yi Kong39bbd962022-01-09 19:41:38 +0800784
Alistair Delvabeaee832021-02-24 11:27:23 -0800785 case 0:
786 /*
787 * Start the proxy work in the new socket.
788 */
789#endif
Yi Kong39bbd962022-01-09 19:41:38 +0800790 serve_client(new_sock, device_name, n_dev, 0);
Alistair Delvabeaee832021-02-24 11:27:23 -0800791 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 */
806static void usage(char *prog, const char *opt, int ret) NORETURN;
807static void usage(char *prog, const char *opt, int ret)
808{
809 if (opt)
810 {
811 fprintf(stderr, "%s: %s\n", prog, opt);
812 }
Yi Kong39bbd962022-01-09 19:41:38 +0800813 fprintf(stderr, "usage: %s [-s port [-r user] [-b ipaddr]] devicename [Names of local host]\n",
Alistair Delvabeaee832021-02-24 11:27:23 -0800814 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
824static char *makeDisplayName(int dispNr)
825{
826 char result[80];
827 sprintf(result, ":%d.0", dispNr);
828 return strdup(result);
829}
830
Yi Kong39bbd962022-01-09 19:41:38 +0800831int main (int argc, char** argv)
Alistair Delvabeaee832021-02-24 11:27:23 -0800832{
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
Yi Kong39bbd962022-01-09 19:41:38 +0800843 const char *const* device_name = NULL;
Alistair Delvabeaee832021-02-24 11:27:23 -0800844 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) {
Yi Kong39bbd962022-01-09 19:41:38 +0800887 device_name = (const char * const *) argv + optind;
888 n_dev = (unsigned int) (argc - optind);
Alistair Delvabeaee832021-02-24 11:27:23 -0800889 } else {
Yi Kong39bbd962022-01-09 19:41:38 +0800890 device_name = &floppy0;
Alistair Delvabeaee832021-02-24 11:27:23 -0800891 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));
Yi Kong39bbd962022-01-09 19:41:38 +0800898 if(dispName==NULL)
Alistair Delvabeaee832021-02-24 11:27:23 -0800899 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);
Yi Kong39bbd962022-01-09 19:41:38 +0800911
Alistair Delvabeaee832021-02-24 11:27:23 -0800912 /* try to find out port that we are connected to */
Yi Kong39bbd962022-01-09 19:41:38 +0800913 if(getsockname(0, (struct sockaddr*) &addr, &len) >= 0 &&
Alistair Delvabeaee832021-02-24 11:27:23 -0800914 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);
Yi Kong39bbd962022-01-09 19:41:38 +0800940
Alistair Delvabeaee832021-02-24 11:27:23 -0800941 /*
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);
Yi Kong39bbd962022-01-09 19:41:38 +0800954
Alistair Delvabeaee832021-02-24 11:27:23 -0800955 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);*/
Yi Kong39bbd962022-01-09 19:41:38 +0800968
Alistair Delvabeaee832021-02-24 11:27:23 -0800969 /*
970 * Drop back to an untrusted user.
971 */
972 setgid(run_gid);
973 initgroups(username, run_gid);
974 setuid(run_uid);
Yi Kong39bbd962022-01-09 19:41:38 +0800975
Alistair Delvabeaee832021-02-24 11:27:23 -0800976 /*
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 }
Yi Kong39bbd962022-01-09 19:41:38 +0800997
Alistair Delvabeaee832021-02-24 11:27:23 -0800998 /*
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
1021static 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
1035static void send_reply64(int rval, io_buffer sock, mt_off_t len) {
1036 Packet reply = newPacket();
1037
1038 make_new(reply, 12);
Yi Kong39bbd962022-01-09 19:41:38 +08001039 put_qword(reply, 0, (Qword) len);
Alistair Delvabeaee832021-02-24 11:27:23 -08001040 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
1049static void cleanup(int x UNUSEDP) NORETURN;
1050static void cleanup(int x UNUSEDP) {
1051 unlink(XauFileName());
1052 exit(-1);
1053}
1054
1055#include "lockdev.h"
1056
Yi Kong39bbd962022-01-09 19:41:38 +08001057void serve_client(int sockhandle, const char *const*device_name,
1058 unsigned int n_dev, int close_stderr) {
Alistair Delvabeaee832021-02-24 11:27:23 -08001059 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;
Yi Kong39bbd962022-01-09 19:41:38 +08001069
Alistair Delvabeaee832021-02-24 11:27:23 -08001070 /*
1071 * Set the keepalive socket option to on.
1072 */
1073 {
1074 int on = 1;
Yi Kong39bbd962022-01-09 19:41:38 +08001075 if(setsockopt(sockhandle, SOL_SOCKET,
Alistair Delvabeaee832021-02-24 11:27:23 -08001076 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);
Yi Kong39bbd962022-01-09 19:41:38 +08001092
Alistair Delvabeaee832021-02-24 11:27:23 -08001093 /*
1094 * Allow 60 seconds for any activity.
1095 */
1096 alarm(60);
Yi Kong39bbd962022-01-09 19:41:38 +08001097
Alistair Delvabeaee832021-02-24 11:27:23 -08001098 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);
Yi Kong39bbd962022-01-09 19:41:38 +08001125
Alistair Delvabeaee832021-02-24 11:27:23 -08001126 if (devFd < 0) {
1127 readOnly = 1;
Yi Kong39bbd962022-01-09 19:41:38 +08001128 devFd = open(device_name[0],
Alistair Delvabeaee832021-02-24 11:27:23 -08001129 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 }
Yi Kong39bbd962022-01-09 19:41:38 +08001231 send_reply(devFd, sock, (Dword) rval);
Alistair Delvabeaee832021-02-24 11:27:23 -08001232 break;
1233 case OP_SEEK:
1234#if DEBUG
1235 fprintf(stderr, "SEEK:\n");
1236#endif
1237
Yi Kong39bbd962022-01-09 19:41:38 +08001238 lseek(devFd,
1239 (off_t) get_dword(parm, 0),
1240 (int) get_dword(parm, 4));
1241 send_reply(devFd,
1242 sock,
Alistair Delvabeaee832021-02-24 11:27:23 -08001243 (Dword) lseek(devFd, 0, SEEK_CUR));
1244 break;
1245 case OP_SEEK64:
1246 if(sizeof(mt_off_t) < 8) {
1247#if DEBUG
1248 fprintf(stderr, "64 bit requested where not available!\n");
1249#endif
1250 errno = EINVAL;
1251 send_reply(devFd, sock, DWORD_ERR);
1252 break;
1253 }
1254#if DEBUG
1255 fprintf(stderr, "SEEK64:\n");
1256#endif
Yi Kong39bbd962022-01-09 19:41:38 +08001257 mt_lseek(devFd,
1258 (mt_off_t) get_qword(parm,0),
1259 (int) get_dword(parm,8));
1260 send_reply64(devFd,
1261 sock,
Alistair Delvabeaee832021-02-24 11:27:23 -08001262 mt_lseek(devFd, 0, SEEK_CUR));
1263 break;
1264 case OP_FLUSH:
1265#if DEBUG
1266 fprintf(stderr, "FLUSH:\n");
1267#endif
1268 fsync(devFd);
1269 send_reply(devFd, sock, 0);
1270 break;
1271 case OP_CLOSE:
1272#if DEBUG
1273 fprintf(stderr, "CLOSE:\n");
1274#endif
1275
1276 close(devFd);
1277 needSendReply = 1;
1278 rval = devFd;
1279 devFd = -1;
1280 stopLoop = 1;
1281 break;
1282 case OP_IOCTL:
1283 /* Unimplemented for now... */
1284 break;
1285 default:
1286#if DEBUG
1287 fprintf(stderr, "Invalid Opcode!\n");
1288#endif
1289 errno = EINVAL;
1290 send_reply(devFd, sock, DWORD_ERR);
1291 break;
1292 }
1293 cork(sock->handle, 0);
1294 kill_packet(parm);
1295 alarm(0);
1296 }
1297
Yi Kong39bbd962022-01-09 19:41:38 +08001298
Alistair Delvabeaee832021-02-24 11:27:23 -08001299
1300#if DEBUG
1301 fprintf(stderr, "Closing down...\n");
1302#endif
1303
1304 if (devFd >= 0) {
1305 close(devFd);
1306 devFd = -1;
1307 }
1308
1309 free_io_buffer(sock);
1310
1311 /* remove "Lock"-File */
1312 unlink(XauFileName());
1313
1314 if(needSendReply)
1315 send_reply(rval, sock, 0);
1316 destroyPacket(opcode);
1317 destroyPacket(parm);
1318}
1319
1320#else
1321#include <stdio.h>
1322
Yi Kong39bbd962022-01-09 19:41:38 +08001323int main(int argc, char **argv)
Alistair Delvabeaee832021-02-24 11:27:23 -08001324{
1325 puts("Floppyd support not included!");
1326 return -1;
1327}
Yi Kong39bbd962022-01-09 19:41:38 +08001328
Alistair Delvabeaee832021-02-24 11:27:23 -08001329#endif