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