• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*  Copyright 1999 Peter Schlaile.
2  *  Copyright 1999-2002,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  * IO to the floppyd daemon running on the local X-Server Host
19  *
20  * written by:
21  *
22  * Peter Schlaile
23  *
24  * udbz@rz.uni-karlsruhe.de
25  *
26  */
27 
28 #include "sysincludes.h"
29 #include "stream.h"
30 #include "mtools.h"
31 #include "msdos.h"
32 #include "scsi.h"
33 #include "partition.h"
34 #include "floppyd_io.h"
35 
36 #ifdef USE_FLOPPYD
37 
38 /* ######################################################################## */
39 
40 
41 static const char* AuthErrors[] = {
42 	"Auth success",
43 	"Auth failed: Packet oversized",
44 	"Auth failed: X-Cookie doesn't match",
45 	"Auth failed: Wrong transmission protocol version",
46 	"Auth failed: Device locked"
47 	"Auth failed: Bad packet",
48 	"Auth failed: I/O Error"
49 };
50 
51 
52 typedef struct RemoteFile_t {
53 	Class_t *Class;
54 	int refs;
55 	Stream_t *Next;
56 	Stream_t *Buffer;
57 	int fd;
58 	mt_off_t offset;
59 	mt_off_t lastwhere;
60 	mt_off_t size;
61 	unsigned int version;
62 	unsigned int capabilities;
63 	int drive;
64 } RemoteFile_t;
65 
66 
67 #include "byte_dword.h"
68 #include "read_dword.h"
69 
70 
71 /* ######################################################################## */
72 
authenticate_to_floppyd(RemoteFile_t * floppyd,int sock,char * display)73 static unsigned int authenticate_to_floppyd(RemoteFile_t *floppyd,
74 					    int sock, char *display)
75 {
76 	size_t filelen;
77 	ssize_t newlen;
78 	Byte buf[16];
79 	const char *command[] = { "xauth", "xauth", "extract", "-", 0, 0 };
80 	char *xcookie;
81 	Dword errcode;
82 	int l;
83 
84 	command[4] = display;
85 
86 	filelen=strlen(display);
87 	filelen += 100;
88 
89 	xcookie = (char *) safe_malloc(filelen+4);
90 	newlen = safePopenOut(command, xcookie+4, filelen);
91 	if(newlen < 1)
92 		return AUTH_AUTHFAILED;
93 	filelen = (size_t) newlen;
94 
95 	/* Version negotiation */
96 	dword2byte(4,buf);
97 	dword2byte(floppyd->version,buf+4);
98 	if(write(sock, buf, 8) < 8)
99 		return AUTH_IO_ERROR;
100 
101 	if ( (l = (int) read_dword(sock)) < 4) {
102 		return AUTH_WRONGVERSION;
103 	}
104 
105 	errcode = read_dword(sock);
106 
107 	if (errcode != AUTH_SUCCESS) {
108 		return errcode;
109 	}
110 
111 	if(l >= 8)
112 		floppyd->version = read_dword(sock);
113 	if(l >= 12)
114 		floppyd->capabilities = read_dword(sock);
115 
116 	dword2byte(filelen, (Byte *)xcookie);
117 	if(write(sock, xcookie, filelen+4) < ((ssize_t) (filelen + 4)))
118 		return AUTH_IO_ERROR;
119 
120 	if (read_dword(sock) != 4) {
121 		return AUTH_PACKETOVERSIZE;
122 	}
123 
124 	errcode = read_dword(sock);
125 
126 	return errcode;
127 }
128 
129 
floppyd_reader(int fd,char * buffer,size_t len)130 static int floppyd_reader(int fd, char* buffer, size_t len)
131 {
132 	Dword errcode;
133 	Dword gotlen;
134 	Byte buf[16];
135 
136 	dword2byte(1, buf);
137 	buf[4] = OP_READ;
138 	dword2byte(4, buf+5);
139 	dword2byte(len, buf+9);
140 	if(write(fd, buf, 13) < 13)
141 		return AUTH_IO_ERROR;
142 
143 	if (read_dword(fd) != 8) {
144 		errno = EIO;
145 		return -1;
146 	}
147 
148 	gotlen = read_dword(fd);
149 	errcode = read_dword(fd);
150 
151 	if (gotlen != (Dword) -1) {
152 		size_t l;
153 		unsigned int start;
154 		if (read_dword(fd) != gotlen) {
155 			errno = EIO;
156 			return -1;
157 		}
158 		for (start = 0, l = 0; start < gotlen; start += l) {
159 			ssize_t ret = read(fd, buffer+start, gotlen-start);
160 			if( ret < 0)
161 				return -1;
162 			if (ret == 0) {
163 				errno = EIO;
164 				return -1;
165 			}
166 			l = (size_t) ret;
167 		}
168 	} else {
169 		errno = errcode;
170 	}
171 	return gotlen;
172 }
173 
floppyd_writer(int fd,char * buffer,size_t len)174 static int floppyd_writer(int fd, char* buffer, size_t len)
175 {
176 	Dword errcode;
177 	Dword gotlen;
178 	Byte buf[16];
179 
180 	dword2byte(1, buf);
181 	buf[4] = OP_WRITE;
182 	dword2byte(len, buf+5);
183 
184 	cork(fd, 1);
185 	if(write(fd, buf, 9) < 9)
186 		return AUTH_IO_ERROR;
187 	if(write(fd, buffer, len) < len)
188 		return AUTH_IO_ERROR;
189 	cork(fd, 0);
190 
191 	if (read_dword(fd) != 8) {
192 		errno = EIO;
193 		return -1;
194 	}
195 
196 	gotlen = read_dword(fd);
197 	errcode = read_dword(fd);
198 
199 	errno = errcode;
200 	if(errno != 0 && gotlen == 0) {
201 	    if (errno == EBADF)
202 		errno = EROFS;
203 	    gotlen = -1;
204 	}
205 
206 	return gotlen;
207 }
208 
floppyd_lseek(int fd,mt_off_t offset,int whence)209 static int floppyd_lseek(int fd, mt_off_t offset, int whence)
210 {
211 	Dword errcode;
212 	Dword gotlen;
213 	Byte buf[32];
214 
215 	dword2byte(1, buf);
216 	buf[4] = OP_SEEK;
217 
218 	dword2byte(8, buf+5);
219 	dword2byte(truncBytes32(offset), buf+9);
220 	dword2byte(whence, buf+13);
221 
222 	if(write(fd, buf, 17) < 17)
223 		return AUTH_IO_ERROR;
224 
225 	if (read_dword(fd) != 8) {
226 		errno = EIO;
227 		return -1;
228 	}
229 
230 	gotlen = read_dword(fd);
231 	errcode = read_dword(fd);
232 
233 	errno = errcode;
234 
235 	return gotlen;
236 }
237 
floppyd_lseek64(int fd,mt_off_t offset,int whence)238 static mt_off_t floppyd_lseek64(int fd, mt_off_t offset, int whence)
239 {
240 	Dword errcode;
241 	Qword gotlen;
242 	Byte buf[32];
243 
244 	dword2byte(1, buf);
245 	buf[4] = OP_SEEK64;
246 
247 	dword2byte(12, buf+5);
248 	qword2byte(offset, buf+9);
249 	dword2byte(whence, buf+17);
250 
251 	if(write(fd, buf, 21) < 21)
252 		return AUTH_IO_ERROR;
253 
254 	if (read_dword(fd) != 12) {
255 		errno = EIO;
256 		return -1;
257 	}
258 
259 	gotlen = read_qword(fd);
260 	errcode = read_dword(fd);
261 
262 	errno = errcode;
263 
264 	return gotlen;
265 }
266 
floppyd_open(RemoteFile_t * This,int mode)267 static int floppyd_open(RemoteFile_t *This, int mode)
268 {
269 	Dword errcode;
270 	Dword gotlen;
271 	Byte buf[16];
272 
273 	if(! (This->capabilities & FLOPPYD_CAP_EXPLICIT_OPEN) ) {
274 		/* floppyd has no "explicit seek" capabilities */
275 		return 0;
276 	}
277 
278 	dword2byte(1, buf);
279 	if((mode & O_ACCMODE) == O_RDONLY)
280 		buf[4] = OP_OPRO;
281 	else
282 		buf[4] = OP_OPRW;
283 	dword2byte(4, buf+5);
284 	dword2byte(This->drive, buf+9);
285 
286 	if(write(This->fd, buf, 13) < 13)
287 		return AUTH_IO_ERROR;
288 
289 	if (read_dword(This->fd) != 8) {
290 		errno = EIO;
291 		return -1;
292 	}
293 
294 	gotlen = read_dword(This->fd);
295 	errcode = read_dword(This->fd);
296 
297 	errno = errcode;
298 
299 	return gotlen;
300 }
301 
302 
303 /* ######################################################################## */
304 
305 typedef int (*iofn) (int, char *, size_t);
306 
floppyd_io(Stream_t * Stream,char * buf,mt_off_t where,size_t len,iofn io)307 static int floppyd_io(Stream_t *Stream, char *buf, mt_off_t where, size_t len,
308 		      iofn io)
309 {
310 	DeclareThis(RemoteFile_t);
311 	int ret;
312 
313 	where += This->offset;
314 
315 	if (where != This->lastwhere ){
316 		if(This->capabilities & FLOPPYD_CAP_LARGE_SEEK) {
317 			if(floppyd_lseek64( This->fd, where, SEEK_SET) < 0 ){
318 				perror("floppyd_lseek64");
319 				This->lastwhere = (mt_off_t) -1;
320 				return -1;
321 			}
322 		} else {
323 			if(floppyd_lseek( This->fd, where, SEEK_SET) < 0 ){
324 				perror("floppyd_lseek");
325 				This->lastwhere = (mt_off_t) -1;
326 				return -1;
327 			}
328 		}
329 	}
330 	ret = io(This->fd, buf, len);
331 	if ( ret == -1 ){
332 		perror("floppyd_io");
333 		This->lastwhere = (mt_off_t) -1;
334 		return -1;
335 	}
336 	This->lastwhere = where + ret;
337 	return ret;
338 }
339 
floppyd_read(Stream_t * Stream,char * buf,mt_off_t where,size_t len)340 static int floppyd_read(Stream_t *Stream, char *buf, mt_off_t where, size_t len)
341 {
342 	return floppyd_io(Stream, buf, where, len, floppyd_reader);
343 }
344 
floppyd_write(Stream_t * Stream,char * buf,mt_off_t where,size_t len)345 static int floppyd_write(Stream_t *Stream, char *buf, mt_off_t where, size_t len)
346 {
347 	return floppyd_io(Stream, buf, where, len, floppyd_writer);
348 }
349 
floppyd_flush(Stream_t * Stream)350 static int floppyd_flush(Stream_t *Stream)
351 {
352 	Byte buf[16];
353 
354 	DeclareThis(RemoteFile_t);
355 
356 	dword2byte(1, buf);
357 	buf[4] = OP_FLUSH;
358 	dword2byte(1, buf+5);
359 	buf[9] = '\0';
360 
361 	if(write(This->fd, buf, 10) < 10)
362 		return AUTH_IO_ERROR;
363 
364 	if (read_dword(This->fd) != 8) {
365 		errno = EIO;
366 		return -1;
367 	}
368 
369 	read_dword(This->fd);
370 	read_dword(This->fd);
371 	return 0;
372 }
373 
floppyd_free(Stream_t * Stream)374 static int floppyd_free(Stream_t *Stream)
375 {
376 	Byte buf[16];
377 	unsigned int gotlen;
378 	unsigned int errcode;
379 	DeclareThis(RemoteFile_t);
380 
381 	if (This->fd > 2) {
382 		dword2byte(1, buf);
383 		buf[4] = OP_CLOSE;
384 		if(write(This->fd, buf, 5) < 5)
385 			return AUTH_IO_ERROR;
386 		shutdown(This->fd, 1);
387 		if (read_dword(This->fd) != 8) {
388 		    errno = EIO;
389 		    return -1;
390 		}
391 
392 		gotlen = read_dword(This->fd);
393 		errcode = read_dword(This->fd);
394 
395 		errno = errcode;
396 
397 		close(This->fd);
398 		return gotlen;
399 	} else {
400 		return 0;
401 	}
402 }
403 
floppyd_geom(Stream_t * Stream,struct device * dev,struct device * orig_dev UNUSEDP,int media,union bootsector * boot)404 static int floppyd_geom(Stream_t *Stream, struct device *dev,
405 			struct device *orig_dev UNUSEDP,
406 			int media, union bootsector *boot)
407 {
408 	size_t tot_sectors;
409 	unsigned int sect_per_track;
410 	DeclareThis(RemoteFile_t);
411 
412 	dev->ssize = 2; /* allow for init_geom to change it */
413 	dev->use_2m = 0x80; /* disable 2m mode to begin */
414 
415 	if(media == 0xf0 || media >= 0x100){
416 		dev->heads = WORD(nheads);
417 		dev->sectors = WORD(nsect);
418 		tot_sectors = DWORD(bigsect);
419 		SET_INT(tot_sectors, WORD(psect));
420 		sect_per_track = dev->heads * dev->sectors;
421 		tot_sectors += sect_per_track - 1; /* round size up */
422 		dev->tracks = tot_sectors / sect_per_track;
423 
424 	} else
425 		if(setDeviceFromOldDos(media, dev) < 0)
426 			exit(1);
427 
428 	This->size = (mt_off_t) 512 * dev->sectors * dev->tracks * dev->heads;
429 
430 	return 0;
431 }
432 
433 
floppyd_data(Stream_t * Stream,time_t * date,mt_size_t * size,int * type,int * address)434 static int floppyd_data(Stream_t *Stream, time_t *date, mt_size_t *size,
435 		     int *type, int *address)
436 {
437 	DeclareThis(RemoteFile_t);
438 
439 	if(date)
440 		/* unknown, and irrelevant anyways */
441 		*date = 0;
442 	if(size)
443 		/* the size derived from the geometry */
444 		*size = (mt_size_t) This->size;
445 	if(type)
446 		*type = 0; /* not a directory */
447 	if(address)
448 		*address = 0;
449 	return 0;
450 }
451 
452 /* ######################################################################## */
453 
454 static Class_t FloppydFileClass = {
455 	floppyd_read,
456 	floppyd_write,
457 	floppyd_flush,
458 	floppyd_free,
459 	floppyd_geom,
460 	floppyd_data,
461 	0, /* pre_allocate */
462 	0, /* get_dosConvert */
463 	0  /* discard */
464 };
465 
466 /* ######################################################################## */
467 
get_host_and_port_and_drive(const char * name,char ** hostname,char ** display,uint16_t * port,int * drive)468 static int get_host_and_port_and_drive(const char* name, char** hostname,
469 				       char **display, uint16_t* port,
470 				       int *drive)
471 {
472 	char* newname = strdup(name);
473 	char* p;
474 	char* p2;
475 
476 	p = newname;
477 	while (*p != '/' && *p) p++;
478 	p2 = p;
479 	if (*p) p++;
480 	*p2 = 0;
481 
482 	*port = FLOPPYD_DEFAULT_PORT;
483 	if(*p >= '0' && *p <= '9')
484 	  *port = strtou16(p, &p, 0);
485 	if(*p == '/')
486 	  p++;
487 	*drive = 0;
488 	if(*p >= '0' && *p <= '9')
489 	  *drive = strtoi(p, &p, 0);
490 
491 	*display = strdup(newname);
492 
493 	p = newname;
494 	while (*p != ':' && *p) p++;
495 	p2 = p;
496 	if (*p) p++;
497 	*p2 = 0;
498 
499 	*port += atoi(p);  /* add display number to the port */
500 
501 	if (!*newname || strcmp(newname, "unix") == 0) {
502 		free(newname);
503 		newname = strdup("localhost");
504 	}
505 
506 	*hostname = newname;
507 	return 1;
508 }
509 
510 /*
511  *  * Return the IP address of the specified host.
512  *  */
getipaddress(char * ipaddr)513 static in_addr_t getipaddress(char *ipaddr)
514 {
515 	struct hostent  *host;
516 	in_addr_t        ip;
517 
518 	if (((ip = inet_addr(ipaddr)) == INADDR_NONE) &&
519 	    (strcmp(ipaddr, "255.255.255.255") != 0)) {
520 
521 		if ((host = gethostbyname(ipaddr)) != NULL) {
522 			memcpy(&ip, host->h_addr, sizeof(ip));
523 		}
524 
525 		endhostent();
526 	}
527 
528 #ifdef DEBUG
529 	fprintf(stderr, "IP lookup %s -> 0x%08lx\n", ipaddr, ip);
530 #endif
531 
532 	return (ip);
533 }
534 
535 /*
536  *  * Connect to the floppyd server.
537  *  */
connect_to_server(in_addr_t ip,uint16_t port)538 static int connect_to_server(in_addr_t ip, uint16_t port)
539 {
540 
541 	struct sockaddr_in      addr;
542 	int                     sock;
543 
544 	/*
545 	 * Allocate a socket.
546 	 */
547 	if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
548 		return (-1);
549 	}
550 
551 	/*
552 	 * Set the address to connect to.
553 	 */
554 
555 	addr.sin_family = AF_INET;
556 	addr.sin_port = htons(port);
557 	addr.sin_addr.s_addr = ip;
558 
559         /*
560 	 * Connect our socket to the above address.
561 	 */
562 	if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
563 		return (-1);
564 	}
565 
566         /*
567 	 * Set the keepalive socket option to on.
568 	 */
569 	{
570 		int             on = 1;
571 		setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
572 			   (char *)&on, sizeof(on));
573 	}
574 
575 	return (sock);
576 }
577 
578 static int ConnectToFloppyd(RemoteFile_t *floppyd, const char* name,
579 			    char *errmsg);
580 
FloppydOpen(struct device * dev,char * name,int mode,char * errmsg,mt_size_t * maxSize)581 Stream_t *FloppydOpen(struct device *dev,
582 		      char *name, int mode, char *errmsg,
583 		      mt_size_t *maxSize)
584 {
585 	RemoteFile_t *This;
586 
587 	if (!dev ||  !(dev->misc_flags & FLOPPYD_FLAG))
588 		return NULL;
589 
590 	This = New(RemoteFile_t);
591 	if (!This){
592 		printOom();
593 		return NULL;
594 	}
595 	This->Class = &FloppydFileClass;
596 	This->Next = 0;
597 	This->offset = 0;
598 	This->lastwhere = 0;
599 	This->refs = 1;
600 	This->Buffer = 0;
601 
602 	This->fd = ConnectToFloppyd(This, name, errmsg);
603 	if (This->fd == -1) {
604 		Free(This);
605 		return NULL;
606 	}
607 
608 	if(floppyd_open(This, mode) < 0) {
609 		sprintf(errmsg,
610 			"Can't open remote drive: %s", strerror(errno));
611 		close(This->fd);
612 		Free(This);
613 		return NULL;
614 	}
615 
616 	if(maxSize) {
617 		*maxSize =
618 			(This->capabilities & FLOPPYD_CAP_LARGE_SEEK) ?
619 			max_off_t_seek : max_off_t_31;
620 	}
621 	return (Stream_t *) This;
622 }
623 
ConnectToFloppyd(RemoteFile_t * floppyd,const char * name,char * errmsg)624 static int ConnectToFloppyd(RemoteFile_t *floppyd, const char* name,
625 			    char *errmsg)
626 {
627 	char* hostname;
628 	char* display;
629 	uint16_t port;
630 	int rval = get_host_and_port_and_drive(name, &hostname, &display,
631 					       &port, &floppyd->drive);
632 	int sock;
633 	unsigned int reply;
634 
635 	if (!rval) return -1;
636 
637 	floppyd->version = FLOPPYD_PROTOCOL_VERSION;
638 	floppyd->capabilities = 0;
639 	while(1) {
640 		sock = connect_to_server(getipaddress(hostname), port);
641 
642 		if (sock == -1) {
643 #ifdef HAVE_SNPRINTF
644 			snprintf(errmsg, 200,
645 				 "Can't connect to floppyd server on %s, port %i (%s)!",
646 				 hostname, port, strerror(errno));
647 #else
648 			sprintf(errmsg,
649 				 "Can't connect to floppyd server on %s, port %i!",
650 				 hostname, port);
651 #endif
652 			return -1;
653 		}
654 
655 		reply = authenticate_to_floppyd(floppyd, sock, display);
656 		if(floppyd->version == FLOPPYD_PROTOCOL_VERSION_OLD)
657 			break;
658 		if(reply == AUTH_WRONGVERSION) {
659 			/* fall back on old version */
660 			floppyd->version = FLOPPYD_PROTOCOL_VERSION_OLD;
661 			continue;
662 		}
663 		break;
664 	}
665 
666 	if (reply != 0) {
667 		fprintf(stderr,
668 			"Permission denied, authentication failed!\n"
669 			"%s\n", AuthErrors[reply]);
670 		return -1;
671 	}
672 
673 	free(hostname);
674 	free(display);
675 
676 	return sock;
677 }
678 #endif
679