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