45077955b08b117692799bdaa40033f89d75f934
[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         int                     port_is_supplied = 0;
828
829         char *server_hostname=NULL;
830         char **device_name = NULL; 
831         const char *floppy0 = "/dev/fd0";
832         int n_dev;
833
834
835         /*
836          * Parse the command line arguments.
837          */
838         if(argc > 1 && !strcmp(argv[0], "--help"))
839                 usage(argv[0], NULL, 0);
840         while ((arg = getopt(argc, argv, "ds:r:b:x:h")) != EOF)
841                 {
842                         switch (arg)
843                                 {
844                                         case 'd':
845                                                 run_as_server = 1;
846                                                 break;
847                                         case 's':
848                                                 run_as_server = 1;
849                                                 port_is_supplied = 1;
850                                                 bind_port = getportnum(optarg);
851                                                 break;
852
853                                         case 'r':
854                                                 free(username); username = strdup(optarg);
855                                                 run_uid = getuserid(optarg);
856                                                 run_gid = getgroupid(run_uid);
857                                                 break;
858
859                                         case 'b':
860                                                 run_as_server = 1;
861                                                 bind_ip = getipaddress(optarg);
862                                                 server_hostname=optarg;
863                                                 break;
864                                         case 'x':
865                                                 dispName = strdup(optarg);
866                                                 break;
867
868                                         case 'h':
869                                                 usage(argv[0], NULL, 0);
870                                                 break;
871                                         case '?':
872                                                 usage(argv[0], NULL, 1);
873                                                 break;
874                                 }
875                 }
876
877         if(optind < argc) {
878                 device_name = argv + optind;
879                 n_dev = argc - optind;
880         } else {
881                 device_name = (char **)&floppy0;
882                 n_dev = 1;
883         }
884
885         if(dispName == NULL)
886                 dispName = getenv("DISPLAY");
887         if(dispName==NULL && bind_port != 0)
888                 dispName=makeDisplayName((unsigned short)(bind_port - 5703));
889         if(dispName==NULL)              
890                 dispName=":0";
891
892         if(bind_port == 0) {
893                 char *p = strchr(dispName,':');
894                 bind_port = FLOPPYD_DEFAULT_PORT;
895                 if(p != NULL)
896                         bind_port += atoi(p+1);
897         }
898
899         if(!run_as_server) {
900                 struct sockaddr_in      addr;
901                 unsigned int len = sizeof(addr);
902                 
903                 /* try to find out port that we are connected to */
904                 if(getsockname(0, (struct sockaddr*) &addr, &len) >= 0 && 
905                    len == sizeof(addr)) {
906                         port_is_supplied = 1;
907                         bind_port = ntohs(addr.sin_port);
908                         server_hostname = strdup(inet_ntoa(addr.sin_addr));
909                 }
910         }
911
912         umask(0077);
913
914         /*
915          * Test to make sure required args were provided and are valid.
916          */
917         if (run_as_server && (bind_ip == INADDR_NONE)) {
918                 usage(argv[0], "The server ipaddr is invalid.", 1);
919         }
920         if (run_as_server && (bind_port == 0))  {
921                 usage(argv[0], "No server port was specified (or it was invalid).", 1);
922         }
923
924
925         /*
926          * See if we should run as a server.
927          */
928         if (run_as_server) {
929                 /*
930                  * Start by binding to the port, the child inherits this socket.
931                  */
932                 sock = bind_to_port(bind_ip, bind_port);
933                 
934                 /*
935                  * Start a server process. When DEBUG is defined, just run
936                  * in the foreground.
937                  */
938 #if DEBUG
939                 switch (0)
940 #else
941                         switch (fork())
942 #endif
943                                 {
944                                 case -1:
945                                         perror("fork()");
946                                         exit(1);
947                                         
948                                 case 0:
949                                         /*
950                                          * Ignore some signals.
951                                          */
952                                         signal(SIGHUP, SIG_IGN);
953 #if DEBUG
954                                         signal(SIGINT, SIG_IGN);
955 #endif
956                                         signal(SIGQUIT, SIG_IGN);
957                                         signal(SIGTSTP, SIG_IGN);
958                                         signal(SIGCONT, SIG_IGN);
959                                         signal(SIGPIPE, alarm_signal);
960                                         /*signal(SIGALRM, alarm_signal);*/
961                                         
962                                         /*
963                                          * Drop back to an untrusted user.
964                                          */
965                                         setgid(run_gid);
966                                         initgroups(username, -1);
967                                         setuid(run_uid);
968                                         
969                                         /*
970                                          * Start a new session and group.
971                                          */
972                                         setsid();
973 #ifdef HAVE_SETPGRP
974 #ifdef SETPGRP_VOID
975                                         setpgrp();
976 #else
977                                         setpgrp(0,0);
978 #endif
979 #endif
980 #if DEBUG
981                                         close(2);
982                                         open("/dev/null", O_WRONLY);
983 #endif
984                                         /*
985                                          * Handle the server main loop.
986                                          */
987                                         server_main_loop(sock, device_name, n_dev);
988                                         
989                                         /*
990                                          * Should never exit.
991                                          */
992                                         exit(1);
993                                 }
994                 
995                 /*
996                  * Parent exits at this stage.
997                  */
998                 exit(0);
999         }
1000
1001         signal(SIGHUP, alarm_signal);
1002 #if DEBUG == 0
1003         signal(SIGINT, alarm_signal);
1004 #endif
1005         signal(SIGQUIT, alarm_signal);
1006         signal(SIGTERM, alarm_signal);
1007         signal(SIGTSTP, SIG_IGN);
1008         signal(SIGCONT, SIG_IGN);
1009         signal(SIGPIPE, alarm_signal);
1010         /*signal(SIGALRM, alarm_signal);*/
1011
1012         /* Starting from inetd */
1013
1014         serve_client(sockfd, device_name, n_dev, 1);
1015         return 0;
1016 }
1017
1018 static void send_reply(int rval, io_buffer sock, int len) {
1019         Packet reply = newPacket();
1020
1021         make_new(reply, 8);
1022         put_dword(reply, 0, len);
1023         if (rval == -1) {
1024                 put_dword(reply, 4, 0);
1025         } else {
1026                 put_dword(reply, 4, errno);
1027         }
1028         send_packet(reply, sock);
1029         destroyPacket(reply);
1030 }
1031
1032 static void send_reply64(int rval, io_buffer sock, mt_off_t len) {
1033         Packet reply = newPacket();
1034
1035         make_new(reply, 12);
1036         put_qword(reply, 0, len);
1037         if (rval == -1) {
1038                 put_dword(reply, 8, 0);
1039         } else {
1040                 put_dword(reply, 8, errno);
1041         }
1042         send_packet(reply, sock);
1043         destroyPacket(reply);
1044 }
1045
1046 static void cleanup(int x) {
1047         unlink(XauFileName());
1048         exit(-1);
1049 }
1050
1051 #include "lockdev.h"
1052
1053 void serve_client(int sockhandle, char **device_name, int n_dev,
1054                   int close_stderr) {
1055         Packet opcode;
1056         Packet parm;
1057
1058         int readOnly;
1059         int devFd;
1060         io_buffer sock;
1061         int stopLoop;
1062         int version;
1063         int needSendReply=0;
1064         int rval=0;
1065         
1066         /*
1067          * Set the keepalive socket option to on.
1068          */
1069         {
1070                 int             on = 1;
1071                 if(setsockopt(sockhandle, SOL_SOCKET, 
1072                               SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0) {
1073                         perror("setsockopt");
1074                         exit(1);
1075                 }
1076                         
1077         }
1078
1079
1080 #if DEBUG == 0
1081         if(close_stderr) {
1082                 close(2);
1083                 open("/dev/null", O_WRONLY);
1084         }
1085 #endif
1086
1087         sock = new_io_buffer(sockhandle);
1088         
1089         /*
1090          * Allow 60 seconds for any activity.
1091          */
1092         alarm(60);
1093         
1094         version = 0;
1095         if (!do_auth(sock, &version)) {
1096                 free_io_buffer(sock);
1097                 return;
1098         }
1099         alarm(0);
1100
1101
1102         signal(SIGTERM, cleanup);
1103         signal(SIGALRM, cleanup);
1104
1105
1106
1107         sockethandle_now = sockhandle;
1108
1109
1110         opcode = newPacket();
1111         parm = newPacket();
1112
1113         devFd = -1;
1114         readOnly = 1;
1115
1116         stopLoop = 0;
1117         if(version == FLOPPYD_PROTOCOL_VERSION_OLD) {
1118                                 /* old protocol */
1119                 readOnly = 0;
1120                 devFd = open(device_name[0], O_RDWR|O_LARGEFILE);
1121                 
1122                 if (devFd < 0) {
1123                         readOnly = 1;
1124                         devFd = open(device_name[0], 
1125                                      O_RDONLY|O_LARGEFILE);
1126                 }
1127                 if(devFd < 0) {
1128                         send_reply(0, sock, devFd);
1129                         stopLoop = 1;
1130                 }
1131                 lock_dev(devFd, !readOnly, NULL);
1132         }
1133
1134
1135         while(!stopLoop) {
1136                 int dev_nr = 0;
1137                 /*
1138                  * Allow 60 seconds for any activity.
1139                  */
1140                 /*alarm(60);*/
1141
1142                 if (!recv_packet(opcode, sock, 1)) {
1143                         break;
1144                 }
1145 /*              if(opcode->data[0] != OP_CLOSE)*/
1146                     recv_packet(parm, sock, MAX_DATA_REQUEST);
1147
1148
1149                 switch(opcode->data[0]) {
1150                         case OP_OPRO:
1151                                 if(get_length(parm) >= 4)
1152                                         dev_nr = get_dword(parm,0);
1153                                 else
1154                                         dev_nr = 0;
1155                                 if(dev_nr >= n_dev) {
1156                                         send_reply(0, sock, -1);
1157                                         break;
1158                                 }
1159
1160                                 devFd = open(device_name[dev_nr],
1161                                              O_RDONLY | O_LARGEFILE);
1162 #if DEBUG
1163                                 fprintf(stderr, "Device opened\n");
1164 #endif
1165                                 if(devFd >= 0 && lock_dev(devFd, 0, NULL)) {
1166                                         send_reply(0, sock, -1);
1167                                         break;
1168                                 }
1169                                 send_reply(0, sock, devFd);
1170                                 readOnly = 1;
1171                                 break;
1172                         case OP_OPRW:
1173                                 if(get_length(parm) >= 4)
1174                                         dev_nr = get_dword(parm,0);
1175                                 else
1176                                         dev_nr = 0;
1177                                 if(dev_nr >= n_dev) {
1178                                         send_reply(0, sock, -1);
1179                                         break;
1180                                 }
1181                                 devFd = open(device_name[dev_nr], O_RDWR);
1182                                 if(devFd >= 0 && lock_dev(devFd, 1, NULL)) {
1183                                         send_reply(0, sock, -1);
1184                                         break;
1185                                 }
1186                                 send_reply(0, sock, devFd);
1187                                 readOnly = 0;
1188                                 break;
1189                         case OP_READ:
1190 #if DEBUG
1191                                 fprintf(stderr, "READ:\n");
1192 #endif
1193                                 read_packet(parm, devFd, get_dword(parm, 0));
1194                                 send_reply(devFd, sock, get_length(parm));
1195                                 if(get_length(parm) >= 0)
1196                                         send_packet(parm, sock);
1197                                 break;
1198                         case OP_WRITE:
1199 #if DEBUG
1200                                 fprintf(stderr, "WRITE:\n");
1201 #endif
1202                                 if(readOnly) {
1203                                         errno = -EROFS;
1204                                         rval = -1;
1205                                 } else {
1206                                         rval = write_packet(parm, devFd);
1207                                 }
1208                                 send_reply(devFd, sock, rval);
1209                                 break;
1210                         case OP_SEEK:
1211 #if DEBUG
1212                                 fprintf(stderr, "SEEK:\n");
1213 #endif
1214
1215                                 lseek(devFd, 
1216                                       get_dword(parm, 0), get_dword(parm, 4));
1217                                 send_reply(devFd, 
1218                                            sock, 
1219                                            lseek(devFd, 0, SEEK_CUR));
1220                                 break;
1221                         case OP_SEEK64:
1222                                 if(sizeof(mt_off_t) < 8) {
1223 #if DEBUG
1224                                         fprintf(stderr, "64 bit requested where not available!\n");
1225 #endif
1226                                         errno = EINVAL;
1227                                         send_reply(devFd, sock, -1);
1228                                         break;
1229                                 }
1230 #if DEBUG
1231                                 fprintf(stderr, "SEEK64:\n");
1232 #endif
1233                                 mt_lseek(devFd, 
1234                                          get_qword(parm,0), get_dword(parm,8));
1235                                 send_reply64(devFd, 
1236                                              sock, 
1237                                              mt_lseek(devFd, 0, SEEK_CUR));
1238                                 break;
1239                         case OP_FLUSH:
1240 #if DEBUG
1241                                 fprintf(stderr, "FLUSH:\n");
1242 #endif
1243                                 fsync(devFd);
1244                                 send_reply(devFd, sock, 0);
1245                                 break;
1246                         case OP_CLOSE:
1247 #if DEBUG
1248                                 fprintf(stderr, "CLOSE:\n");
1249 #endif
1250
1251                                 close(devFd);
1252                                 needSendReply = 1;
1253                                 rval = devFd;
1254                                 devFd = -1;
1255                                 stopLoop = 1;
1256                                 break;
1257                         case OP_IOCTL:
1258                                 /* Unimplemented for now... */
1259                                 break;
1260                         default:
1261 #if DEBUG
1262                                 fprintf(stderr, "Invalid Opcode!\n");
1263 #endif
1264                                 errno = EINVAL;
1265                                 send_reply(devFd, sock, -1);
1266                                 break;
1267                 }
1268                 kill_packet(parm);
1269                 alarm(0);
1270         }
1271
1272         
1273
1274 #if DEBUG
1275         fprintf(stderr, "Closing down...\n");
1276 #endif
1277
1278         if (devFd >= 0) {
1279                 close(devFd);
1280                 devFd = -1;
1281         }
1282
1283         free_io_buffer(sock);
1284
1285         /* remove "Lock"-File  */
1286         unlink(XauFileName());
1287
1288         if(needSendReply)
1289             send_reply(rval, sock, 0);
1290         destroyPacket(opcode);
1291         destroyPacket(parm);
1292 }
1293
1294 #else
1295 #include <stdio.h>
1296
1297 int main(int argc, char **argv) 
1298 {
1299         puts("Floppyd support not included!");
1300         return -1;
1301 }
1302         
1303 #endif