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